opencode-codebase-index 0.25.0 → 0.25.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -328,7 +328,7 @@ var require_ignore = __commonJS({
328
328
  // path matching.
329
329
  // - check `string` either `MODE_IGNORE` or `MODE_CHECK_IGNORE`
330
330
  // @returns {TestResult} true if a file is ignored
331
- test(path30, checkUnignored, mode) {
331
+ test(path31, checkUnignored, mode) {
332
332
  let ignored = false;
333
333
  let unignored = false;
334
334
  let matchedRule;
@@ -337,7 +337,7 @@ var require_ignore = __commonJS({
337
337
  if (unignored === negative && ignored !== unignored || negative && !ignored && !unignored && !checkUnignored) {
338
338
  return;
339
339
  }
340
- const matched = rule[mode].test(path30);
340
+ const matched = rule[mode].test(path31);
341
341
  if (!matched) {
342
342
  return;
343
343
  }
@@ -358,17 +358,17 @@ var require_ignore = __commonJS({
358
358
  var throwError = (message, Ctor) => {
359
359
  throw new Ctor(message);
360
360
  };
361
- var checkPath = (path30, originalPath, doThrow) => {
362
- if (!isString(path30)) {
361
+ var checkPath = (path31, originalPath, doThrow) => {
362
+ if (!isString(path31)) {
363
363
  return doThrow(
364
364
  `path must be a string, but got \`${originalPath}\``,
365
365
  TypeError
366
366
  );
367
367
  }
368
- if (!path30) {
368
+ if (!path31) {
369
369
  return doThrow(`path must not be empty`, TypeError);
370
370
  }
371
- if (checkPath.isNotRelative(path30)) {
371
+ if (checkPath.isNotRelative(path31)) {
372
372
  const r = "`path.relative()`d";
373
373
  return doThrow(
374
374
  `path should be a ${r} string, but got "${originalPath}"`,
@@ -377,7 +377,7 @@ var require_ignore = __commonJS({
377
377
  }
378
378
  return true;
379
379
  };
380
- var isNotRelative = (path30) => REGEX_TEST_INVALID_PATH.test(path30);
380
+ var isNotRelative = (path31) => REGEX_TEST_INVALID_PATH.test(path31);
381
381
  checkPath.isNotRelative = isNotRelative;
382
382
  checkPath.convert = (p) => p;
383
383
  var Ignore2 = class {
@@ -407,19 +407,19 @@ var require_ignore = __commonJS({
407
407
  }
408
408
  // @returns {TestResult}
409
409
  _test(originalPath, cache, checkUnignored, slices) {
410
- const path30 = originalPath && checkPath.convert(originalPath);
410
+ const path31 = originalPath && checkPath.convert(originalPath);
411
411
  checkPath(
412
- path30,
412
+ path31,
413
413
  originalPath,
414
414
  this._strictPathCheck ? throwError : RETURN_FALSE
415
415
  );
416
- return this._t(path30, cache, checkUnignored, slices);
416
+ return this._t(path31, cache, checkUnignored, slices);
417
417
  }
418
- checkIgnore(path30) {
419
- if (!REGEX_TEST_TRAILING_SLASH.test(path30)) {
420
- return this.test(path30);
418
+ checkIgnore(path31) {
419
+ if (!REGEX_TEST_TRAILING_SLASH.test(path31)) {
420
+ return this.test(path31);
421
421
  }
422
- const slices = path30.split(SLASH2).filter(Boolean);
422
+ const slices = path31.split(SLASH2).filter(Boolean);
423
423
  slices.pop();
424
424
  if (slices.length) {
425
425
  const parent = this._t(
@@ -432,18 +432,18 @@ var require_ignore = __commonJS({
432
432
  return parent;
433
433
  }
434
434
  }
435
- return this._rules.test(path30, false, MODE_CHECK_IGNORE);
435
+ return this._rules.test(path31, false, MODE_CHECK_IGNORE);
436
436
  }
437
- _t(path30, cache, checkUnignored, slices) {
438
- if (path30 in cache) {
439
- return cache[path30];
437
+ _t(path31, cache, checkUnignored, slices) {
438
+ if (path31 in cache) {
439
+ return cache[path31];
440
440
  }
441
441
  if (!slices) {
442
- slices = path30.split(SLASH2).filter(Boolean);
442
+ slices = path31.split(SLASH2).filter(Boolean);
443
443
  }
444
444
  slices.pop();
445
445
  if (!slices.length) {
446
- return cache[path30] = this._rules.test(path30, checkUnignored, MODE_IGNORE);
446
+ return cache[path31] = this._rules.test(path31, checkUnignored, MODE_IGNORE);
447
447
  }
448
448
  const parent = this._t(
449
449
  slices.join(SLASH2) + SLASH2,
@@ -451,29 +451,29 @@ var require_ignore = __commonJS({
451
451
  checkUnignored,
452
452
  slices
453
453
  );
454
- return cache[path30] = parent.ignored ? parent : this._rules.test(path30, checkUnignored, MODE_IGNORE);
454
+ return cache[path31] = parent.ignored ? parent : this._rules.test(path31, checkUnignored, MODE_IGNORE);
455
455
  }
456
- ignores(path30) {
457
- return this._test(path30, this._ignoreCache, false).ignored;
456
+ ignores(path31) {
457
+ return this._test(path31, this._ignoreCache, false).ignored;
458
458
  }
459
459
  createFilter() {
460
- return (path30) => !this.ignores(path30);
460
+ return (path31) => !this.ignores(path31);
461
461
  }
462
462
  filter(paths) {
463
463
  return makeArray(paths).filter(this.createFilter());
464
464
  }
465
465
  // @returns {TestResult}
466
- test(path30) {
467
- return this._test(path30, this._testCache, true);
466
+ test(path31) {
467
+ return this._test(path31, this._testCache, true);
468
468
  }
469
469
  };
470
470
  var factory = (options) => new Ignore2(options);
471
- var isPathValid = (path30) => checkPath(path30 && checkPath.convert(path30), path30, RETURN_FALSE);
471
+ var isPathValid = (path31) => checkPath(path31 && checkPath.convert(path31), path31, RETURN_FALSE);
472
472
  var setupWindows = () => {
473
473
  const makePosix = (str) => /^\\\\\?\\/.test(str) || /["<>|\u0000-\u001F]+/u.test(str) ? str : str.replace(/\\/g, "/");
474
474
  checkPath.convert = makePosix;
475
475
  const REGEX_TEST_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i;
476
- checkPath.isNotRelative = (path30) => REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path30) || isNotRelative(path30);
476
+ checkPath.isNotRelative = (path31) => REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path31) || isNotRelative(path31);
477
477
  };
478
478
  if (
479
479
  // Detect `process` so that it can run in browsers.
@@ -651,7 +651,7 @@ var require_eventemitter3 = __commonJS({
651
651
  });
652
652
 
653
653
  // src/adapters/opencode.ts
654
- import * as path29 from "path";
654
+ import * as path30 from "path";
655
655
  import { fileURLToPath as fileURLToPath2 } from "url";
656
656
 
657
657
  // src/config/constants.ts
@@ -1749,8 +1749,8 @@ function loadMergedConfig(projectRoot, host) {
1749
1749
  }
1750
1750
 
1751
1751
  // src/tools/operations.ts
1752
- import { existsSync as existsSync12, realpathSync as realpathSync5, statSync as statSync5 } from "fs";
1753
- import * as path20 from "path";
1752
+ import { existsSync as existsSync13, realpathSync as realpathSync6, statSync as statSync5 } from "fs";
1753
+ import * as path21 from "path";
1754
1754
 
1755
1755
  // src/tools/knowledge-base-paths.ts
1756
1756
  import * as path8 from "path";
@@ -2599,8 +2599,8 @@ function formatExactSearchHandoff(results) {
2599
2599
  }
2600
2600
  function formatContextEvidence(result, index) {
2601
2601
  const symbol = result.name ? ` ${JSON.stringify(compactEvidenceValue(result.name, 80))}` : "";
2602
- const path30 = compactEvidenceValue(result.filePath, 120);
2603
- return `[${index}] ${result.chunkType}${symbol} in ${path30}:${result.startLine}-${result.endLine} (score ${result.score.toFixed(2)})`;
2602
+ const path31 = compactEvidenceValue(result.filePath, 120);
2603
+ return `[${index}] ${result.chunkType}${symbol} in ${path31}:${result.startLine}-${result.endLine} (score ${result.score.toFixed(2)})`;
2604
2604
  }
2605
2605
  function formatContextPack(heading, selected, candidateCount, duplicateCount, limitOmittedCount, budgetOmittedCount, includeExactSearchHandoff) {
2606
2606
  const lines = selected.map((result, index) => formatContextEvidence(result, index + 1));
@@ -3242,9 +3242,9 @@ function formatEffectivenessMetrics(snapshot) {
3242
3242
  }
3243
3243
 
3244
3244
  // src/utils/auto-index.ts
3245
- import { existsSync as existsSync7, realpathSync as realpathSync3 } from "fs";
3246
- import * as os3 from "os";
3247
- import * as path11 from "path";
3245
+ import { existsSync as existsSync8, realpathSync as realpathSync4 } from "fs";
3246
+ import * as os4 from "os";
3247
+ import * as path12 from "path";
3248
3248
 
3249
3249
  // src/indexer/index-lock.ts
3250
3250
  import { randomUUID } from "crypto";
@@ -3501,7 +3501,7 @@ function removeDeadReclaimMarker(lockPath, expectedOwner) {
3501
3501
  return true;
3502
3502
  }
3503
3503
  function reclaimDeadOwner(indexPath, lockPath, expectedOwner) {
3504
- const reclaimPath = path9.join(lockPath, RECLAIM_DIRECTORY_NAME);
3504
+ const reclaimPath2 = path9.join(lockPath, RECLAIM_DIRECTORY_NAME);
3505
3505
  const reclaimOwner = {
3506
3506
  pid: process.pid,
3507
3507
  hostname: os2.hostname(),
@@ -3510,19 +3510,19 @@ function reclaimDeadOwner(indexPath, lockPath, expectedOwner) {
3510
3510
  expectedOwnerToken: expectedOwner.token
3511
3511
  };
3512
3512
  for (let attempt = 0; attempt < 2; attempt += 1) {
3513
- if (publishJsonDirectory(reclaimPath, reclaimOwner)) break;
3513
+ if (publishJsonDirectory(reclaimPath2, reclaimOwner)) break;
3514
3514
  if (attempt === 0 && removeDeadReclaimMarker(lockPath, expectedOwner)) continue;
3515
3515
  return false;
3516
3516
  }
3517
3517
  try {
3518
- const currentReclaimer = readReclaimOwner(reclaimPath);
3518
+ const currentReclaimer = readReclaimOwner(reclaimPath2);
3519
3519
  const currentOwner = readDirectoryOwner(lockPath);
3520
3520
  if (!currentReclaimer || !sameReclaimOwner(currentReclaimer, reclaimOwner) || !currentOwner || !sameOwner(currentOwner, expectedOwner) || getOwnerLiveness(currentOwner) !== "dead") {
3521
3521
  return false;
3522
3522
  }
3523
3523
  publishRecoveryMarker(indexPath, expectedOwner);
3524
3524
  const ownerBeforeQuarantine = readDirectoryOwner(lockPath);
3525
- const reclaimerBeforeQuarantine = readReclaimOwner(reclaimPath);
3525
+ const reclaimerBeforeQuarantine = readReclaimOwner(reclaimPath2);
3526
3526
  if (!ownerBeforeQuarantine || !sameOwner(ownerBeforeQuarantine, expectedOwner) || getOwnerLiveness(ownerBeforeQuarantine) !== "dead" || !reclaimerBeforeQuarantine || !sameReclaimOwner(reclaimerBeforeQuarantine, reclaimOwner)) {
3527
3527
  return false;
3528
3528
  }
@@ -3692,10 +3692,893 @@ function completeLeaseRecovery(lease) {
3692
3692
  }
3693
3693
  }
3694
3694
 
3695
+ // src/utils/background-worker.ts
3696
+ import { createHash, randomUUID as randomUUID2 } from "crypto";
3697
+ import {
3698
+ existsSync as existsSync6,
3699
+ lstatSync as lstatSync2,
3700
+ mkdirSync as mkdirSync2,
3701
+ readFileSync as readFileSync5,
3702
+ realpathSync as realpathSync3,
3703
+ renameSync as renameSync2,
3704
+ rmSync as rmSync2,
3705
+ writeFileSync as writeFileSync2
3706
+ } from "fs";
3707
+ import * as os3 from "os";
3708
+ import * as path10 from "path";
3709
+ var OWNER_FILE_NAME2 = "owner.json";
3710
+ var HEARTBEAT_FILE_PREFIX = "heartbeat.";
3711
+ var RECLAIM_DIRECTORY_NAME2 = "reclaim";
3712
+ var REFRESH_REQUEST_FILE_NAME = "refresh-request.json";
3713
+ var HEARTBEAT_INTERVAL_MS = 5e3;
3714
+ var STALE_LEASE_MS = 3e4;
3715
+ var RETRY_DELAY_MS = 5e3;
3716
+ var UUID_PATTERN2 = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
3717
+ var BackgroundWorkerStopError = class extends Error {
3718
+ constructor(watcherError, autoIndexError) {
3719
+ super("Failed to stop background worker");
3720
+ this.watcherError = watcherError;
3721
+ this.autoIndexError = autoIndexError;
3722
+ this.name = "BackgroundWorkerStopError";
3723
+ }
3724
+ watcherError;
3725
+ autoIndexError;
3726
+ };
3727
+ var workers = /* @__PURE__ */ new Map();
3728
+ var workerKeysByProject = /* @__PURE__ */ new Map();
3729
+ var workerReplacementBarriers = /* @__PURE__ */ new Map();
3730
+ function getErrorCode2(error) {
3731
+ return typeof error === "object" && error !== null && "code" in error ? String(error.code) : void 0;
3732
+ }
3733
+ function canonicalizePath(targetPath) {
3734
+ const resolved = path10.resolve(targetPath);
3735
+ if (existsSync6(resolved)) {
3736
+ try {
3737
+ return realpathSync3.native(resolved);
3738
+ } catch {
3739
+ return resolved;
3740
+ }
3741
+ }
3742
+ const parent = path10.dirname(resolved);
3743
+ if (parent === resolved) return resolved;
3744
+ return path10.join(canonicalizePath(parent), path10.basename(resolved));
3745
+ }
3746
+ function projectLookupKey(projectRoot, host) {
3747
+ return `${host}::${canonicalizePath(projectRoot)}`;
3748
+ }
3749
+ function resolveIdentity(projectRoot, config, host) {
3750
+ const canonicalProjectRoot = canonicalizePath(projectRoot);
3751
+ const canonicalIndexPath = canonicalizePath(resolveProjectIndexPath(projectRoot, config.scope, host));
3752
+ return {
3753
+ canonicalIndexPath,
3754
+ canonicalProjectRoot,
3755
+ key: `${canonicalIndexPath}::${canonicalProjectRoot}`
3756
+ };
3757
+ }
3758
+ function controllerKey(identity, host) {
3759
+ return `${identity.key}::${host}`;
3760
+ }
3761
+ function leaseDirectoryName(identity) {
3762
+ const hash = createHash("sha256").update(identity.key).digest("hex").slice(0, 32);
3763
+ return `background-worker.${hash}.lease`;
3764
+ }
3765
+ function leasePathFor(identity) {
3766
+ return path10.join(identity.canonicalIndexPath, leaseDirectoryName(identity));
3767
+ }
3768
+ function parseOwner2(value) {
3769
+ if (typeof value !== "object" || value === null) return null;
3770
+ const candidate = value;
3771
+ if (candidate.version !== 1) return null;
3772
+ if (!Number.isInteger(candidate.pid) || (candidate.pid ?? 0) <= 0) return null;
3773
+ if (typeof candidate.hostname !== "string" || candidate.hostname.length === 0) return null;
3774
+ if (typeof candidate.startedAt !== "string" || Number.isNaN(Date.parse(candidate.startedAt))) return null;
3775
+ if (typeof candidate.heartbeatAt !== "string" || Number.isNaN(Date.parse(candidate.heartbeatAt))) return null;
3776
+ if (typeof candidate.projectRoot !== "string" || candidate.projectRoot.length === 0) return null;
3777
+ if (typeof candidate.indexPath !== "string" || candidate.indexPath.length === 0) return null;
3778
+ if (typeof candidate.token !== "string" || !UUID_PATTERN2.test(candidate.token)) return null;
3779
+ return candidate;
3780
+ }
3781
+ function parseHeartbeat(value, expectedToken) {
3782
+ if (typeof value !== "object" || value === null) return null;
3783
+ const candidate = value;
3784
+ if (candidate.version !== 1 || candidate.token !== expectedToken) return null;
3785
+ if (typeof candidate.heartbeatAt !== "string" || Number.isNaN(Date.parse(candidate.heartbeatAt))) return null;
3786
+ return candidate;
3787
+ }
3788
+ function parseReclaimOwner2(value) {
3789
+ if (typeof value !== "object" || value === null) return null;
3790
+ const candidate = value;
3791
+ if (candidate.version !== 1) return null;
3792
+ if (!Number.isInteger(candidate.pid) || (candidate.pid ?? 0) <= 0) return null;
3793
+ if (typeof candidate.hostname !== "string" || candidate.hostname.length === 0) return null;
3794
+ if (typeof candidate.startedAt !== "string" || Number.isNaN(Date.parse(candidate.startedAt))) return null;
3795
+ if (typeof candidate.token !== "string" || !UUID_PATTERN2.test(candidate.token)) return null;
3796
+ if (candidate.expectedOwnerToken !== null && (typeof candidate.expectedOwnerToken !== "string" || !UUID_PATTERN2.test(candidate.expectedOwnerToken))) return null;
3797
+ return candidate;
3798
+ }
3799
+ function heartbeatPath(leasePath, token) {
3800
+ return path10.join(leasePath, `${HEARTBEAT_FILE_PREFIX}${token}.json`);
3801
+ }
3802
+ function reclaimPath(leasePath) {
3803
+ return path10.join(leasePath, RECLAIM_DIRECTORY_NAME2);
3804
+ }
3805
+ function refreshRequestPath(leasePath) {
3806
+ return path10.join(leasePath, REFRESH_REQUEST_FILE_NAME);
3807
+ }
3808
+ function readLeaseOwner(leasePath) {
3809
+ try {
3810
+ return parseOwner2(JSON.parse(readFileSync5(path10.join(leasePath, OWNER_FILE_NAME2), "utf-8")));
3811
+ } catch {
3812
+ return null;
3813
+ }
3814
+ }
3815
+ function readOwner(leasePath) {
3816
+ const owner = readLeaseOwner(leasePath);
3817
+ if (!owner) return null;
3818
+ try {
3819
+ const heartbeat = parseHeartbeat(
3820
+ JSON.parse(readFileSync5(heartbeatPath(leasePath, owner.token), "utf-8")),
3821
+ owner.token
3822
+ );
3823
+ return heartbeat ? { ...owner, heartbeatAt: heartbeat.heartbeatAt } : owner;
3824
+ } catch {
3825
+ return owner;
3826
+ }
3827
+ }
3828
+ function readReclaimOwner2(leasePath) {
3829
+ try {
3830
+ return parseReclaimOwner2(JSON.parse(readFileSync5(path10.join(reclaimPath(leasePath), OWNER_FILE_NAME2), "utf-8")));
3831
+ } catch {
3832
+ return null;
3833
+ }
3834
+ }
3835
+ function ownerLiveness(owner) {
3836
+ if (owner.hostname !== os3.hostname()) return "unknown";
3837
+ try {
3838
+ process.kill(owner.pid, 0);
3839
+ return "alive";
3840
+ } catch (error) {
3841
+ const code = getErrorCode2(error);
3842
+ if (code === "ESRCH") return "dead";
3843
+ if (code === "EPERM") return "alive";
3844
+ return "unknown";
3845
+ }
3846
+ }
3847
+ function isHeartbeatExpired(owner) {
3848
+ return Date.now() - Date.parse(owner.heartbeatAt) >= STALE_LEASE_MS;
3849
+ }
3850
+ function sameOwner2(left, right) {
3851
+ return left.pid === right.pid && left.hostname === right.hostname && left.token === right.token;
3852
+ }
3853
+ function writeHeartbeat(leasePath, owner) {
3854
+ const targetPath = heartbeatPath(leasePath, owner.token);
3855
+ const temporaryPath = `${targetPath}.tmp.${process.pid}.${owner.token}.${randomUUID2()}`;
3856
+ const heartbeat = {
3857
+ version: 1,
3858
+ token: owner.token,
3859
+ heartbeatAt: owner.heartbeatAt
3860
+ };
3861
+ try {
3862
+ writeFileSync2(temporaryPath, JSON.stringify(heartbeat), {
3863
+ encoding: "utf-8",
3864
+ flag: "wx",
3865
+ mode: 384
3866
+ });
3867
+ renameSync2(temporaryPath, targetPath);
3868
+ const currentOwner = readLeaseOwner(leasePath);
3869
+ return currentOwner !== null && sameOwner2(currentOwner, owner);
3870
+ } finally {
3871
+ if (existsSync6(temporaryPath)) rmSync2(temporaryPath, { force: true });
3872
+ }
3873
+ }
3874
+ function requestRefreshFromLeader(leasePath, allowDisabledAutoIndex) {
3875
+ const requestPath = refreshRequestPath(leasePath);
3876
+ const temporaryPath = `${requestPath}.tmp.${process.pid}.${randomUUID2()}`;
3877
+ try {
3878
+ const request = {
3879
+ allowDisabledAutoIndex,
3880
+ requestedAt: (/* @__PURE__ */ new Date()).toISOString(),
3881
+ version: 1
3882
+ };
3883
+ writeFileSync2(temporaryPath, JSON.stringify(request), {
3884
+ encoding: "utf-8",
3885
+ flag: "wx",
3886
+ mode: 384
3887
+ });
3888
+ renameSync2(temporaryPath, requestPath);
3889
+ } catch (error) {
3890
+ if (getErrorCode2(error) !== "ENOENT") {
3891
+ console.error("[codebase-index] Failed to request background index refresh from the project worker:", error);
3892
+ }
3893
+ } finally {
3894
+ if (existsSync6(temporaryPath)) rmSync2(temporaryPath, { force: true });
3895
+ }
3896
+ }
3897
+ function consumeRefreshRequest(leasePath) {
3898
+ const requestPath = refreshRequestPath(leasePath);
3899
+ const claimedPath = `${requestPath}.handling.${process.pid}.${randomUUID2()}`;
3900
+ try {
3901
+ renameSync2(requestPath, claimedPath);
3902
+ } catch (error) {
3903
+ if (getErrorCode2(error) === "ENOENT") return null;
3904
+ throw error;
3905
+ }
3906
+ try {
3907
+ const value = JSON.parse(readFileSync5(claimedPath, "utf-8"));
3908
+ return {
3909
+ allowDisabledAutoIndex: value.version === 1 && value.allowDisabledAutoIndex === true,
3910
+ requestedAt: typeof value.requestedAt === "string" ? value.requestedAt : (/* @__PURE__ */ new Date()).toISOString(),
3911
+ version: 1
3912
+ };
3913
+ } catch {
3914
+ return { allowDisabledAutoIndex: false, requestedAt: (/* @__PURE__ */ new Date()).toISOString(), version: 1 };
3915
+ } finally {
3916
+ rmSync2(claimedPath, { force: true });
3917
+ }
3918
+ }
3919
+ function publishLease(leasePath, owner) {
3920
+ const candidatePath = `${leasePath}.candidate.${process.pid}.${owner.token}`;
3921
+ try {
3922
+ mkdirSync2(candidatePath, { mode: 448 });
3923
+ } catch (error) {
3924
+ if (getErrorCode2(error) === "ENOENT") return false;
3925
+ throw error;
3926
+ }
3927
+ try {
3928
+ writeFileSync2(path10.join(candidatePath, OWNER_FILE_NAME2), JSON.stringify(owner), {
3929
+ encoding: "utf-8",
3930
+ flag: "wx",
3931
+ mode: 384
3932
+ });
3933
+ if (existsSync6(leasePath)) return false;
3934
+ try {
3935
+ renameSync2(candidatePath, leasePath);
3936
+ return true;
3937
+ } catch (error) {
3938
+ if (existsSync6(leasePath) || getErrorCode2(error) === "ENOENT") return false;
3939
+ throw error;
3940
+ }
3941
+ } finally {
3942
+ if (existsSync6(candidatePath)) rmSync2(candidatePath, { recursive: true, force: true });
3943
+ }
3944
+ }
3945
+ function sameReclaimOwner2(left, right) {
3946
+ return left.pid === right.pid && left.hostname === right.hostname && left.token === right.token && left.expectedOwnerToken === right.expectedOwnerToken;
3947
+ }
3948
+ function reclaimerLiveness(owner) {
3949
+ return ownerLiveness(owner);
3950
+ }
3951
+ function isReclaimMarkerExpired(leasePath, owner) {
3952
+ const startedAt = owner ? Date.parse(owner.startedAt) : (() => {
3953
+ try {
3954
+ return lstatSync2(reclaimPath(leasePath)).mtimeMs;
3955
+ } catch {
3956
+ return Date.now();
3957
+ }
3958
+ })();
3959
+ return Date.now() - startedAt >= STALE_LEASE_MS;
3960
+ }
3961
+ function hasActiveReclaimMarker(leasePath, owner) {
3962
+ const marker = readReclaimOwner2(leasePath);
3963
+ return marker !== null && marker.expectedOwnerToken === owner.token && (marker.hostname !== os3.hostname() || ownerLiveness(owner) !== "alive");
3964
+ }
3965
+ function publishReclaimMarker(leasePath, expectedOwner) {
3966
+ const markerPath = reclaimPath(leasePath);
3967
+ const owner = {
3968
+ version: 1,
3969
+ pid: process.pid,
3970
+ hostname: os3.hostname(),
3971
+ startedAt: (/* @__PURE__ */ new Date()).toISOString(),
3972
+ token: randomUUID2(),
3973
+ expectedOwnerToken: expectedOwner?.token ?? null
3974
+ };
3975
+ try {
3976
+ mkdirSync2(markerPath, { mode: 448 });
3977
+ } catch (error) {
3978
+ if (getErrorCode2(error) === "EEXIST" || getErrorCode2(error) === "ENOENT") return null;
3979
+ throw error;
3980
+ }
3981
+ try {
3982
+ writeFileSync2(path10.join(markerPath, OWNER_FILE_NAME2), JSON.stringify(owner), {
3983
+ encoding: "utf-8",
3984
+ flag: "wx",
3985
+ mode: 384
3986
+ });
3987
+ return owner;
3988
+ } catch (error) {
3989
+ rmSync2(markerPath, { recursive: true, force: true });
3990
+ throw error;
3991
+ }
3992
+ }
3993
+ function removeExpiredReclaimMarker(leasePath, expectedOwner) {
3994
+ const marker = readReclaimOwner2(leasePath);
3995
+ const markerPath = reclaimPath(leasePath);
3996
+ if (!existsSync6(markerPath)) return false;
3997
+ if (marker && marker.expectedOwnerToken !== (expectedOwner?.token ?? null)) return false;
3998
+ if (marker && (reclaimerLiveness(marker) === "alive" || !isReclaimMarkerExpired(leasePath, marker))) return false;
3999
+ if (!marker && !isReclaimMarkerExpired(leasePath, null)) return false;
4000
+ const staleMarkerPath = `${markerPath}.stale.${marker?.pid ?? process.pid}.${marker?.token ?? randomUUID2()}.${randomUUID2()}`;
4001
+ try {
4002
+ renameSync2(markerPath, staleMarkerPath);
4003
+ } catch (error) {
4004
+ if (getErrorCode2(error) === "ENOENT") return false;
4005
+ throw error;
4006
+ }
4007
+ try {
4008
+ let claimedMarker = null;
4009
+ try {
4010
+ claimedMarker = parseReclaimOwner2(
4011
+ JSON.parse(readFileSync5(path10.join(staleMarkerPath, OWNER_FILE_NAME2), "utf-8"))
4012
+ );
4013
+ } catch {
4014
+ claimedMarker = null;
4015
+ }
4016
+ const markerMatches = marker ? claimedMarker !== null && sameReclaimOwner2(claimedMarker, marker) : claimedMarker === null;
4017
+ if (!markerMatches || !canReclaimLease(leasePath, expectedOwner)) {
4018
+ if (!existsSync6(markerPath) && existsSync6(staleMarkerPath)) renameSync2(staleMarkerPath, markerPath);
4019
+ return false;
4020
+ }
4021
+ rmSync2(staleMarkerPath, { recursive: true, force: true });
4022
+ return true;
4023
+ } catch (error) {
4024
+ if (getErrorCode2(error) === "ENOENT") return false;
4025
+ throw error;
4026
+ }
4027
+ }
4028
+ function canReclaimLease(leasePath, expectedOwner) {
4029
+ if (!existsSync6(leasePath)) return false;
4030
+ if (!expectedOwner) return false;
4031
+ const currentOwner = readOwner(leasePath);
4032
+ if (!currentOwner || !sameOwner2(currentOwner, expectedOwner)) return false;
4033
+ if (currentOwner.hostname === os3.hostname()) {
4034
+ return ownerLiveness(currentOwner) === "dead";
4035
+ }
4036
+ return isHeartbeatExpired(currentOwner);
4037
+ }
4038
+ function reclaimLease(leasePath, expectedOwner) {
4039
+ let marker = null;
4040
+ for (let attempt = 0; attempt < 2; attempt += 1) {
4041
+ marker = publishReclaimMarker(leasePath, expectedOwner);
4042
+ if (marker) break;
4043
+ if (attempt === 0 && removeExpiredReclaimMarker(leasePath, expectedOwner)) continue;
4044
+ return false;
4045
+ }
4046
+ if (!marker) return false;
4047
+ const markerPath = reclaimPath(leasePath);
4048
+ try {
4049
+ const currentMarker = readReclaimOwner2(leasePath);
4050
+ if (!currentMarker || !sameReclaimOwner2(currentMarker, marker) || !canReclaimLease(leasePath, expectedOwner)) {
4051
+ return false;
4052
+ }
4053
+ const stalePath = `${leasePath}.stale.${process.pid}.${marker.token}`;
4054
+ renameSync2(leasePath, stalePath);
4055
+ const quarantinedOwner = readOwner(stalePath);
4056
+ const quarantinedMarker = readReclaimOwner2(stalePath);
4057
+ if (!quarantinedMarker || !sameReclaimOwner2(quarantinedMarker, marker) || expectedOwner !== null && (!quarantinedOwner || !sameOwner2(quarantinedOwner, expectedOwner))) {
4058
+ if (!existsSync6(leasePath) && existsSync6(stalePath)) renameSync2(stalePath, leasePath);
4059
+ return false;
4060
+ }
4061
+ rmSync2(stalePath, { recursive: true, force: true });
4062
+ return true;
4063
+ } catch (error) {
4064
+ if (getErrorCode2(error) === "ENOENT") return false;
4065
+ throw error;
4066
+ } finally {
4067
+ const currentMarker = readReclaimOwner2(leasePath);
4068
+ if (currentMarker && sameReclaimOwner2(currentMarker, marker)) {
4069
+ rmSync2(markerPath, { recursive: true, force: true });
4070
+ }
4071
+ }
4072
+ }
4073
+ function acquireLease(identity) {
4074
+ mkdirSync2(identity.canonicalIndexPath, { recursive: true, mode: 448 });
4075
+ const canonicalIndexPath = realpathSync3.native(identity.canonicalIndexPath);
4076
+ const leasePath = path10.join(canonicalIndexPath, leaseDirectoryName({ ...identity, canonicalIndexPath }));
4077
+ for (let attempt = 0; attempt < 4; attempt += 1) {
4078
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
4079
+ const owner = {
4080
+ version: 1,
4081
+ pid: process.pid,
4082
+ hostname: os3.hostname(),
4083
+ startedAt: timestamp,
4084
+ heartbeatAt: timestamp,
4085
+ projectRoot: identity.canonicalProjectRoot,
4086
+ indexPath: canonicalIndexPath,
4087
+ token: randomUUID2()
4088
+ };
4089
+ if (publishLease(leasePath, owner)) {
4090
+ return { leasePath, owner };
4091
+ }
4092
+ const existingOwner = readOwner(leasePath);
4093
+ if (existingOwner) {
4094
+ if (canReclaimLease(leasePath, existingOwner) && reclaimLease(leasePath, existingOwner)) continue;
4095
+ return null;
4096
+ }
4097
+ return null;
4098
+ }
4099
+ return null;
4100
+ }
4101
+ function releaseLease(lease) {
4102
+ const currentOwner = readOwner(lease.leasePath);
4103
+ if (!currentOwner || !sameOwner2(currentOwner, lease.owner)) return false;
4104
+ const releasePath = `${lease.leasePath}.release.${lease.owner.pid}.${lease.owner.token}`;
4105
+ try {
4106
+ renameSync2(lease.leasePath, releasePath);
4107
+ } catch (error) {
4108
+ if (getErrorCode2(error) === "ENOENT") return false;
4109
+ throw error;
4110
+ }
4111
+ const claimedOwner = readOwner(releasePath);
4112
+ if (!claimedOwner || !sameOwner2(claimedOwner, lease.owner)) {
4113
+ if (!existsSync6(lease.leasePath) && existsSync6(releasePath)) {
4114
+ renameSync2(releasePath, lease.leasePath);
4115
+ }
4116
+ return false;
4117
+ }
4118
+ rmSync2(releasePath, { recursive: true, force: true });
4119
+ return true;
4120
+ }
4121
+ var BackgroundWorkerController = class {
4122
+ constructor(projectRoot, host, config, hooks, identity) {
4123
+ this.projectRoot = projectRoot;
4124
+ this.host = host;
4125
+ this.config = config;
4126
+ this.hooks = hooks;
4127
+ this.identity = identity;
4128
+ }
4129
+ projectRoot;
4130
+ host;
4131
+ config;
4132
+ hooks;
4133
+ identity;
4134
+ lease = null;
4135
+ watcher = null;
4136
+ leaderReady = Promise.resolve();
4137
+ heartbeatTimer = null;
4138
+ retryTimer = null;
4139
+ teardownRetryTimer = null;
4140
+ transition = Promise.resolve();
4141
+ stopPromise = null;
4142
+ stopped = false;
4143
+ stopping = false;
4144
+ losingLeadership = false;
4145
+ restartAfterStop = false;
4146
+ leaderWorkStopped = false;
4147
+ startingLeaderWork = false;
4148
+ stopAutoIndexOnTeardown = true;
4149
+ autoIndexStarted = false;
4150
+ reportedError = null;
4151
+ update(config, hooks, options) {
4152
+ const autoIndexWasEnabled = this.config.indexing.autoIndex;
4153
+ const shouldReplaceWatcher = this.watcher !== null && hooks.watcherFactory !== void 0 && (hooks.watcherFactory === null || hooks.replaceWatcher === true);
4154
+ this.config = config;
4155
+ this.hooks = {
4156
+ ...this.hooks,
4157
+ ...hooks,
4158
+ watcherFactory: hooks.watcherFactory === void 0 ? this.hooks.watcherFactory : hooks.watcherFactory,
4159
+ watcherFactoryForConfig: hooks.watcherFactoryForConfig === void 0 ? this.hooks.watcherFactoryForConfig : hooks.watcherFactoryForConfig
4160
+ };
4161
+ if (autoIndexWasEnabled && !config.indexing.autoIndex || options.restartAutoIndex === true && config.indexing.autoIndex && !this.startingLeaderWork) {
4162
+ this.autoIndexStarted = false;
4163
+ }
4164
+ if (!this.canRun()) {
4165
+ void this.stop().catch((error) => {
4166
+ console.error("[codebase-index] Failed to stop background worker after disabling automatic work:", error);
4167
+ });
4168
+ return;
4169
+ }
4170
+ if (shouldReplaceWatcher) {
4171
+ void this.enqueue(async () => {
4172
+ const watcher = this.watcher;
4173
+ if (watcher) {
4174
+ await watcher.stop();
4175
+ if (this.watcher === watcher) this.watcher = null;
4176
+ }
4177
+ if (this.lease && !this.stopped) this.startLeaderWork();
4178
+ }).catch((error) => {
4179
+ console.error("[codebase-index] Failed to replace background file watcher:", error);
4180
+ });
4181
+ }
4182
+ this.start();
4183
+ }
4184
+ startAfter(activation) {
4185
+ this.transition = activation.catch(() => void 0);
4186
+ this.start();
4187
+ }
4188
+ start() {
4189
+ if (!this.canRun() || this.losingLeadership) return;
4190
+ if (this.stopping) {
4191
+ this.restartAfterStop = true;
4192
+ return;
4193
+ }
4194
+ this.stopped = false;
4195
+ void this.enqueue(async () => {
4196
+ if (this.stopped || this.stopping || this.losingLeadership || !this.canRun()) return;
4197
+ if (!this.lease) {
4198
+ try {
4199
+ this.lease = acquireLease(this.identity);
4200
+ this.reportedError = null;
4201
+ } catch (error) {
4202
+ this.reportAcquireError(error);
4203
+ this.scheduleRetry();
4204
+ return;
4205
+ }
4206
+ }
4207
+ if (!this.lease) {
4208
+ this.scheduleRetry();
4209
+ return;
4210
+ }
4211
+ this.startHeartbeat();
4212
+ this.startLeaderWork();
4213
+ });
4214
+ }
4215
+ waitForStart() {
4216
+ return this.transition.catch(() => void 0).then(() => this.leaderReady);
4217
+ }
4218
+ requestRefresh(allowDisabledAutoIndex = false) {
4219
+ this.start();
4220
+ if (!this.isLeader()) {
4221
+ requestRefreshFromLeader(leasePathFor(this.identity), allowDisabledAutoIndex);
4222
+ return;
4223
+ }
4224
+ void this.enqueue(async () => {
4225
+ if (this.stopped || !this.lease) return;
4226
+ this.hooks.startAutoIndex("retrieval", allowDisabledAutoIndex);
4227
+ });
4228
+ }
4229
+ isLeader() {
4230
+ return this.lease !== null && !this.stopping && !this.losingLeadership;
4231
+ }
4232
+ isStopping() {
4233
+ return this.stopping;
4234
+ }
4235
+ getHooksForConfig(config) {
4236
+ const watcherFactoryForConfig = this.hooks.watcherFactoryForConfig;
4237
+ if (!watcherFactoryForConfig) return this.hooks;
4238
+ return {
4239
+ ...this.hooks,
4240
+ watcherFactory: watcherFactoryForConfig(config),
4241
+ replaceWatcher: true
4242
+ };
4243
+ }
4244
+ attachWatcher(watcherFactory, watcherFactoryForConfig) {
4245
+ if (this.hooks.watcherFactory !== void 0) return;
4246
+ this.hooks = {
4247
+ ...this.hooks,
4248
+ watcherFactory,
4249
+ watcherFactoryForConfig: watcherFactoryForConfig ?? this.hooks.watcherFactoryForConfig
4250
+ };
4251
+ this.start();
4252
+ }
4253
+ async stop(stopAutoIndex = true) {
4254
+ if (this.stopPromise) return this.stopPromise;
4255
+ this.stopped = true;
4256
+ this.stopping = true;
4257
+ this.stopAutoIndexOnTeardown &&= stopAutoIndex;
4258
+ this.clearRetryTimer();
4259
+ const attempt = this.enqueue(async () => {
4260
+ try {
4261
+ const lease = this.lease;
4262
+ if (this.leaderWorkStopped) {
4263
+ if (lease) {
4264
+ this.releaseStoppedLease(lease);
4265
+ } else {
4266
+ this.finishStoppedLease();
4267
+ }
4268
+ return;
4269
+ }
4270
+ const hadLeaderWork = lease !== null || this.watcher !== null || this.autoIndexStarted;
4271
+ const stopped = await this.stopLeaderWork(hadLeaderWork && this.stopAutoIndexOnTeardown);
4272
+ if (!lease) {
4273
+ this.finishStoppedLease();
4274
+ return;
4275
+ }
4276
+ if (!stopped.completed) {
4277
+ this.releaseLeaseWhenAutoIndexStops(lease, stopped.completion);
4278
+ return;
4279
+ }
4280
+ this.leaderWorkStopped = true;
4281
+ this.releaseStoppedLease(lease);
4282
+ } catch (error) {
4283
+ this.scheduleTeardownRetry();
4284
+ throw error;
4285
+ }
4286
+ });
4287
+ const completion = attempt.finally(() => {
4288
+ if (this.stopPromise === completion) this.stopPromise = null;
4289
+ });
4290
+ this.stopPromise = completion;
4291
+ return completion;
4292
+ }
4293
+ canRun() {
4294
+ return this.config.indexing.autoIndex || this.hooks.watcherFactory != null;
4295
+ }
4296
+ enqueue(operation) {
4297
+ const next = this.transition.catch(() => void 0).then(operation);
4298
+ this.transition = next;
4299
+ return next;
4300
+ }
4301
+ startLeaderWork() {
4302
+ if (this.stopped || this.stopping || this.losingLeadership) return;
4303
+ this.startingLeaderWork = true;
4304
+ try {
4305
+ if (this.config.indexing.autoIndex && !this.autoIndexStarted) {
4306
+ this.autoIndexStarted = true;
4307
+ this.hooks.startAutoIndex("startup");
4308
+ }
4309
+ if (!this.watcher && this.hooks.watcherFactory) {
4310
+ try {
4311
+ const watcher = this.hooks.watcherFactory();
4312
+ this.watcher = watcher;
4313
+ this.leaderReady = watcher.whenReady?.().catch((error) => {
4314
+ console.error("[codebase-index] Failed while waiting for background file watcher startup:", error);
4315
+ }) ?? Promise.resolve();
4316
+ } catch (error) {
4317
+ console.error("[codebase-index] Failed to start background file watcher:", error);
4318
+ this.leaderReady = Promise.resolve();
4319
+ }
4320
+ }
4321
+ } finally {
4322
+ this.startingLeaderWork = false;
4323
+ }
4324
+ }
4325
+ async stopLeaderWork(stopAutoIndex) {
4326
+ const watcher = this.watcher;
4327
+ let watcherError;
4328
+ if (watcher) {
4329
+ try {
4330
+ await watcher.stop();
4331
+ if (this.watcher === watcher) this.watcher = null;
4332
+ } catch (error) {
4333
+ watcherError = error;
4334
+ }
4335
+ }
4336
+ let autoIndexError;
4337
+ let autoIndexStop = {
4338
+ completed: true,
4339
+ completion: Promise.resolve()
4340
+ };
4341
+ if (stopAutoIndex) {
4342
+ try {
4343
+ autoIndexStop = await this.hooks.stopAutoIndex();
4344
+ this.autoIndexStarted = false;
4345
+ } catch (error) {
4346
+ autoIndexError = error;
4347
+ }
4348
+ }
4349
+ if (watcherError !== void 0 || autoIndexError !== void 0) {
4350
+ throw new BackgroundWorkerStopError(watcherError, autoIndexError);
4351
+ }
4352
+ return autoIndexStop;
4353
+ }
4354
+ releaseLeaseWhenAutoIndexStops(lease, completion) {
4355
+ void completion.then(
4356
+ () => {
4357
+ void this.enqueue(async () => {
4358
+ if (this.lease !== lease || !this.stopping) return;
4359
+ this.leaderWorkStopped = true;
4360
+ this.releaseStoppedLease(lease);
4361
+ }).catch((error) => {
4362
+ console.error("[codebase-index] Failed to release background worker lease after automatic indexing stopped:", error);
4363
+ this.scheduleTeardownRetry();
4364
+ });
4365
+ },
4366
+ (error) => {
4367
+ console.error("[codebase-index] Failed while waiting for automatic indexing to stop:", error);
4368
+ this.scheduleTeardownRetry();
4369
+ }
4370
+ );
4371
+ }
4372
+ releaseStoppedLease(lease) {
4373
+ if (this.lease !== lease) {
4374
+ this.finishStoppedLease();
4375
+ return;
4376
+ }
4377
+ releaseLease(lease);
4378
+ this.lease = null;
4379
+ this.finishStoppedLease();
4380
+ }
4381
+ finishStoppedLease() {
4382
+ this.leaderWorkStopped = false;
4383
+ this.stopAutoIndexOnTeardown = true;
4384
+ this.stopping = false;
4385
+ this.clearTimers();
4386
+ this.restartAfterTeardown();
4387
+ if (!this.stopped || this.stopping) return;
4388
+ const projectKey = projectLookupKey(this.projectRoot, this.host);
4389
+ const key = controllerKey(this.identity, this.host);
4390
+ if (workers.get(key) === this) workers.delete(key);
4391
+ if (workerKeysByProject.get(projectKey) === key) workerKeysByProject.delete(projectKey);
4392
+ }
4393
+ startHeartbeat() {
4394
+ if (this.heartbeatTimer) return;
4395
+ const heartbeat = () => {
4396
+ void this.heartbeat();
4397
+ };
4398
+ this.heartbeatTimer = setInterval(heartbeat, HEARTBEAT_INTERVAL_MS);
4399
+ this.heartbeatTimer.unref?.();
4400
+ }
4401
+ async heartbeat() {
4402
+ const lease = this.lease;
4403
+ if (!lease || this.losingLeadership || this.stopped && !this.stopping) return;
4404
+ if (hasActiveReclaimMarker(lease.leasePath, lease.owner)) {
4405
+ await this.loseLeadership();
4406
+ return;
4407
+ }
4408
+ const currentOwner = readOwner(lease.leasePath);
4409
+ if (!currentOwner || !sameOwner2(currentOwner, lease.owner)) {
4410
+ await this.loseLeadership();
4411
+ return;
4412
+ }
4413
+ try {
4414
+ const nextOwner = { ...lease.owner, heartbeatAt: (/* @__PURE__ */ new Date()).toISOString() };
4415
+ if (!writeHeartbeat(lease.leasePath, nextOwner)) {
4416
+ await this.loseLeadership();
4417
+ return;
4418
+ }
4419
+ lease.owner = nextOwner;
4420
+ const refreshRequest = !this.stopping ? consumeRefreshRequest(lease.leasePath) : null;
4421
+ if (refreshRequest) {
4422
+ this.hooks.startAutoIndex("retrieval", refreshRequest.allowDisabledAutoIndex);
4423
+ }
4424
+ } catch (error) {
4425
+ const ownerAfterError = readOwner(lease.leasePath);
4426
+ if (hasActiveReclaimMarker(lease.leasePath, lease.owner) || !ownerAfterError || !sameOwner2(ownerAfterError, lease.owner)) {
4427
+ await this.loseLeadership();
4428
+ return;
4429
+ }
4430
+ console.error("[codebase-index] Failed to renew background worker lease:", error);
4431
+ }
4432
+ }
4433
+ async loseLeadership() {
4434
+ if (this.losingLeadership) return;
4435
+ this.losingLeadership = true;
4436
+ this.clearHeartbeat();
4437
+ await this.enqueue(async () => this.stopAfterLeadershipLoss());
4438
+ }
4439
+ async stopAfterLeadershipLoss() {
4440
+ const lease = this.lease;
4441
+ if (!lease) {
4442
+ this.losingLeadership = false;
4443
+ return;
4444
+ }
4445
+ try {
4446
+ const stopped = await this.stopLeaderWork(true);
4447
+ this.lease = null;
4448
+ this.losingLeadership = false;
4449
+ if (stopped.completed) {
4450
+ this.scheduleRetry();
4451
+ } else {
4452
+ void stopped.completion.then(() => this.scheduleRetry());
4453
+ }
4454
+ } catch (error) {
4455
+ console.error("[codebase-index] Failed to stop background work after losing its lease:", error);
4456
+ this.scheduleLostLeadershipTeardownRetry();
4457
+ }
4458
+ }
4459
+ scheduleRetry() {
4460
+ if (this.stopped || !this.canRun() || this.retryTimer) return;
4461
+ this.retryTimer = setTimeout(() => {
4462
+ this.retryTimer = null;
4463
+ this.start();
4464
+ }, RETRY_DELAY_MS);
4465
+ this.retryTimer.unref?.();
4466
+ }
4467
+ scheduleTeardownRetry() {
4468
+ if (!this.stopping || this.teardownRetryTimer) return;
4469
+ this.teardownRetryTimer = setTimeout(() => {
4470
+ this.teardownRetryTimer = null;
4471
+ void this.stop(this.stopAutoIndexOnTeardown).catch((error) => {
4472
+ console.error("[codebase-index] Failed to retry background worker teardown:", error);
4473
+ });
4474
+ }, RETRY_DELAY_MS);
4475
+ this.teardownRetryTimer.unref?.();
4476
+ }
4477
+ restartAfterTeardown() {
4478
+ if (!this.restartAfterStop || !this.canRun() || this.losingLeadership) return;
4479
+ this.restartAfterStop = false;
4480
+ this.stopped = false;
4481
+ this.start();
4482
+ }
4483
+ scheduleLostLeadershipTeardownRetry() {
4484
+ if (this.stopped || !this.losingLeadership || this.retryTimer) return;
4485
+ this.retryTimer = setTimeout(() => {
4486
+ this.retryTimer = null;
4487
+ void this.enqueue(async () => this.stopAfterLeadershipLoss());
4488
+ }, RETRY_DELAY_MS);
4489
+ this.retryTimer.unref?.();
4490
+ }
4491
+ clearHeartbeat() {
4492
+ if (!this.heartbeatTimer) return;
4493
+ clearInterval(this.heartbeatTimer);
4494
+ this.heartbeatTimer = null;
4495
+ }
4496
+ clearTimers() {
4497
+ this.clearHeartbeat();
4498
+ this.clearRetryTimer();
4499
+ if (this.teardownRetryTimer) {
4500
+ clearTimeout(this.teardownRetryTimer);
4501
+ this.teardownRetryTimer = null;
4502
+ }
4503
+ }
4504
+ clearRetryTimer() {
4505
+ if (!this.retryTimer) return;
4506
+ clearTimeout(this.retryTimer);
4507
+ this.retryTimer = null;
4508
+ }
4509
+ reportAcquireError(error) {
4510
+ const message = error instanceof Error ? error.message : String(error);
4511
+ if (this.reportedError === message) return;
4512
+ this.reportedError = message;
4513
+ console.error("[codebase-index] Failed to acquire background worker lease:", error);
4514
+ }
4515
+ };
4516
+ function configureBackgroundWorker(projectRoot, host, config, hooks, options = {}) {
4517
+ const projectKey = projectLookupKey(projectRoot, host);
4518
+ const identity = resolveIdentity(projectRoot, config, host);
4519
+ const key = controllerKey(identity, host);
4520
+ const previousKey = workerKeysByProject.get(projectKey);
4521
+ if (previousKey && previousKey !== key) {
4522
+ const previous = workers.get(previousKey);
4523
+ const previousBarrier = workerReplacementBarriers.get(projectKey) ?? Promise.resolve();
4524
+ const stopPrevious = previous?.stop(options.stopPreviousAutoIndex ?? true) ?? Promise.resolve();
4525
+ const activation = Promise.all([previousBarrier, stopPrevious]).then(() => void 0);
4526
+ workerReplacementBarriers.set(projectKey, activation);
4527
+ workers.delete(previousKey);
4528
+ const worker2 = new BackgroundWorkerController(projectRoot, host, config, hooks, identity);
4529
+ worker2.startAfter(activation);
4530
+ workers.set(key, worker2);
4531
+ workerKeysByProject.set(projectKey, key);
4532
+ return;
4533
+ }
4534
+ let worker = workers.get(key);
4535
+ if (!worker) {
4536
+ worker = new BackgroundWorkerController(projectRoot, host, config, hooks, identity);
4537
+ workers.set(key, worker);
4538
+ } else {
4539
+ worker.update(config, hooks, options);
4540
+ }
4541
+ workerKeysByProject.set(projectKey, key);
4542
+ worker.start();
4543
+ }
4544
+ function updateBackgroundWorkerConfig(projectRoot, host, config) {
4545
+ const projectKey = projectLookupKey(projectRoot, host);
4546
+ const key = workerKeysByProject.get(projectKey);
4547
+ const worker = key ? workers.get(key) : void 0;
4548
+ if (!worker) return;
4549
+ configureBackgroundWorker(projectRoot, host, config, worker.getHooksForConfig(config), {
4550
+ stopPreviousAutoIndex: false,
4551
+ restartAutoIndex: true
4552
+ });
4553
+ }
4554
+ function waitForBackgroundWorkerStart(projectRoot, host) {
4555
+ const key = workerKeysByProject.get(projectLookupKey(projectRoot, host));
4556
+ return workers.get(key ?? "")?.waitForStart() ?? Promise.resolve();
4557
+ }
4558
+ function requestBackgroundWorkerRefresh(projectRoot, host, allowDisabledAutoIndex = false) {
4559
+ const key = workerKeysByProject.get(projectLookupKey(projectRoot, host));
4560
+ workers.get(key ?? "")?.requestRefresh(allowDisabledAutoIndex);
4561
+ }
4562
+ function isBackgroundWorkerManaged(projectRoot, host) {
4563
+ const key = workerKeysByProject.get(projectLookupKey(projectRoot, host));
4564
+ return key !== void 0 && workers.has(key);
4565
+ }
4566
+ function isBackgroundWorkerLeader(projectRoot, host) {
4567
+ const key = workerKeysByProject.get(projectLookupKey(projectRoot, host));
4568
+ return key !== void 0 && workers.get(key)?.isLeader() === true;
4569
+ }
4570
+ async function stopBackgroundWorker(projectRoot, host) {
4571
+ const projectKey = projectLookupKey(projectRoot, host);
4572
+ const key = workerKeysByProject.get(projectKey);
4573
+ const worker = key ? workers.get(key) : void 0;
4574
+ if (!worker) return;
4575
+ await worker.stop();
4576
+ }
4577
+
3695
4578
  // src/utils/files.ts
3696
4579
  var import_ignore = __toESM(require_ignore(), 1);
3697
- import { existsSync as existsSync6, readFileSync as readFileSync5, promises as fsPromises } from "fs";
3698
- import * as path10 from "path";
4580
+ import { existsSync as existsSync7, readFileSync as readFileSync6, promises as fsPromises } from "fs";
4581
+ import * as path11 from "path";
3699
4582
  var PROJECT_MARKERS = [
3700
4583
  ".git",
3701
4584
  "package.json",
@@ -3713,7 +4596,7 @@ var PROJECT_MARKERS = [
3713
4596
  ];
3714
4597
  function hasProjectMarker(projectRoot) {
3715
4598
  for (const marker of PROJECT_MARKERS) {
3716
- if (existsSync6(path10.join(projectRoot, marker))) {
4599
+ if (existsSync7(path11.join(projectRoot, marker))) {
3717
4600
  return true;
3718
4601
  }
3719
4602
  }
@@ -3740,33 +4623,53 @@ function createIgnoreFilter(projectRoot) {
3740
4623
  "**/*build*/**"
3741
4624
  ];
3742
4625
  ig.add(defaultIgnores);
3743
- const gitignorePath = path10.join(projectRoot, ".gitignore");
3744
- if (existsSync6(gitignorePath)) {
3745
- const gitignoreContent = readFileSync5(gitignorePath, "utf-8");
4626
+ const gitignorePath = path11.join(projectRoot, ".gitignore");
4627
+ if (existsSync7(gitignorePath)) {
4628
+ const gitignoreContent = readFileSync6(gitignorePath, "utf-8");
3746
4629
  ig.add(gitignoreContent);
3747
4630
  }
3748
4631
  return ig;
3749
4632
  }
3750
- function shouldIncludeFile(filePath, projectRoot, includePatterns, excludePatterns, ignoreFilter) {
3751
- const relativePath = path10.relative(projectRoot, filePath);
3752
- if (hasFilteredPathSegment(relativePath, path10.sep)) {
3753
- return false;
3754
- }
3755
- if (ignoreFilter.ignores(relativePath)) {
3756
- return false;
4633
+ function toPosixRelativePath(relativePath) {
4634
+ return relativePath.split(path11.sep).join("/");
4635
+ }
4636
+ function matchesAnyGlob(filePath, patterns) {
4637
+ const normalized = toPosixRelativePath(filePath);
4638
+ return patterns.some((pattern) => matchGlob(normalized, pattern));
4639
+ }
4640
+ function isExcludedByPatterns(relativePath, excludePatterns) {
4641
+ return matchesAnyGlob(relativePath, excludePatterns);
4642
+ }
4643
+ function isExcludedDirectory(relativePath, excludePatterns) {
4644
+ const normalized = toPosixRelativePath(relativePath);
4645
+ if (matchesAnyGlob(normalized, excludePatterns)) {
4646
+ return true;
3757
4647
  }
3758
4648
  for (const pattern of excludePatterns) {
3759
- if (matchGlob(relativePath, pattern)) {
3760
- return false;
4649
+ const posixPattern = toPosixRelativePath(pattern).replace(/\/+$/, "");
4650
+ if (!posixPattern.endsWith("/**")) {
4651
+ continue;
3761
4652
  }
3762
- }
3763
- for (const pattern of includePatterns) {
3764
- if (matchGlob(relativePath, pattern)) {
4653
+ const directoryPattern = posixPattern.slice(0, -3);
4654
+ if (directoryPattern && matchesAnyGlob(normalized, [directoryPattern])) {
3765
4655
  return true;
3766
4656
  }
3767
4657
  }
3768
4658
  return false;
3769
4659
  }
4660
+ function shouldIncludeFile(filePath, projectRoot, includePatterns, excludePatterns, ignoreFilter) {
4661
+ const relativePath = toPosixRelativePath(path11.relative(projectRoot, filePath));
4662
+ if (hasFilteredPathSegment(relativePath, "/")) {
4663
+ return false;
4664
+ }
4665
+ if (ignoreFilter.ignores(relativePath)) {
4666
+ return false;
4667
+ }
4668
+ if (isExcludedByPatterns(relativePath, excludePatterns)) {
4669
+ return false;
4670
+ }
4671
+ return matchesAnyGlob(relativePath, includePatterns);
4672
+ }
3770
4673
  function matchGlob(filePath, pattern) {
3771
4674
  if (pattern.startsWith("**/")) {
3772
4675
  const withoutPrefix = pattern.slice(3);
@@ -3787,8 +4690,8 @@ async function* walkDirectory(dir, projectRoot, includePatterns, excludePatterns
3787
4690
  const filesInDir = [];
3788
4691
  const subdirs = [];
3789
4692
  for (const entry of entries) {
3790
- const fullPath = path10.join(dir, entry.name);
3791
- const relativePath = path10.relative(projectRoot, fullPath);
4693
+ const fullPath = path11.join(dir, entry.name);
4694
+ const relativePath = toPosixRelativePath(path11.relative(projectRoot, fullPath));
3792
4695
  if (isHiddenPathSegment(entry.name)) {
3793
4696
  if (entry.isDirectory()) {
3794
4697
  skipped.push({ path: relativePath, reason: "excluded" });
@@ -3806,6 +4709,10 @@ async function* walkDirectory(dir, projectRoot, includePatterns, excludePatterns
3806
4709
  continue;
3807
4710
  }
3808
4711
  if (entry.isDirectory()) {
4712
+ if (isExcludedDirectory(relativePath, excludePatterns)) {
4713
+ skipped.push({ path: relativePath, reason: "excluded" });
4714
+ continue;
4715
+ }
3809
4716
  subdirs.push({ fullPath, relativePath });
3810
4717
  } else if (entry.isFile()) {
3811
4718
  const stat5 = await fsPromises.stat(fullPath);
@@ -3813,20 +4720,11 @@ async function* walkDirectory(dir, projectRoot, includePatterns, excludePatterns
3813
4720
  skipped.push({ path: relativePath, reason: "too_large" });
3814
4721
  continue;
3815
4722
  }
3816
- for (const pattern of excludePatterns) {
3817
- if (matchGlob(relativePath, pattern)) {
3818
- skipped.push({ path: relativePath, reason: "excluded" });
3819
- continue;
3820
- }
3821
- }
3822
- let matched = false;
3823
- for (const pattern of includePatterns) {
3824
- if (matchGlob(relativePath, pattern)) {
3825
- matched = true;
3826
- break;
3827
- }
4723
+ if (isExcludedByPatterns(relativePath, excludePatterns)) {
4724
+ skipped.push({ path: relativePath, reason: "excluded" });
4725
+ continue;
3828
4726
  }
3829
- if (matched) {
4727
+ if (matchesAnyGlob(relativePath, includePatterns)) {
3830
4728
  filesInDir.push({ path: fullPath, size: stat5.size });
3831
4729
  }
3832
4730
  }
@@ -3837,7 +4735,7 @@ async function* walkDirectory(dir, projectRoot, includePatterns, excludePatterns
3837
4735
  yield f;
3838
4736
  }
3839
4737
  for (let i = options.maxFilesPerDirectory; i < filesInDir.length; i++) {
3840
- skipped.push({ path: path10.relative(projectRoot, filesInDir[i].path), reason: "excluded" });
4738
+ skipped.push({ path: toPosixRelativePath(path11.relative(projectRoot, filesInDir[i].path)), reason: "excluded" });
3841
4739
  }
3842
4740
  const canRecurse = options.maxDepth === -1 || currentDepth < options.maxDepth;
3843
4741
  if (canRecurse) {
@@ -3877,8 +4775,8 @@ async function collectFiles(projectRoot, includePatterns, excludePatterns, maxFi
3877
4775
  if (additionalRoots && additionalRoots.length > 0) {
3878
4776
  const normalizedRoots = /* @__PURE__ */ new Set();
3879
4777
  for (const kbRoot of additionalRoots) {
3880
- const resolved = path10.normalize(
3881
- path10.isAbsolute(kbRoot) ? kbRoot : path10.resolve(projectRoot, kbRoot)
4778
+ const resolved = path11.normalize(
4779
+ path11.isAbsolute(kbRoot) ? kbRoot : path11.resolve(projectRoot, kbRoot)
3882
4780
  );
3883
4781
  normalizedRoots.add(resolved);
3884
4782
  }
@@ -3919,7 +4817,7 @@ function getErrorMessage(error) {
3919
4817
  return error instanceof Error ? error.message : String(error);
3920
4818
  }
3921
4819
  function runCommand(file, args, options) {
3922
- return new Promise((resolve17, reject) => {
4820
+ return new Promise((resolve18, reject) => {
3923
4821
  childProcess.execFile(
3924
4822
  file,
3925
4823
  args,
@@ -3929,7 +4827,7 @@ function runCommand(file, args, options) {
3929
4827
  reject(error);
3930
4828
  return;
3931
4829
  }
3932
- resolve17(stdout);
4830
+ resolve18(stdout);
3933
4831
  }
3934
4832
  );
3935
4833
  });
@@ -4021,29 +4919,29 @@ var AutoIndexCancelledError = class extends Error {
4021
4919
  function now() {
4022
4920
  return (/* @__PURE__ */ new Date()).toISOString();
4023
4921
  }
4024
- function canonicalizePath(targetPath) {
4025
- const resolved = path11.resolve(targetPath);
4026
- if (existsSync7(resolved)) {
4922
+ function canonicalizePath2(targetPath) {
4923
+ const resolved = path12.resolve(targetPath);
4924
+ if (existsSync8(resolved)) {
4027
4925
  try {
4028
- return realpathSync3.native(resolved);
4926
+ return realpathSync4.native(resolved);
4029
4927
  } catch {
4030
4928
  return resolved;
4031
4929
  }
4032
4930
  }
4033
- const parent = path11.dirname(resolved);
4931
+ const parent = path12.dirname(resolved);
4034
4932
  if (parent === resolved) return resolved;
4035
- return path11.join(canonicalizePath(parent), path11.basename(resolved));
4933
+ return path12.join(canonicalizePath2(parent), path12.basename(resolved));
4036
4934
  }
4037
4935
  function isHomeDirectory(projectRoot) {
4038
- return canonicalizePath(projectRoot) === canonicalizePath(os3.homedir());
4936
+ return canonicalizePath2(projectRoot) === canonicalizePath2(os4.homedir());
4039
4937
  }
4040
- function projectLookupKey(projectRoot, host) {
4041
- return `${host}::${canonicalizePath(projectRoot)}`;
4938
+ function projectLookupKey2(projectRoot, host) {
4939
+ return `${host}::${canonicalizePath2(projectRoot)}`;
4042
4940
  }
4043
4941
  function coordinatorKey(projectRoot, config, host) {
4044
- const canonicalProjectRoot = canonicalizePath(projectRoot);
4942
+ const canonicalProjectRoot = canonicalizePath2(projectRoot);
4045
4943
  const indexPath = resolveProjectIndexPath(projectRoot, config.scope, host);
4046
- return `${canonicalizePath(indexPath)}::${canonicalProjectRoot}`;
4944
+ return `${canonicalizePath2(indexPath)}::${canonicalProjectRoot}`;
4047
4945
  }
4048
4946
  function getProjectSafety(projectRoot, config) {
4049
4947
  if (isHomeDirectory(projectRoot)) {
@@ -4074,10 +4972,10 @@ function safeFailureMessage(error) {
4074
4972
  }
4075
4973
  function cancellableDelay(delayMs, signal) {
4076
4974
  if (signal.aborted) return Promise.reject(new AutoIndexCancelledError());
4077
- return new Promise((resolve17, reject) => {
4975
+ return new Promise((resolve18, reject) => {
4078
4976
  const timer = setTimeout(() => {
4079
4977
  signal.removeEventListener("abort", onAbort);
4080
- resolve17();
4978
+ resolve18();
4081
4979
  }, delayMs);
4082
4980
  timer.unref?.();
4083
4981
  const onAbort = () => {
@@ -4089,18 +4987,44 @@ function cancellableDelay(delayMs, signal) {
4089
4987
  }
4090
4988
  function withTimeout(promise, timeoutMs) {
4091
4989
  if (timeoutMs <= 0) return Promise.resolve(void 0);
4092
- return new Promise((resolve17) => {
4093
- const timer = setTimeout(() => resolve17(void 0), timeoutMs);
4990
+ return new Promise((resolve18) => {
4991
+ const timer = setTimeout(() => resolve18(void 0), timeoutMs);
4094
4992
  timer.unref?.();
4095
4993
  void promise.then((value) => {
4096
4994
  clearTimeout(timer);
4097
- resolve17(value);
4995
+ resolve18(value);
4098
4996
  }, () => {
4099
4997
  clearTimeout(timer);
4100
- resolve17(void 0);
4998
+ resolve18(void 0);
4101
4999
  });
4102
5000
  });
4103
5001
  }
5002
+ function settlesWithin(promise, timeoutMs) {
5003
+ if (timeoutMs <= 0) return Promise.resolve(false);
5004
+ return new Promise((resolve18) => {
5005
+ let settled = false;
5006
+ const timer = setTimeout(() => {
5007
+ if (settled) return;
5008
+ settled = true;
5009
+ resolve18(false);
5010
+ }, timeoutMs);
5011
+ timer.unref?.();
5012
+ void promise.then(
5013
+ () => {
5014
+ if (settled) return;
5015
+ settled = true;
5016
+ clearTimeout(timer);
5017
+ resolve18(true);
5018
+ },
5019
+ () => {
5020
+ if (settled) return;
5021
+ settled = true;
5022
+ clearTimeout(timer);
5023
+ resolve18(true);
5024
+ }
5025
+ );
5026
+ });
5027
+ }
4104
5028
  function requestPriority(request) {
4105
5029
  if (request.force) return 4;
4106
5030
  if (request.source === "manual") return 3;
@@ -4111,6 +5035,7 @@ function mergeRequests(current, next) {
4111
5035
  if (!current) return next;
4112
5036
  const preferred = requestPriority(next) > requestPriority(current) ? next : current;
4113
5037
  return {
5038
+ allowDisabledAutoIndex: current.allowDisabledAutoIndex || next.allowDisabledAutoIndex,
4114
5039
  checkFreshness: current.checkFreshness && next.checkFreshness,
4115
5040
  force: current.force || next.force,
4116
5041
  onProgress: next.onProgress ?? current.onProgress,
@@ -4172,11 +5097,11 @@ var AutoIndexCoordinator = class {
4172
5097
  progress: this.status.progress ? { ...this.status.progress } : void 0
4173
5098
  };
4174
5099
  }
4175
- start(source) {
5100
+ start(source, allowDisabledAutoIndex = false) {
4176
5101
  this.refreshSafety();
4177
- if (!this.registration.config.indexing.autoIndex || !this.registration.safeToRun) return null;
5102
+ if (!this.registration.config.indexing.autoIndex && !allowDisabledAutoIndex || !this.registration.safeToRun) return null;
4178
5103
  if (this.status.state === "failed") return this.inFlight;
4179
- return this.request({ checkFreshness: true, force: false, source });
5104
+ return this.request({ allowDisabledAutoIndex, checkFreshness: true, force: false, source });
4180
5105
  }
4181
5106
  request(request) {
4182
5107
  if (this.stopped) {
@@ -4251,13 +5176,15 @@ var AutoIndexCoordinator = class {
4251
5176
  retryAttempt: void 0
4252
5177
  });
4253
5178
  const inFlight = this.inFlight;
4254
- if (inFlight) {
4255
- if (waitForCompletion) {
4256
- await inFlight;
4257
- } else {
4258
- await withTimeout(inFlight, SHUTDOWN_WAIT_MS);
4259
- }
5179
+ const completion = inFlight ? inFlight.then(() => void 0, () => void 0) : Promise.resolve();
5180
+ if (!inFlight) {
5181
+ return { completed: true, completion };
5182
+ }
5183
+ if (waitForCompletion) {
5184
+ await completion;
5185
+ return { completed: true, completion };
4260
5186
  }
5187
+ return { completed: await settlesWithin(completion, SHUTDOWN_WAIT_MS), completion };
4261
5188
  }
4262
5189
  startRequest(request) {
4263
5190
  if (this.stopped || !this.canRun(request)) {
@@ -4446,7 +5373,7 @@ var AutoIndexCoordinator = class {
4446
5373
  if (request.source === "manual" || request.source === "watcher") {
4447
5374
  return true;
4448
5375
  }
4449
- return this.registration.safeToRun && this.registration.config.indexing.autoIndex;
5376
+ return this.registration.safeToRun && (this.registration.config.indexing.autoIndex || request.allowDisabledAutoIndex === true);
4450
5377
  }
4451
5378
  shouldDeferForBattery(request) {
4452
5379
  return this.registration.backgroundIndexingPolicy !== null && (request.source === "startup" || request.source === "watcher");
@@ -4479,17 +5406,17 @@ var AutoIndexCoordinator = class {
4479
5406
  }
4480
5407
  }
4481
5408
  waitForBatteryRetry(delayMs) {
4482
- return new Promise((resolve17) => {
5409
+ return new Promise((resolve18) => {
4483
5410
  const timer = setTimeout(() => {
4484
5411
  if (this.batteryRetryTimer === timer) {
4485
5412
  this.batteryRetryTimer = null;
4486
5413
  this.resolveBatteryRetry = null;
4487
5414
  }
4488
- resolve17();
5415
+ resolve18();
4489
5416
  }, delayMs);
4490
5417
  timer.unref?.();
4491
5418
  this.batteryRetryTimer = timer;
4492
- this.resolveBatteryRetry = resolve17;
5419
+ this.resolveBatteryRetry = resolve18;
4493
5420
  });
4494
5421
  }
4495
5422
  cancelBatteryRetry() {
@@ -4497,9 +5424,9 @@ var AutoIndexCoordinator = class {
4497
5424
  clearTimeout(this.batteryRetryTimer);
4498
5425
  this.batteryRetryTimer = null;
4499
5426
  }
4500
- const resolve17 = this.resolveBatteryRetry;
5427
+ const resolve18 = this.resolveBatteryRetry;
4501
5428
  this.resolveBatteryRetry = null;
4502
- resolve17?.();
5429
+ resolve18?.();
4503
5430
  }
4504
5431
  finishBatteryCheck(batteryCheck) {
4505
5432
  if (this.batteryCheck !== batteryCheck) return;
@@ -4512,12 +5439,25 @@ var AutoIndexCoordinator = class {
4512
5439
  }
4513
5440
  };
4514
5441
  function getCoordinator(projectRoot, host) {
4515
- const key = coordinatorKeysByProject.get(projectLookupKey(projectRoot, host));
5442
+ const key = coordinatorKeysByProject.get(projectLookupKey2(projectRoot, host));
4516
5443
  return key ? coordinators.get(key) ?? null : null;
4517
5444
  }
4518
- function configureAutoIndex(projectRoot, host, config, getIndexer) {
4519
- const projectKey = projectLookupKey(projectRoot, host);
5445
+ function synchronizeBackgroundWorker(projectRoot, host, config, safeToRun) {
5446
+ if (safeToRun) {
5447
+ updateBackgroundWorkerConfig(projectRoot, host, config);
5448
+ return;
5449
+ }
5450
+ void stopBackgroundWorker(projectRoot, host).catch((error) => {
5451
+ console.error("[codebase-index] Failed to stop background worker after project safety changed:", error);
5452
+ });
5453
+ }
5454
+ function configureAutoIndex(projectRoot, host, config, getIndexer, options = {}) {
5455
+ const projectKey = projectLookupKey2(projectRoot, host);
4520
5456
  const safety = getProjectSafety(projectRoot, config);
5457
+ const synchronizeWorker = options.synchronizeBackgroundWorker ?? true;
5458
+ if (options.preserveManagedWorker === true && isBackgroundWorkerManaged(projectRoot, host)) {
5459
+ return;
5460
+ }
4521
5461
  const registration = {
4522
5462
  backgroundIndexingPolicy: createBackgroundIndexingPolicy(
4523
5463
  config.indexing.pauseBackgroundIndexingOnBattery
@@ -4535,6 +5475,9 @@ function configureAutoIndex(projectRoot, host, config, getIndexer) {
4535
5475
  const stopPrevious = previousCoordinator?.stop(true) ?? Promise.resolve();
4536
5476
  const activation = Promise.all([previousBarrier, stopPrevious]).then(() => void 0);
4537
5477
  coordinatorReplacementBarriers.set(projectKey, activation);
5478
+ if (synchronizeWorker) {
5479
+ synchronizeBackgroundWorker(projectRoot, host, config, safety.safeToRun);
5480
+ }
4538
5481
  coordinators.delete(previousKey);
4539
5482
  const coordinator2 = new AutoIndexCoordinator(registration);
4540
5483
  coordinator2.activateAfter(activation);
@@ -4550,11 +5493,17 @@ function configureAutoIndex(projectRoot, host, config, getIndexer) {
4550
5493
  coordinator.update(registration);
4551
5494
  }
4552
5495
  coordinatorKeysByProject.set(projectKey, key);
5496
+ if (synchronizeWorker) {
5497
+ synchronizeBackgroundWorker(projectRoot, host, config, safety.safeToRun);
5498
+ }
4553
5499
  }
4554
- function startAutoIndex(projectRoot, host, source = "startup") {
4555
- return getCoordinator(projectRoot, host)?.start(source) ?? null;
5500
+ function startAutoIndexForBackgroundWorker(projectRoot, host, source = "startup", allowDisabledAutoIndex = false) {
5501
+ return getCoordinator(projectRoot, host)?.start(source, allowDisabledAutoIndex) ?? null;
4556
5502
  }
4557
5503
  function requestBackgroundIndex(projectRoot, host) {
5504
+ if (isBackgroundWorkerManaged(projectRoot, host) && !isBackgroundWorkerLeader(projectRoot, host)) {
5505
+ return null;
5506
+ }
4558
5507
  return getCoordinator(projectRoot, host)?.request({
4559
5508
  checkFreshness: false,
4560
5509
  force: false,
@@ -4594,15 +5543,23 @@ async function waitForAutoIndexForRetrieval(projectRoot, host) {
4594
5543
  };
4595
5544
  }
4596
5545
  try {
4597
- if (await hasReadableCurrentIndex(coordinator)) return { ready: true };
5546
+ const readiness = await getSearchReadiness(coordinator);
5547
+ if (readiness.searchable) {
5548
+ return { ready: true };
5549
+ }
5550
+ if (readiness.blocked) return unavailableSnapshotResult(readiness.reason);
4598
5551
  } catch {
4599
5552
  }
4600
- const job = coordinator.start("retrieval") ?? coordinator.currentJob();
5553
+ const job = startRetrievalRefresh(projectRoot, host, coordinator);
4601
5554
  if (job) {
4602
5555
  await withTimeout(job, coordinator.getWaitMs());
5556
+ } else if (isBackgroundWorkerManaged(projectRoot, host)) {
5557
+ await waitForPublishedSnapshot(coordinator, coordinator.getWaitMs());
4603
5558
  }
4604
5559
  try {
4605
- if (await hasReadableCurrentIndex(coordinator)) return { ready: true };
5560
+ const readiness = await getSearchReadiness(coordinator);
5561
+ if (readiness.searchable) return { ready: true };
5562
+ if (readiness.blocked) return unavailableSnapshotResult(readiness.reason);
4606
5563
  } catch {
4607
5564
  }
4608
5565
  const status = coordinator.snapshot();
@@ -4623,18 +5580,52 @@ async function waitForAutoIndexForRetrieval(projectRoot, host) {
4623
5580
  text: `Automatic indexing is ${status.state}. Retry shortly or call index_status for progress. You can also run index_codebase explicitly.`
4624
5581
  };
4625
5582
  }
4626
- async function hasReadableCurrentIndex(coordinator) {
5583
+ async function stopAutoIndexForBackgroundWorker(projectRoot, host, waitForCompletion = false) {
5584
+ const coordinator = getCoordinator(projectRoot, host);
5585
+ if (!coordinator) {
5586
+ return { completed: true, completion: Promise.resolve() };
5587
+ }
5588
+ return coordinator.stop(waitForCompletion);
5589
+ }
5590
+ async function getSearchReadiness(coordinator) {
4627
5591
  const indexer = coordinator.getIndexer();
4628
5592
  if (indexer.getIndexFreshness) {
4629
5593
  const freshness = await indexer.getIndexFreshness();
4630
- return freshness.readable && freshness.current;
5594
+ const searchable = freshness.readable && freshness.current && freshness.reason === "current";
5595
+ return {
5596
+ blocked: freshness.reason === "unreadable" || freshness.reason === "incompatible" || freshness.reason === "failed-batches" || freshness.reason === "migration-required",
5597
+ reason: freshness.reason,
5598
+ searchable
5599
+ };
5600
+ }
5601
+ const indexed = (await indexer.getStatus()).indexed;
5602
+ return { blocked: false, searchable: indexed };
5603
+ }
5604
+ function unavailableSnapshotResult(reason) {
5605
+ const detail = reason === "incompatible" ? "The existing index is incompatible with the configured embedding provider." : reason === "migration-required" ? "The existing index requires a storage migration." : reason === "failed-batches" ? "The existing index has failed embedding batches." : "The existing index is unreadable.";
5606
+ return {
5607
+ ready: false,
5608
+ text: `${detail} Run index_codebase before retrying retrieval.`
5609
+ };
5610
+ }
5611
+ function startRetrievalRefresh(projectRoot, host, coordinator) {
5612
+ if (isBackgroundWorkerManaged(projectRoot, host)) {
5613
+ requestBackgroundWorkerRefresh(projectRoot, host, true);
5614
+ return isBackgroundWorkerLeader(projectRoot, host) ? coordinator.currentJob() : null;
5615
+ }
5616
+ return coordinator.start("retrieval") ?? coordinator.currentJob();
5617
+ }
5618
+ async function waitForPublishedSnapshot(coordinator, waitMs) {
5619
+ const deadline = Date.now() + waitMs;
5620
+ while (Date.now() < deadline) {
5621
+ if ((await getSearchReadiness(coordinator)).searchable) return;
5622
+ await new Promise((resolve18) => setTimeout(resolve18, Math.min(250, deadline - Date.now())));
4631
5623
  }
4632
- return (await indexer.getStatus()).indexed;
4633
5624
  }
4634
5625
 
4635
5626
  // src/tools/config-state.ts
4636
- import { existsSync as existsSync8, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "fs";
4637
- import * as path12 from "path";
5627
+ import { existsSync as existsSync9, mkdirSync as mkdirSync3, writeFileSync as writeFileSync3 } from "fs";
5628
+ import * as path13 from "path";
4638
5629
  function normalizeKnowledgeBasePaths(config, projectRoot) {
4639
5630
  const normalized = { ...config };
4640
5631
  if (Array.isArray(normalized.knowledgeBases)) {
@@ -4661,10 +5652,10 @@ function loadEditableConfig(projectRoot, host) {
4661
5652
  }
4662
5653
  function saveConfig(projectRoot, config, host) {
4663
5654
  const configPath = getConfigPath(projectRoot, host);
4664
- const configDir = path12.dirname(configPath);
4665
- const configBaseDir = path12.dirname(configDir);
4666
- if (!existsSync8(configDir)) {
4667
- mkdirSync2(configDir, { recursive: true });
5655
+ const configDir = path13.dirname(configPath);
5656
+ const configBaseDir = path13.dirname(configDir);
5657
+ if (!existsSync9(configDir)) {
5658
+ mkdirSync3(configDir, { recursive: true });
4668
5659
  }
4669
5660
  const serializableConfig = { ...config };
4670
5661
  if (Array.isArray(serializableConfig.knowledgeBases)) {
@@ -4672,12 +5663,12 @@ function saveConfig(projectRoot, config, host) {
4672
5663
  (kb) => serializeConfigPathValue(kb, configBaseDir)
4673
5664
  );
4674
5665
  }
4675
- writeFileSync2(configPath, JSON.stringify(serializableConfig, null, 2) + "\n", "utf-8");
5666
+ writeFileSync3(configPath, JSON.stringify(serializableConfig, null, 2) + "\n", "utf-8");
4676
5667
  }
4677
5668
 
4678
5669
  // src/indexer/index.ts
4679
- import { existsSync as existsSync11, readFileSync as readFileSync8, statSync as statSync4, writeFileSync as writeFileSync3, renameSync as renameSync3, unlinkSync as unlinkSync2, mkdirSync as mkdirSync4, promises as fsPromises3 } from "fs";
4680
- import * as path19 from "path";
5670
+ import { existsSync as existsSync12, readFileSync as readFileSync9, statSync as statSync4, writeFileSync as writeFileSync4, renameSync as renameSync4, unlinkSync as unlinkSync2, mkdirSync as mkdirSync5, promises as fsPromises3 } from "fs";
5671
+ import * as path20 from "path";
4681
5672
  import { performance as performance2 } from "perf_hooks";
4682
5673
  import { execFile as execFile5 } from "child_process";
4683
5674
  import { promisify as promisify4 } from "util";
@@ -4704,7 +5695,7 @@ function pTimeout(promise, options) {
4704
5695
  } = options;
4705
5696
  let timer;
4706
5697
  let abortHandler;
4707
- const wrappedPromise = new Promise((resolve17, reject) => {
5698
+ const wrappedPromise = new Promise((resolve18, reject) => {
4708
5699
  if (typeof milliseconds !== "number" || Math.sign(milliseconds) !== 1) {
4709
5700
  throw new TypeError(`Expected \`milliseconds\` to be a positive number, got \`${milliseconds}\``);
4710
5701
  }
@@ -4718,7 +5709,7 @@ function pTimeout(promise, options) {
4718
5709
  };
4719
5710
  signal.addEventListener("abort", abortHandler, { once: true });
4720
5711
  }
4721
- promise.then(resolve17, reject);
5712
+ promise.then(resolve18, reject);
4722
5713
  if (milliseconds === Number.POSITIVE_INFINITY) {
4723
5714
  return;
4724
5715
  }
@@ -4726,7 +5717,7 @@ function pTimeout(promise, options) {
4726
5717
  timer = customTimers.setTimeout.call(void 0, () => {
4727
5718
  if (fallback) {
4728
5719
  try {
4729
- resolve17(fallback());
5720
+ resolve18(fallback());
4730
5721
  } catch (error) {
4731
5722
  reject(error);
4732
5723
  }
@@ -4736,7 +5727,7 @@ function pTimeout(promise, options) {
4736
5727
  promise.cancel();
4737
5728
  }
4738
5729
  if (message === false) {
4739
- resolve17();
5730
+ resolve18();
4740
5731
  } else if (message instanceof Error) {
4741
5732
  reject(message);
4742
5733
  } else {
@@ -5138,7 +6129,7 @@ var PQueue = class extends import_index.default {
5138
6129
  // Assign unique ID if not provided
5139
6130
  id: options.id ?? (this.#idAssigner++).toString()
5140
6131
  };
5141
- return new Promise((resolve17, reject) => {
6132
+ return new Promise((resolve18, reject) => {
5142
6133
  const taskSymbol = /* @__PURE__ */ Symbol(`task-${options.id}`);
5143
6134
  let cleanupQueueAbortHandler = () => void 0;
5144
6135
  const run = async () => {
@@ -5178,7 +6169,7 @@ var PQueue = class extends import_index.default {
5178
6169
  })]);
5179
6170
  }
5180
6171
  const result = await operation;
5181
- resolve17(result);
6172
+ resolve18(result);
5182
6173
  this.emit("completed", result);
5183
6174
  } catch (error) {
5184
6175
  reject(error);
@@ -5366,13 +6357,13 @@ var PQueue = class extends import_index.default {
5366
6357
  });
5367
6358
  }
5368
6359
  async #onEvent(event, filter) {
5369
- return new Promise((resolve17) => {
6360
+ return new Promise((resolve18) => {
5370
6361
  const listener = () => {
5371
6362
  if (filter && !filter()) {
5372
6363
  return;
5373
6364
  }
5374
6365
  this.off(event, listener);
5375
- resolve17();
6366
+ resolve18();
5376
6367
  };
5377
6368
  this.on(event, listener);
5378
6369
  });
@@ -5658,7 +6649,7 @@ async function onAttemptFailure({ error, attemptNumber, retriesConsumed, startTi
5658
6649
  const finalDelay = Math.min(delayTime, remainingTime);
5659
6650
  options.signal?.throwIfAborted();
5660
6651
  if (finalDelay > 0) {
5661
- await new Promise((resolve17, reject) => {
6652
+ await new Promise((resolve18, reject) => {
5662
6653
  const onAbort = () => {
5663
6654
  clearTimeout(timeoutToken);
5664
6655
  options.signal?.removeEventListener("abort", onAbort);
@@ -5666,7 +6657,7 @@ async function onAttemptFailure({ error, attemptNumber, retriesConsumed, startTi
5666
6657
  };
5667
6658
  const timeoutToken = setTimeout(() => {
5668
6659
  options.signal?.removeEventListener("abort", onAbort);
5669
- resolve17();
6660
+ resolve18();
5670
6661
  }, finalDelay);
5671
6662
  if (options.unref) {
5672
6663
  timeoutToken.unref?.();
@@ -5727,17 +6718,17 @@ async function pRetry(input, options = {}) {
5727
6718
  }
5728
6719
 
5729
6720
  // src/embeddings/detector.ts
5730
- import { existsSync as existsSync9, readFileSync as readFileSync6 } from "fs";
5731
- import * as path13 from "path";
5732
- import * as os4 from "os";
6721
+ import { existsSync as existsSync10, readFileSync as readFileSync7 } from "fs";
6722
+ import * as path14 from "path";
6723
+ import * as os5 from "os";
5733
6724
  function getOpenCodeAuthPath() {
5734
- return path13.join(os4.homedir(), ".local", "share", "opencode", "auth.json");
6725
+ return path14.join(os5.homedir(), ".local", "share", "opencode", "auth.json");
5735
6726
  }
5736
6727
  function loadOpenCodeAuth() {
5737
6728
  const authPath = getOpenCodeAuthPath();
5738
6729
  try {
5739
- if (existsSync9(authPath)) {
5740
- return JSON.parse(readFileSync6(authPath, "utf-8"));
6730
+ if (existsSync10(authPath)) {
6731
+ return JSON.parse(readFileSync7(authPath, "utf-8"));
5741
6732
  }
5742
6733
  } catch {
5743
6734
  }
@@ -6028,17 +7019,17 @@ function validateExternalUrl(urlString) {
6028
7019
  if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
6029
7020
  return { valid: false, reason: `Blocked protocol: ${parsed.protocol}` };
6030
7021
  }
6031
- const hostname2 = parsed.hostname.toLowerCase();
6032
- if (BLOCKED_HOSTNAMES.has(hostname2)) {
6033
- return { valid: false, reason: `Blocked: cloud metadata service (${hostname2})` };
7022
+ const hostname3 = parsed.hostname.toLowerCase();
7023
+ if (BLOCKED_HOSTNAMES.has(hostname3)) {
7024
+ return { valid: false, reason: `Blocked: cloud metadata service (${hostname3})` };
6034
7025
  }
6035
7026
  for (const pattern of BLOCKED_METADATA_IPS) {
6036
- if (pattern.test(hostname2)) {
6037
- return { valid: false, reason: `Blocked: cloud metadata IP (${hostname2})` };
7027
+ if (pattern.test(hostname3)) {
7028
+ return { valid: false, reason: `Blocked: cloud metadata IP (${hostname3})` };
6038
7029
  }
6039
7030
  }
6040
- if (/^169\.254\./.test(hostname2)) {
6041
- return { valid: false, reason: `Blocked: link-local address (${hostname2})` };
7031
+ if (/^169\.254\./.test(hostname3)) {
7032
+ return { valid: false, reason: `Blocked: link-local address (${hostname3})` };
6042
7033
  }
6043
7034
  return { valid: true };
6044
7035
  }
@@ -7130,8 +8121,8 @@ function extractParamNames(params) {
7130
8121
  }
7131
8122
 
7132
8123
  // src/native/binding.ts
7133
- import * as os5 from "os";
7134
- import * as path14 from "path";
8124
+ import * as os6 from "os";
8125
+ import * as path15 from "path";
7135
8126
  import * as module from "module";
7136
8127
  import { fileURLToPath } from "url";
7137
8128
 
@@ -7167,7 +8158,7 @@ var MCP_BINARY_CURRENT_NAME = CURRENT_PRODUCT.mcpBinary;
7167
8158
  var STABLE_NATIVE_BINARY_NAME = IDENTITY_CATALOG.native.binaryName;
7168
8159
 
7169
8160
  // src/native/binding.ts
7170
- function getNativeBindingFilename(platform2 = os5.platform(), arch2 = os5.arch()) {
8161
+ function getNativeBindingFilename(platform2 = os6.platform(), arch2 = os6.arch()) {
7171
8162
  if (platform2 === "darwin" && arch2 === "arm64") {
7172
8163
  return `${STABLE_NATIVE_BINARY_NAME}.darwin-arm64.node`;
7173
8164
  }
@@ -7185,25 +8176,25 @@ function getNativeBindingFilename(platform2 = os5.platform(), arch2 = os5.arch()
7185
8176
  }
7186
8177
  throw new Error(`Unsupported platform: ${platform2}-${arch2}`);
7187
8178
  }
7188
- function resolveNativeBindingPath(packageRoot, platform2 = os5.platform(), arch2 = os5.arch()) {
7189
- return path14.join(packageRoot, "native", getNativeBindingFilename(platform2, arch2));
8179
+ function resolveNativeBindingPath(packageRoot, platform2 = os6.platform(), arch2 = os6.arch()) {
8180
+ return path15.join(packageRoot, "native", getNativeBindingFilename(platform2, arch2));
7190
8181
  }
7191
8182
  function getNativeBinding() {
7192
8183
  let currentDir;
7193
8184
  let requireTarget;
7194
8185
  if (typeof import.meta !== "undefined" && import.meta.url) {
7195
- currentDir = path14.dirname(fileURLToPath(import.meta.url));
8186
+ currentDir = path15.dirname(fileURLToPath(import.meta.url));
7196
8187
  requireTarget = import.meta.url;
7197
8188
  } else if (typeof __dirname !== "undefined") {
7198
8189
  currentDir = __dirname;
7199
8190
  requireTarget = __filename;
7200
8191
  } else {
7201
8192
  currentDir = process.cwd();
7202
- requireTarget = path14.join(currentDir, "index.js");
8193
+ requireTarget = path15.join(currentDir, "index.js");
7203
8194
  }
7204
8195
  const normalizedDir = currentDir.replace(/\\/g, "/");
7205
- const isDevMode = normalizedDir.includes("/src/native") || currentDir.includes(path14.join("src", "native"));
7206
- const packageRoot = isDevMode ? path14.resolve(currentDir, "../..") : path14.resolve(currentDir, "..");
8196
+ const isDevMode = normalizedDir.includes("/src/native") || currentDir.includes(path15.join("src", "native"));
8197
+ const packageRoot = isDevMode ? path15.resolve(currentDir, "../..") : path15.resolve(currentDir, "..");
7207
8198
  const nativePath = resolveNativeBindingPath(packageRoot);
7208
8199
  const require2 = module.createRequire(requireTarget);
7209
8200
  return require2(nativePath);
@@ -7787,8 +8778,8 @@ var Database = class _Database {
7787
8778
 
7788
8779
  // src/git/branch-materialization.ts
7789
8780
  import { promises as fsPromises2 } from "fs";
7790
- import * as os6 from "os";
7791
- import * as path15 from "path";
8781
+ import * as os7 from "os";
8782
+ import * as path16 from "path";
7792
8783
 
7793
8784
  // src/git/branch-resolution.ts
7794
8785
  import { execFile as execFile2 } from "child_process";
@@ -8107,13 +9098,13 @@ async function isWorktreeRegistered(projectRoot, worktreePath) {
8107
9098
  return false;
8108
9099
  }
8109
9100
  function isPathWithinRoot(filePath, rootPath) {
8110
- const relative14 = path15.relative(path15.resolve(rootPath), path15.resolve(filePath));
8111
- return relative14 === "" || !relative14.startsWith(`..${path15.sep}`) && relative14 !== ".." && !path15.isAbsolute(relative14);
9101
+ const relative14 = path16.relative(path16.resolve(rootPath), path16.resolve(filePath));
9102
+ return relative14 === "" || !relative14.startsWith(`..${path16.sep}`) && relative14 !== ".." && !path16.isAbsolute(relative14);
8112
9103
  }
8113
9104
  async function pruneExactMissingWorktreeRegistration(projectRoot, worktreePath) {
8114
9105
  if (await pathExists(worktreePath)) return false;
8115
9106
  const commonDir = await runGit(projectRoot, ["rev-parse", "--path-format=absolute", "--git-common-dir"]);
8116
- const registrationsRoot = path15.join(commonDir, "worktrees");
9107
+ const registrationsRoot = path16.join(commonDir, "worktrees");
8117
9108
  let entries;
8118
9109
  try {
8119
9110
  entries = await fsPromises2.readdir(registrationsRoot, { withFileTypes: true });
@@ -8124,16 +9115,16 @@ async function pruneExactMissingWorktreeRegistration(projectRoot, worktreePath)
8124
9115
  const target = canonicalizePathForComparison(worktreePath);
8125
9116
  for (const entry of entries) {
8126
9117
  if (!entry.isDirectory()) continue;
8127
- const registrationPath = path15.join(registrationsRoot, entry.name);
9118
+ const registrationPath = path16.join(registrationsRoot, entry.name);
8128
9119
  if (!isPathWithinRoot(registrationPath, registrationsRoot)) continue;
8129
9120
  let gitdirPath;
8130
9121
  try {
8131
- gitdirPath = (await fsPromises2.readFile(path15.join(registrationPath, "gitdir"), "utf8")).trim();
9122
+ gitdirPath = (await fsPromises2.readFile(path16.join(registrationPath, "gitdir"), "utf8")).trim();
8132
9123
  } catch {
8133
9124
  continue;
8134
9125
  }
8135
- const resolvedGitdirPath = path15.isAbsolute(gitdirPath) ? gitdirPath : path15.resolve(registrationPath, gitdirPath);
8136
- if (canonicalizePathForComparison(path15.dirname(resolvedGitdirPath)) !== target) continue;
9126
+ const resolvedGitdirPath = path16.isAbsolute(gitdirPath) ? gitdirPath : path16.resolve(registrationPath, gitdirPath);
9127
+ if (canonicalizePathForComparison(path16.dirname(resolvedGitdirPath)) !== target) continue;
8137
9128
  await fsPromises2.rm(registrationPath, { recursive: true, force: true });
8138
9129
  return true;
8139
9130
  }
@@ -8151,7 +9142,7 @@ async function removeWorktree(projectRoot, worktreePath) {
8151
9142
  registered = await isWorktreeRegistered(projectRoot, worktreePath);
8152
9143
  } catch (error) {
8153
9144
  errors.push(asError(error));
8154
- throw new AggregateError(errors, `Could not verify temporary worktree deregistration; preserved ${path15.dirname(worktreePath)}`);
9145
+ throw new AggregateError(errors, `Could not verify temporary worktree deregistration; preserved ${path16.dirname(worktreePath)}`);
8155
9146
  }
8156
9147
  if (registered) {
8157
9148
  try {
@@ -8167,7 +9158,7 @@ async function removeWorktree(projectRoot, worktreePath) {
8167
9158
  registered = await isWorktreeRegistered(projectRoot, worktreePath);
8168
9159
  } catch (error) {
8169
9160
  errors.push(asError(error));
8170
- throw new AggregateError(errors, `Could not verify temporary worktree deregistration; preserved ${path15.dirname(worktreePath)}`);
9161
+ throw new AggregateError(errors, `Could not verify temporary worktree deregistration; preserved ${path16.dirname(worktreePath)}`);
8171
9162
  }
8172
9163
  }
8173
9164
  if (registered && !await pathExists(worktreePath)) {
@@ -8180,13 +9171,13 @@ async function removeWorktree(projectRoot, worktreePath) {
8180
9171
  }
8181
9172
  if (registered) {
8182
9173
  errors.push(new Error(`Temporary worktree remains registered: ${worktreePath}`));
8183
- throw new AggregateError(errors, `Failed to deregister temporary worktree; preserved ${path15.dirname(worktreePath)}`);
9174
+ throw new AggregateError(errors, `Failed to deregister temporary worktree; preserved ${path16.dirname(worktreePath)}`);
8184
9175
  }
8185
9176
  try {
8186
- await fsPromises2.rm(path15.dirname(worktreePath), { recursive: true, force: true });
9177
+ await fsPromises2.rm(path16.dirname(worktreePath), { recursive: true, force: true });
8187
9178
  } catch (error) {
8188
9179
  errors.push(asError(error));
8189
- throw new AggregateError(errors, `Deregistered the temporary worktree but could not remove ${path15.dirname(worktreePath)}`);
9180
+ throw new AggregateError(errors, `Deregistered the temporary worktree but could not remove ${path16.dirname(worktreePath)}`);
8190
9181
  }
8191
9182
  }
8192
9183
  async function cleanupTemporaryWorktree(projectRoot, worktreePath, temporaryRoot) {
@@ -8222,9 +9213,9 @@ async function withMaterializedBranch(request, callback) {
8222
9213
  `Git ref ${JSON.stringify(request.ref ?? request.branch)} is not available locally. For an unfetched branch, pass a remote-qualified name such as origin/feature.`
8223
9214
  );
8224
9215
  }
8225
- const temporaryRoot = await fsPromises2.mkdtemp(path15.join(os6.tmpdir(), "codebase-index-branch-"));
8226
- const worktreePath = path15.join(temporaryRoot, "worktree");
8227
- const hooksPath = path15.join(temporaryRoot, "hooks");
9216
+ const temporaryRoot = await fsPromises2.mkdtemp(path16.join(os7.tmpdir(), "codebase-index-branch-"));
9217
+ const worktreePath = path16.join(temporaryRoot, "worktree");
9218
+ const hooksPath = path16.join(temporaryRoot, "hooks");
8228
9219
  await fsPromises2.mkdir(hooksPath);
8229
9220
  const info = {
8230
9221
  branch: request.branch,
@@ -8275,8 +9266,8 @@ async function withMaterializedBranch(request, callback) {
8275
9266
 
8276
9267
  // src/tools/changed-files.ts
8277
9268
  import { execFile as execFile3 } from "child_process";
8278
- import { realpathSync as realpathSync4 } from "fs";
8279
- import * as path16 from "path";
9269
+ import { realpathSync as realpathSync5 } from "fs";
9270
+ import * as path17 from "path";
8280
9271
  import { promisify as promisify2 } from "util";
8281
9272
  var execFileAsync2 = promisify2(execFile3);
8282
9273
  var GH_PR_VIEW_FIELDS = [
@@ -8418,9 +9409,9 @@ function getHeadRepositoryIdentity(data, host) {
8418
9409
  return `${host}/${owner.toLowerCase()}/${repository.replace(/\.git$/i, "").toLowerCase()}`;
8419
9410
  }
8420
9411
  function getLocalRepositoryIdentity(projectRoot) {
8421
- let canonicalRoot = path16.resolve(projectRoot);
9412
+ let canonicalRoot = path17.resolve(projectRoot);
8422
9413
  try {
8423
- canonicalRoot = realpathSync4.native(canonicalRoot);
9414
+ canonicalRoot = realpathSync5.native(canonicalRoot);
8424
9415
  } catch {
8425
9416
  }
8426
9417
  return `local:${canonicalRoot}`;
@@ -8479,17 +9470,17 @@ async function getMergeBase(projectRoot, baseCommit, headCommit) {
8479
9470
  return commit;
8480
9471
  }
8481
9472
  function normalizeFiles(rawFiles, projectRoot) {
8482
- const root = path16.resolve(projectRoot);
9473
+ const root = path17.resolve(projectRoot);
8483
9474
  const seen = /* @__PURE__ */ new Set();
8484
9475
  const result = [];
8485
9476
  for (const raw of rawFiles) {
8486
9477
  if (raw.length === 0) continue;
8487
- const absolute = path16.resolve(root, raw);
8488
- const relative14 = path16.relative(root, absolute);
8489
- if (path16.isAbsolute(raw) || relative14 === ".." || relative14.startsWith(`..${path16.sep}`) || path16.isAbsolute(relative14)) {
9478
+ const absolute = path17.resolve(root, raw);
9479
+ const relative14 = path17.relative(root, absolute);
9480
+ if (path17.isAbsolute(raw) || relative14 === ".." || relative14.startsWith(`..${path17.sep}`) || path17.isAbsolute(relative14)) {
8490
9481
  throw new Error(`Changed file escapes the project root: ${JSON.stringify(raw)}`);
8491
9482
  }
8492
- const cleaned = relative14.startsWith(`.${path16.sep}`) ? relative14.slice(2) : relative14;
9483
+ const cleaned = relative14.startsWith(`.${path17.sep}`) ? relative14.slice(2) : relative14;
8493
9484
  if (!seen.has(cleaned)) {
8494
9485
  seen.add(cleaned);
8495
9486
  result.push(cleaned);
@@ -8500,7 +9491,7 @@ function normalizeFiles(rawFiles, projectRoot) {
8500
9491
 
8501
9492
  // src/indexer/git-blame.ts
8502
9493
  import { execFile as execFile4 } from "child_process";
8503
- import * as path17 from "path";
9494
+ import * as path18 from "path";
8504
9495
  import { promisify as promisify3 } from "util";
8505
9496
  var execFileAsync3 = promisify3(execFile4);
8506
9497
  function parseGitBlamePorcelain(output) {
@@ -8538,7 +9529,7 @@ function parseGitBlamePorcelain(output) {
8538
9529
  return Array.from(commits.values()).filter((commit) => commit.lines > 0).sort((a, b) => b.lines - a.lines || b.committedAt - a.committedAt)[0];
8539
9530
  }
8540
9531
  async function getChunkGitBlame(projectRoot, filePath, startLine, endLine) {
8541
- const relativePath = path17.relative(projectRoot, filePath);
9532
+ const relativePath = path18.relative(projectRoot, filePath);
8542
9533
  try {
8543
9534
  const { stdout } = await execFileAsync3(
8544
9535
  "git",
@@ -9117,8 +10108,8 @@ function pathSegmentsForAffinityMatch(filePath) {
9117
10108
  if (segments.length === 0) {
9118
10109
  return [];
9119
10110
  }
9120
- const basename9 = segments[segments.length - 1] ?? "";
9121
- const basenameWithoutExt = basename9.replace(/\.[^/.]+$/u, "");
10111
+ const basename10 = segments[segments.length - 1] ?? "";
10112
+ const basenameWithoutExt = basename10.replace(/\.[^/.]+$/u, "");
9122
10113
  const normalizedSegments = segments.map((segment) => segment.toLowerCase());
9123
10114
  return Array.from(/* @__PURE__ */ new Set([
9124
10115
  ...normalizedSegments,
@@ -9427,8 +10418,8 @@ function hasAllEmbeddingParts(parts, expectedPartCount) {
9427
10418
 
9428
10419
  // src/indexer/failed-state-persistence.ts
9429
10420
  import * as fs2 from "fs";
9430
- import { createHash, randomBytes as randomBytes3 } from "crypto";
9431
- import * as path18 from "path";
10421
+ import { createHash as createHash2, randomBytes as randomBytes3 } from "crypto";
10422
+ import * as path19 from "path";
9432
10423
  import { StringDecoder } from "string_decoder";
9433
10424
  var CURRENT_FAILED_BATCH_VERSION = 1;
9434
10425
  var DEFAULT_MALFORMED_LINE_ACTION = "skip";
@@ -9446,7 +10437,7 @@ function* readFailedBatchRecords(filePath, options = {}) {
9446
10437
  function createFailedBatchWriter(targetPath) {
9447
10438
  const temporaryPath = createTemporaryPath(targetPath);
9448
10439
  let finalized = false;
9449
- fs2.mkdirSync(path18.dirname(targetPath), { recursive: true });
10440
+ fs2.mkdirSync(path19.dirname(targetPath), { recursive: true });
9450
10441
  fs2.closeSync(fs2.openSync(temporaryPath, "w"));
9451
10442
  const write = (record) => {
9452
10443
  if (finalized) {
@@ -9465,7 +10456,7 @@ function createFailedBatchWriter(targetPath) {
9465
10456
  if (lines.length === 0) {
9466
10457
  return;
9467
10458
  }
9468
- fs2.mkdirSync(path18.dirname(targetPath), { recursive: true });
10459
+ fs2.mkdirSync(path19.dirname(targetPath), { recursive: true });
9469
10460
  fs2.appendFileSync(temporaryPath, `${lines.join("\n")}
9470
10461
  `, "utf-8");
9471
10462
  };
@@ -9473,7 +10464,7 @@ function createFailedBatchWriter(targetPath) {
9473
10464
  if (finalized) {
9474
10465
  return;
9475
10466
  }
9476
- fs2.mkdirSync(path18.dirname(targetPath), { recursive: true });
10467
+ fs2.mkdirSync(path19.dirname(targetPath), { recursive: true });
9477
10468
  fs2.renameSync(temporaryPath, targetPath);
9478
10469
  finalized = true;
9479
10470
  };
@@ -9619,10 +10610,10 @@ function stripLeadingBomAndWhitespace(value) {
9619
10610
  return result;
9620
10611
  }
9621
10612
  function createTemporaryPath(targetPath) {
9622
- const randomId = createHash("sha1").update(`${Date.now()}:${randomBytes3(8).toString("hex")}`).digest("hex");
9623
- const targetDir = path18.dirname(targetPath);
9624
- const baseName = path18.basename(targetPath);
9625
- return path18.join(targetDir, `.${baseName}.${randomId}.tmp`);
10613
+ const randomId = createHash2("sha1").update(`${Date.now()}:${randomBytes3(8).toString("hex")}`).digest("hex");
10614
+ const targetDir = path19.dirname(targetPath);
10615
+ const baseName = path19.basename(targetPath);
10616
+ return path19.join(targetDir, `.${baseName}.${randomId}.tmp`);
9626
10617
  }
9627
10618
  function handleMalformedLine(filePath, lineNumber, line, error, options) {
9628
10619
  const action = options.malformedLineAction ?? DEFAULT_MALFORMED_LINE_ACTION;
@@ -9868,9 +10859,9 @@ var SWIFT_PARSER_VERSION = "1";
9868
10859
  var METAL_PARSER_VERSION = "1";
9869
10860
  var SYMBOL_EXTRACTOR_VERSION = "1";
9870
10861
  function isPathWithinRoot2(filePath, rootPath) {
9871
- const normalizedFilePath = path19.resolve(filePath);
9872
- const normalizedRoot = path19.resolve(rootPath);
9873
- return normalizedFilePath === normalizedRoot || normalizedFilePath.startsWith(`${normalizedRoot}${path19.sep}`);
10862
+ const normalizedFilePath = path20.resolve(filePath);
10863
+ const normalizedRoot = path20.resolve(rootPath);
10864
+ return normalizedFilePath === normalizedRoot || normalizedFilePath.startsWith(`${normalizedRoot}${path20.sep}`);
9874
10865
  }
9875
10866
  function promoteIdentifierMatches(query, combined, semanticCandidates, keywordCandidates, database, branchChunkIds, prioritizeSourcePaths = classifyQueryIntentRaw(query) === "source") {
9876
10867
  if (combined.length === 0) {
@@ -10201,10 +11192,10 @@ function matchesHardSearchFilters(candidate, options, projectRoot) {
10201
11192
  }
10202
11193
  if (options?.directory) {
10203
11194
  const candidatePath = canonicalizePathForComparison(
10204
- path19.resolve(projectRoot, candidate.metadata.filePath.replace(/\\/g, path19.sep))
11195
+ path20.resolve(projectRoot, candidate.metadata.filePath.replace(/\\/g, path20.sep))
10205
11196
  );
10206
11197
  const directoryPath = canonicalizePathForComparison(
10207
- path19.resolve(projectRoot, options.directory.trim().replace(/\\/g, path19.sep))
11198
+ path20.resolve(projectRoot, options.directory.trim().replace(/\\/g, path20.sep))
10208
11199
  );
10209
11200
  if (!isPathWithinRoot2(candidatePath, directoryPath)) return false;
10210
11201
  }
@@ -10317,26 +11308,37 @@ var Indexer = class _Indexer {
10317
11308
  return this.indexPathOverride ?? resolveProjectIndexPath(this.projectRoot, this.config.scope, this.host);
10318
11309
  }
10319
11310
  toCanonicalFilePath(filePath) {
10320
- if (!path19.isAbsolute(filePath)) {
11311
+ if (!path20.isAbsolute(filePath)) {
10321
11312
  return this.resolveStoredFilePath(filePath, this.projectRoot);
10322
11313
  }
10323
- if (path19.resolve(this.materializedProjectRoot) === path19.resolve(this.projectRoot) || !isPathWithinRoot2(filePath, this.materializedProjectRoot)) {
11314
+ if (path20.resolve(this.materializedProjectRoot) === path20.resolve(this.projectRoot) || !isPathWithinRoot2(filePath, this.materializedProjectRoot)) {
10324
11315
  return filePath;
10325
11316
  }
10326
- return path19.resolve(this.projectRoot, path19.relative(this.materializedProjectRoot, filePath));
11317
+ return path20.resolve(this.projectRoot, path20.relative(this.materializedProjectRoot, filePath));
10327
11318
  }
10328
11319
  toStoredFilePath(filePath) {
10329
11320
  const canonicalFilePath = this.toCanonicalFilePath(filePath);
10330
11321
  if (this.config.scope !== "project" || !isPathWithinRoot2(canonicalFilePath, this.projectRoot)) {
10331
11322
  return canonicalFilePath;
10332
11323
  }
10333
- return path19.relative(this.projectRoot, canonicalFilePath).split(path19.sep).join("/");
11324
+ return path20.relative(this.projectRoot, canonicalFilePath).split(path20.sep).join("/");
11325
+ }
11326
+ isStoredPathExcluded(storedPath) {
11327
+ let matchPath = storedPath.split(path20.sep).join("/");
11328
+ if (path20.isAbsolute(storedPath)) {
11329
+ const relativePath = path20.relative(this.projectRoot, storedPath).split(path20.sep).join("/");
11330
+ if (relativePath.startsWith("..") || path20.isAbsolute(relativePath)) {
11331
+ return false;
11332
+ }
11333
+ matchPath = relativePath;
11334
+ }
11335
+ return isExcludedByPatterns(matchPath, this.config.exclude);
10334
11336
  }
10335
11337
  resolveStoredFilePath(filePath, rootPath = this.projectRoot) {
10336
- if (path19.isAbsolute(filePath)) {
11338
+ if (path20.isAbsolute(filePath)) {
10337
11339
  return filePath;
10338
11340
  }
10339
- const resolvedPath = path19.resolve(rootPath, ...filePath.split("/"));
11341
+ const resolvedPath = path20.resolve(rootPath, ...filePath.split("/"));
10340
11342
  if (!isPathWithinRoot2(resolvedPath, rootPath)) {
10341
11343
  throw new Error(`Stored project path escapes project root: ${JSON.stringify(filePath)}`);
10342
11344
  }
@@ -10360,7 +11362,7 @@ var Indexer = class _Indexer {
10360
11362
  }
10361
11363
  toMaterializedFilePath(filePath) {
10362
11364
  const storedFilePath = this.toStoredFilePath(filePath);
10363
- if (path19.isAbsolute(storedFilePath)) {
11365
+ if (path20.isAbsolute(storedFilePath)) {
10364
11366
  return storedFilePath;
10365
11367
  }
10366
11368
  return this.resolveStoredFilePath(storedFilePath, this.materializedProjectRoot);
@@ -10377,10 +11379,10 @@ var Indexer = class _Indexer {
10377
11379
  }
10378
11380
  getRuntimeArtifactPath(fileName) {
10379
11381
  const namespace = this.getRuntimeArtifactNamespace();
10380
- if (!namespace) return path19.join(this.indexPath, fileName);
10381
- const extension = path19.extname(fileName);
11382
+ if (!namespace) return path20.join(this.indexPath, fileName);
11383
+ const extension = path20.extname(fileName);
10382
11384
  const baseName = fileName.slice(0, fileName.length - extension.length);
10383
- return path19.join(this.indexPath, `${baseName}.${namespace}${extension}`);
11385
+ return path20.join(this.indexPath, `${baseName}.${namespace}${extension}`);
10384
11386
  }
10385
11387
  refreshRuntimeArtifactPaths() {
10386
11388
  this.fileHashCachePath = this.getRuntimeArtifactPath("file-hashes.json");
@@ -10393,14 +11395,14 @@ var Indexer = class _Indexer {
10393
11395
  getMaterializedKnowledgeBases() {
10394
11396
  const canonicalProjectRoot = this.getCanonicalPath(this.projectRoot);
10395
11397
  return this.config.knowledgeBases.map((knowledgeBase) => {
10396
- const configuredPath = path19.isAbsolute(knowledgeBase) ? knowledgeBase : path19.resolve(this.projectRoot, knowledgeBase);
11398
+ const configuredPath = path20.isAbsolute(knowledgeBase) ? knowledgeBase : path20.resolve(this.projectRoot, knowledgeBase);
10397
11399
  const canonicalPath = this.getCanonicalPath(configuredPath);
10398
11400
  if (!isPathWithinRoot2(canonicalPath, canonicalProjectRoot)) {
10399
11401
  return canonicalPath;
10400
11402
  }
10401
- return path19.resolve(
11403
+ return path20.resolve(
10402
11404
  this.materializedProjectRoot,
10403
- path19.relative(canonicalProjectRoot, canonicalPath)
11405
+ path20.relative(canonicalProjectRoot, canonicalPath)
10404
11406
  );
10405
11407
  });
10406
11408
  }
@@ -10408,7 +11410,7 @@ var Indexer = class _Indexer {
10408
11410
  try {
10409
11411
  return canonicalizePathForComparison(targetPath);
10410
11412
  } catch {
10411
- return path19.resolve(targetPath);
11413
+ return path20.resolve(targetPath);
10412
11414
  }
10413
11415
  }
10414
11416
  getProjectIdentityHash(projectRoot) {
@@ -10489,7 +11491,7 @@ var Indexer = class _Indexer {
10489
11491
  } catch (error) {
10490
11492
  releaseError = error;
10491
11493
  this.writerArtifactFingerprint = null;
10492
- if (!existsSync11(lease.lockPath) && this.activeIndexLease?.owner.token === lease.owner.token) {
11494
+ if (!existsSync12(lease.lockPath) && this.activeIndexLease?.owner.token === lease.owner.token) {
10493
11495
  this.activeIndexLease = null;
10494
11496
  }
10495
11497
  }
@@ -10507,12 +11509,12 @@ var Indexer = class _Indexer {
10507
11509
  return this.activeIndexLease;
10508
11510
  }
10509
11511
  loadFileHashCache() {
10510
- if (!existsSync11(this.fileHashCachePath)) {
11512
+ if (!existsSync12(this.fileHashCachePath)) {
10511
11513
  this.fileHashCache = /* @__PURE__ */ new Map();
10512
11514
  return;
10513
11515
  }
10514
11516
  try {
10515
- const data = readFileSync8(this.fileHashCachePath, "utf-8");
11517
+ const data = readFileSync9(this.fileHashCachePath, "utf-8");
10516
11518
  const parsed = JSON.parse(data);
10517
11519
  this.fileHashCache = new Map(Object.entries(parsed));
10518
11520
  } catch (error) {
@@ -10534,24 +11536,24 @@ var Indexer = class _Indexer {
10534
11536
  atomicWriteSync(targetPath, data) {
10535
11537
  const lease = this.requireActiveLease();
10536
11538
  const tempPath = createLeaseTemporaryPath(targetPath, lease.owner, "tmp");
10537
- mkdirSync4(path19.dirname(targetPath), { recursive: true });
11539
+ mkdirSync5(path20.dirname(targetPath), { recursive: true });
10538
11540
  try {
10539
- writeFileSync3(tempPath, data);
10540
- renameSync3(tempPath, targetPath);
11541
+ writeFileSync4(tempPath, data);
11542
+ renameSync4(tempPath, targetPath);
10541
11543
  } finally {
10542
11544
  removeLeaseTemporaryPath(tempPath);
10543
11545
  }
10544
11546
  }
10545
11547
  saveInvertedIndex(invertedIndex) {
10546
11548
  this.atomicWriteSync(
10547
- path19.join(this.indexPath, "inverted-index.json"),
11549
+ path20.join(this.indexPath, "inverted-index.json"),
10548
11550
  invertedIndex.serialize()
10549
11551
  );
10550
11552
  }
10551
11553
  getScopedRoots(projectRoot = this.projectRoot) {
10552
11554
  const roots = /* @__PURE__ */ new Set([this.getCanonicalPath(projectRoot)]);
10553
11555
  for (const kbRoot of this.config.knowledgeBases) {
10554
- roots.add(this.getCanonicalPath(path19.resolve(projectRoot, kbRoot)));
11556
+ roots.add(this.getCanonicalPath(path20.resolve(projectRoot, kbRoot)));
10555
11557
  }
10556
11558
  return Array.from(roots);
10557
11559
  }
@@ -10968,7 +11970,7 @@ var Indexer = class _Indexer {
10968
11970
  return configuredProviderInfo !== null && recovery.embeddingProvider === configuredProviderInfo.provider && recovery.embeddingModel === configuredProviderInfo.modelInfo.model && recovery.embeddingDimensions === configuredProviderInfo.modelInfo.dimensions && recovery.embeddingStrategyVersion === EMBEDDING_STRATEGY_VERSION;
10969
11971
  }
10970
11972
  hasUnknownLegacyForceIndexClear(owner) {
10971
- return owner.operation === "force-index" && owner.clearRecovery === void 0 && owner.recoveryProtocolVersion !== 1 && existsSync11(path19.join(this.indexPath, "force-index-phase"));
11973
+ return owner.operation === "force-index" && owner.clearRecovery === void 0 && owner.recoveryProtocolVersion !== 1 && existsSync12(path20.join(this.indexPath, "force-index-phase"));
10972
11974
  }
10973
11975
  async recoverFromInterruptedIndexingUnlocked(owners) {
10974
11976
  for (const owner of owners) {
@@ -11154,7 +12156,7 @@ var Indexer = class _Indexer {
11154
12156
  }
11155
12157
  }
11156
12158
  clearFailedBatchState() {
11157
- if (existsSync11(this.failedBatchesPath)) {
12159
+ if (existsSync12(this.failedBatchesPath)) {
11158
12160
  try {
11159
12161
  unlinkSync2(this.failedBatchesPath);
11160
12162
  } catch {
@@ -11356,7 +12358,7 @@ var Indexer = class _Indexer {
11356
12358
  await options.queue.onSizeLessThan(Math.max(1, options.providerRateLimits.concurrency));
11357
12359
  const task = options.queue.add(async () => {
11358
12360
  if (options.rateLimitState.backoffMs > 0) {
11359
- await new Promise((resolve17) => setTimeout(resolve17, options.rateLimitState.backoffMs));
12361
+ await new Promise((resolve18) => setTimeout(resolve18, options.rateLimitState.backoffMs));
11360
12362
  }
11361
12363
  try {
11362
12364
  const embeddingResult = await pRetry(
@@ -11775,12 +12777,12 @@ var Indexer = class _Indexer {
11775
12777
  }
11776
12778
  }
11777
12779
  captureReaderArtifactFingerprint() {
11778
- const storePath = path19.join(this.indexPath, "vectors");
12780
+ const storePath = path20.join(this.indexPath, "vectors");
11779
12781
  return {
11780
12782
  vectors: `${this.getReaderFileFingerprint(storePath)}|${this.getReaderFileFingerprint(`${storePath}.meta.json`)}`,
11781
- keyword: this.getReaderFileFingerprint(path19.join(this.indexPath, "inverted-index.json")),
11782
- database: this.getReaderFileFingerprint(path19.join(this.indexPath, "codebase.db")),
11783
- databaseIdentity: this.getReaderFileFingerprint(path19.join(this.indexPath, "codebase.db"), true)
12783
+ keyword: this.getReaderFileFingerprint(path20.join(this.indexPath, "inverted-index.json")),
12784
+ database: this.getReaderFileFingerprint(path20.join(this.indexPath, "codebase.db")),
12785
+ databaseIdentity: this.getReaderFileFingerprint(path20.join(this.indexPath, "codebase.db"), true)
11784
12786
  };
11785
12787
  }
11786
12788
  refreshReaderArtifacts() {
@@ -11805,13 +12807,13 @@ var Indexer = class _Indexer {
11805
12807
  issues.set(component, this.createReadIssue(component, message));
11806
12808
  this.readerArtifactRetryAfter.set(component, Date.now() + READER_ARTIFACT_RETRY_INTERVAL_MS);
11807
12809
  };
11808
- const storePath = path19.join(this.indexPath, "vectors");
12810
+ const storePath = path20.join(this.indexPath, "vectors");
11809
12811
  const vectorMetadataPath = `${storePath}.meta.json`;
11810
- const invertedIndexPath = path19.join(this.indexPath, "inverted-index.json");
11811
- const dbPath = path19.join(this.indexPath, "codebase.db");
12812
+ const invertedIndexPath = path20.join(this.indexPath, "inverted-index.json");
12813
+ const dbPath = path20.join(this.indexPath, "codebase.db");
11812
12814
  if (vectorsChanged || retryDue("vectors")) {
11813
- const vectorStoreExists = existsSync11(storePath);
11814
- const vectorMetadataExists = existsSync11(vectorMetadataPath);
12815
+ const vectorStoreExists = existsSync12(storePath);
12816
+ const vectorMetadataExists = existsSync12(vectorMetadataPath);
11815
12817
  if (vectorStoreExists && vectorMetadataExists) {
11816
12818
  try {
11817
12819
  const store = new VectorStore(storePath, this.configuredProviderInfo.modelInfo.dimensions);
@@ -11826,8 +12828,8 @@ var Indexer = class _Indexer {
11826
12828
  setIssue("vectors", this.getVectorReadIssueMessage());
11827
12829
  }
11828
12830
  }
11829
- if (keywordChanged || retryDue("keyword") || !existsSync11(invertedIndexPath) && (this.store?.count() ?? 0) > 0) {
11830
- if (existsSync11(invertedIndexPath)) {
12831
+ if (keywordChanged || retryDue("keyword") || !existsSync12(invertedIndexPath) && (this.store?.count() ?? 0) > 0) {
12832
+ if (existsSync12(invertedIndexPath)) {
11831
12833
  try {
11832
12834
  const invertedIndex = new InvertedIndex(invertedIndexPath);
11833
12835
  invertedIndex.load();
@@ -11842,7 +12844,7 @@ var Indexer = class _Indexer {
11842
12844
  }
11843
12845
  }
11844
12846
  if (databaseReplaced || databaseChanged && issues.has("database") || retryDue("database")) {
11845
- if (existsSync11(dbPath)) {
12847
+ if (existsSync12(dbPath)) {
11846
12848
  try {
11847
12849
  const database = Database.openReadOnly(dbPath);
11848
12850
  if (this.database) {
@@ -11924,11 +12926,11 @@ var Indexer = class _Indexer {
11924
12926
  });
11925
12927
  this.provider = createEmbeddingProvider(this.configuredProviderInfo);
11926
12928
  const dimensions = this.configuredProviderInfo.modelInfo.dimensions;
11927
- const storePath = path19.join(this.indexPath, "vectors");
12929
+ const storePath = path20.join(this.indexPath, "vectors");
11928
12930
  const vectorMetadataPath = `${storePath}.meta.json`;
11929
- const invertedIndexPath = path19.join(this.indexPath, "inverted-index.json");
11930
- const dbPath = path19.join(this.indexPath, "codebase.db");
11931
- let dbIsNew = !existsSync11(dbPath);
12931
+ const invertedIndexPath = path20.join(this.indexPath, "inverted-index.json");
12932
+ const dbPath = path20.join(this.indexPath, "codebase.db");
12933
+ let dbIsNew = !existsSync12(dbPath);
11932
12934
  const readerArtifactFingerprint = mode === "reader" ? this.captureReaderArtifactFingerprint() : null;
11933
12935
  if (mode === "writer") {
11934
12936
  await fsPromises3.mkdir(this.indexPath, { recursive: true });
@@ -11960,14 +12962,14 @@ var Indexer = class _Indexer {
11960
12962
  }
11961
12963
  }
11962
12964
  this.store = new VectorStore(storePath, dimensions);
11963
- if (existsSync11(storePath) || existsSync11(vectorMetadataPath)) {
12965
+ if (existsSync12(storePath) || existsSync12(vectorMetadataPath)) {
11964
12966
  this.store.load();
11965
12967
  }
11966
12968
  this.invertedIndex = new InvertedIndex(invertedIndexPath);
11967
12969
  try {
11968
12970
  this.invertedIndex.load();
11969
12971
  } catch {
11970
- if (existsSync11(invertedIndexPath)) {
12972
+ if (existsSync12(invertedIndexPath)) {
11971
12973
  await fsPromises3.unlink(invertedIndexPath);
11972
12974
  }
11973
12975
  this.invertedIndex = new InvertedIndex(invertedIndexPath);
@@ -11985,8 +12987,8 @@ var Indexer = class _Indexer {
11985
12987
  }
11986
12988
  } else {
11987
12989
  this.store = new VectorStore(storePath, dimensions);
11988
- const vectorStoreExists = existsSync11(storePath);
11989
- const vectorMetadataExists = existsSync11(vectorMetadataPath);
12990
+ const vectorStoreExists = existsSync12(storePath);
12991
+ const vectorMetadataExists = existsSync12(vectorMetadataPath);
11990
12992
  const vectorReadFailureMessage = this.getVectorReadIssueMessage();
11991
12993
  if (vectorStoreExists !== vectorMetadataExists) {
11992
12994
  this.recordReadIssue("vectors", vectorReadFailureMessage);
@@ -11999,7 +13001,7 @@ var Indexer = class _Indexer {
11999
13001
  }
12000
13002
  }
12001
13003
  this.invertedIndex = new InvertedIndex(invertedIndexPath);
12002
- if (existsSync11(invertedIndexPath)) {
13004
+ if (existsSync12(invertedIndexPath)) {
12003
13005
  try {
12004
13006
  this.invertedIndex.load();
12005
13007
  } catch (error) {
@@ -12013,7 +13015,7 @@ var Indexer = class _Indexer {
12013
13015
  } else if (this.store.count() > 0) {
12014
13016
  this.recordReadIssue("keyword", this.getKeywordReadIssueMessage());
12015
13017
  }
12016
- if (existsSync11(dbPath)) {
13018
+ if (existsSync12(dbPath)) {
12017
13019
  try {
12018
13020
  this.database = Database.openReadOnly(dbPath);
12019
13021
  } catch (error) {
@@ -12105,7 +13107,7 @@ var Indexer = class _Indexer {
12105
13107
  if (await this.tryResetCorruptedIndex("running automatic orphan garbage collection", error)) {
12106
13108
  return {
12107
13109
  resetCorruptedIndex: true,
12108
- warning: this.getCorruptedIndexWarning(path19.join(this.indexPath, "codebase.db"))
13110
+ warning: this.getCorruptedIndexWarning(path20.join(this.indexPath, "codebase.db"))
12109
13111
  };
12110
13112
  }
12111
13113
  throw error;
@@ -12120,7 +13122,7 @@ var Indexer = class _Indexer {
12120
13122
  return;
12121
13123
  }
12122
13124
  const retainedEntries = store.getAllMetadata().filter(({ key }) => !excludedSet.has(key));
12123
- const storeBasePath = path19.join(this.indexPath, "vectors");
13125
+ const storeBasePath = path20.join(this.indexPath, "vectors");
12124
13126
  const storeIndexPath = storeBasePath;
12125
13127
  const storeMetadataPath = `${storeBasePath}.meta.json`;
12126
13128
  const lease = this.requireActiveLease();
@@ -12130,19 +13132,19 @@ var Indexer = class _Indexer {
12130
13132
  let backedUpMetadata = false;
12131
13133
  let rebuiltCount = 0;
12132
13134
  let skippedCount = 0;
12133
- if (existsSync11(backupIndexPath)) {
13135
+ if (existsSync12(backupIndexPath)) {
12134
13136
  unlinkSync2(backupIndexPath);
12135
13137
  }
12136
- if (existsSync11(backupMetadataPath)) {
13138
+ if (existsSync12(backupMetadataPath)) {
12137
13139
  unlinkSync2(backupMetadataPath);
12138
13140
  }
12139
13141
  try {
12140
- if (existsSync11(storeIndexPath)) {
12141
- renameSync3(storeIndexPath, backupIndexPath);
13142
+ if (existsSync12(storeIndexPath)) {
13143
+ renameSync4(storeIndexPath, backupIndexPath);
12142
13144
  backedUpIndex = true;
12143
13145
  }
12144
- if (existsSync11(storeMetadataPath)) {
12145
- renameSync3(storeMetadataPath, backupMetadataPath);
13146
+ if (existsSync12(storeMetadataPath)) {
13147
+ renameSync4(storeMetadataPath, backupMetadataPath);
12146
13148
  backedUpMetadata = true;
12147
13149
  }
12148
13150
  store.clear();
@@ -12162,10 +13164,10 @@ var Indexer = class _Indexer {
12162
13164
  rebuiltCount += 1;
12163
13165
  }
12164
13166
  store.save();
12165
- if (backedUpIndex && existsSync11(backupIndexPath)) {
13167
+ if (backedUpIndex && existsSync12(backupIndexPath)) {
12166
13168
  unlinkSync2(backupIndexPath);
12167
13169
  }
12168
- if (backedUpMetadata && existsSync11(backupMetadataPath)) {
13170
+ if (backedUpMetadata && existsSync12(backupMetadataPath)) {
12169
13171
  unlinkSync2(backupMetadataPath);
12170
13172
  }
12171
13173
  this.logger.gc("info", "Rebuilt vector store to avoid native remove", {
@@ -12178,17 +13180,17 @@ var Indexer = class _Indexer {
12178
13180
  store.clear();
12179
13181
  } catch {
12180
13182
  }
12181
- if (existsSync11(storeIndexPath)) {
13183
+ if (existsSync12(storeIndexPath)) {
12182
13184
  unlinkSync2(storeIndexPath);
12183
13185
  }
12184
- if (existsSync11(storeMetadataPath)) {
13186
+ if (existsSync12(storeMetadataPath)) {
12185
13187
  unlinkSync2(storeMetadataPath);
12186
13188
  }
12187
- if (backedUpIndex && existsSync11(backupIndexPath)) {
12188
- renameSync3(backupIndexPath, storeIndexPath);
13189
+ if (backedUpIndex && existsSync12(backupIndexPath)) {
13190
+ renameSync4(backupIndexPath, storeIndexPath);
12189
13191
  }
12190
- if (backedUpMetadata && existsSync11(backupMetadataPath)) {
12191
- renameSync3(backupMetadataPath, storeMetadataPath);
13192
+ if (backedUpMetadata && existsSync12(backupMetadataPath)) {
13193
+ renameSync4(backupMetadataPath, storeMetadataPath);
12192
13194
  }
12193
13195
  if (backedUpIndex || backedUpMetadata) {
12194
13196
  store.load();
@@ -12203,11 +13205,11 @@ var Indexer = class _Indexer {
12203
13205
  return `Detected a corrupted local SQLite index at ${dbPath} and reset the local index. Run index_codebase to rebuild search data.`;
12204
13206
  }
12205
13207
  async removeProjectRuntimeStateArtifacts() {
12206
- if (!existsSync11(this.indexPath)) return;
13208
+ if (!existsSync12(this.indexPath)) return;
12207
13209
  const names = await fsPromises3.readdir(this.indexPath);
12208
13210
  const runtimeStatePattern = /^(?:file-hashes|failed-batches)(?:\.[a-f0-9]{16})?\.json$/;
12209
13211
  await Promise.all(
12210
- names.filter((name) => runtimeStatePattern.test(name)).map((name) => fsPromises3.rm(path19.join(this.indexPath, name), { force: true }))
13212
+ names.filter((name) => runtimeStatePattern.test(name)).map((name) => fsPromises3.rm(path20.join(this.indexPath, name), { force: true }))
12211
13213
  );
12212
13214
  }
12213
13215
  async resetLocalIndexArtifacts() {
@@ -12223,13 +13225,13 @@ var Indexer = class _Indexer {
12223
13225
  this.readerArtifactRetryAfter.clear();
12224
13226
  this.fileHashCache.clear();
12225
13227
  const resetPaths = [
12226
- path19.join(this.indexPath, "codebase.db"),
12227
- path19.join(this.indexPath, "codebase.db-shm"),
12228
- path19.join(this.indexPath, "codebase.db-wal"),
12229
- path19.join(this.indexPath, "vectors"),
12230
- path19.join(this.indexPath, "vectors.usearch"),
12231
- path19.join(this.indexPath, "vectors.meta.json"),
12232
- path19.join(this.indexPath, "inverted-index.json")
13228
+ path20.join(this.indexPath, "codebase.db"),
13229
+ path20.join(this.indexPath, "codebase.db-shm"),
13230
+ path20.join(this.indexPath, "codebase.db-wal"),
13231
+ path20.join(this.indexPath, "vectors"),
13232
+ path20.join(this.indexPath, "vectors.usearch"),
13233
+ path20.join(this.indexPath, "vectors.meta.json"),
13234
+ path20.join(this.indexPath, "inverted-index.json")
12233
13235
  ];
12234
13236
  await Promise.all(resetPaths.map((targetPath) => fsPromises3.rm(targetPath, { recursive: true, force: true })));
12235
13237
  await this.removeProjectRuntimeStateArtifacts();
@@ -12239,7 +13241,7 @@ var Indexer = class _Indexer {
12239
13241
  if (!isSqliteCorruptionError(error)) {
12240
13242
  return false;
12241
13243
  }
12242
- const dbPath = path19.join(this.indexPath, "codebase.db");
13244
+ const dbPath = path20.join(this.indexPath, "codebase.db");
12243
13245
  const warning = this.getCorruptedIndexWarning(dbPath);
12244
13246
  const errorMessage = getErrorMessage4(error);
12245
13247
  if (this.config.scope === "global") {
@@ -12626,10 +13628,10 @@ var Indexer = class _Indexer {
12626
13628
  const reparseCachedMetalFiles = database.getMetadata(metalParserMetadataKey) !== METAL_PARSER_VERSION;
12627
13629
  const symbolExtractorMetadataKey = this.getSymbolExtractorVersionMetadataKey();
12628
13630
  const refreshCachedSymbols = database.getMetadata(symbolExtractorMetadataKey) !== SYMBOL_EXTRACTOR_VERSION;
12629
- if (reparseCachedSwiftFiles && Array.from(this.fileHashCache.keys()).some((filePath) => path19.extname(filePath).toLowerCase() === ".swift")) {
13631
+ if (reparseCachedSwiftFiles && Array.from(this.fileHashCache.keys()).some((filePath) => path20.extname(filePath).toLowerCase() === ".swift")) {
12630
13632
  this.logger.info("Reindexing cached Swift files for parser support");
12631
13633
  }
12632
- if (reparseCachedMetalFiles && Array.from(this.fileHashCache.keys()).some((filePath) => path19.extname(filePath).toLowerCase() === ".metal")) {
13634
+ if (reparseCachedMetalFiles && Array.from(this.fileHashCache.keys()).some((filePath) => path20.extname(filePath).toLowerCase() === ".metal")) {
12633
13635
  this.logger.info("Reindexing cached Metal files for parser support");
12634
13636
  }
12635
13637
  const includePatterns = [...this.config.include, ...this.config.additionalInclude];
@@ -12673,8 +13675,8 @@ var Indexer = class _Indexer {
12673
13675
  const needsCallGraphRefresh = cachedHashMatches && needsCallGraphResolutionMigration && database.getChunksByFile(storedPath).some(
12674
13676
  (chunk) => chunk.language === "php" || chunk.language === "c" || chunk.language === "cpp"
12675
13677
  );
12676
- const requiresSwiftParserUpgrade = reparseCachedSwiftFiles && path19.extname(storedPath).toLowerCase() === ".swift";
12677
- const requiresMetalParserUpgrade = reparseCachedMetalFiles && path19.extname(storedPath).toLowerCase() === ".metal";
13678
+ const requiresSwiftParserUpgrade = reparseCachedSwiftFiles && path20.extname(storedPath).toLowerCase() === ".swift";
13679
+ const requiresMetalParserUpgrade = reparseCachedMetalFiles && path20.extname(storedPath).toLowerCase() === ".metal";
12678
13680
  const inMigrationScope = forceScopedReembed && scopedRoots !== null && this.isFileInCurrentScope(storedPath, scopedRoots);
12679
13681
  if (cachedHashMatches && !inMigrationScope && !needsCallGraphRefresh && !requiresSwiftParserUpgrade && !requiresMetalParserUpgrade && !refreshCachedSymbols) {
12680
13682
  unchangedFilePaths.add(storedPath);
@@ -12733,7 +13735,7 @@ var Indexer = class _Indexer {
12733
13735
  }
12734
13736
  }
12735
13737
  }
12736
- const shouldRetryFailedPath = (filePath) => filePath !== null && currentFileHashes.has(filePath) && unchangedFilePaths.has(filePath);
13738
+ const shouldRetryFailedPath = (filePath) => filePath !== null && !this.isStoredPathExcluded(filePath) && currentFileHashes.has(filePath) && unchangedFilePaths.has(filePath);
12737
13739
  const failedProcessing = this.prepareFailedBatchProcessing(scopedRoots, shouldRetryFailedPath);
12738
13740
  const maxChunkTokens = getSafeEmbeddingChunkTokenLimit(configuredProviderInfo);
12739
13741
  const providerRateLimits = this.getProviderRateLimits(configuredProviderInfo.provider);
@@ -12837,7 +13839,7 @@ var Indexer = class _Indexer {
12837
13839
  throw new Error(`Parsed file was not present in its source batch: ${parsed.path}`);
12838
13840
  }
12839
13841
  if (parsed.chunks.length === 0) {
12840
- stats.parseFailures.push(path19.isAbsolute(parsed.path) ? path19.relative(this.projectRoot, parsed.path) : parsed.path);
13842
+ stats.parseFailures.push(path20.isAbsolute(parsed.path) ? path20.relative(this.projectRoot, parsed.path) : parsed.path);
12841
13843
  }
12842
13844
  let chunksToProcess = parsed.chunks;
12843
13845
  if (this.config.indexing.fallbackToTextOnMaxChunks && chunksToProcess.length > this.config.indexing.maxChunksPerFile) {
@@ -13172,8 +14174,8 @@ var Indexer = class _Indexer {
13172
14174
  previousBranchSymbolIds,
13173
14175
  Array.from(allSymbolIds)
13174
14176
  );
13175
- const vectorPath = path19.join(this.indexPath, "vectors");
13176
- const shouldFingerprintLegacyPair = !store.hasFingerprint() && existsSync11(vectorPath) && existsSync11(`${vectorPath}.meta.json`);
14177
+ const vectorPath = path20.join(this.indexPath, "vectors");
14178
+ const shouldFingerprintLegacyPair = !store.hasFingerprint() && existsSync12(vectorPath) && existsSync12(`${vectorPath}.meta.json`);
13177
14179
  if (backfilledBlameMetadata || shouldFingerprintLegacyPair || removedStoredChunks) {
13178
14180
  store.save();
13179
14181
  }
@@ -13968,7 +14970,7 @@ var Indexer = class _Indexer {
13968
14970
  const missingChunkKeys = [];
13969
14971
  const chunkKeysByRemovedFile = /* @__PURE__ */ new Map();
13970
14972
  for (const [filePath, chunkKeys] of filePathsToChunkKeys) {
13971
- if (!existsSync11(this.toMaterializedFilePath(filePath))) {
14973
+ if (!existsSync12(this.toMaterializedFilePath(filePath))) {
13972
14974
  chunkKeysByRemovedFile.set(filePath, chunkKeys);
13973
14975
  for (const key of chunkKeys) {
13974
14976
  missingChunkKeys.push(key);
@@ -14031,7 +15033,7 @@ var Indexer = class _Indexer {
14031
15033
  gcOrphanSymbols: 0,
14032
15034
  gcOrphanCallEdges: 0,
14033
15035
  resetCorruptedIndex: true,
14034
- warning: this.getCorruptedIndexWarning(path19.join(this.indexPath, "codebase.db"))
15036
+ warning: this.getCorruptedIndexWarning(path20.join(this.indexPath, "codebase.db"))
14035
15037
  };
14036
15038
  }
14037
15039
  this.logger.recordGc(removedCount, gcOrphanChunks, gcOrphanEmbeddings);
@@ -14061,7 +15063,8 @@ var Indexer = class _Indexer {
14061
15063
  const maxChunkTokens = getSafeEmbeddingChunkTokenLimit(configuredProviderInfo);
14062
15064
  const providerRateLimits = this.getProviderRateLimits(configuredProviderInfo.provider);
14063
15065
  const roots = this.config.scope === "global" ? this.getScopedRoots() : null;
14064
- const failedProcessing = this.prepareFailedBatchProcessing(roots, () => true);
15066
+ const shouldProcessFailedPath = (filePath) => filePath === null || !this.isStoredPathExcluded(filePath);
15067
+ const failedProcessing = this.prepareFailedBatchProcessing(roots, shouldProcessFailedPath);
14065
15068
  if (failedProcessing.latestById.size === 0) {
14066
15069
  this.finalizeFailedBatchWriteState(failedProcessing.state);
14067
15070
  return { succeeded: 0, failed: 0, remaining: 0 };
@@ -14074,7 +15077,7 @@ var Indexer = class _Indexer {
14074
15077
  const retryableChunks = this.iterateLatestFailedChunks(
14075
15078
  failedProcessing.latestById,
14076
15079
  roots,
14077
- () => true,
15080
+ shouldProcessFailedPath,
14078
15081
  maxChunkTokens
14079
15082
  );
14080
15083
  for (const retryBatch of iterateOrderedFileBatches(
@@ -14344,9 +15347,9 @@ var Indexer = class _Indexer {
14344
15347
  this.requireReadableComponents(readIssues, "database");
14345
15348
  let shortest = [];
14346
15349
  for (const branchKey of this.getBranchCatalogKeys()) {
14347
- const path30 = database.findShortestPath(fromName, toName, branchKey, maxDepth);
14348
- if (path30.length > 0 && (shortest.length === 0 || path30.length < shortest.length)) {
14349
- shortest = path30;
15350
+ const path31 = database.findShortestPath(fromName, toName, branchKey, maxDepth);
15351
+ if (path31.length > 0 && (shortest.length === 0 || path31.length < shortest.length)) {
15352
+ shortest = path31;
14350
15353
  }
14351
15354
  }
14352
15355
  return shortest.map((hop) => this.resolveFilePathRecord(hop));
@@ -14394,13 +15397,13 @@ var Indexer = class _Indexer {
14394
15397
  }
14395
15398
  }
14396
15399
  if (!found) continue;
14397
- const path30 = [];
15400
+ const path31 = [];
14398
15401
  let currentSymbolId = toSymbolId;
14399
15402
  while (true) {
14400
15403
  const symbol = symbolsById.get(currentSymbolId);
14401
15404
  if (!symbol) break;
14402
15405
  const parent = parentBySymbolId.get(currentSymbolId);
14403
- path30.push({
15406
+ path31.push({
14404
15407
  symbolId: symbol.id,
14405
15408
  symbolName: symbol.name,
14406
15409
  filePath: symbol.filePath,
@@ -14410,9 +15413,9 @@ var Indexer = class _Indexer {
14410
15413
  if (!parent) break;
14411
15414
  currentSymbolId = parent.parentId;
14412
15415
  }
14413
- path30.reverse();
14414
- if (path30.length > 0 && (shortest.length === 0 || path30.length < shortest.length)) {
14415
- shortest = path30;
15416
+ path31.reverse();
15417
+ if (path31.length > 0 && (shortest.length === 0 || path31.length < shortest.length)) {
15418
+ shortest = path31;
14416
15419
  }
14417
15420
  }
14418
15421
  return shortest.map((hop) => this.resolveFilePathRecord(hop));
@@ -14563,7 +15566,7 @@ var Indexer = class _Indexer {
14563
15566
  );
14564
15567
  }
14565
15568
  }
14566
- const toStoredChangedFiles = (filePaths) => filePaths.map((filePath) => this.toStoredFilePath(path19.resolve(this.projectRoot, filePath)));
15569
+ const toStoredChangedFiles = (filePaths) => filePaths.map((filePath) => this.toStoredFilePath(path20.resolve(this.projectRoot, filePath)));
14567
15570
  const storedChangedFiles = toStoredChangedFiles(changedFiles);
14568
15571
  const directSymbols = database.getSymbolsForFiles(storedChangedFiles, branchKey);
14569
15572
  const directIds = directSymbols.map((s) => s.id);
@@ -14712,12 +15715,12 @@ var Indexer = class _Indexer {
14712
15715
  if (meta.filePath) filePaths.add(meta.filePath);
14713
15716
  }
14714
15717
  const directory = options?.directory?.replace(/\/$/, "");
14715
- const absoluteDirectoryFilter = directory ? path19.resolve(this.projectRoot, directory) : void 0;
15718
+ const absoluteDirectoryFilter = directory ? path20.resolve(this.projectRoot, directory) : void 0;
14716
15719
  for (const filePath of filePaths) {
14717
15720
  if (directory) {
14718
15721
  const absoluteFilePath = this.resolveStoredFilePath(filePath);
14719
15722
  const matchesRelative = filePath === directory || filePath.startsWith(directory + "/");
14720
- const matchesProjectRelative = absoluteDirectoryFilter !== void 0 && (absoluteFilePath === absoluteDirectoryFilter || absoluteFilePath.startsWith(absoluteDirectoryFilter + path19.sep));
15723
+ const matchesProjectRelative = absoluteDirectoryFilter !== void 0 && (absoluteFilePath === absoluteDirectoryFilter || absoluteFilePath.startsWith(absoluteDirectoryFilter + path20.sep));
14721
15724
  if (!matchesRelative && !matchesProjectRelative) {
14722
15725
  continue;
14723
15726
  }
@@ -14834,15 +15837,24 @@ function getOrCreateIndexer(projectRoot, host) {
14834
15837
  }
14835
15838
  const indexer = new Indexer(projectRoot, config, host);
14836
15839
  indexerCache.set(key, indexer);
14837
- configureAutoIndex(projectRoot, host, config, () => getOrCreateIndexer(projectRoot, host));
15840
+ configureAutoIndex(projectRoot, host, config, () => getOrCreateIndexer(projectRoot, host), {
15841
+ preserveManagedWorker: true,
15842
+ synchronizeBackgroundWorker: false
15843
+ });
14838
15844
  return indexer;
14839
15845
  }
14840
- function initializeTools(projectRoot, config, host) {
15846
+ function initializeTools(projectRoot, config, host, options = {}) {
14841
15847
  defaultProjectRoots.set(host, projectRoot);
14842
15848
  const key = getIndexerCacheKey(projectRoot, host);
15849
+ if (options.preserveManagedWorker === true && isBackgroundWorkerManaged(projectRoot, host) && indexerCache.has(key)) {
15850
+ return;
15851
+ }
14843
15852
  configCache.set(key, config);
14844
15853
  indexerCache.set(key, new Indexer(projectRoot, config, host));
14845
- configureAutoIndex(projectRoot, host, config, () => getOrCreateIndexer(projectRoot, host));
15854
+ configureAutoIndex(projectRoot, host, config, () => getOrCreateIndexer(projectRoot, host), {
15855
+ preserveManagedWorker: options.preserveManagedWorker,
15856
+ synchronizeBackgroundWorker: false
15857
+ });
14846
15858
  }
14847
15859
  function getIndexerForProject(projectRoot, host) {
14848
15860
  const root = getProjectRoot(projectRoot, host);
@@ -14856,7 +15868,9 @@ function refreshIndexerForDirectory(projectRoot, host, config = parseConfig(load
14856
15868
  const key = getIndexerCacheKey(projectRoot, host);
14857
15869
  configCache.set(key, config);
14858
15870
  indexerCache.set(key, new Indexer(projectRoot, config, host));
14859
- configureAutoIndex(projectRoot, host, config, () => getOrCreateIndexer(projectRoot, host));
15871
+ configureAutoIndex(projectRoot, host, config, () => getOrCreateIndexer(projectRoot, host), {
15872
+ synchronizeBackgroundWorker: true
15873
+ });
14860
15874
  return config;
14861
15875
  }
14862
15876
  var AutoIndexRetrievalUnavailableError = class extends Error {
@@ -14883,7 +15897,7 @@ function trimOrUndefined(value) {
14883
15897
  return normalized || void 0;
14884
15898
  }
14885
15899
  function normalizeCallGraphPath(value) {
14886
- let normalized = path20.posix.normalize(value.trim().replaceAll("\\", "/"));
15900
+ let normalized = path21.posix.normalize(value.trim().replaceAll("\\", "/"));
14887
15901
  if (normalized.startsWith("./")) {
14888
15902
  normalized = normalized.slice(2);
14889
15903
  }
@@ -15076,12 +16090,12 @@ async function getCallGraphPath(projectRoot, host, from, to, maxDepth, fromFileP
15076
16090
  if (fromResolution.status !== "resolved" || toResolution.status !== "resolved") {
15077
16091
  return { from: fromResolution, to: toResolution, path: [] };
15078
16092
  }
15079
- const path30 = await indexer.findCallPathBySymbolIds(
16093
+ const path31 = await indexer.findCallPathBySymbolIds(
15080
16094
  fromResolution.symbolId,
15081
16095
  toResolution.symbolId,
15082
16096
  maxDepth
15083
16097
  );
15084
- return { from: fromResolution, to: toResolution, path: path30 };
16098
+ return { from: fromResolution, to: toResolution, path: path31 };
15085
16099
  }
15086
16100
  async function runIndexCodebase(projectRoot, host, args, onProgress) {
15087
16101
  const root = getProjectRoot(projectRoot, host);
@@ -15267,15 +16281,15 @@ async function getIndexLogs(projectRoot, host, args) {
15267
16281
  function addKnowledgeBase(projectRoot, host, knowledgeBasePath) {
15268
16282
  const root = getProjectRoot(projectRoot, host);
15269
16283
  const inputPath = knowledgeBasePath.trim();
15270
- const normalizedPath2 = path20.resolve(
15271
- path20.isAbsolute(inputPath) ? inputPath : resolveKnowledgeBasePath(inputPath, root)
16284
+ const normalizedPath2 = path21.resolve(
16285
+ path21.isAbsolute(inputPath) ? inputPath : resolveKnowledgeBasePath(inputPath, root)
15272
16286
  );
15273
- if (!existsSync12(normalizedPath2)) {
16287
+ if (!existsSync13(normalizedPath2)) {
15274
16288
  return `Error: Directory does not exist: ${normalizedPath2}`;
15275
16289
  }
15276
16290
  let realPath;
15277
16291
  try {
15278
- realPath = realpathSync5(normalizedPath2);
16292
+ realPath = realpathSync6(normalizedPath2);
15279
16293
  } catch {
15280
16294
  return `Error: Cannot resolve path: ${normalizedPath2}`;
15281
16295
  }
@@ -15304,7 +16318,7 @@ function addKnowledgeBase(projectRoot, host, knowledgeBasePath) {
15304
16318
  }
15305
16319
  }
15306
16320
  for (const dotDir of sensitiveDotDirs) {
15307
- const sensitiveDir = path20.join(homeDir, dotDir);
16321
+ const sensitiveDir = path21.join(homeDir, dotDir);
15308
16322
  if (sensitiveDir && (realPath === sensitiveDir || realPath.startsWith(`${sensitiveDir}/`))) {
15309
16323
  return `Error: Adding sensitive directory as knowledge base is not allowed: ${normalizedPath2}`;
15310
16324
  }
@@ -15350,7 +16364,7 @@ function listKnowledgeBases(projectRoot, host) {
15350
16364
  for (let i = 0; i < knowledgeBases.length; i++) {
15351
16365
  const kb = knowledgeBases[i];
15352
16366
  const resolvedPath = resolveKnowledgeBasePath(kb, root);
15353
- const exists = existsSync12(resolvedPath);
16367
+ const exists = existsSync13(resolvedPath);
15354
16368
  result += `[${i + 1}] ${kb}
15355
16369
  `;
15356
16370
  result += ` Resolved: ${resolvedPath}
@@ -15367,7 +16381,7 @@ function listKnowledgeBases(projectRoot, host) {
15367
16381
  }
15368
16382
  result += "\n";
15369
16383
  }
15370
- const hasHostConfig = existsSync12(path20.join(root, getHostProjectConfigRelativePath(host)));
16384
+ const hasHostConfig = existsSync13(path21.join(root, getHostProjectConfigRelativePath(host)));
15371
16385
  if (hasHostConfig) {
15372
16386
  result += `
15373
16387
  Config sources: 1 file(s).`;
@@ -15401,7 +16415,7 @@ Run /index to rebuild the index without the removed knowledge base.`;
15401
16415
  }
15402
16416
 
15403
16417
  // src/watcher/file-watcher.ts
15404
- import { existsSync as existsSync13, statSync as statSync6 } from "fs";
16418
+ import { existsSync as existsSync14, statSync as statSync6 } from "fs";
15405
16419
 
15406
16420
  // node_modules/chokidar/index.js
15407
16421
  import { EventEmitter as EventEmitter2 } from "events";
@@ -15493,7 +16507,7 @@ var ReaddirpStream = class extends Readable {
15493
16507
  this._directoryFilter = normalizeFilter(opts.directoryFilter);
15494
16508
  const statMethod = opts.lstat ? lstat : stat;
15495
16509
  if (wantBigintFsStats) {
15496
- this._stat = (path30) => statMethod(path30, { bigint: true });
16510
+ this._stat = (path31) => statMethod(path31, { bigint: true });
15497
16511
  } else {
15498
16512
  this._stat = statMethod;
15499
16513
  }
@@ -15518,8 +16532,8 @@ var ReaddirpStream = class extends Readable {
15518
16532
  const par = this.parent;
15519
16533
  const fil = par && par.files;
15520
16534
  if (fil && fil.length > 0) {
15521
- const { path: path30, depth } = par;
15522
- const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path30));
16535
+ const { path: path31, depth } = par;
16536
+ const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path31));
15523
16537
  const awaited = await Promise.all(slice);
15524
16538
  for (const entry of awaited) {
15525
16539
  if (!entry)
@@ -15559,21 +16573,21 @@ var ReaddirpStream = class extends Readable {
15559
16573
  this.reading = false;
15560
16574
  }
15561
16575
  }
15562
- async _exploreDir(path30, depth) {
16576
+ async _exploreDir(path31, depth) {
15563
16577
  let files;
15564
16578
  try {
15565
- files = await readdir(path30, this._rdOptions);
16579
+ files = await readdir(path31, this._rdOptions);
15566
16580
  } catch (error) {
15567
16581
  this._onError(error);
15568
16582
  }
15569
- return { files, depth, path: path30 };
16583
+ return { files, depth, path: path31 };
15570
16584
  }
15571
- async _formatEntry(dirent, path30) {
16585
+ async _formatEntry(dirent, path31) {
15572
16586
  let entry;
15573
- const basename9 = this._isDirent ? dirent.name : dirent;
16587
+ const basename10 = this._isDirent ? dirent.name : dirent;
15574
16588
  try {
15575
- const fullPath = presolve(pjoin(path30, basename9));
15576
- entry = { path: prelative(this._root, fullPath), fullPath, basename: basename9 };
16589
+ const fullPath = presolve(pjoin(path31, basename10));
16590
+ entry = { path: prelative(this._root, fullPath), fullPath, basename: basename10 };
15577
16591
  entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
15578
16592
  } catch (err) {
15579
16593
  this._onError(err);
@@ -15972,16 +16986,16 @@ var delFromSet = (main, prop, item) => {
15972
16986
  };
15973
16987
  var isEmptySet = (val) => val instanceof Set ? val.size === 0 : !val;
15974
16988
  var FsWatchInstances = /* @__PURE__ */ new Map();
15975
- function createFsWatchInstance(path30, options, listener, errHandler, emitRaw) {
16989
+ function createFsWatchInstance(path31, options, listener, errHandler, emitRaw) {
15976
16990
  const handleEvent = (rawEvent, evPath) => {
15977
- listener(path30);
15978
- emitRaw(rawEvent, evPath, { watchedPath: path30 });
15979
- if (evPath && path30 !== evPath) {
15980
- fsWatchBroadcast(sp.resolve(path30, evPath), KEY_LISTENERS, sp.join(path30, evPath));
16991
+ listener(path31);
16992
+ emitRaw(rawEvent, evPath, { watchedPath: path31 });
16993
+ if (evPath && path31 !== evPath) {
16994
+ fsWatchBroadcast(sp.resolve(path31, evPath), KEY_LISTENERS, sp.join(path31, evPath));
15981
16995
  }
15982
16996
  };
15983
16997
  try {
15984
- return fs_watch(path30, {
16998
+ return fs_watch(path31, {
15985
16999
  persistent: options.persistent
15986
17000
  }, handleEvent);
15987
17001
  } catch (error) {
@@ -15997,12 +17011,12 @@ var fsWatchBroadcast = (fullPath, listenerType, val1, val2, val3) => {
15997
17011
  listener(val1, val2, val3);
15998
17012
  });
15999
17013
  };
16000
- var setFsWatchListener = (path30, fullPath, options, handlers) => {
17014
+ var setFsWatchListener = (path31, fullPath, options, handlers) => {
16001
17015
  const { listener, errHandler, rawEmitter } = handlers;
16002
17016
  let cont = FsWatchInstances.get(fullPath);
16003
17017
  let watcher;
16004
17018
  if (!options.persistent) {
16005
- watcher = createFsWatchInstance(path30, options, listener, errHandler, rawEmitter);
17019
+ watcher = createFsWatchInstance(path31, options, listener, errHandler, rawEmitter);
16006
17020
  if (!watcher)
16007
17021
  return;
16008
17022
  return watcher.close.bind(watcher);
@@ -16013,7 +17027,7 @@ var setFsWatchListener = (path30, fullPath, options, handlers) => {
16013
17027
  addAndConvert(cont, KEY_RAW, rawEmitter);
16014
17028
  } else {
16015
17029
  watcher = createFsWatchInstance(
16016
- path30,
17030
+ path31,
16017
17031
  options,
16018
17032
  fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS),
16019
17033
  errHandler,
@@ -16028,7 +17042,7 @@ var setFsWatchListener = (path30, fullPath, options, handlers) => {
16028
17042
  cont.watcherUnusable = true;
16029
17043
  if (isWindows && error.code === "EPERM") {
16030
17044
  try {
16031
- const fd = await open(path30, "r");
17045
+ const fd = await open(path31, "r");
16032
17046
  await fd.close();
16033
17047
  broadcastErr(error);
16034
17048
  } catch (err) {
@@ -16059,7 +17073,7 @@ var setFsWatchListener = (path30, fullPath, options, handlers) => {
16059
17073
  };
16060
17074
  };
16061
17075
  var FsWatchFileInstances = /* @__PURE__ */ new Map();
16062
- var setFsWatchFileListener = (path30, fullPath, options, handlers) => {
17076
+ var setFsWatchFileListener = (path31, fullPath, options, handlers) => {
16063
17077
  const { listener, rawEmitter } = handlers;
16064
17078
  let cont = FsWatchFileInstances.get(fullPath);
16065
17079
  const copts = cont && cont.options;
@@ -16081,7 +17095,7 @@ var setFsWatchFileListener = (path30, fullPath, options, handlers) => {
16081
17095
  });
16082
17096
  const currmtime = curr.mtimeMs;
16083
17097
  if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {
16084
- foreach(cont.listeners, (listener2) => listener2(path30, curr));
17098
+ foreach(cont.listeners, (listener2) => listener2(path31, curr));
16085
17099
  }
16086
17100
  })
16087
17101
  };
@@ -16111,13 +17125,13 @@ var NodeFsHandler = class {
16111
17125
  * @param listener on fs change
16112
17126
  * @returns closer for the watcher instance
16113
17127
  */
16114
- _watchWithNodeFs(path30, listener) {
17128
+ _watchWithNodeFs(path31, listener) {
16115
17129
  const opts = this.fsw.options;
16116
- const directory = sp.dirname(path30);
16117
- const basename9 = sp.basename(path30);
17130
+ const directory = sp.dirname(path31);
17131
+ const basename10 = sp.basename(path31);
16118
17132
  const parent = this.fsw._getWatchedDir(directory);
16119
- parent.add(basename9);
16120
- const absolutePath = sp.resolve(path30);
17133
+ parent.add(basename10);
17134
+ const absolutePath = sp.resolve(path31);
16121
17135
  const options = {
16122
17136
  persistent: opts.persistent
16123
17137
  };
@@ -16126,13 +17140,13 @@ var NodeFsHandler = class {
16126
17140
  let closer;
16127
17141
  if (opts.usePolling) {
16128
17142
  const enableBin = opts.interval !== opts.binaryInterval;
16129
- options.interval = enableBin && isBinaryPath(basename9) ? opts.binaryInterval : opts.interval;
16130
- closer = setFsWatchFileListener(path30, absolutePath, options, {
17143
+ options.interval = enableBin && isBinaryPath(basename10) ? opts.binaryInterval : opts.interval;
17144
+ closer = setFsWatchFileListener(path31, absolutePath, options, {
16131
17145
  listener,
16132
17146
  rawEmitter: this.fsw._emitRaw
16133
17147
  });
16134
17148
  } else {
16135
- closer = setFsWatchListener(path30, absolutePath, options, {
17149
+ closer = setFsWatchListener(path31, absolutePath, options, {
16136
17150
  listener,
16137
17151
  errHandler: this._boundHandleError,
16138
17152
  rawEmitter: this.fsw._emitRaw
@@ -16148,13 +17162,13 @@ var NodeFsHandler = class {
16148
17162
  if (this.fsw.closed) {
16149
17163
  return;
16150
17164
  }
16151
- const dirname15 = sp.dirname(file);
16152
- const basename9 = sp.basename(file);
16153
- const parent = this.fsw._getWatchedDir(dirname15);
17165
+ const dirname16 = sp.dirname(file);
17166
+ const basename10 = sp.basename(file);
17167
+ const parent = this.fsw._getWatchedDir(dirname16);
16154
17168
  let prevStats = stats;
16155
- if (parent.has(basename9))
17169
+ if (parent.has(basename10))
16156
17170
  return;
16157
- const listener = async (path30, newStats) => {
17171
+ const listener = async (path31, newStats) => {
16158
17172
  if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5))
16159
17173
  return;
16160
17174
  if (!newStats || newStats.mtimeMs === 0) {
@@ -16168,18 +17182,18 @@ var NodeFsHandler = class {
16168
17182
  this.fsw._emit(EV.CHANGE, file, newStats2);
16169
17183
  }
16170
17184
  if ((isMacos || isLinux || isFreeBSD) && prevStats.ino !== newStats2.ino) {
16171
- this.fsw._closeFile(path30);
17185
+ this.fsw._closeFile(path31);
16172
17186
  prevStats = newStats2;
16173
17187
  const closer2 = this._watchWithNodeFs(file, listener);
16174
17188
  if (closer2)
16175
- this.fsw._addPathCloser(path30, closer2);
17189
+ this.fsw._addPathCloser(path31, closer2);
16176
17190
  } else {
16177
17191
  prevStats = newStats2;
16178
17192
  }
16179
17193
  } catch (error) {
16180
- this.fsw._remove(dirname15, basename9);
17194
+ this.fsw._remove(dirname16, basename10);
16181
17195
  }
16182
- } else if (parent.has(basename9)) {
17196
+ } else if (parent.has(basename10)) {
16183
17197
  const at = newStats.atimeMs;
16184
17198
  const mt = newStats.mtimeMs;
16185
17199
  if (!at || at <= mt || mt !== prevStats.mtimeMs) {
@@ -16204,7 +17218,7 @@ var NodeFsHandler = class {
16204
17218
  * @param item basename of this item
16205
17219
  * @returns true if no more processing is needed for this entry.
16206
17220
  */
16207
- async _handleSymlink(entry, directory, path30, item) {
17221
+ async _handleSymlink(entry, directory, path31, item) {
16208
17222
  if (this.fsw.closed) {
16209
17223
  return;
16210
17224
  }
@@ -16214,7 +17228,7 @@ var NodeFsHandler = class {
16214
17228
  this.fsw._incrReadyCount();
16215
17229
  let linkPath;
16216
17230
  try {
16217
- linkPath = await fsrealpath(path30);
17231
+ linkPath = await fsrealpath(path31);
16218
17232
  } catch (e) {
16219
17233
  this.fsw._emitReady();
16220
17234
  return true;
@@ -16224,12 +17238,12 @@ var NodeFsHandler = class {
16224
17238
  if (dir.has(item)) {
16225
17239
  if (this.fsw._symlinkPaths.get(full) !== linkPath) {
16226
17240
  this.fsw._symlinkPaths.set(full, linkPath);
16227
- this.fsw._emit(EV.CHANGE, path30, entry.stats);
17241
+ this.fsw._emit(EV.CHANGE, path31, entry.stats);
16228
17242
  }
16229
17243
  } else {
16230
17244
  dir.add(item);
16231
17245
  this.fsw._symlinkPaths.set(full, linkPath);
16232
- this.fsw._emit(EV.ADD, path30, entry.stats);
17246
+ this.fsw._emit(EV.ADD, path31, entry.stats);
16233
17247
  }
16234
17248
  this.fsw._emitReady();
16235
17249
  return true;
@@ -16259,9 +17273,9 @@ var NodeFsHandler = class {
16259
17273
  return;
16260
17274
  }
16261
17275
  const item = entry.path;
16262
- let path30 = sp.join(directory, item);
17276
+ let path31 = sp.join(directory, item);
16263
17277
  current.add(item);
16264
- if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path30, item)) {
17278
+ if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path31, item)) {
16265
17279
  return;
16266
17280
  }
16267
17281
  if (this.fsw.closed) {
@@ -16270,11 +17284,11 @@ var NodeFsHandler = class {
16270
17284
  }
16271
17285
  if (item === target || !target && !previous.has(item)) {
16272
17286
  this.fsw._incrReadyCount();
16273
- path30 = sp.join(dir, sp.relative(dir, path30));
16274
- this._addToNodeFs(path30, initialAdd, wh, depth + 1);
17287
+ path31 = sp.join(dir, sp.relative(dir, path31));
17288
+ this._addToNodeFs(path31, initialAdd, wh, depth + 1);
16275
17289
  }
16276
17290
  }).on(EV.ERROR, this._boundHandleError);
16277
- return new Promise((resolve17, reject) => {
17291
+ return new Promise((resolve18, reject) => {
16278
17292
  if (!stream)
16279
17293
  return reject();
16280
17294
  stream.once(STR_END, () => {
@@ -16283,7 +17297,7 @@ var NodeFsHandler = class {
16283
17297
  return;
16284
17298
  }
16285
17299
  const wasThrottled = throttler ? throttler.clear() : false;
16286
- resolve17(void 0);
17300
+ resolve18(void 0);
16287
17301
  previous.getChildren().filter((item) => {
16288
17302
  return item !== directory && !current.has(item);
16289
17303
  }).forEach((item) => {
@@ -16340,13 +17354,13 @@ var NodeFsHandler = class {
16340
17354
  * @param depth Child path actually targeted for watch
16341
17355
  * @param target Child path actually targeted for watch
16342
17356
  */
16343
- async _addToNodeFs(path30, initialAdd, priorWh, depth, target) {
17357
+ async _addToNodeFs(path31, initialAdd, priorWh, depth, target) {
16344
17358
  const ready = this.fsw._emitReady;
16345
- if (this.fsw._isIgnored(path30) || this.fsw.closed) {
17359
+ if (this.fsw._isIgnored(path31) || this.fsw.closed) {
16346
17360
  ready();
16347
17361
  return false;
16348
17362
  }
16349
- const wh = this.fsw._getWatchHelpers(path30);
17363
+ const wh = this.fsw._getWatchHelpers(path31);
16350
17364
  if (priorWh) {
16351
17365
  wh.filterPath = (entry) => priorWh.filterPath(entry);
16352
17366
  wh.filterDir = (entry) => priorWh.filterDir(entry);
@@ -16362,8 +17376,8 @@ var NodeFsHandler = class {
16362
17376
  const follow = this.fsw.options.followSymlinks;
16363
17377
  let closer;
16364
17378
  if (stats.isDirectory()) {
16365
- const absPath = sp.resolve(path30);
16366
- const targetPath = follow ? await fsrealpath(path30) : path30;
17379
+ const absPath = sp.resolve(path31);
17380
+ const targetPath = follow ? await fsrealpath(path31) : path31;
16367
17381
  if (this.fsw.closed)
16368
17382
  return;
16369
17383
  closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
@@ -16373,29 +17387,29 @@ var NodeFsHandler = class {
16373
17387
  this.fsw._symlinkPaths.set(absPath, targetPath);
16374
17388
  }
16375
17389
  } else if (stats.isSymbolicLink()) {
16376
- const targetPath = follow ? await fsrealpath(path30) : path30;
17390
+ const targetPath = follow ? await fsrealpath(path31) : path31;
16377
17391
  if (this.fsw.closed)
16378
17392
  return;
16379
17393
  const parent = sp.dirname(wh.watchPath);
16380
17394
  this.fsw._getWatchedDir(parent).add(wh.watchPath);
16381
17395
  this.fsw._emit(EV.ADD, wh.watchPath, stats);
16382
- closer = await this._handleDir(parent, stats, initialAdd, depth, path30, wh, targetPath);
17396
+ closer = await this._handleDir(parent, stats, initialAdd, depth, path31, wh, targetPath);
16383
17397
  if (this.fsw.closed)
16384
17398
  return;
16385
17399
  if (targetPath !== void 0) {
16386
- this.fsw._symlinkPaths.set(sp.resolve(path30), targetPath);
17400
+ this.fsw._symlinkPaths.set(sp.resolve(path31), targetPath);
16387
17401
  }
16388
17402
  } else {
16389
17403
  closer = this._handleFile(wh.watchPath, stats, initialAdd);
16390
17404
  }
16391
17405
  ready();
16392
17406
  if (closer)
16393
- this.fsw._addPathCloser(path30, closer);
17407
+ this.fsw._addPathCloser(path31, closer);
16394
17408
  return false;
16395
17409
  } catch (error) {
16396
17410
  if (this.fsw._handleError(error)) {
16397
17411
  ready();
16398
- return path30;
17412
+ return path31;
16399
17413
  }
16400
17414
  }
16401
17415
  }
@@ -16438,24 +17452,24 @@ function createPattern(matcher) {
16438
17452
  }
16439
17453
  return () => false;
16440
17454
  }
16441
- function normalizePath2(path30) {
16442
- if (typeof path30 !== "string")
17455
+ function normalizePath2(path31) {
17456
+ if (typeof path31 !== "string")
16443
17457
  throw new Error("string expected");
16444
- path30 = sp2.normalize(path30);
16445
- path30 = path30.replace(/\\/g, "/");
17458
+ path31 = sp2.normalize(path31);
17459
+ path31 = path31.replace(/\\/g, "/");
16446
17460
  let prepend = false;
16447
- if (path30.startsWith("//"))
17461
+ if (path31.startsWith("//"))
16448
17462
  prepend = true;
16449
- path30 = path30.replace(DOUBLE_SLASH_RE, "/");
17463
+ path31 = path31.replace(DOUBLE_SLASH_RE, "/");
16450
17464
  if (prepend)
16451
- path30 = "/" + path30;
16452
- return path30;
17465
+ path31 = "/" + path31;
17466
+ return path31;
16453
17467
  }
16454
17468
  function matchPatterns(patterns, testString, stats) {
16455
- const path30 = normalizePath2(testString);
17469
+ const path31 = normalizePath2(testString);
16456
17470
  for (let index = 0; index < patterns.length; index++) {
16457
17471
  const pattern = patterns[index];
16458
- if (pattern(path30, stats)) {
17472
+ if (pattern(path31, stats)) {
16459
17473
  return true;
16460
17474
  }
16461
17475
  }
@@ -16493,19 +17507,19 @@ var toUnix = (string) => {
16493
17507
  }
16494
17508
  return str;
16495
17509
  };
16496
- var normalizePathToUnix = (path30) => toUnix(sp2.normalize(toUnix(path30)));
16497
- var normalizeIgnored = (cwd = "") => (path30) => {
16498
- if (typeof path30 === "string") {
16499
- return normalizePathToUnix(sp2.isAbsolute(path30) ? path30 : sp2.join(cwd, path30));
17510
+ var normalizePathToUnix = (path31) => toUnix(sp2.normalize(toUnix(path31)));
17511
+ var normalizeIgnored = (cwd = "") => (path31) => {
17512
+ if (typeof path31 === "string") {
17513
+ return normalizePathToUnix(sp2.isAbsolute(path31) ? path31 : sp2.join(cwd, path31));
16500
17514
  } else {
16501
- return path30;
17515
+ return path31;
16502
17516
  }
16503
17517
  };
16504
- var getAbsolutePath = (path30, cwd) => {
16505
- if (sp2.isAbsolute(path30)) {
16506
- return path30;
17518
+ var getAbsolutePath = (path31, cwd) => {
17519
+ if (sp2.isAbsolute(path31)) {
17520
+ return path31;
16507
17521
  }
16508
- return sp2.join(cwd, path30);
17522
+ return sp2.join(cwd, path31);
16509
17523
  };
16510
17524
  var EMPTY_SET = Object.freeze(/* @__PURE__ */ new Set());
16511
17525
  var DirEntry = class {
@@ -16570,10 +17584,10 @@ var WatchHelper = class {
16570
17584
  dirParts;
16571
17585
  followSymlinks;
16572
17586
  statMethod;
16573
- constructor(path30, follow, fsw) {
17587
+ constructor(path31, follow, fsw) {
16574
17588
  this.fsw = fsw;
16575
- const watchPath = path30;
16576
- this.path = path30 = path30.replace(REPLACER_RE, "");
17589
+ const watchPath = path31;
17590
+ this.path = path31 = path31.replace(REPLACER_RE, "");
16577
17591
  this.watchPath = watchPath;
16578
17592
  this.fullWatchPath = sp2.resolve(watchPath);
16579
17593
  this.dirParts = [];
@@ -16713,20 +17727,20 @@ var FSWatcher = class extends EventEmitter2 {
16713
17727
  this._closePromise = void 0;
16714
17728
  let paths = unifyPaths(paths_);
16715
17729
  if (cwd) {
16716
- paths = paths.map((path30) => {
16717
- const absPath = getAbsolutePath(path30, cwd);
17730
+ paths = paths.map((path31) => {
17731
+ const absPath = getAbsolutePath(path31, cwd);
16718
17732
  return absPath;
16719
17733
  });
16720
17734
  }
16721
- paths.forEach((path30) => {
16722
- this._removeIgnoredPath(path30);
17735
+ paths.forEach((path31) => {
17736
+ this._removeIgnoredPath(path31);
16723
17737
  });
16724
17738
  this._userIgnored = void 0;
16725
17739
  if (!this._readyCount)
16726
17740
  this._readyCount = 0;
16727
17741
  this._readyCount += paths.length;
16728
- Promise.all(paths.map(async (path30) => {
16729
- const res = await this._nodeFsHandler._addToNodeFs(path30, !_internal, void 0, 0, _origAdd);
17742
+ Promise.all(paths.map(async (path31) => {
17743
+ const res = await this._nodeFsHandler._addToNodeFs(path31, !_internal, void 0, 0, _origAdd);
16730
17744
  if (res)
16731
17745
  this._emitReady();
16732
17746
  return res;
@@ -16748,17 +17762,17 @@ var FSWatcher = class extends EventEmitter2 {
16748
17762
  return this;
16749
17763
  const paths = unifyPaths(paths_);
16750
17764
  const { cwd } = this.options;
16751
- paths.forEach((path30) => {
16752
- if (!sp2.isAbsolute(path30) && !this._closers.has(path30)) {
17765
+ paths.forEach((path31) => {
17766
+ if (!sp2.isAbsolute(path31) && !this._closers.has(path31)) {
16753
17767
  if (cwd)
16754
- path30 = sp2.join(cwd, path30);
16755
- path30 = sp2.resolve(path30);
17768
+ path31 = sp2.join(cwd, path31);
17769
+ path31 = sp2.resolve(path31);
16756
17770
  }
16757
- this._closePath(path30);
16758
- this._addIgnoredPath(path30);
16759
- if (this._watched.has(path30)) {
17771
+ this._closePath(path31);
17772
+ this._addIgnoredPath(path31);
17773
+ if (this._watched.has(path31)) {
16760
17774
  this._addIgnoredPath({
16761
- path: path30,
17775
+ path: path31,
16762
17776
  recursive: true
16763
17777
  });
16764
17778
  }
@@ -16822,38 +17836,38 @@ var FSWatcher = class extends EventEmitter2 {
16822
17836
  * @param stats arguments to be passed with event
16823
17837
  * @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag
16824
17838
  */
16825
- async _emit(event, path30, stats) {
17839
+ async _emit(event, path31, stats) {
16826
17840
  if (this.closed)
16827
17841
  return;
16828
17842
  const opts = this.options;
16829
17843
  if (isWindows)
16830
- path30 = sp2.normalize(path30);
17844
+ path31 = sp2.normalize(path31);
16831
17845
  if (opts.cwd)
16832
- path30 = sp2.relative(opts.cwd, path30);
16833
- const args = [path30];
17846
+ path31 = sp2.relative(opts.cwd, path31);
17847
+ const args = [path31];
16834
17848
  if (stats != null)
16835
17849
  args.push(stats);
16836
17850
  const awf = opts.awaitWriteFinish;
16837
17851
  let pw;
16838
- if (awf && (pw = this._pendingWrites.get(path30))) {
17852
+ if (awf && (pw = this._pendingWrites.get(path31))) {
16839
17853
  pw.lastChange = /* @__PURE__ */ new Date();
16840
17854
  return this;
16841
17855
  }
16842
17856
  if (opts.atomic) {
16843
17857
  if (event === EVENTS.UNLINK) {
16844
- this._pendingUnlinks.set(path30, [event, ...args]);
17858
+ this._pendingUnlinks.set(path31, [event, ...args]);
16845
17859
  setTimeout(() => {
16846
- this._pendingUnlinks.forEach((entry, path31) => {
17860
+ this._pendingUnlinks.forEach((entry, path32) => {
16847
17861
  this.emit(...entry);
16848
17862
  this.emit(EVENTS.ALL, ...entry);
16849
- this._pendingUnlinks.delete(path31);
17863
+ this._pendingUnlinks.delete(path32);
16850
17864
  });
16851
17865
  }, typeof opts.atomic === "number" ? opts.atomic : 100);
16852
17866
  return this;
16853
17867
  }
16854
- if (event === EVENTS.ADD && this._pendingUnlinks.has(path30)) {
17868
+ if (event === EVENTS.ADD && this._pendingUnlinks.has(path31)) {
16855
17869
  event = EVENTS.CHANGE;
16856
- this._pendingUnlinks.delete(path30);
17870
+ this._pendingUnlinks.delete(path31);
16857
17871
  }
16858
17872
  }
16859
17873
  if (awf && (event === EVENTS.ADD || event === EVENTS.CHANGE) && this._readyEmitted) {
@@ -16871,16 +17885,16 @@ var FSWatcher = class extends EventEmitter2 {
16871
17885
  this.emitWithAll(event, args);
16872
17886
  }
16873
17887
  };
16874
- this._awaitWriteFinish(path30, awf.stabilityThreshold, event, awfEmit);
17888
+ this._awaitWriteFinish(path31, awf.stabilityThreshold, event, awfEmit);
16875
17889
  return this;
16876
17890
  }
16877
17891
  if (event === EVENTS.CHANGE) {
16878
- const isThrottled = !this._throttle(EVENTS.CHANGE, path30, 50);
17892
+ const isThrottled = !this._throttle(EVENTS.CHANGE, path31, 50);
16879
17893
  if (isThrottled)
16880
17894
  return this;
16881
17895
  }
16882
17896
  if (opts.alwaysStat && stats === void 0 && (event === EVENTS.ADD || event === EVENTS.ADD_DIR || event === EVENTS.CHANGE)) {
16883
- const fullPath = opts.cwd ? sp2.join(opts.cwd, path30) : path30;
17897
+ const fullPath = opts.cwd ? sp2.join(opts.cwd, path31) : path31;
16884
17898
  let stats2;
16885
17899
  try {
16886
17900
  stats2 = await stat3(fullPath);
@@ -16911,23 +17925,23 @@ var FSWatcher = class extends EventEmitter2 {
16911
17925
  * @param timeout duration of time to suppress duplicate actions
16912
17926
  * @returns tracking object or false if action should be suppressed
16913
17927
  */
16914
- _throttle(actionType, path30, timeout) {
17928
+ _throttle(actionType, path31, timeout) {
16915
17929
  if (!this._throttled.has(actionType)) {
16916
17930
  this._throttled.set(actionType, /* @__PURE__ */ new Map());
16917
17931
  }
16918
17932
  const action = this._throttled.get(actionType);
16919
17933
  if (!action)
16920
17934
  throw new Error("invalid throttle");
16921
- const actionPath = action.get(path30);
17935
+ const actionPath = action.get(path31);
16922
17936
  if (actionPath) {
16923
17937
  actionPath.count++;
16924
17938
  return false;
16925
17939
  }
16926
17940
  let timeoutObject;
16927
17941
  const clear = () => {
16928
- const item = action.get(path30);
17942
+ const item = action.get(path31);
16929
17943
  const count = item ? item.count : 0;
16930
- action.delete(path30);
17944
+ action.delete(path31);
16931
17945
  clearTimeout(timeoutObject);
16932
17946
  if (item)
16933
17947
  clearTimeout(item.timeoutObject);
@@ -16935,7 +17949,7 @@ var FSWatcher = class extends EventEmitter2 {
16935
17949
  };
16936
17950
  timeoutObject = setTimeout(clear, timeout);
16937
17951
  const thr = { timeoutObject, clear, count: 0 };
16938
- action.set(path30, thr);
17952
+ action.set(path31, thr);
16939
17953
  return thr;
16940
17954
  }
16941
17955
  _incrReadyCount() {
@@ -16949,44 +17963,44 @@ var FSWatcher = class extends EventEmitter2 {
16949
17963
  * @param event
16950
17964
  * @param awfEmit Callback to be called when ready for event to be emitted.
16951
17965
  */
16952
- _awaitWriteFinish(path30, threshold, event, awfEmit) {
17966
+ _awaitWriteFinish(path31, threshold, event, awfEmit) {
16953
17967
  const awf = this.options.awaitWriteFinish;
16954
17968
  if (typeof awf !== "object")
16955
17969
  return;
16956
17970
  const pollInterval = awf.pollInterval;
16957
17971
  let timeoutHandler;
16958
- let fullPath = path30;
16959
- if (this.options.cwd && !sp2.isAbsolute(path30)) {
16960
- fullPath = sp2.join(this.options.cwd, path30);
17972
+ let fullPath = path31;
17973
+ if (this.options.cwd && !sp2.isAbsolute(path31)) {
17974
+ fullPath = sp2.join(this.options.cwd, path31);
16961
17975
  }
16962
17976
  const now2 = /* @__PURE__ */ new Date();
16963
17977
  const writes = this._pendingWrites;
16964
17978
  function awaitWriteFinishFn(prevStat) {
16965
17979
  statcb(fullPath, (err, curStat) => {
16966
- if (err || !writes.has(path30)) {
17980
+ if (err || !writes.has(path31)) {
16967
17981
  if (err && err.code !== "ENOENT")
16968
17982
  awfEmit(err);
16969
17983
  return;
16970
17984
  }
16971
17985
  const now3 = Number(/* @__PURE__ */ new Date());
16972
17986
  if (prevStat && curStat.size !== prevStat.size) {
16973
- writes.get(path30).lastChange = now3;
17987
+ writes.get(path31).lastChange = now3;
16974
17988
  }
16975
- const pw = writes.get(path30);
17989
+ const pw = writes.get(path31);
16976
17990
  const df = now3 - pw.lastChange;
16977
17991
  if (df >= threshold) {
16978
- writes.delete(path30);
17992
+ writes.delete(path31);
16979
17993
  awfEmit(void 0, curStat);
16980
17994
  } else {
16981
17995
  timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat);
16982
17996
  }
16983
17997
  });
16984
17998
  }
16985
- if (!writes.has(path30)) {
16986
- writes.set(path30, {
17999
+ if (!writes.has(path31)) {
18000
+ writes.set(path31, {
16987
18001
  lastChange: now2,
16988
18002
  cancelWait: () => {
16989
- writes.delete(path30);
18003
+ writes.delete(path31);
16990
18004
  clearTimeout(timeoutHandler);
16991
18005
  return event;
16992
18006
  }
@@ -16997,8 +18011,8 @@ var FSWatcher = class extends EventEmitter2 {
16997
18011
  /**
16998
18012
  * Determines whether user has asked to ignore this path.
16999
18013
  */
17000
- _isIgnored(path30, stats) {
17001
- if (this.options.atomic && DOT_RE.test(path30))
18014
+ _isIgnored(path31, stats) {
18015
+ if (this.options.atomic && DOT_RE.test(path31))
17002
18016
  return true;
17003
18017
  if (!this._userIgnored) {
17004
18018
  const { cwd } = this.options;
@@ -17008,17 +18022,17 @@ var FSWatcher = class extends EventEmitter2 {
17008
18022
  const list = [...ignoredPaths.map(normalizeIgnored(cwd)), ...ignored];
17009
18023
  this._userIgnored = anymatch(list, void 0);
17010
18024
  }
17011
- return this._userIgnored(path30, stats);
18025
+ return this._userIgnored(path31, stats);
17012
18026
  }
17013
- _isntIgnored(path30, stat5) {
17014
- return !this._isIgnored(path30, stat5);
18027
+ _isntIgnored(path31, stat5) {
18028
+ return !this._isIgnored(path31, stat5);
17015
18029
  }
17016
18030
  /**
17017
18031
  * Provides a set of common helpers and properties relating to symlink handling.
17018
18032
  * @param path file or directory pattern being watched
17019
18033
  */
17020
- _getWatchHelpers(path30) {
17021
- return new WatchHelper(path30, this.options.followSymlinks, this);
18034
+ _getWatchHelpers(path31) {
18035
+ return new WatchHelper(path31, this.options.followSymlinks, this);
17022
18036
  }
17023
18037
  // Directory helpers
17024
18038
  // -----------------
@@ -17050,63 +18064,63 @@ var FSWatcher = class extends EventEmitter2 {
17050
18064
  * @param item base path of item/directory
17051
18065
  */
17052
18066
  _remove(directory, item, isDirectory) {
17053
- const path30 = sp2.join(directory, item);
17054
- const fullPath = sp2.resolve(path30);
17055
- isDirectory = isDirectory != null ? isDirectory : this._watched.has(path30) || this._watched.has(fullPath);
17056
- if (!this._throttle("remove", path30, 100))
18067
+ const path31 = sp2.join(directory, item);
18068
+ const fullPath = sp2.resolve(path31);
18069
+ isDirectory = isDirectory != null ? isDirectory : this._watched.has(path31) || this._watched.has(fullPath);
18070
+ if (!this._throttle("remove", path31, 100))
17057
18071
  return;
17058
18072
  if (!isDirectory && this._watched.size === 1) {
17059
18073
  this.add(directory, item, true);
17060
18074
  }
17061
- const wp = this._getWatchedDir(path30);
18075
+ const wp = this._getWatchedDir(path31);
17062
18076
  const nestedDirectoryChildren = wp.getChildren();
17063
- nestedDirectoryChildren.forEach((nested) => this._remove(path30, nested));
18077
+ nestedDirectoryChildren.forEach((nested) => this._remove(path31, nested));
17064
18078
  const parent = this._getWatchedDir(directory);
17065
18079
  const wasTracked = parent.has(item);
17066
18080
  parent.remove(item);
17067
18081
  if (this._symlinkPaths.has(fullPath)) {
17068
18082
  this._symlinkPaths.delete(fullPath);
17069
18083
  }
17070
- let relPath = path30;
18084
+ let relPath = path31;
17071
18085
  if (this.options.cwd)
17072
- relPath = sp2.relative(this.options.cwd, path30);
18086
+ relPath = sp2.relative(this.options.cwd, path31);
17073
18087
  if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
17074
18088
  const event = this._pendingWrites.get(relPath).cancelWait();
17075
18089
  if (event === EVENTS.ADD)
17076
18090
  return;
17077
18091
  }
17078
- this._watched.delete(path30);
18092
+ this._watched.delete(path31);
17079
18093
  this._watched.delete(fullPath);
17080
18094
  const eventName = isDirectory ? EVENTS.UNLINK_DIR : EVENTS.UNLINK;
17081
- if (wasTracked && !this._isIgnored(path30))
17082
- this._emit(eventName, path30);
17083
- this._closePath(path30);
18095
+ if (wasTracked && !this._isIgnored(path31))
18096
+ this._emit(eventName, path31);
18097
+ this._closePath(path31);
17084
18098
  }
17085
18099
  /**
17086
18100
  * Closes all watchers for a path
17087
18101
  */
17088
- _closePath(path30) {
17089
- this._closeFile(path30);
17090
- const dir = sp2.dirname(path30);
17091
- this._getWatchedDir(dir).remove(sp2.basename(path30));
18102
+ _closePath(path31) {
18103
+ this._closeFile(path31);
18104
+ const dir = sp2.dirname(path31);
18105
+ this._getWatchedDir(dir).remove(sp2.basename(path31));
17092
18106
  }
17093
18107
  /**
17094
18108
  * Closes only file-specific watchers
17095
18109
  */
17096
- _closeFile(path30) {
17097
- const closers = this._closers.get(path30);
18110
+ _closeFile(path31) {
18111
+ const closers = this._closers.get(path31);
17098
18112
  if (!closers)
17099
18113
  return;
17100
18114
  closers.forEach((closer) => closer());
17101
- this._closers.delete(path30);
18115
+ this._closers.delete(path31);
17102
18116
  }
17103
- _addPathCloser(path30, closer) {
18117
+ _addPathCloser(path31, closer) {
17104
18118
  if (!closer)
17105
18119
  return;
17106
- let list = this._closers.get(path30);
18120
+ let list = this._closers.get(path31);
17107
18121
  if (!list) {
17108
18122
  list = [];
17109
- this._closers.set(path30, list);
18123
+ this._closers.set(path31, list);
17110
18124
  }
17111
18125
  list.push(closer);
17112
18126
  }
@@ -17136,11 +18150,11 @@ function watch(paths, options = {}) {
17136
18150
  var chokidar_default = { watch, FSWatcher };
17137
18151
 
17138
18152
  // src/watcher/file-watcher.ts
17139
- import * as path23 from "path";
18153
+ import * as path24 from "path";
17140
18154
 
17141
18155
  // src/watcher/native-recursive-watcher.ts
17142
18156
  import { watch as watch2 } from "fs";
17143
- import * as path21 from "path";
18157
+ import * as path22 from "path";
17144
18158
  var NativeRecursiveWatcher = class {
17145
18159
  constructor(root, onChange, options = {}) {
17146
18160
  this.root = root;
@@ -17188,9 +18202,9 @@ var NativeRecursiveWatcher = class {
17188
18202
  toAbsolutePath(filename) {
17189
18203
  if (filename == null) return null;
17190
18204
  const normalizedFilename = typeof filename === "string" ? filename : filename.toString();
17191
- const absolutePath = path21.resolve(this.root, normalizedFilename);
17192
- const relativePath = path21.relative(this.root, absolutePath);
17193
- const outsideRoot = relativePath === ".." || relativePath.startsWith(`..${path21.sep}`) || path21.isAbsolute(relativePath);
18205
+ const absolutePath = path22.resolve(this.root, normalizedFilename);
18206
+ const relativePath = path22.relative(this.root, absolutePath);
18207
+ const outsideRoot = relativePath === ".." || relativePath.startsWith(`..${path22.sep}`) || path22.isAbsolute(relativePath);
17194
18208
  return outsideRoot ? null : absolutePath;
17195
18209
  }
17196
18210
  defaultWatchFactory = (root, listener, options) => watch2(root, options, listener);
@@ -17198,16 +18212,16 @@ var NativeRecursiveWatcher = class {
17198
18212
 
17199
18213
  // src/watcher/snapshot.ts
17200
18214
  import * as fsPromises4 from "fs/promises";
17201
- import * as path22 from "path";
18215
+ import * as path23 from "path";
17202
18216
  async function buildFileSnapshotScan(projectRoot, config, configPaths = []) {
17203
- const normalizedProjectRoot = path22.resolve(projectRoot);
18217
+ const normalizedProjectRoot = path23.resolve(projectRoot);
17204
18218
  const ignoreFilter = createIgnoreFilter(normalizedProjectRoot);
17205
18219
  const includePatterns = [...config.include, ...config.additionalInclude ?? []];
17206
18220
  const maxDepth = config.indexing?.maxDepth ?? -1;
17207
18221
  const snapshot = /* @__PURE__ */ new Map();
17208
18222
  const unreadablePrefixes = /* @__PURE__ */ new Set();
17209
18223
  const includeFile = async (filePath) => {
17210
- const normalizedPath2 = path22.resolve(filePath);
18224
+ const normalizedPath2 = path23.resolve(filePath);
17211
18225
  if (!shouldIncludeFile(normalizedPath2, normalizedProjectRoot, includePatterns, config.exclude, ignoreFilter)) return;
17212
18226
  const stat5 = await readStatIfFile(normalizedPath2, unreadablePrefixes);
17213
18227
  if (stat5) snapshot.set(normalizedPath2, { size: stat5.size, mtimeMs: stat5.mtimeMs });
@@ -17219,16 +18233,16 @@ async function buildFileSnapshotScan(projectRoot, config, configPaths = []) {
17219
18233
  } catch (error) {
17220
18234
  if (isMissingFsError(error)) return;
17221
18235
  if (isPermissionFsError(error)) {
17222
- unreadablePrefixes.add(path22.resolve(directoryPath));
18236
+ unreadablePrefixes.add(path23.resolve(directoryPath));
17223
18237
  return;
17224
18238
  }
17225
18239
  throw error;
17226
18240
  }
17227
18241
  for (const entry of entries) {
17228
- const fullPath = path22.join(directoryPath, entry.name);
17229
- const relativePath = path22.relative(normalizedProjectRoot, fullPath);
18242
+ const fullPath = path23.join(directoryPath, entry.name);
18243
+ const relativePath = path23.relative(normalizedProjectRoot, fullPath);
17230
18244
  if (entry.isDirectory()) {
17231
- if (hasFilteredPathSegment(relativePath, path22.sep) || isRestrictedDirectory(relativePath, path22.sep)) continue;
18245
+ if (hasFilteredPathSegment(relativePath, path23.sep) || isRestrictedDirectory(relativePath, path23.sep)) continue;
17232
18246
  if (ignoreFilter.ignores(relativePath)) continue;
17233
18247
  if (maxDepth === -1 || depth < maxDepth) await walk(fullPath, depth + 1);
17234
18248
  } else if (entry.isFile()) {
@@ -17241,19 +18255,19 @@ async function buildFileSnapshotScan(projectRoot, config, configPaths = []) {
17241
18255
  return { entries: snapshot, unreadablePrefixes };
17242
18256
  }
17243
18257
  async function buildFileSnapshotForPathScan(projectRoot, config, configPaths, targetPath) {
17244
- const normalizedProjectRoot = path22.resolve(projectRoot);
17245
- const normalizedTargetPath = path22.resolve(targetPath);
18258
+ const normalizedProjectRoot = path23.resolve(projectRoot);
18259
+ const normalizedTargetPath = path23.resolve(targetPath);
17246
18260
  if (!isWithinPath(normalizedProjectRoot, normalizedTargetPath)) {
17247
18261
  return { entries: /* @__PURE__ */ new Map(), unreadablePrefixes: /* @__PURE__ */ new Set() };
17248
18262
  }
17249
18263
  const ignoreFilter = createIgnoreFilter(normalizedProjectRoot);
17250
18264
  const includePatterns = [...config.include, ...config.additionalInclude ?? []];
17251
18265
  const maxDepth = config.indexing?.maxDepth ?? -1;
17252
- const explicitConfigPaths = new Set(configPaths.map((configPath) => path22.resolve(configPath)));
18266
+ const explicitConfigPaths = new Set(configPaths.map((configPath) => path23.resolve(configPath)));
17253
18267
  const snapshot = /* @__PURE__ */ new Map();
17254
18268
  const unreadablePrefixes = /* @__PURE__ */ new Set();
17255
18269
  const includeFile = async (filePath) => {
17256
- const normalizedPath2 = path22.resolve(filePath);
18270
+ const normalizedPath2 = path23.resolve(filePath);
17257
18271
  if (!explicitConfigPaths.has(normalizedPath2) && !shouldIncludeFile(
17258
18272
  normalizedPath2,
17259
18273
  normalizedProjectRoot,
@@ -17271,16 +18285,16 @@ async function buildFileSnapshotForPathScan(projectRoot, config, configPaths, ta
17271
18285
  } catch (error) {
17272
18286
  if (isMissingFsError(error)) return;
17273
18287
  if (isPermissionFsError(error)) {
17274
- unreadablePrefixes.add(path22.resolve(directoryPath));
18288
+ unreadablePrefixes.add(path23.resolve(directoryPath));
17275
18289
  return;
17276
18290
  }
17277
18291
  throw error;
17278
18292
  }
17279
18293
  for (const entry of entries) {
17280
- const fullPath = path22.join(directoryPath, entry.name);
17281
- const relativePath = path22.relative(normalizedProjectRoot, fullPath);
18294
+ const fullPath = path23.join(directoryPath, entry.name);
18295
+ const relativePath = path23.relative(normalizedProjectRoot, fullPath);
17282
18296
  if (entry.isDirectory()) {
17283
- if (hasFilteredPathSegment(relativePath, path22.sep) || isRestrictedDirectory(relativePath, path22.sep)) continue;
18297
+ if (hasFilteredPathSegment(relativePath, path23.sep) || isRestrictedDirectory(relativePath, path23.sep)) continue;
17284
18298
  if (ignoreFilter.ignores(relativePath)) continue;
17285
18299
  if (maxDepth === -1 || depth < maxDepth) await walk(fullPath, depth + 1);
17286
18300
  } else if (entry.isFile()) {
@@ -17304,7 +18318,7 @@ function completeFileSnapshot(previous, scan) {
17304
18318
  return completed;
17305
18319
  }
17306
18320
  async function includeExplicitConfigPaths(snapshot, unreadablePrefixes, configPaths) {
17307
- for (const configPath of [...new Set(configPaths.map((value) => path22.resolve(value)))]) {
18321
+ for (const configPath of [...new Set(configPaths.map((value) => path23.resolve(value)))]) {
17308
18322
  if (snapshot.has(configPath)) continue;
17309
18323
  const stat5 = await readStatIfFile(configPath, unreadablePrefixes);
17310
18324
  if (stat5) snapshot.set(configPath, { size: stat5.size, mtimeMs: stat5.mtimeMs });
@@ -17314,12 +18328,12 @@ async function includeExplicitConfigPathsInPath(snapshot, unreadablePrefixes, co
17314
18328
  await includeExplicitConfigPaths(
17315
18329
  snapshot,
17316
18330
  unreadablePrefixes,
17317
- configPaths.filter((configPath) => isWithinPath(targetPath, path22.resolve(configPath)))
18331
+ configPaths.filter((configPath) => isWithinPath(targetPath, path23.resolve(configPath)))
17318
18332
  );
17319
18333
  }
17320
18334
  function isWithinPath(parentPath, childPath) {
17321
- const relativePath = path22.relative(parentPath, childPath);
17322
- return relativePath === "" || !relativePath.startsWith(`..${path22.sep}`) && relativePath !== ".." && !path22.isAbsolute(relativePath);
18335
+ const relativePath = path23.relative(parentPath, childPath);
18336
+ return relativePath === "" || !relativePath.startsWith(`..${path23.sep}`) && relativePath !== ".." && !path23.isAbsolute(relativePath);
17323
18337
  }
17324
18338
  async function readStatIfFile(filePath, unreadablePrefixes) {
17325
18339
  try {
@@ -17328,7 +18342,7 @@ async function readStatIfFile(filePath, unreadablePrefixes) {
17328
18342
  } catch (error) {
17329
18343
  if (isMissingFsError(error)) return null;
17330
18344
  if (isPermissionFsError(error)) {
17331
- unreadablePrefixes.add(path22.resolve(filePath));
18345
+ unreadablePrefixes.add(path23.resolve(filePath));
17332
18346
  return null;
17333
18347
  }
17334
18348
  throw error;
@@ -17465,8 +18479,8 @@ var FileWatcher = class {
17465
18479
  this.createWatcher();
17466
18480
  }
17467
18481
  resetReady() {
17468
- this.readyPromise = new Promise((resolve17) => {
17469
- this.resolveReady = resolve17;
18482
+ this.readyPromise = new Promise((resolve18) => {
18483
+ this.resolveReady = resolve18;
17470
18484
  });
17471
18485
  this.startupReadySignals = 1;
17472
18486
  }
@@ -17497,7 +18511,7 @@ var FileWatcher = class {
17497
18511
  const resolvedWatchTargets = watchTargets ?? this.getFullChokidarWatchTargets();
17498
18512
  const watcherOptions = {
17499
18513
  ignored: (filePath) => {
17500
- const relativePath = path23.relative(this.projectRoot, filePath);
18514
+ const relativePath = path24.relative(this.projectRoot, filePath);
17501
18515
  if (!relativePath) return false;
17502
18516
  if (this.isProjectConfigPathOrAncestor(relativePath)) {
17503
18517
  return false;
@@ -17505,10 +18519,10 @@ var FileWatcher = class {
17505
18519
  if (this.isOutsideProjectPath(relativePath)) {
17506
18520
  return true;
17507
18521
  }
17508
- if (hasFilteredPathSegment(relativePath, path23.sep)) {
18522
+ if (hasFilteredPathSegment(relativePath, path24.sep)) {
17509
18523
  return true;
17510
18524
  }
17511
- if (isRestrictedDirectory(relativePath, path23.sep)) {
18525
+ if (isRestrictedDirectory(relativePath, path24.sep)) {
17512
18526
  return true;
17513
18527
  }
17514
18528
  if (ignoreFilter.ignores(relativePath)) {
@@ -17599,13 +18613,13 @@ var FileWatcher = class {
17599
18613
  getExternalConfigWatchTargets() {
17600
18614
  return [...new Set(
17601
18615
  this.projectConfigPaths.filter((projectConfigPath) => {
17602
- const relativeConfigPath = path23.relative(this.projectRoot, projectConfigPath);
18616
+ const relativeConfigPath = path24.relative(this.projectRoot, projectConfigPath);
17603
18617
  return this.isOutsideProjectPath(relativeConfigPath);
17604
18618
  }).map((projectConfigPath) => {
17605
- if (existsSync13(projectConfigPath)) {
18619
+ if (existsSync14(projectConfigPath)) {
17606
18620
  return projectConfigPath;
17607
18621
  }
17608
- return this.getNearestExistingDirectory(path23.dirname(projectConfigPath));
18622
+ return this.getNearestExistingDirectory(path24.dirname(projectConfigPath));
17609
18623
  })
17610
18624
  )];
17611
18625
  }
@@ -17667,7 +18681,7 @@ var FileWatcher = class {
17667
18681
  }
17668
18682
  scheduleNativeReconciliation(generation, filePath) {
17669
18683
  if (!this.isCurrentNativeSetup(generation)) return;
17670
- const requiresFullReconciliation = filePath === path23.join(this.projectRoot, ".gitignore");
18684
+ const requiresFullReconciliation = filePath === path24.join(this.projectRoot, ".gitignore");
17671
18685
  const invalidatedPath = requiresFullReconciliation ? null : filePath;
17672
18686
  this.nativeInvalidatedPaths.set(invalidatedPath, invalidatedPath !== null);
17673
18687
  if (this.nativeReconcileTimer) {
@@ -17762,23 +18776,23 @@ var FileWatcher = class {
17762
18776
  this.scheduleFlush();
17763
18777
  }
17764
18778
  isProjectConfigPath(filePath) {
17765
- const relativePath = path23.relative(this.projectRoot, filePath);
17766
- const normalizedRelativePath = path23.normalize(relativePath);
18779
+ const relativePath = path24.relative(this.projectRoot, filePath);
18780
+ const normalizedRelativePath = path24.normalize(relativePath);
17767
18781
  return this.getProjectConfigRelativePaths().some((configPath) => configPath === normalizedRelativePath);
17768
18782
  }
17769
18783
  isProjectConfigPathOrAncestor(relativePath) {
17770
- const normalizedRelativePath = path23.normalize(relativePath);
18784
+ const normalizedRelativePath = path24.normalize(relativePath);
17771
18785
  return this.getProjectConfigRelativePaths().some(
17772
- (configPath) => configPath === normalizedRelativePath || configPath.startsWith(`${normalizedRelativePath}${path23.sep}`)
18786
+ (configPath) => configPath === normalizedRelativePath || configPath.startsWith(`${normalizedRelativePath}${path24.sep}`)
17773
18787
  );
17774
18788
  }
17775
18789
  isOutsideProjectPath(relativePath) {
17776
- return relativePath === ".." || relativePath.startsWith(`..${path23.sep}`) || path23.isAbsolute(relativePath);
18790
+ return relativePath === ".." || relativePath.startsWith(`..${path24.sep}`) || path24.isAbsolute(relativePath);
17777
18791
  }
17778
18792
  getNearestExistingDirectory(directoryPath) {
17779
18793
  let candidate = directoryPath;
17780
- while (!existsSync13(candidate)) {
17781
- const parent = path23.dirname(candidate);
18794
+ while (!existsSync14(candidate)) {
18795
+ const parent = path24.dirname(candidate);
17782
18796
  if (parent === candidate) break;
17783
18797
  candidate = parent;
17784
18798
  }
@@ -17786,7 +18800,7 @@ var FileWatcher = class {
17786
18800
  }
17787
18801
  getProjectConfigRelativePaths() {
17788
18802
  return this.projectConfigPaths.map(
17789
- (configPath) => path23.normalize(path23.relative(this.projectRoot, configPath))
18803
+ (configPath) => path24.normalize(path24.relative(this.projectRoot, configPath))
17790
18804
  );
17791
18805
  }
17792
18806
  getConfigPathStates() {
@@ -17844,7 +18858,7 @@ var FileWatcher = class {
17844
18858
  return;
17845
18859
  }
17846
18860
  const changes = Array.from(this.pendingChanges.entries()).map(
17847
- ([path30, type]) => ({ path: path30, type })
18861
+ ([path31, type]) => ({ path: path31, type })
17848
18862
  );
17849
18863
  this.pendingChanges.clear();
17850
18864
  try {
@@ -17890,7 +18904,7 @@ var FileWatcher = class {
17890
18904
  };
17891
18905
 
17892
18906
  // src/watcher/git-head-watcher.ts
17893
- import * as path24 from "path";
18907
+ import * as path25 from "path";
17894
18908
  var GitHeadWatcher = class {
17895
18909
  watcher = null;
17896
18910
  projectRoot;
@@ -17912,13 +18926,13 @@ var GitHeadWatcher = class {
17912
18926
  this.readyPromise = Promise.resolve();
17913
18927
  return;
17914
18928
  }
17915
- this.readyPromise = new Promise((resolve17) => {
17916
- this.resolveReady = resolve17;
18929
+ this.readyPromise = new Promise((resolve18) => {
18930
+ this.resolveReady = resolve18;
17917
18931
  });
17918
18932
  this.onBranchChange = handler;
17919
18933
  this.currentBranch = getCurrentBranch(this.projectRoot);
17920
18934
  const headPath = getHeadPath(this.projectRoot);
17921
- const refsPath = path24.join(this.projectRoot, ".git", "refs", "heads");
18935
+ const refsPath = path25.join(this.projectRoot, ".git", "refs", "heads");
17922
18936
  this.watcher = chokidar_default.watch([headPath, refsPath], {
17923
18937
  persistent: true,
17924
18938
  ignoreInitial: true,
@@ -17986,7 +19000,9 @@ var GitHeadWatcher = class {
17986
19000
  function createWatcherWithIndexer(getIndexer, projectRoot, config, host, options = {}) {
17987
19001
  const fileWatcher = new FileWatcher(projectRoot, config, host, options);
17988
19002
  const configPaths = getConfigPaths(projectRoot, host, options);
17989
- configureAutoIndex(projectRoot, host, parseConfig(config), getIndexer);
19003
+ configureAutoIndex(projectRoot, host, parseConfig(config), getIndexer, {
19004
+ synchronizeBackgroundWorker: false
19005
+ });
17990
19006
  let stopped = false;
17991
19007
  const requestReindex = () => {
17992
19008
  if (stopped) return;
@@ -18006,7 +19022,9 @@ function createWatcherWithIndexer(getIndexer, projectRoot, config, host, options
18006
19022
  const parsedConfig = options.configPath ? parseConfig(loadConfigFile(options.configPath)) : void 0;
18007
19023
  const refreshedConfig = refreshIndexerForDirectory(projectRoot, host, parsedConfig);
18008
19024
  if (refreshedConfig) {
18009
- configureAutoIndex(projectRoot, host, refreshedConfig, getIndexer);
19025
+ configureAutoIndex(projectRoot, host, refreshedConfig, getIndexer, {
19026
+ synchronizeBackgroundWorker: false
19027
+ });
18010
19028
  }
18011
19029
  }
18012
19030
  requestReindex();
@@ -18782,7 +19800,7 @@ async function resolveCodebaseContextUnmeasured(projectRoot, host, input) {
18782
19800
  const directory = input.directory ?? void 0;
18783
19801
  const tokenBudget = input.tokenBudget ?? void 0;
18784
19802
  if (from && to) {
18785
- const path30 = await getCallGraphPath(
19803
+ const path31 = await getCallGraphPath(
18786
19804
  projectRoot,
18787
19805
  host,
18788
19806
  from,
@@ -18791,25 +19809,25 @@ async function resolveCodebaseContextUnmeasured(projectRoot, host, input) {
18791
19809
  fromFilePath,
18792
19810
  toFilePath
18793
19811
  );
18794
- const pathText = formatCallGraphPathResult(path30);
18795
- if (path30.path.length > 0) {
19812
+ const pathText = formatCallGraphPathResult(path31);
19813
+ if (path31.path.length > 0) {
18796
19814
  const fitted2 = fitTextToContextBudget(
18797
19815
  pathText,
18798
19816
  tokenBudget
18799
19817
  );
18800
19818
  return {
18801
19819
  text: fitted2.text,
18802
- details: fittedDetails("path", fitted2, path30.path.length)
19820
+ details: fittedDetails("path", fitted2, path31.path.length)
18803
19821
  };
18804
19822
  }
18805
- if (path30.from.status !== "resolved" || path30.to.status !== "resolved") {
19823
+ if (path31.from.status !== "resolved" || path31.to.status !== "resolved") {
18806
19824
  const fitted2 = fitTextToContextBudget(pathText, tokenBudget);
18807
19825
  return {
18808
19826
  text: fitted2.text,
18809
19827
  details: fittedDetails("path", fitted2, 0)
18810
19828
  };
18811
19829
  }
18812
- const resolvedFrom = path30.from;
19830
+ const resolvedFrom = path31.from;
18813
19831
  const { callers } = await getCallGraphData(projectRoot, host, {
18814
19832
  name: to,
18815
19833
  direction: "callers",
@@ -18970,7 +19988,7 @@ async function executeCallGraph(projectRoot, host, args) {
18970
19988
  return { text: formatCallGraphResult(await getCallGraphData(projectRoot, host, args)) };
18971
19989
  }
18972
19990
  async function executeCallGraphPath(projectRoot, host, args) {
18973
- const path30 = await getCallGraphPath(
19991
+ const path31 = await getCallGraphPath(
18974
19992
  projectRoot,
18975
19993
  host,
18976
19994
  args.from,
@@ -18979,7 +19997,7 @@ async function executeCallGraphPath(projectRoot, host, args) {
18979
19997
  args.fromFilePath,
18980
19998
  args.toFilePath
18981
19999
  );
18982
- return { text: formatCallGraphPathResult(path30) };
20000
+ return { text: formatCallGraphPathResult(path31) };
18983
20001
  }
18984
20002
  async function executeCodeCommunities(projectRoot, host, args) {
18985
20003
  const result = await getCodeCommunities(projectRoot, host, args);
@@ -18987,13 +20005,13 @@ async function executeCodeCommunities(projectRoot, host, args) {
18987
20005
  }
18988
20006
 
18989
20007
  // src/adapters/opencode/tools.ts
18990
- import { writeFileSync as writeFileSync4 } from "fs";
18991
- import * as os7 from "os";
18992
- import * as path27 from "path";
20008
+ import { writeFileSync as writeFileSync5 } from "fs";
20009
+ import * as os8 from "os";
20010
+ import * as path28 from "path";
18993
20011
 
18994
20012
  // src/tools/visualize/activity.ts
18995
20013
  import { execFileSync } from "child_process";
18996
- import * as path25 from "path";
20014
+ import * as path26 from "path";
18997
20015
  function attachRecentActivity(data, projectRoot) {
18998
20016
  const activity = readGitActivity(projectRoot);
18999
20017
  const changes = activity.size > 0 ? buildGitChanges(data, activity, projectRoot) : buildGraphChanges(data);
@@ -19155,7 +20173,7 @@ function normalizePath3(filePath) {
19155
20173
  return filePath.replace(/\\/g, "/");
19156
20174
  }
19157
20175
  function toGitRelativePath(projectRoot, filePath) {
19158
- const relativePath = path25.isAbsolute(filePath) ? path25.relative(projectRoot, filePath) : filePath;
20176
+ const relativePath = path26.isAbsolute(filePath) ? path26.relative(projectRoot, filePath) : filePath;
19159
20177
  return normalizePath3(relativePath);
19160
20178
  }
19161
20179
 
@@ -19413,7 +20431,7 @@ render();
19413
20431
  }
19414
20432
 
19415
20433
  // src/tools/visualize/transform.ts
19416
- import * as path26 from "path";
20434
+ import * as path27 from "path";
19417
20435
 
19418
20436
  // src/tools/visualize/modules.ts
19419
20437
  var MAX_MODULES = 18;
@@ -19673,7 +20691,7 @@ function transformForVisualization(symbols, edges, options = {}) {
19673
20691
  filePath: s.filePath,
19674
20692
  kind: s.kind,
19675
20693
  line: s.startLine,
19676
- directory: path26.dirname(s.filePath),
20694
+ directory: path27.dirname(s.filePath),
19677
20695
  moduleId: "",
19678
20696
  moduleLabel: ""
19679
20697
  }));
@@ -20002,8 +21020,8 @@ var index_visualize = tool({
20002
21020
  return "No connected symbols found for visualization. Try including orphans with includeOrphans=true, or check that the call graph has resolved edges.";
20003
21021
  }
20004
21022
  const html = generateVisualizationHtml(vizData);
20005
- const outputPath = path27.join(os7.tmpdir(), `call-graph-${Date.now()}.html`);
20006
- writeFileSync4(outputPath, html, "utf-8");
21023
+ const outputPath = path28.join(os8.tmpdir(), `call-graph-${Date.now()}.html`);
21024
+ writeFileSync5(outputPath, html, "utf-8");
20007
21025
  let result = `Temporal call graph visualization generated: ${outputPath}
20008
21026
 
20009
21027
  `;
@@ -20114,8 +21132,8 @@ var MCP_TOOL_NAMES = [
20114
21132
  ];
20115
21133
 
20116
21134
  // src/commands/loader.ts
20117
- import { existsSync as existsSync14, readdirSync as readdirSync3, readFileSync as readFileSync9 } from "fs";
20118
- import * as path28 from "path";
21135
+ import { existsSync as existsSync15, readdirSync as readdirSync3, readFileSync as readFileSync10 } from "fs";
21136
+ import * as path29 from "path";
20119
21137
  function parseFrontmatter(content) {
20120
21138
  const frontmatterRegex = /^---\s*\n([\s\S]*?)\n---\s*\n([\s\S]*)$/;
20121
21139
  const match = content.match(frontmatterRegex);
@@ -20136,21 +21154,21 @@ function parseFrontmatter(content) {
20136
21154
  }
20137
21155
  function loadCommandsFromDirectory(commandsDir) {
20138
21156
  const commands = /* @__PURE__ */ new Map();
20139
- if (!existsSync14(commandsDir)) {
21157
+ if (!existsSync15(commandsDir)) {
20140
21158
  return commands;
20141
21159
  }
20142
21160
  const files = readdirSync3(commandsDir).filter((f) => f.endsWith(".md"));
20143
21161
  for (const file of files) {
20144
- const filePath = path28.join(commandsDir, file);
21162
+ const filePath = path29.join(commandsDir, file);
20145
21163
  let content;
20146
21164
  try {
20147
- content = readFileSync9(filePath, "utf-8");
21165
+ content = readFileSync10(filePath, "utf-8");
20148
21166
  } catch (error) {
20149
21167
  const message = error instanceof Error ? error.message : String(error);
20150
21168
  throw new Error(`Failed to load command file ${filePath}: ${message}`);
20151
21169
  }
20152
21170
  const { frontmatter, body } = parseFrontmatter(content);
20153
- const name = path28.basename(file, ".md");
21171
+ const name = path29.basename(file, ".md");
20154
21172
  const description = frontmatter.description || `Run the ${name} command`;
20155
21173
  commands.set(name, {
20156
21174
  description,
@@ -20485,42 +21503,13 @@ var RoutingHintController = class {
20485
21503
  };
20486
21504
 
20487
21505
  // src/adapters/opencode.ts
20488
- var activeWatchers = /* @__PURE__ */ new Map();
20489
- var watcherReplacementChains = /* @__PURE__ */ new Map();
20490
- async function replaceActiveWatcher(projectRoot, createNextWatcher) {
20491
- const chain = (watcherReplacementChains.get(projectRoot) ?? Promise.resolve()).catch(() => void 0).then(async () => {
20492
- const existing = activeWatchers.get(projectRoot);
20493
- if (existing) {
20494
- try {
20495
- await existing.stop();
20496
- } catch (error) {
20497
- console.error("[codebase-index] Failed to stop replaced watcher:", error);
20498
- throw error;
20499
- }
20500
- if (activeWatchers.get(projectRoot) === existing) {
20501
- activeWatchers.delete(projectRoot);
20502
- }
20503
- }
20504
- if (createNextWatcher) {
20505
- activeWatchers.set(projectRoot, createNextWatcher());
20506
- }
20507
- });
20508
- watcherReplacementChains.set(projectRoot, chain);
20509
- try {
20510
- await chain;
20511
- } finally {
20512
- if (watcherReplacementChains.get(projectRoot) === chain) {
20513
- watcherReplacementChains.delete(projectRoot);
20514
- }
20515
- }
20516
- }
20517
21506
  function getCommandsDir() {
20518
21507
  let currentDir = process.cwd();
20519
21508
  if (typeof import.meta !== "undefined" && import.meta.url) {
20520
- currentDir = path29.dirname(fileURLToPath2(import.meta.url));
21509
+ currentDir = path30.dirname(fileURLToPath2(import.meta.url));
20521
21510
  }
20522
- const packageRoot = path29.basename(currentDir) === "adapters" ? path29.join(currentDir, "..", "..") : path29.join(currentDir, "..");
20523
- return path29.join(packageRoot, "commands");
21511
+ const packageRoot = path30.basename(currentDir) === "adapters" ? path30.join(currentDir, "..", "..") : path30.join(currentDir, "..");
21512
+ return path30.join(packageRoot, "commands");
20524
21513
  }
20525
21514
  function appendRoutingHints(output, hints, preferredRole) {
20526
21515
  const preferredBucket = preferredRole === "developer" ? output.developer : output.system;
@@ -20546,8 +21535,9 @@ var plugin = async ({ directory, worktree }) => {
20546
21535
  initializeTools2(projectRoot, config);
20547
21536
  const getProjectIndexer = () => getIndexerForProject2(projectRoot);
20548
21537
  const routingHints = config.search.routingHints ? new RoutingHintController(() => getProjectIndexer().getStatus(), 200, config.search.routingGraphHandoffHints) : null;
20549
- const isHomeDir = isHomeDirectory(projectRoot);
20550
- const isValidProject = !isHomeDir && (!config.indexing.requireProjectMarker || hasProjectMarker(projectRoot));
21538
+ const projectSafety = getProjectSafety(projectRoot, config);
21539
+ const isHomeDir = projectSafety.blockedReason === "home-directory";
21540
+ const isValidProject = projectSafety.safeToRun;
20551
21541
  if (isHomeDir) {
20552
21542
  console.warn(
20553
21543
  `[codebase-index] Refusing to watch or index home directory "${projectRoot}". Open a specific project directory instead.`
@@ -20557,16 +21547,24 @@ var plugin = async ({ directory, worktree }) => {
20557
21547
  `[codebase-index] Skipping file watching and auto-indexing: no project marker found in "${projectRoot}". Set "indexing.requireProjectMarker": false in config to override.`
20558
21548
  );
20559
21549
  }
20560
- if (config.indexing.autoIndex && isValidProject) {
20561
- startAutoIndex(projectRoot, "opencode", "startup");
20562
- }
20563
- if (config.indexing.watchFiles && isValidProject) {
20564
- await replaceActiveWatcher(
20565
- projectRoot,
20566
- () => createWatcherWithIndexer(getProjectIndexer, projectRoot, config, "opencode")
20567
- );
21550
+ if (!isValidProject) {
21551
+ await stopBackgroundWorker(projectRoot, "opencode").catch((error) => {
21552
+ console.error("[codebase-index] Failed to stop unsafe OpenCode background worker:", error);
21553
+ });
20568
21554
  } else {
20569
- await replaceActiveWatcher(projectRoot, null);
21555
+ const watcherFactoryForConfig = (refreshedConfig) => refreshedConfig.indexing.watchFiles ? () => createWatcherWithIndexer(getProjectIndexer, projectRoot, refreshedConfig, "opencode") : null;
21556
+ configureBackgroundWorker(projectRoot, "opencode", config, {
21557
+ startAutoIndex: (source, allowDisabledAutoIndex) => {
21558
+ startAutoIndexForBackgroundWorker(projectRoot, "opencode", source, allowDisabledAutoIndex);
21559
+ },
21560
+ stopAutoIndex: () => stopAutoIndexForBackgroundWorker(projectRoot, "opencode"),
21561
+ watcherFactory: watcherFactoryForConfig(config),
21562
+ watcherFactoryForConfig,
21563
+ replaceWatcher: true
21564
+ }, {
21565
+ restartAutoIndex: true
21566
+ });
21567
+ await waitForBackgroundWorkerStart(projectRoot, "opencode");
20570
21568
  }
20571
21569
  return {
20572
21570
  tool: {