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.cjs CHANGED
@@ -333,7 +333,7 @@ var require_ignore = __commonJS({
333
333
  // path matching.
334
334
  // - check `string` either `MODE_IGNORE` or `MODE_CHECK_IGNORE`
335
335
  // @returns {TestResult} true if a file is ignored
336
- test(path30, checkUnignored, mode) {
336
+ test(path31, checkUnignored, mode) {
337
337
  let ignored = false;
338
338
  let unignored = false;
339
339
  let matchedRule;
@@ -342,7 +342,7 @@ var require_ignore = __commonJS({
342
342
  if (unignored === negative && ignored !== unignored || negative && !ignored && !unignored && !checkUnignored) {
343
343
  return;
344
344
  }
345
- const matched = rule[mode].test(path30);
345
+ const matched = rule[mode].test(path31);
346
346
  if (!matched) {
347
347
  return;
348
348
  }
@@ -363,17 +363,17 @@ var require_ignore = __commonJS({
363
363
  var throwError = (message, Ctor) => {
364
364
  throw new Ctor(message);
365
365
  };
366
- var checkPath = (path30, originalPath, doThrow) => {
367
- if (!isString(path30)) {
366
+ var checkPath = (path31, originalPath, doThrow) => {
367
+ if (!isString(path31)) {
368
368
  return doThrow(
369
369
  `path must be a string, but got \`${originalPath}\``,
370
370
  TypeError
371
371
  );
372
372
  }
373
- if (!path30) {
373
+ if (!path31) {
374
374
  return doThrow(`path must not be empty`, TypeError);
375
375
  }
376
- if (checkPath.isNotRelative(path30)) {
376
+ if (checkPath.isNotRelative(path31)) {
377
377
  const r = "`path.relative()`d";
378
378
  return doThrow(
379
379
  `path should be a ${r} string, but got "${originalPath}"`,
@@ -382,7 +382,7 @@ var require_ignore = __commonJS({
382
382
  }
383
383
  return true;
384
384
  };
385
- var isNotRelative = (path30) => REGEX_TEST_INVALID_PATH.test(path30);
385
+ var isNotRelative = (path31) => REGEX_TEST_INVALID_PATH.test(path31);
386
386
  checkPath.isNotRelative = isNotRelative;
387
387
  checkPath.convert = (p) => p;
388
388
  var Ignore2 = class {
@@ -412,19 +412,19 @@ var require_ignore = __commonJS({
412
412
  }
413
413
  // @returns {TestResult}
414
414
  _test(originalPath, cache, checkUnignored, slices) {
415
- const path30 = originalPath && checkPath.convert(originalPath);
415
+ const path31 = originalPath && checkPath.convert(originalPath);
416
416
  checkPath(
417
- path30,
417
+ path31,
418
418
  originalPath,
419
419
  this._strictPathCheck ? throwError : RETURN_FALSE
420
420
  );
421
- return this._t(path30, cache, checkUnignored, slices);
421
+ return this._t(path31, cache, checkUnignored, slices);
422
422
  }
423
- checkIgnore(path30) {
424
- if (!REGEX_TEST_TRAILING_SLASH.test(path30)) {
425
- return this.test(path30);
423
+ checkIgnore(path31) {
424
+ if (!REGEX_TEST_TRAILING_SLASH.test(path31)) {
425
+ return this.test(path31);
426
426
  }
427
- const slices = path30.split(SLASH2).filter(Boolean);
427
+ const slices = path31.split(SLASH2).filter(Boolean);
428
428
  slices.pop();
429
429
  if (slices.length) {
430
430
  const parent = this._t(
@@ -437,18 +437,18 @@ var require_ignore = __commonJS({
437
437
  return parent;
438
438
  }
439
439
  }
440
- return this._rules.test(path30, false, MODE_CHECK_IGNORE);
440
+ return this._rules.test(path31, false, MODE_CHECK_IGNORE);
441
441
  }
442
- _t(path30, cache, checkUnignored, slices) {
443
- if (path30 in cache) {
444
- return cache[path30];
442
+ _t(path31, cache, checkUnignored, slices) {
443
+ if (path31 in cache) {
444
+ return cache[path31];
445
445
  }
446
446
  if (!slices) {
447
- slices = path30.split(SLASH2).filter(Boolean);
447
+ slices = path31.split(SLASH2).filter(Boolean);
448
448
  }
449
449
  slices.pop();
450
450
  if (!slices.length) {
451
- return cache[path30] = this._rules.test(path30, checkUnignored, MODE_IGNORE);
451
+ return cache[path31] = this._rules.test(path31, checkUnignored, MODE_IGNORE);
452
452
  }
453
453
  const parent = this._t(
454
454
  slices.join(SLASH2) + SLASH2,
@@ -456,29 +456,29 @@ var require_ignore = __commonJS({
456
456
  checkUnignored,
457
457
  slices
458
458
  );
459
- return cache[path30] = parent.ignored ? parent : this._rules.test(path30, checkUnignored, MODE_IGNORE);
459
+ return cache[path31] = parent.ignored ? parent : this._rules.test(path31, checkUnignored, MODE_IGNORE);
460
460
  }
461
- ignores(path30) {
462
- return this._test(path30, this._ignoreCache, false).ignored;
461
+ ignores(path31) {
462
+ return this._test(path31, this._ignoreCache, false).ignored;
463
463
  }
464
464
  createFilter() {
465
- return (path30) => !this.ignores(path30);
465
+ return (path31) => !this.ignores(path31);
466
466
  }
467
467
  filter(paths) {
468
468
  return makeArray(paths).filter(this.createFilter());
469
469
  }
470
470
  // @returns {TestResult}
471
- test(path30) {
472
- return this._test(path30, this._testCache, true);
471
+ test(path31) {
472
+ return this._test(path31, this._testCache, true);
473
473
  }
474
474
  };
475
475
  var factory = (options) => new Ignore2(options);
476
- var isPathValid = (path30) => checkPath(path30 && checkPath.convert(path30), path30, RETURN_FALSE);
476
+ var isPathValid = (path31) => checkPath(path31 && checkPath.convert(path31), path31, RETURN_FALSE);
477
477
  var setupWindows = () => {
478
478
  const makePosix = (str) => /^\\\\\?\\/.test(str) || /["<>|\u0000-\u001F]+/u.test(str) ? str : str.replace(/\\/g, "/");
479
479
  checkPath.convert = makePosix;
480
480
  const REGEX_TEST_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i;
481
- checkPath.isNotRelative = (path30) => REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path30) || isNotRelative(path30);
481
+ checkPath.isNotRelative = (path31) => REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path31) || isNotRelative(path31);
482
482
  };
483
483
  if (
484
484
  // Detect `process` so that it can run in browsers.
@@ -663,7 +663,7 @@ __export(index_exports, {
663
663
  module.exports = __toCommonJS(index_exports);
664
664
 
665
665
  // src/adapters/opencode.ts
666
- var path29 = __toESM(require("path"), 1);
666
+ var path30 = __toESM(require("path"), 1);
667
667
  var import_url = require("url");
668
668
 
669
669
  // src/config/constants.ts
@@ -1762,7 +1762,7 @@ function loadMergedConfig(projectRoot, host) {
1762
1762
 
1763
1763
  // src/tools/operations.ts
1764
1764
  var import_fs13 = require("fs");
1765
- var path20 = __toESM(require("path"), 1);
1765
+ var path21 = __toESM(require("path"), 1);
1766
1766
 
1767
1767
  // src/tools/knowledge-base-paths.ts
1768
1768
  var path8 = __toESM(require("path"), 1);
@@ -2611,8 +2611,8 @@ function formatExactSearchHandoff(results) {
2611
2611
  }
2612
2612
  function formatContextEvidence(result, index) {
2613
2613
  const symbol = result.name ? ` ${JSON.stringify(compactEvidenceValue(result.name, 80))}` : "";
2614
- const path30 = compactEvidenceValue(result.filePath, 120);
2615
- return `[${index}] ${result.chunkType}${symbol} in ${path30}:${result.startLine}-${result.endLine} (score ${result.score.toFixed(2)})`;
2614
+ const path31 = compactEvidenceValue(result.filePath, 120);
2615
+ return `[${index}] ${result.chunkType}${symbol} in ${path31}:${result.startLine}-${result.endLine} (score ${result.score.toFixed(2)})`;
2616
2616
  }
2617
2617
  function formatContextPack(heading, selected, candidateCount, duplicateCount, limitOmittedCount, budgetOmittedCount, includeExactSearchHandoff) {
2618
2618
  const lines = selected.map((result, index) => formatContextEvidence(result, index + 1));
@@ -3255,8 +3255,8 @@ function formatEffectivenessMetrics(snapshot) {
3255
3255
 
3256
3256
  // src/utils/auto-index.ts
3257
3257
  var import_fs7 = require("fs");
3258
- var os3 = __toESM(require("os"), 1);
3259
- var path11 = __toESM(require("path"), 1);
3258
+ var os4 = __toESM(require("os"), 1);
3259
+ var path12 = __toESM(require("path"), 1);
3260
3260
 
3261
3261
  // src/indexer/index-lock.ts
3262
3262
  var import_crypto = require("crypto");
@@ -3503,7 +3503,7 @@ function removeDeadReclaimMarker(lockPath, expectedOwner) {
3503
3503
  return true;
3504
3504
  }
3505
3505
  function reclaimDeadOwner(indexPath, lockPath, expectedOwner) {
3506
- const reclaimPath = path9.join(lockPath, RECLAIM_DIRECTORY_NAME);
3506
+ const reclaimPath2 = path9.join(lockPath, RECLAIM_DIRECTORY_NAME);
3507
3507
  const reclaimOwner = {
3508
3508
  pid: process.pid,
3509
3509
  hostname: os2.hostname(),
@@ -3512,19 +3512,19 @@ function reclaimDeadOwner(indexPath, lockPath, expectedOwner) {
3512
3512
  expectedOwnerToken: expectedOwner.token
3513
3513
  };
3514
3514
  for (let attempt = 0; attempt < 2; attempt += 1) {
3515
- if (publishJsonDirectory(reclaimPath, reclaimOwner)) break;
3515
+ if (publishJsonDirectory(reclaimPath2, reclaimOwner)) break;
3516
3516
  if (attempt === 0 && removeDeadReclaimMarker(lockPath, expectedOwner)) continue;
3517
3517
  return false;
3518
3518
  }
3519
3519
  try {
3520
- const currentReclaimer = readReclaimOwner(reclaimPath);
3520
+ const currentReclaimer = readReclaimOwner(reclaimPath2);
3521
3521
  const currentOwner = readDirectoryOwner(lockPath);
3522
3522
  if (!currentReclaimer || !sameReclaimOwner(currentReclaimer, reclaimOwner) || !currentOwner || !sameOwner(currentOwner, expectedOwner) || getOwnerLiveness(currentOwner) !== "dead") {
3523
3523
  return false;
3524
3524
  }
3525
3525
  publishRecoveryMarker(indexPath, expectedOwner);
3526
3526
  const ownerBeforeQuarantine = readDirectoryOwner(lockPath);
3527
- const reclaimerBeforeQuarantine = readReclaimOwner(reclaimPath);
3527
+ const reclaimerBeforeQuarantine = readReclaimOwner(reclaimPath2);
3528
3528
  if (!ownerBeforeQuarantine || !sameOwner(ownerBeforeQuarantine, expectedOwner) || getOwnerLiveness(ownerBeforeQuarantine) !== "dead" || !reclaimerBeforeQuarantine || !sameReclaimOwner(reclaimerBeforeQuarantine, reclaimOwner)) {
3529
3529
  return false;
3530
3530
  }
@@ -3694,10 +3694,884 @@ function completeLeaseRecovery(lease) {
3694
3694
  }
3695
3695
  }
3696
3696
 
3697
+ // src/utils/background-worker.ts
3698
+ var import_node_crypto = require("crypto");
3699
+ var import_node_fs = require("fs");
3700
+ var os3 = __toESM(require("os"), 1);
3701
+ var path10 = __toESM(require("path"), 1);
3702
+ var OWNER_FILE_NAME2 = "owner.json";
3703
+ var HEARTBEAT_FILE_PREFIX = "heartbeat.";
3704
+ var RECLAIM_DIRECTORY_NAME2 = "reclaim";
3705
+ var REFRESH_REQUEST_FILE_NAME = "refresh-request.json";
3706
+ var HEARTBEAT_INTERVAL_MS = 5e3;
3707
+ var STALE_LEASE_MS = 3e4;
3708
+ var RETRY_DELAY_MS = 5e3;
3709
+ 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;
3710
+ var BackgroundWorkerStopError = class extends Error {
3711
+ constructor(watcherError, autoIndexError) {
3712
+ super("Failed to stop background worker");
3713
+ this.watcherError = watcherError;
3714
+ this.autoIndexError = autoIndexError;
3715
+ this.name = "BackgroundWorkerStopError";
3716
+ }
3717
+ watcherError;
3718
+ autoIndexError;
3719
+ };
3720
+ var workers = /* @__PURE__ */ new Map();
3721
+ var workerKeysByProject = /* @__PURE__ */ new Map();
3722
+ var workerReplacementBarriers = /* @__PURE__ */ new Map();
3723
+ function getErrorCode2(error) {
3724
+ return typeof error === "object" && error !== null && "code" in error ? String(error.code) : void 0;
3725
+ }
3726
+ function canonicalizePath(targetPath) {
3727
+ const resolved = path10.resolve(targetPath);
3728
+ if ((0, import_node_fs.existsSync)(resolved)) {
3729
+ try {
3730
+ return import_node_fs.realpathSync.native(resolved);
3731
+ } catch {
3732
+ return resolved;
3733
+ }
3734
+ }
3735
+ const parent = path10.dirname(resolved);
3736
+ if (parent === resolved) return resolved;
3737
+ return path10.join(canonicalizePath(parent), path10.basename(resolved));
3738
+ }
3739
+ function projectLookupKey(projectRoot, host) {
3740
+ return `${host}::${canonicalizePath(projectRoot)}`;
3741
+ }
3742
+ function resolveIdentity(projectRoot, config, host) {
3743
+ const canonicalProjectRoot = canonicalizePath(projectRoot);
3744
+ const canonicalIndexPath = canonicalizePath(resolveProjectIndexPath(projectRoot, config.scope, host));
3745
+ return {
3746
+ canonicalIndexPath,
3747
+ canonicalProjectRoot,
3748
+ key: `${canonicalIndexPath}::${canonicalProjectRoot}`
3749
+ };
3750
+ }
3751
+ function controllerKey(identity, host) {
3752
+ return `${identity.key}::${host}`;
3753
+ }
3754
+ function leaseDirectoryName(identity) {
3755
+ const hash = (0, import_node_crypto.createHash)("sha256").update(identity.key).digest("hex").slice(0, 32);
3756
+ return `background-worker.${hash}.lease`;
3757
+ }
3758
+ function leasePathFor(identity) {
3759
+ return path10.join(identity.canonicalIndexPath, leaseDirectoryName(identity));
3760
+ }
3761
+ function parseOwner2(value) {
3762
+ if (typeof value !== "object" || value === null) return null;
3763
+ const candidate = value;
3764
+ if (candidate.version !== 1) return null;
3765
+ if (!Number.isInteger(candidate.pid) || (candidate.pid ?? 0) <= 0) return null;
3766
+ if (typeof candidate.hostname !== "string" || candidate.hostname.length === 0) return null;
3767
+ if (typeof candidate.startedAt !== "string" || Number.isNaN(Date.parse(candidate.startedAt))) return null;
3768
+ if (typeof candidate.heartbeatAt !== "string" || Number.isNaN(Date.parse(candidate.heartbeatAt))) return null;
3769
+ if (typeof candidate.projectRoot !== "string" || candidate.projectRoot.length === 0) return null;
3770
+ if (typeof candidate.indexPath !== "string" || candidate.indexPath.length === 0) return null;
3771
+ if (typeof candidate.token !== "string" || !UUID_PATTERN2.test(candidate.token)) return null;
3772
+ return candidate;
3773
+ }
3774
+ function parseHeartbeat(value, expectedToken) {
3775
+ if (typeof value !== "object" || value === null) return null;
3776
+ const candidate = value;
3777
+ if (candidate.version !== 1 || candidate.token !== expectedToken) return null;
3778
+ if (typeof candidate.heartbeatAt !== "string" || Number.isNaN(Date.parse(candidate.heartbeatAt))) return null;
3779
+ return candidate;
3780
+ }
3781
+ function parseReclaimOwner2(value) {
3782
+ if (typeof value !== "object" || value === null) return null;
3783
+ const candidate = value;
3784
+ if (candidate.version !== 1) return null;
3785
+ if (!Number.isInteger(candidate.pid) || (candidate.pid ?? 0) <= 0) return null;
3786
+ if (typeof candidate.hostname !== "string" || candidate.hostname.length === 0) return null;
3787
+ if (typeof candidate.startedAt !== "string" || Number.isNaN(Date.parse(candidate.startedAt))) return null;
3788
+ if (typeof candidate.token !== "string" || !UUID_PATTERN2.test(candidate.token)) return null;
3789
+ if (candidate.expectedOwnerToken !== null && (typeof candidate.expectedOwnerToken !== "string" || !UUID_PATTERN2.test(candidate.expectedOwnerToken))) return null;
3790
+ return candidate;
3791
+ }
3792
+ function heartbeatPath(leasePath, token) {
3793
+ return path10.join(leasePath, `${HEARTBEAT_FILE_PREFIX}${token}.json`);
3794
+ }
3795
+ function reclaimPath(leasePath) {
3796
+ return path10.join(leasePath, RECLAIM_DIRECTORY_NAME2);
3797
+ }
3798
+ function refreshRequestPath(leasePath) {
3799
+ return path10.join(leasePath, REFRESH_REQUEST_FILE_NAME);
3800
+ }
3801
+ function readLeaseOwner(leasePath) {
3802
+ try {
3803
+ return parseOwner2(JSON.parse((0, import_node_fs.readFileSync)(path10.join(leasePath, OWNER_FILE_NAME2), "utf-8")));
3804
+ } catch {
3805
+ return null;
3806
+ }
3807
+ }
3808
+ function readOwner(leasePath) {
3809
+ const owner = readLeaseOwner(leasePath);
3810
+ if (!owner) return null;
3811
+ try {
3812
+ const heartbeat = parseHeartbeat(
3813
+ JSON.parse((0, import_node_fs.readFileSync)(heartbeatPath(leasePath, owner.token), "utf-8")),
3814
+ owner.token
3815
+ );
3816
+ return heartbeat ? { ...owner, heartbeatAt: heartbeat.heartbeatAt } : owner;
3817
+ } catch {
3818
+ return owner;
3819
+ }
3820
+ }
3821
+ function readReclaimOwner2(leasePath) {
3822
+ try {
3823
+ return parseReclaimOwner2(JSON.parse((0, import_node_fs.readFileSync)(path10.join(reclaimPath(leasePath), OWNER_FILE_NAME2), "utf-8")));
3824
+ } catch {
3825
+ return null;
3826
+ }
3827
+ }
3828
+ function ownerLiveness(owner) {
3829
+ if (owner.hostname !== os3.hostname()) return "unknown";
3830
+ try {
3831
+ process.kill(owner.pid, 0);
3832
+ return "alive";
3833
+ } catch (error) {
3834
+ const code = getErrorCode2(error);
3835
+ if (code === "ESRCH") return "dead";
3836
+ if (code === "EPERM") return "alive";
3837
+ return "unknown";
3838
+ }
3839
+ }
3840
+ function isHeartbeatExpired(owner) {
3841
+ return Date.now() - Date.parse(owner.heartbeatAt) >= STALE_LEASE_MS;
3842
+ }
3843
+ function sameOwner2(left, right) {
3844
+ return left.pid === right.pid && left.hostname === right.hostname && left.token === right.token;
3845
+ }
3846
+ function writeHeartbeat(leasePath, owner) {
3847
+ const targetPath = heartbeatPath(leasePath, owner.token);
3848
+ const temporaryPath = `${targetPath}.tmp.${process.pid}.${owner.token}.${(0, import_node_crypto.randomUUID)()}`;
3849
+ const heartbeat = {
3850
+ version: 1,
3851
+ token: owner.token,
3852
+ heartbeatAt: owner.heartbeatAt
3853
+ };
3854
+ try {
3855
+ (0, import_node_fs.writeFileSync)(temporaryPath, JSON.stringify(heartbeat), {
3856
+ encoding: "utf-8",
3857
+ flag: "wx",
3858
+ mode: 384
3859
+ });
3860
+ (0, import_node_fs.renameSync)(temporaryPath, targetPath);
3861
+ const currentOwner = readLeaseOwner(leasePath);
3862
+ return currentOwner !== null && sameOwner2(currentOwner, owner);
3863
+ } finally {
3864
+ if ((0, import_node_fs.existsSync)(temporaryPath)) (0, import_node_fs.rmSync)(temporaryPath, { force: true });
3865
+ }
3866
+ }
3867
+ function requestRefreshFromLeader(leasePath, allowDisabledAutoIndex) {
3868
+ const requestPath = refreshRequestPath(leasePath);
3869
+ const temporaryPath = `${requestPath}.tmp.${process.pid}.${(0, import_node_crypto.randomUUID)()}`;
3870
+ try {
3871
+ const request = {
3872
+ allowDisabledAutoIndex,
3873
+ requestedAt: (/* @__PURE__ */ new Date()).toISOString(),
3874
+ version: 1
3875
+ };
3876
+ (0, import_node_fs.writeFileSync)(temporaryPath, JSON.stringify(request), {
3877
+ encoding: "utf-8",
3878
+ flag: "wx",
3879
+ mode: 384
3880
+ });
3881
+ (0, import_node_fs.renameSync)(temporaryPath, requestPath);
3882
+ } catch (error) {
3883
+ if (getErrorCode2(error) !== "ENOENT") {
3884
+ console.error("[codebase-index] Failed to request background index refresh from the project worker:", error);
3885
+ }
3886
+ } finally {
3887
+ if ((0, import_node_fs.existsSync)(temporaryPath)) (0, import_node_fs.rmSync)(temporaryPath, { force: true });
3888
+ }
3889
+ }
3890
+ function consumeRefreshRequest(leasePath) {
3891
+ const requestPath = refreshRequestPath(leasePath);
3892
+ const claimedPath = `${requestPath}.handling.${process.pid}.${(0, import_node_crypto.randomUUID)()}`;
3893
+ try {
3894
+ (0, import_node_fs.renameSync)(requestPath, claimedPath);
3895
+ } catch (error) {
3896
+ if (getErrorCode2(error) === "ENOENT") return null;
3897
+ throw error;
3898
+ }
3899
+ try {
3900
+ const value = JSON.parse((0, import_node_fs.readFileSync)(claimedPath, "utf-8"));
3901
+ return {
3902
+ allowDisabledAutoIndex: value.version === 1 && value.allowDisabledAutoIndex === true,
3903
+ requestedAt: typeof value.requestedAt === "string" ? value.requestedAt : (/* @__PURE__ */ new Date()).toISOString(),
3904
+ version: 1
3905
+ };
3906
+ } catch {
3907
+ return { allowDisabledAutoIndex: false, requestedAt: (/* @__PURE__ */ new Date()).toISOString(), version: 1 };
3908
+ } finally {
3909
+ (0, import_node_fs.rmSync)(claimedPath, { force: true });
3910
+ }
3911
+ }
3912
+ function publishLease(leasePath, owner) {
3913
+ const candidatePath = `${leasePath}.candidate.${process.pid}.${owner.token}`;
3914
+ try {
3915
+ (0, import_node_fs.mkdirSync)(candidatePath, { mode: 448 });
3916
+ } catch (error) {
3917
+ if (getErrorCode2(error) === "ENOENT") return false;
3918
+ throw error;
3919
+ }
3920
+ try {
3921
+ (0, import_node_fs.writeFileSync)(path10.join(candidatePath, OWNER_FILE_NAME2), JSON.stringify(owner), {
3922
+ encoding: "utf-8",
3923
+ flag: "wx",
3924
+ mode: 384
3925
+ });
3926
+ if ((0, import_node_fs.existsSync)(leasePath)) return false;
3927
+ try {
3928
+ (0, import_node_fs.renameSync)(candidatePath, leasePath);
3929
+ return true;
3930
+ } catch (error) {
3931
+ if ((0, import_node_fs.existsSync)(leasePath) || getErrorCode2(error) === "ENOENT") return false;
3932
+ throw error;
3933
+ }
3934
+ } finally {
3935
+ if ((0, import_node_fs.existsSync)(candidatePath)) (0, import_node_fs.rmSync)(candidatePath, { recursive: true, force: true });
3936
+ }
3937
+ }
3938
+ function sameReclaimOwner2(left, right) {
3939
+ return left.pid === right.pid && left.hostname === right.hostname && left.token === right.token && left.expectedOwnerToken === right.expectedOwnerToken;
3940
+ }
3941
+ function reclaimerLiveness(owner) {
3942
+ return ownerLiveness(owner);
3943
+ }
3944
+ function isReclaimMarkerExpired(leasePath, owner) {
3945
+ const startedAt = owner ? Date.parse(owner.startedAt) : (() => {
3946
+ try {
3947
+ return (0, import_node_fs.lstatSync)(reclaimPath(leasePath)).mtimeMs;
3948
+ } catch {
3949
+ return Date.now();
3950
+ }
3951
+ })();
3952
+ return Date.now() - startedAt >= STALE_LEASE_MS;
3953
+ }
3954
+ function hasActiveReclaimMarker(leasePath, owner) {
3955
+ const marker = readReclaimOwner2(leasePath);
3956
+ return marker !== null && marker.expectedOwnerToken === owner.token && (marker.hostname !== os3.hostname() || ownerLiveness(owner) !== "alive");
3957
+ }
3958
+ function publishReclaimMarker(leasePath, expectedOwner) {
3959
+ const markerPath = reclaimPath(leasePath);
3960
+ const owner = {
3961
+ version: 1,
3962
+ pid: process.pid,
3963
+ hostname: os3.hostname(),
3964
+ startedAt: (/* @__PURE__ */ new Date()).toISOString(),
3965
+ token: (0, import_node_crypto.randomUUID)(),
3966
+ expectedOwnerToken: expectedOwner?.token ?? null
3967
+ };
3968
+ try {
3969
+ (0, import_node_fs.mkdirSync)(markerPath, { mode: 448 });
3970
+ } catch (error) {
3971
+ if (getErrorCode2(error) === "EEXIST" || getErrorCode2(error) === "ENOENT") return null;
3972
+ throw error;
3973
+ }
3974
+ try {
3975
+ (0, import_node_fs.writeFileSync)(path10.join(markerPath, OWNER_FILE_NAME2), JSON.stringify(owner), {
3976
+ encoding: "utf-8",
3977
+ flag: "wx",
3978
+ mode: 384
3979
+ });
3980
+ return owner;
3981
+ } catch (error) {
3982
+ (0, import_node_fs.rmSync)(markerPath, { recursive: true, force: true });
3983
+ throw error;
3984
+ }
3985
+ }
3986
+ function removeExpiredReclaimMarker(leasePath, expectedOwner) {
3987
+ const marker = readReclaimOwner2(leasePath);
3988
+ const markerPath = reclaimPath(leasePath);
3989
+ if (!(0, import_node_fs.existsSync)(markerPath)) return false;
3990
+ if (marker && marker.expectedOwnerToken !== (expectedOwner?.token ?? null)) return false;
3991
+ if (marker && (reclaimerLiveness(marker) === "alive" || !isReclaimMarkerExpired(leasePath, marker))) return false;
3992
+ if (!marker && !isReclaimMarkerExpired(leasePath, null)) return false;
3993
+ const staleMarkerPath = `${markerPath}.stale.${marker?.pid ?? process.pid}.${marker?.token ?? (0, import_node_crypto.randomUUID)()}.${(0, import_node_crypto.randomUUID)()}`;
3994
+ try {
3995
+ (0, import_node_fs.renameSync)(markerPath, staleMarkerPath);
3996
+ } catch (error) {
3997
+ if (getErrorCode2(error) === "ENOENT") return false;
3998
+ throw error;
3999
+ }
4000
+ try {
4001
+ let claimedMarker = null;
4002
+ try {
4003
+ claimedMarker = parseReclaimOwner2(
4004
+ JSON.parse((0, import_node_fs.readFileSync)(path10.join(staleMarkerPath, OWNER_FILE_NAME2), "utf-8"))
4005
+ );
4006
+ } catch {
4007
+ claimedMarker = null;
4008
+ }
4009
+ const markerMatches = marker ? claimedMarker !== null && sameReclaimOwner2(claimedMarker, marker) : claimedMarker === null;
4010
+ if (!markerMatches || !canReclaimLease(leasePath, expectedOwner)) {
4011
+ if (!(0, import_node_fs.existsSync)(markerPath) && (0, import_node_fs.existsSync)(staleMarkerPath)) (0, import_node_fs.renameSync)(staleMarkerPath, markerPath);
4012
+ return false;
4013
+ }
4014
+ (0, import_node_fs.rmSync)(staleMarkerPath, { recursive: true, force: true });
4015
+ return true;
4016
+ } catch (error) {
4017
+ if (getErrorCode2(error) === "ENOENT") return false;
4018
+ throw error;
4019
+ }
4020
+ }
4021
+ function canReclaimLease(leasePath, expectedOwner) {
4022
+ if (!(0, import_node_fs.existsSync)(leasePath)) return false;
4023
+ if (!expectedOwner) return false;
4024
+ const currentOwner = readOwner(leasePath);
4025
+ if (!currentOwner || !sameOwner2(currentOwner, expectedOwner)) return false;
4026
+ if (currentOwner.hostname === os3.hostname()) {
4027
+ return ownerLiveness(currentOwner) === "dead";
4028
+ }
4029
+ return isHeartbeatExpired(currentOwner);
4030
+ }
4031
+ function reclaimLease(leasePath, expectedOwner) {
4032
+ let marker = null;
4033
+ for (let attempt = 0; attempt < 2; attempt += 1) {
4034
+ marker = publishReclaimMarker(leasePath, expectedOwner);
4035
+ if (marker) break;
4036
+ if (attempt === 0 && removeExpiredReclaimMarker(leasePath, expectedOwner)) continue;
4037
+ return false;
4038
+ }
4039
+ if (!marker) return false;
4040
+ const markerPath = reclaimPath(leasePath);
4041
+ try {
4042
+ const currentMarker = readReclaimOwner2(leasePath);
4043
+ if (!currentMarker || !sameReclaimOwner2(currentMarker, marker) || !canReclaimLease(leasePath, expectedOwner)) {
4044
+ return false;
4045
+ }
4046
+ const stalePath = `${leasePath}.stale.${process.pid}.${marker.token}`;
4047
+ (0, import_node_fs.renameSync)(leasePath, stalePath);
4048
+ const quarantinedOwner = readOwner(stalePath);
4049
+ const quarantinedMarker = readReclaimOwner2(stalePath);
4050
+ if (!quarantinedMarker || !sameReclaimOwner2(quarantinedMarker, marker) || expectedOwner !== null && (!quarantinedOwner || !sameOwner2(quarantinedOwner, expectedOwner))) {
4051
+ if (!(0, import_node_fs.existsSync)(leasePath) && (0, import_node_fs.existsSync)(stalePath)) (0, import_node_fs.renameSync)(stalePath, leasePath);
4052
+ return false;
4053
+ }
4054
+ (0, import_node_fs.rmSync)(stalePath, { recursive: true, force: true });
4055
+ return true;
4056
+ } catch (error) {
4057
+ if (getErrorCode2(error) === "ENOENT") return false;
4058
+ throw error;
4059
+ } finally {
4060
+ const currentMarker = readReclaimOwner2(leasePath);
4061
+ if (currentMarker && sameReclaimOwner2(currentMarker, marker)) {
4062
+ (0, import_node_fs.rmSync)(markerPath, { recursive: true, force: true });
4063
+ }
4064
+ }
4065
+ }
4066
+ function acquireLease(identity) {
4067
+ (0, import_node_fs.mkdirSync)(identity.canonicalIndexPath, { recursive: true, mode: 448 });
4068
+ const canonicalIndexPath = import_node_fs.realpathSync.native(identity.canonicalIndexPath);
4069
+ const leasePath = path10.join(canonicalIndexPath, leaseDirectoryName({ ...identity, canonicalIndexPath }));
4070
+ for (let attempt = 0; attempt < 4; attempt += 1) {
4071
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
4072
+ const owner = {
4073
+ version: 1,
4074
+ pid: process.pid,
4075
+ hostname: os3.hostname(),
4076
+ startedAt: timestamp,
4077
+ heartbeatAt: timestamp,
4078
+ projectRoot: identity.canonicalProjectRoot,
4079
+ indexPath: canonicalIndexPath,
4080
+ token: (0, import_node_crypto.randomUUID)()
4081
+ };
4082
+ if (publishLease(leasePath, owner)) {
4083
+ return { leasePath, owner };
4084
+ }
4085
+ const existingOwner = readOwner(leasePath);
4086
+ if (existingOwner) {
4087
+ if (canReclaimLease(leasePath, existingOwner) && reclaimLease(leasePath, existingOwner)) continue;
4088
+ return null;
4089
+ }
4090
+ return null;
4091
+ }
4092
+ return null;
4093
+ }
4094
+ function releaseLease(lease) {
4095
+ const currentOwner = readOwner(lease.leasePath);
4096
+ if (!currentOwner || !sameOwner2(currentOwner, lease.owner)) return false;
4097
+ const releasePath = `${lease.leasePath}.release.${lease.owner.pid}.${lease.owner.token}`;
4098
+ try {
4099
+ (0, import_node_fs.renameSync)(lease.leasePath, releasePath);
4100
+ } catch (error) {
4101
+ if (getErrorCode2(error) === "ENOENT") return false;
4102
+ throw error;
4103
+ }
4104
+ const claimedOwner = readOwner(releasePath);
4105
+ if (!claimedOwner || !sameOwner2(claimedOwner, lease.owner)) {
4106
+ if (!(0, import_node_fs.existsSync)(lease.leasePath) && (0, import_node_fs.existsSync)(releasePath)) {
4107
+ (0, import_node_fs.renameSync)(releasePath, lease.leasePath);
4108
+ }
4109
+ return false;
4110
+ }
4111
+ (0, import_node_fs.rmSync)(releasePath, { recursive: true, force: true });
4112
+ return true;
4113
+ }
4114
+ var BackgroundWorkerController = class {
4115
+ constructor(projectRoot, host, config, hooks, identity) {
4116
+ this.projectRoot = projectRoot;
4117
+ this.host = host;
4118
+ this.config = config;
4119
+ this.hooks = hooks;
4120
+ this.identity = identity;
4121
+ }
4122
+ projectRoot;
4123
+ host;
4124
+ config;
4125
+ hooks;
4126
+ identity;
4127
+ lease = null;
4128
+ watcher = null;
4129
+ leaderReady = Promise.resolve();
4130
+ heartbeatTimer = null;
4131
+ retryTimer = null;
4132
+ teardownRetryTimer = null;
4133
+ transition = Promise.resolve();
4134
+ stopPromise = null;
4135
+ stopped = false;
4136
+ stopping = false;
4137
+ losingLeadership = false;
4138
+ restartAfterStop = false;
4139
+ leaderWorkStopped = false;
4140
+ startingLeaderWork = false;
4141
+ stopAutoIndexOnTeardown = true;
4142
+ autoIndexStarted = false;
4143
+ reportedError = null;
4144
+ update(config, hooks, options) {
4145
+ const autoIndexWasEnabled = this.config.indexing.autoIndex;
4146
+ const shouldReplaceWatcher = this.watcher !== null && hooks.watcherFactory !== void 0 && (hooks.watcherFactory === null || hooks.replaceWatcher === true);
4147
+ this.config = config;
4148
+ this.hooks = {
4149
+ ...this.hooks,
4150
+ ...hooks,
4151
+ watcherFactory: hooks.watcherFactory === void 0 ? this.hooks.watcherFactory : hooks.watcherFactory,
4152
+ watcherFactoryForConfig: hooks.watcherFactoryForConfig === void 0 ? this.hooks.watcherFactoryForConfig : hooks.watcherFactoryForConfig
4153
+ };
4154
+ if (autoIndexWasEnabled && !config.indexing.autoIndex || options.restartAutoIndex === true && config.indexing.autoIndex && !this.startingLeaderWork) {
4155
+ this.autoIndexStarted = false;
4156
+ }
4157
+ if (!this.canRun()) {
4158
+ void this.stop().catch((error) => {
4159
+ console.error("[codebase-index] Failed to stop background worker after disabling automatic work:", error);
4160
+ });
4161
+ return;
4162
+ }
4163
+ if (shouldReplaceWatcher) {
4164
+ void this.enqueue(async () => {
4165
+ const watcher = this.watcher;
4166
+ if (watcher) {
4167
+ await watcher.stop();
4168
+ if (this.watcher === watcher) this.watcher = null;
4169
+ }
4170
+ if (this.lease && !this.stopped) this.startLeaderWork();
4171
+ }).catch((error) => {
4172
+ console.error("[codebase-index] Failed to replace background file watcher:", error);
4173
+ });
4174
+ }
4175
+ this.start();
4176
+ }
4177
+ startAfter(activation) {
4178
+ this.transition = activation.catch(() => void 0);
4179
+ this.start();
4180
+ }
4181
+ start() {
4182
+ if (!this.canRun() || this.losingLeadership) return;
4183
+ if (this.stopping) {
4184
+ this.restartAfterStop = true;
4185
+ return;
4186
+ }
4187
+ this.stopped = false;
4188
+ void this.enqueue(async () => {
4189
+ if (this.stopped || this.stopping || this.losingLeadership || !this.canRun()) return;
4190
+ if (!this.lease) {
4191
+ try {
4192
+ this.lease = acquireLease(this.identity);
4193
+ this.reportedError = null;
4194
+ } catch (error) {
4195
+ this.reportAcquireError(error);
4196
+ this.scheduleRetry();
4197
+ return;
4198
+ }
4199
+ }
4200
+ if (!this.lease) {
4201
+ this.scheduleRetry();
4202
+ return;
4203
+ }
4204
+ this.startHeartbeat();
4205
+ this.startLeaderWork();
4206
+ });
4207
+ }
4208
+ waitForStart() {
4209
+ return this.transition.catch(() => void 0).then(() => this.leaderReady);
4210
+ }
4211
+ requestRefresh(allowDisabledAutoIndex = false) {
4212
+ this.start();
4213
+ if (!this.isLeader()) {
4214
+ requestRefreshFromLeader(leasePathFor(this.identity), allowDisabledAutoIndex);
4215
+ return;
4216
+ }
4217
+ void this.enqueue(async () => {
4218
+ if (this.stopped || !this.lease) return;
4219
+ this.hooks.startAutoIndex("retrieval", allowDisabledAutoIndex);
4220
+ });
4221
+ }
4222
+ isLeader() {
4223
+ return this.lease !== null && !this.stopping && !this.losingLeadership;
4224
+ }
4225
+ isStopping() {
4226
+ return this.stopping;
4227
+ }
4228
+ getHooksForConfig(config) {
4229
+ const watcherFactoryForConfig = this.hooks.watcherFactoryForConfig;
4230
+ if (!watcherFactoryForConfig) return this.hooks;
4231
+ return {
4232
+ ...this.hooks,
4233
+ watcherFactory: watcherFactoryForConfig(config),
4234
+ replaceWatcher: true
4235
+ };
4236
+ }
4237
+ attachWatcher(watcherFactory, watcherFactoryForConfig) {
4238
+ if (this.hooks.watcherFactory !== void 0) return;
4239
+ this.hooks = {
4240
+ ...this.hooks,
4241
+ watcherFactory,
4242
+ watcherFactoryForConfig: watcherFactoryForConfig ?? this.hooks.watcherFactoryForConfig
4243
+ };
4244
+ this.start();
4245
+ }
4246
+ async stop(stopAutoIndex = true) {
4247
+ if (this.stopPromise) return this.stopPromise;
4248
+ this.stopped = true;
4249
+ this.stopping = true;
4250
+ this.stopAutoIndexOnTeardown &&= stopAutoIndex;
4251
+ this.clearRetryTimer();
4252
+ const attempt = this.enqueue(async () => {
4253
+ try {
4254
+ const lease = this.lease;
4255
+ if (this.leaderWorkStopped) {
4256
+ if (lease) {
4257
+ this.releaseStoppedLease(lease);
4258
+ } else {
4259
+ this.finishStoppedLease();
4260
+ }
4261
+ return;
4262
+ }
4263
+ const hadLeaderWork = lease !== null || this.watcher !== null || this.autoIndexStarted;
4264
+ const stopped = await this.stopLeaderWork(hadLeaderWork && this.stopAutoIndexOnTeardown);
4265
+ if (!lease) {
4266
+ this.finishStoppedLease();
4267
+ return;
4268
+ }
4269
+ if (!stopped.completed) {
4270
+ this.releaseLeaseWhenAutoIndexStops(lease, stopped.completion);
4271
+ return;
4272
+ }
4273
+ this.leaderWorkStopped = true;
4274
+ this.releaseStoppedLease(lease);
4275
+ } catch (error) {
4276
+ this.scheduleTeardownRetry();
4277
+ throw error;
4278
+ }
4279
+ });
4280
+ const completion = attempt.finally(() => {
4281
+ if (this.stopPromise === completion) this.stopPromise = null;
4282
+ });
4283
+ this.stopPromise = completion;
4284
+ return completion;
4285
+ }
4286
+ canRun() {
4287
+ return this.config.indexing.autoIndex || this.hooks.watcherFactory != null;
4288
+ }
4289
+ enqueue(operation) {
4290
+ const next = this.transition.catch(() => void 0).then(operation);
4291
+ this.transition = next;
4292
+ return next;
4293
+ }
4294
+ startLeaderWork() {
4295
+ if (this.stopped || this.stopping || this.losingLeadership) return;
4296
+ this.startingLeaderWork = true;
4297
+ try {
4298
+ if (this.config.indexing.autoIndex && !this.autoIndexStarted) {
4299
+ this.autoIndexStarted = true;
4300
+ this.hooks.startAutoIndex("startup");
4301
+ }
4302
+ if (!this.watcher && this.hooks.watcherFactory) {
4303
+ try {
4304
+ const watcher = this.hooks.watcherFactory();
4305
+ this.watcher = watcher;
4306
+ this.leaderReady = watcher.whenReady?.().catch((error) => {
4307
+ console.error("[codebase-index] Failed while waiting for background file watcher startup:", error);
4308
+ }) ?? Promise.resolve();
4309
+ } catch (error) {
4310
+ console.error("[codebase-index] Failed to start background file watcher:", error);
4311
+ this.leaderReady = Promise.resolve();
4312
+ }
4313
+ }
4314
+ } finally {
4315
+ this.startingLeaderWork = false;
4316
+ }
4317
+ }
4318
+ async stopLeaderWork(stopAutoIndex) {
4319
+ const watcher = this.watcher;
4320
+ let watcherError;
4321
+ if (watcher) {
4322
+ try {
4323
+ await watcher.stop();
4324
+ if (this.watcher === watcher) this.watcher = null;
4325
+ } catch (error) {
4326
+ watcherError = error;
4327
+ }
4328
+ }
4329
+ let autoIndexError;
4330
+ let autoIndexStop = {
4331
+ completed: true,
4332
+ completion: Promise.resolve()
4333
+ };
4334
+ if (stopAutoIndex) {
4335
+ try {
4336
+ autoIndexStop = await this.hooks.stopAutoIndex();
4337
+ this.autoIndexStarted = false;
4338
+ } catch (error) {
4339
+ autoIndexError = error;
4340
+ }
4341
+ }
4342
+ if (watcherError !== void 0 || autoIndexError !== void 0) {
4343
+ throw new BackgroundWorkerStopError(watcherError, autoIndexError);
4344
+ }
4345
+ return autoIndexStop;
4346
+ }
4347
+ releaseLeaseWhenAutoIndexStops(lease, completion) {
4348
+ void completion.then(
4349
+ () => {
4350
+ void this.enqueue(async () => {
4351
+ if (this.lease !== lease || !this.stopping) return;
4352
+ this.leaderWorkStopped = true;
4353
+ this.releaseStoppedLease(lease);
4354
+ }).catch((error) => {
4355
+ console.error("[codebase-index] Failed to release background worker lease after automatic indexing stopped:", error);
4356
+ this.scheduleTeardownRetry();
4357
+ });
4358
+ },
4359
+ (error) => {
4360
+ console.error("[codebase-index] Failed while waiting for automatic indexing to stop:", error);
4361
+ this.scheduleTeardownRetry();
4362
+ }
4363
+ );
4364
+ }
4365
+ releaseStoppedLease(lease) {
4366
+ if (this.lease !== lease) {
4367
+ this.finishStoppedLease();
4368
+ return;
4369
+ }
4370
+ releaseLease(lease);
4371
+ this.lease = null;
4372
+ this.finishStoppedLease();
4373
+ }
4374
+ finishStoppedLease() {
4375
+ this.leaderWorkStopped = false;
4376
+ this.stopAutoIndexOnTeardown = true;
4377
+ this.stopping = false;
4378
+ this.clearTimers();
4379
+ this.restartAfterTeardown();
4380
+ if (!this.stopped || this.stopping) return;
4381
+ const projectKey = projectLookupKey(this.projectRoot, this.host);
4382
+ const key = controllerKey(this.identity, this.host);
4383
+ if (workers.get(key) === this) workers.delete(key);
4384
+ if (workerKeysByProject.get(projectKey) === key) workerKeysByProject.delete(projectKey);
4385
+ }
4386
+ startHeartbeat() {
4387
+ if (this.heartbeatTimer) return;
4388
+ const heartbeat = () => {
4389
+ void this.heartbeat();
4390
+ };
4391
+ this.heartbeatTimer = setInterval(heartbeat, HEARTBEAT_INTERVAL_MS);
4392
+ this.heartbeatTimer.unref?.();
4393
+ }
4394
+ async heartbeat() {
4395
+ const lease = this.lease;
4396
+ if (!lease || this.losingLeadership || this.stopped && !this.stopping) return;
4397
+ if (hasActiveReclaimMarker(lease.leasePath, lease.owner)) {
4398
+ await this.loseLeadership();
4399
+ return;
4400
+ }
4401
+ const currentOwner = readOwner(lease.leasePath);
4402
+ if (!currentOwner || !sameOwner2(currentOwner, lease.owner)) {
4403
+ await this.loseLeadership();
4404
+ return;
4405
+ }
4406
+ try {
4407
+ const nextOwner = { ...lease.owner, heartbeatAt: (/* @__PURE__ */ new Date()).toISOString() };
4408
+ if (!writeHeartbeat(lease.leasePath, nextOwner)) {
4409
+ await this.loseLeadership();
4410
+ return;
4411
+ }
4412
+ lease.owner = nextOwner;
4413
+ const refreshRequest = !this.stopping ? consumeRefreshRequest(lease.leasePath) : null;
4414
+ if (refreshRequest) {
4415
+ this.hooks.startAutoIndex("retrieval", refreshRequest.allowDisabledAutoIndex);
4416
+ }
4417
+ } catch (error) {
4418
+ const ownerAfterError = readOwner(lease.leasePath);
4419
+ if (hasActiveReclaimMarker(lease.leasePath, lease.owner) || !ownerAfterError || !sameOwner2(ownerAfterError, lease.owner)) {
4420
+ await this.loseLeadership();
4421
+ return;
4422
+ }
4423
+ console.error("[codebase-index] Failed to renew background worker lease:", error);
4424
+ }
4425
+ }
4426
+ async loseLeadership() {
4427
+ if (this.losingLeadership) return;
4428
+ this.losingLeadership = true;
4429
+ this.clearHeartbeat();
4430
+ await this.enqueue(async () => this.stopAfterLeadershipLoss());
4431
+ }
4432
+ async stopAfterLeadershipLoss() {
4433
+ const lease = this.lease;
4434
+ if (!lease) {
4435
+ this.losingLeadership = false;
4436
+ return;
4437
+ }
4438
+ try {
4439
+ const stopped = await this.stopLeaderWork(true);
4440
+ this.lease = null;
4441
+ this.losingLeadership = false;
4442
+ if (stopped.completed) {
4443
+ this.scheduleRetry();
4444
+ } else {
4445
+ void stopped.completion.then(() => this.scheduleRetry());
4446
+ }
4447
+ } catch (error) {
4448
+ console.error("[codebase-index] Failed to stop background work after losing its lease:", error);
4449
+ this.scheduleLostLeadershipTeardownRetry();
4450
+ }
4451
+ }
4452
+ scheduleRetry() {
4453
+ if (this.stopped || !this.canRun() || this.retryTimer) return;
4454
+ this.retryTimer = setTimeout(() => {
4455
+ this.retryTimer = null;
4456
+ this.start();
4457
+ }, RETRY_DELAY_MS);
4458
+ this.retryTimer.unref?.();
4459
+ }
4460
+ scheduleTeardownRetry() {
4461
+ if (!this.stopping || this.teardownRetryTimer) return;
4462
+ this.teardownRetryTimer = setTimeout(() => {
4463
+ this.teardownRetryTimer = null;
4464
+ void this.stop(this.stopAutoIndexOnTeardown).catch((error) => {
4465
+ console.error("[codebase-index] Failed to retry background worker teardown:", error);
4466
+ });
4467
+ }, RETRY_DELAY_MS);
4468
+ this.teardownRetryTimer.unref?.();
4469
+ }
4470
+ restartAfterTeardown() {
4471
+ if (!this.restartAfterStop || !this.canRun() || this.losingLeadership) return;
4472
+ this.restartAfterStop = false;
4473
+ this.stopped = false;
4474
+ this.start();
4475
+ }
4476
+ scheduleLostLeadershipTeardownRetry() {
4477
+ if (this.stopped || !this.losingLeadership || this.retryTimer) return;
4478
+ this.retryTimer = setTimeout(() => {
4479
+ this.retryTimer = null;
4480
+ void this.enqueue(async () => this.stopAfterLeadershipLoss());
4481
+ }, RETRY_DELAY_MS);
4482
+ this.retryTimer.unref?.();
4483
+ }
4484
+ clearHeartbeat() {
4485
+ if (!this.heartbeatTimer) return;
4486
+ clearInterval(this.heartbeatTimer);
4487
+ this.heartbeatTimer = null;
4488
+ }
4489
+ clearTimers() {
4490
+ this.clearHeartbeat();
4491
+ this.clearRetryTimer();
4492
+ if (this.teardownRetryTimer) {
4493
+ clearTimeout(this.teardownRetryTimer);
4494
+ this.teardownRetryTimer = null;
4495
+ }
4496
+ }
4497
+ clearRetryTimer() {
4498
+ if (!this.retryTimer) return;
4499
+ clearTimeout(this.retryTimer);
4500
+ this.retryTimer = null;
4501
+ }
4502
+ reportAcquireError(error) {
4503
+ const message = error instanceof Error ? error.message : String(error);
4504
+ if (this.reportedError === message) return;
4505
+ this.reportedError = message;
4506
+ console.error("[codebase-index] Failed to acquire background worker lease:", error);
4507
+ }
4508
+ };
4509
+ function configureBackgroundWorker(projectRoot, host, config, hooks, options = {}) {
4510
+ const projectKey = projectLookupKey(projectRoot, host);
4511
+ const identity = resolveIdentity(projectRoot, config, host);
4512
+ const key = controllerKey(identity, host);
4513
+ const previousKey = workerKeysByProject.get(projectKey);
4514
+ if (previousKey && previousKey !== key) {
4515
+ const previous = workers.get(previousKey);
4516
+ const previousBarrier = workerReplacementBarriers.get(projectKey) ?? Promise.resolve();
4517
+ const stopPrevious = previous?.stop(options.stopPreviousAutoIndex ?? true) ?? Promise.resolve();
4518
+ const activation = Promise.all([previousBarrier, stopPrevious]).then(() => void 0);
4519
+ workerReplacementBarriers.set(projectKey, activation);
4520
+ workers.delete(previousKey);
4521
+ const worker2 = new BackgroundWorkerController(projectRoot, host, config, hooks, identity);
4522
+ worker2.startAfter(activation);
4523
+ workers.set(key, worker2);
4524
+ workerKeysByProject.set(projectKey, key);
4525
+ return;
4526
+ }
4527
+ let worker = workers.get(key);
4528
+ if (!worker) {
4529
+ worker = new BackgroundWorkerController(projectRoot, host, config, hooks, identity);
4530
+ workers.set(key, worker);
4531
+ } else {
4532
+ worker.update(config, hooks, options);
4533
+ }
4534
+ workerKeysByProject.set(projectKey, key);
4535
+ worker.start();
4536
+ }
4537
+ function updateBackgroundWorkerConfig(projectRoot, host, config) {
4538
+ const projectKey = projectLookupKey(projectRoot, host);
4539
+ const key = workerKeysByProject.get(projectKey);
4540
+ const worker = key ? workers.get(key) : void 0;
4541
+ if (!worker) return;
4542
+ configureBackgroundWorker(projectRoot, host, config, worker.getHooksForConfig(config), {
4543
+ stopPreviousAutoIndex: false,
4544
+ restartAutoIndex: true
4545
+ });
4546
+ }
4547
+ function waitForBackgroundWorkerStart(projectRoot, host) {
4548
+ const key = workerKeysByProject.get(projectLookupKey(projectRoot, host));
4549
+ return workers.get(key ?? "")?.waitForStart() ?? Promise.resolve();
4550
+ }
4551
+ function requestBackgroundWorkerRefresh(projectRoot, host, allowDisabledAutoIndex = false) {
4552
+ const key = workerKeysByProject.get(projectLookupKey(projectRoot, host));
4553
+ workers.get(key ?? "")?.requestRefresh(allowDisabledAutoIndex);
4554
+ }
4555
+ function isBackgroundWorkerManaged(projectRoot, host) {
4556
+ const key = workerKeysByProject.get(projectLookupKey(projectRoot, host));
4557
+ return key !== void 0 && workers.has(key);
4558
+ }
4559
+ function isBackgroundWorkerLeader(projectRoot, host) {
4560
+ const key = workerKeysByProject.get(projectLookupKey(projectRoot, host));
4561
+ return key !== void 0 && workers.get(key)?.isLeader() === true;
4562
+ }
4563
+ async function stopBackgroundWorker(projectRoot, host) {
4564
+ const projectKey = projectLookupKey(projectRoot, host);
4565
+ const key = workerKeysByProject.get(projectKey);
4566
+ const worker = key ? workers.get(key) : void 0;
4567
+ if (!worker) return;
4568
+ await worker.stop();
4569
+ }
4570
+
3697
4571
  // src/utils/files.ts
3698
4572
  var import_ignore = __toESM(require_ignore(), 1);
3699
4573
  var import_fs6 = require("fs");
3700
- var path10 = __toESM(require("path"), 1);
4574
+ var path11 = __toESM(require("path"), 1);
3701
4575
  var PROJECT_MARKERS = [
3702
4576
  ".git",
3703
4577
  "package.json",
@@ -3715,7 +4589,7 @@ var PROJECT_MARKERS = [
3715
4589
  ];
3716
4590
  function hasProjectMarker(projectRoot) {
3717
4591
  for (const marker of PROJECT_MARKERS) {
3718
- if ((0, import_fs6.existsSync)(path10.join(projectRoot, marker))) {
4592
+ if ((0, import_fs6.existsSync)(path11.join(projectRoot, marker))) {
3719
4593
  return true;
3720
4594
  }
3721
4595
  }
@@ -3742,33 +4616,53 @@ function createIgnoreFilter(projectRoot) {
3742
4616
  "**/*build*/**"
3743
4617
  ];
3744
4618
  ig.add(defaultIgnores);
3745
- const gitignorePath = path10.join(projectRoot, ".gitignore");
4619
+ const gitignorePath = path11.join(projectRoot, ".gitignore");
3746
4620
  if ((0, import_fs6.existsSync)(gitignorePath)) {
3747
4621
  const gitignoreContent = (0, import_fs6.readFileSync)(gitignorePath, "utf-8");
3748
4622
  ig.add(gitignoreContent);
3749
4623
  }
3750
4624
  return ig;
3751
4625
  }
3752
- function shouldIncludeFile(filePath, projectRoot, includePatterns, excludePatterns, ignoreFilter) {
3753
- const relativePath = path10.relative(projectRoot, filePath);
3754
- if (hasFilteredPathSegment(relativePath, path10.sep)) {
3755
- return false;
3756
- }
3757
- if (ignoreFilter.ignores(relativePath)) {
3758
- return false;
4626
+ function toPosixRelativePath(relativePath) {
4627
+ return relativePath.split(path11.sep).join("/");
4628
+ }
4629
+ function matchesAnyGlob(filePath, patterns) {
4630
+ const normalized = toPosixRelativePath(filePath);
4631
+ return patterns.some((pattern) => matchGlob(normalized, pattern));
4632
+ }
4633
+ function isExcludedByPatterns(relativePath, excludePatterns) {
4634
+ return matchesAnyGlob(relativePath, excludePatterns);
4635
+ }
4636
+ function isExcludedDirectory(relativePath, excludePatterns) {
4637
+ const normalized = toPosixRelativePath(relativePath);
4638
+ if (matchesAnyGlob(normalized, excludePatterns)) {
4639
+ return true;
3759
4640
  }
3760
4641
  for (const pattern of excludePatterns) {
3761
- if (matchGlob(relativePath, pattern)) {
3762
- return false;
4642
+ const posixPattern = toPosixRelativePath(pattern).replace(/\/+$/, "");
4643
+ if (!posixPattern.endsWith("/**")) {
4644
+ continue;
3763
4645
  }
3764
- }
3765
- for (const pattern of includePatterns) {
3766
- if (matchGlob(relativePath, pattern)) {
4646
+ const directoryPattern = posixPattern.slice(0, -3);
4647
+ if (directoryPattern && matchesAnyGlob(normalized, [directoryPattern])) {
3767
4648
  return true;
3768
4649
  }
3769
4650
  }
3770
4651
  return false;
3771
4652
  }
4653
+ function shouldIncludeFile(filePath, projectRoot, includePatterns, excludePatterns, ignoreFilter) {
4654
+ const relativePath = toPosixRelativePath(path11.relative(projectRoot, filePath));
4655
+ if (hasFilteredPathSegment(relativePath, "/")) {
4656
+ return false;
4657
+ }
4658
+ if (ignoreFilter.ignores(relativePath)) {
4659
+ return false;
4660
+ }
4661
+ if (isExcludedByPatterns(relativePath, excludePatterns)) {
4662
+ return false;
4663
+ }
4664
+ return matchesAnyGlob(relativePath, includePatterns);
4665
+ }
3772
4666
  function matchGlob(filePath, pattern) {
3773
4667
  if (pattern.startsWith("**/")) {
3774
4668
  const withoutPrefix = pattern.slice(3);
@@ -3789,8 +4683,8 @@ async function* walkDirectory(dir, projectRoot, includePatterns, excludePatterns
3789
4683
  const filesInDir = [];
3790
4684
  const subdirs = [];
3791
4685
  for (const entry of entries) {
3792
- const fullPath = path10.join(dir, entry.name);
3793
- const relativePath = path10.relative(projectRoot, fullPath);
4686
+ const fullPath = path11.join(dir, entry.name);
4687
+ const relativePath = toPosixRelativePath(path11.relative(projectRoot, fullPath));
3794
4688
  if (isHiddenPathSegment(entry.name)) {
3795
4689
  if (entry.isDirectory()) {
3796
4690
  skipped.push({ path: relativePath, reason: "excluded" });
@@ -3808,6 +4702,10 @@ async function* walkDirectory(dir, projectRoot, includePatterns, excludePatterns
3808
4702
  continue;
3809
4703
  }
3810
4704
  if (entry.isDirectory()) {
4705
+ if (isExcludedDirectory(relativePath, excludePatterns)) {
4706
+ skipped.push({ path: relativePath, reason: "excluded" });
4707
+ continue;
4708
+ }
3811
4709
  subdirs.push({ fullPath, relativePath });
3812
4710
  } else if (entry.isFile()) {
3813
4711
  const stat5 = await import_fs6.promises.stat(fullPath);
@@ -3815,20 +4713,11 @@ async function* walkDirectory(dir, projectRoot, includePatterns, excludePatterns
3815
4713
  skipped.push({ path: relativePath, reason: "too_large" });
3816
4714
  continue;
3817
4715
  }
3818
- for (const pattern of excludePatterns) {
3819
- if (matchGlob(relativePath, pattern)) {
3820
- skipped.push({ path: relativePath, reason: "excluded" });
3821
- continue;
3822
- }
3823
- }
3824
- let matched = false;
3825
- for (const pattern of includePatterns) {
3826
- if (matchGlob(relativePath, pattern)) {
3827
- matched = true;
3828
- break;
3829
- }
4716
+ if (isExcludedByPatterns(relativePath, excludePatterns)) {
4717
+ skipped.push({ path: relativePath, reason: "excluded" });
4718
+ continue;
3830
4719
  }
3831
- if (matched) {
4720
+ if (matchesAnyGlob(relativePath, includePatterns)) {
3832
4721
  filesInDir.push({ path: fullPath, size: stat5.size });
3833
4722
  }
3834
4723
  }
@@ -3839,7 +4728,7 @@ async function* walkDirectory(dir, projectRoot, includePatterns, excludePatterns
3839
4728
  yield f;
3840
4729
  }
3841
4730
  for (let i = options.maxFilesPerDirectory; i < filesInDir.length; i++) {
3842
- skipped.push({ path: path10.relative(projectRoot, filesInDir[i].path), reason: "excluded" });
4731
+ skipped.push({ path: toPosixRelativePath(path11.relative(projectRoot, filesInDir[i].path)), reason: "excluded" });
3843
4732
  }
3844
4733
  const canRecurse = options.maxDepth === -1 || currentDepth < options.maxDepth;
3845
4734
  if (canRecurse) {
@@ -3879,8 +4768,8 @@ async function collectFiles(projectRoot, includePatterns, excludePatterns, maxFi
3879
4768
  if (additionalRoots && additionalRoots.length > 0) {
3880
4769
  const normalizedRoots = /* @__PURE__ */ new Set();
3881
4770
  for (const kbRoot of additionalRoots) {
3882
- const resolved = path10.normalize(
3883
- path10.isAbsolute(kbRoot) ? kbRoot : path10.resolve(projectRoot, kbRoot)
4771
+ const resolved = path11.normalize(
4772
+ path11.isAbsolute(kbRoot) ? kbRoot : path11.resolve(projectRoot, kbRoot)
3884
4773
  );
3885
4774
  normalizedRoots.add(resolved);
3886
4775
  }
@@ -3921,7 +4810,7 @@ function getErrorMessage(error) {
3921
4810
  return error instanceof Error ? error.message : String(error);
3922
4811
  }
3923
4812
  function runCommand(file, args, options) {
3924
- return new Promise((resolve17, reject) => {
4813
+ return new Promise((resolve18, reject) => {
3925
4814
  childProcess.execFile(
3926
4815
  file,
3927
4816
  args,
@@ -3931,7 +4820,7 @@ function runCommand(file, args, options) {
3931
4820
  reject(error);
3932
4821
  return;
3933
4822
  }
3934
- resolve17(stdout);
4823
+ resolve18(stdout);
3935
4824
  }
3936
4825
  );
3937
4826
  });
@@ -4023,8 +4912,8 @@ var AutoIndexCancelledError = class extends Error {
4023
4912
  function now() {
4024
4913
  return (/* @__PURE__ */ new Date()).toISOString();
4025
4914
  }
4026
- function canonicalizePath(targetPath) {
4027
- const resolved = path11.resolve(targetPath);
4915
+ function canonicalizePath2(targetPath) {
4916
+ const resolved = path12.resolve(targetPath);
4028
4917
  if ((0, import_fs7.existsSync)(resolved)) {
4029
4918
  try {
4030
4919
  return import_fs7.realpathSync.native(resolved);
@@ -4032,20 +4921,20 @@ function canonicalizePath(targetPath) {
4032
4921
  return resolved;
4033
4922
  }
4034
4923
  }
4035
- const parent = path11.dirname(resolved);
4924
+ const parent = path12.dirname(resolved);
4036
4925
  if (parent === resolved) return resolved;
4037
- return path11.join(canonicalizePath(parent), path11.basename(resolved));
4926
+ return path12.join(canonicalizePath2(parent), path12.basename(resolved));
4038
4927
  }
4039
4928
  function isHomeDirectory(projectRoot) {
4040
- return canonicalizePath(projectRoot) === canonicalizePath(os3.homedir());
4929
+ return canonicalizePath2(projectRoot) === canonicalizePath2(os4.homedir());
4041
4930
  }
4042
- function projectLookupKey(projectRoot, host) {
4043
- return `${host}::${canonicalizePath(projectRoot)}`;
4931
+ function projectLookupKey2(projectRoot, host) {
4932
+ return `${host}::${canonicalizePath2(projectRoot)}`;
4044
4933
  }
4045
4934
  function coordinatorKey(projectRoot, config, host) {
4046
- const canonicalProjectRoot = canonicalizePath(projectRoot);
4935
+ const canonicalProjectRoot = canonicalizePath2(projectRoot);
4047
4936
  const indexPath = resolveProjectIndexPath(projectRoot, config.scope, host);
4048
- return `${canonicalizePath(indexPath)}::${canonicalProjectRoot}`;
4937
+ return `${canonicalizePath2(indexPath)}::${canonicalProjectRoot}`;
4049
4938
  }
4050
4939
  function getProjectSafety(projectRoot, config) {
4051
4940
  if (isHomeDirectory(projectRoot)) {
@@ -4076,10 +4965,10 @@ function safeFailureMessage(error) {
4076
4965
  }
4077
4966
  function cancellableDelay(delayMs, signal) {
4078
4967
  if (signal.aborted) return Promise.reject(new AutoIndexCancelledError());
4079
- return new Promise((resolve17, reject) => {
4968
+ return new Promise((resolve18, reject) => {
4080
4969
  const timer = setTimeout(() => {
4081
4970
  signal.removeEventListener("abort", onAbort);
4082
- resolve17();
4971
+ resolve18();
4083
4972
  }, delayMs);
4084
4973
  timer.unref?.();
4085
4974
  const onAbort = () => {
@@ -4091,18 +4980,44 @@ function cancellableDelay(delayMs, signal) {
4091
4980
  }
4092
4981
  function withTimeout(promise, timeoutMs) {
4093
4982
  if (timeoutMs <= 0) return Promise.resolve(void 0);
4094
- return new Promise((resolve17) => {
4095
- const timer = setTimeout(() => resolve17(void 0), timeoutMs);
4983
+ return new Promise((resolve18) => {
4984
+ const timer = setTimeout(() => resolve18(void 0), timeoutMs);
4096
4985
  timer.unref?.();
4097
4986
  void promise.then((value) => {
4098
4987
  clearTimeout(timer);
4099
- resolve17(value);
4988
+ resolve18(value);
4100
4989
  }, () => {
4101
4990
  clearTimeout(timer);
4102
- resolve17(void 0);
4991
+ resolve18(void 0);
4103
4992
  });
4104
4993
  });
4105
4994
  }
4995
+ function settlesWithin(promise, timeoutMs) {
4996
+ if (timeoutMs <= 0) return Promise.resolve(false);
4997
+ return new Promise((resolve18) => {
4998
+ let settled = false;
4999
+ const timer = setTimeout(() => {
5000
+ if (settled) return;
5001
+ settled = true;
5002
+ resolve18(false);
5003
+ }, timeoutMs);
5004
+ timer.unref?.();
5005
+ void promise.then(
5006
+ () => {
5007
+ if (settled) return;
5008
+ settled = true;
5009
+ clearTimeout(timer);
5010
+ resolve18(true);
5011
+ },
5012
+ () => {
5013
+ if (settled) return;
5014
+ settled = true;
5015
+ clearTimeout(timer);
5016
+ resolve18(true);
5017
+ }
5018
+ );
5019
+ });
5020
+ }
4106
5021
  function requestPriority(request) {
4107
5022
  if (request.force) return 4;
4108
5023
  if (request.source === "manual") return 3;
@@ -4113,6 +5028,7 @@ function mergeRequests(current, next) {
4113
5028
  if (!current) return next;
4114
5029
  const preferred = requestPriority(next) > requestPriority(current) ? next : current;
4115
5030
  return {
5031
+ allowDisabledAutoIndex: current.allowDisabledAutoIndex || next.allowDisabledAutoIndex,
4116
5032
  checkFreshness: current.checkFreshness && next.checkFreshness,
4117
5033
  force: current.force || next.force,
4118
5034
  onProgress: next.onProgress ?? current.onProgress,
@@ -4174,11 +5090,11 @@ var AutoIndexCoordinator = class {
4174
5090
  progress: this.status.progress ? { ...this.status.progress } : void 0
4175
5091
  };
4176
5092
  }
4177
- start(source) {
5093
+ start(source, allowDisabledAutoIndex = false) {
4178
5094
  this.refreshSafety();
4179
- if (!this.registration.config.indexing.autoIndex || !this.registration.safeToRun) return null;
5095
+ if (!this.registration.config.indexing.autoIndex && !allowDisabledAutoIndex || !this.registration.safeToRun) return null;
4180
5096
  if (this.status.state === "failed") return this.inFlight;
4181
- return this.request({ checkFreshness: true, force: false, source });
5097
+ return this.request({ allowDisabledAutoIndex, checkFreshness: true, force: false, source });
4182
5098
  }
4183
5099
  request(request) {
4184
5100
  if (this.stopped) {
@@ -4253,13 +5169,15 @@ var AutoIndexCoordinator = class {
4253
5169
  retryAttempt: void 0
4254
5170
  });
4255
5171
  const inFlight = this.inFlight;
4256
- if (inFlight) {
4257
- if (waitForCompletion) {
4258
- await inFlight;
4259
- } else {
4260
- await withTimeout(inFlight, SHUTDOWN_WAIT_MS);
4261
- }
5172
+ const completion = inFlight ? inFlight.then(() => void 0, () => void 0) : Promise.resolve();
5173
+ if (!inFlight) {
5174
+ return { completed: true, completion };
4262
5175
  }
5176
+ if (waitForCompletion) {
5177
+ await completion;
5178
+ return { completed: true, completion };
5179
+ }
5180
+ return { completed: await settlesWithin(completion, SHUTDOWN_WAIT_MS), completion };
4263
5181
  }
4264
5182
  startRequest(request) {
4265
5183
  if (this.stopped || !this.canRun(request)) {
@@ -4448,7 +5366,7 @@ var AutoIndexCoordinator = class {
4448
5366
  if (request.source === "manual" || request.source === "watcher") {
4449
5367
  return true;
4450
5368
  }
4451
- return this.registration.safeToRun && this.registration.config.indexing.autoIndex;
5369
+ return this.registration.safeToRun && (this.registration.config.indexing.autoIndex || request.allowDisabledAutoIndex === true);
4452
5370
  }
4453
5371
  shouldDeferForBattery(request) {
4454
5372
  return this.registration.backgroundIndexingPolicy !== null && (request.source === "startup" || request.source === "watcher");
@@ -4481,17 +5399,17 @@ var AutoIndexCoordinator = class {
4481
5399
  }
4482
5400
  }
4483
5401
  waitForBatteryRetry(delayMs) {
4484
- return new Promise((resolve17) => {
5402
+ return new Promise((resolve18) => {
4485
5403
  const timer = setTimeout(() => {
4486
5404
  if (this.batteryRetryTimer === timer) {
4487
5405
  this.batteryRetryTimer = null;
4488
5406
  this.resolveBatteryRetry = null;
4489
5407
  }
4490
- resolve17();
5408
+ resolve18();
4491
5409
  }, delayMs);
4492
5410
  timer.unref?.();
4493
5411
  this.batteryRetryTimer = timer;
4494
- this.resolveBatteryRetry = resolve17;
5412
+ this.resolveBatteryRetry = resolve18;
4495
5413
  });
4496
5414
  }
4497
5415
  cancelBatteryRetry() {
@@ -4499,9 +5417,9 @@ var AutoIndexCoordinator = class {
4499
5417
  clearTimeout(this.batteryRetryTimer);
4500
5418
  this.batteryRetryTimer = null;
4501
5419
  }
4502
- const resolve17 = this.resolveBatteryRetry;
5420
+ const resolve18 = this.resolveBatteryRetry;
4503
5421
  this.resolveBatteryRetry = null;
4504
- resolve17?.();
5422
+ resolve18?.();
4505
5423
  }
4506
5424
  finishBatteryCheck(batteryCheck) {
4507
5425
  if (this.batteryCheck !== batteryCheck) return;
@@ -4514,12 +5432,25 @@ var AutoIndexCoordinator = class {
4514
5432
  }
4515
5433
  };
4516
5434
  function getCoordinator(projectRoot, host) {
4517
- const key = coordinatorKeysByProject.get(projectLookupKey(projectRoot, host));
5435
+ const key = coordinatorKeysByProject.get(projectLookupKey2(projectRoot, host));
4518
5436
  return key ? coordinators.get(key) ?? null : null;
4519
5437
  }
4520
- function configureAutoIndex(projectRoot, host, config, getIndexer) {
4521
- const projectKey = projectLookupKey(projectRoot, host);
5438
+ function synchronizeBackgroundWorker(projectRoot, host, config, safeToRun) {
5439
+ if (safeToRun) {
5440
+ updateBackgroundWorkerConfig(projectRoot, host, config);
5441
+ return;
5442
+ }
5443
+ void stopBackgroundWorker(projectRoot, host).catch((error) => {
5444
+ console.error("[codebase-index] Failed to stop background worker after project safety changed:", error);
5445
+ });
5446
+ }
5447
+ function configureAutoIndex(projectRoot, host, config, getIndexer, options = {}) {
5448
+ const projectKey = projectLookupKey2(projectRoot, host);
4522
5449
  const safety = getProjectSafety(projectRoot, config);
5450
+ const synchronizeWorker = options.synchronizeBackgroundWorker ?? true;
5451
+ if (options.preserveManagedWorker === true && isBackgroundWorkerManaged(projectRoot, host)) {
5452
+ return;
5453
+ }
4523
5454
  const registration = {
4524
5455
  backgroundIndexingPolicy: createBackgroundIndexingPolicy(
4525
5456
  config.indexing.pauseBackgroundIndexingOnBattery
@@ -4537,6 +5468,9 @@ function configureAutoIndex(projectRoot, host, config, getIndexer) {
4537
5468
  const stopPrevious = previousCoordinator?.stop(true) ?? Promise.resolve();
4538
5469
  const activation = Promise.all([previousBarrier, stopPrevious]).then(() => void 0);
4539
5470
  coordinatorReplacementBarriers.set(projectKey, activation);
5471
+ if (synchronizeWorker) {
5472
+ synchronizeBackgroundWorker(projectRoot, host, config, safety.safeToRun);
5473
+ }
4540
5474
  coordinators.delete(previousKey);
4541
5475
  const coordinator2 = new AutoIndexCoordinator(registration);
4542
5476
  coordinator2.activateAfter(activation);
@@ -4552,11 +5486,17 @@ function configureAutoIndex(projectRoot, host, config, getIndexer) {
4552
5486
  coordinator.update(registration);
4553
5487
  }
4554
5488
  coordinatorKeysByProject.set(projectKey, key);
5489
+ if (synchronizeWorker) {
5490
+ synchronizeBackgroundWorker(projectRoot, host, config, safety.safeToRun);
5491
+ }
4555
5492
  }
4556
- function startAutoIndex(projectRoot, host, source = "startup") {
4557
- return getCoordinator(projectRoot, host)?.start(source) ?? null;
5493
+ function startAutoIndexForBackgroundWorker(projectRoot, host, source = "startup", allowDisabledAutoIndex = false) {
5494
+ return getCoordinator(projectRoot, host)?.start(source, allowDisabledAutoIndex) ?? null;
4558
5495
  }
4559
5496
  function requestBackgroundIndex(projectRoot, host) {
5497
+ if (isBackgroundWorkerManaged(projectRoot, host) && !isBackgroundWorkerLeader(projectRoot, host)) {
5498
+ return null;
5499
+ }
4560
5500
  return getCoordinator(projectRoot, host)?.request({
4561
5501
  checkFreshness: false,
4562
5502
  force: false,
@@ -4596,15 +5536,23 @@ async function waitForAutoIndexForRetrieval(projectRoot, host) {
4596
5536
  };
4597
5537
  }
4598
5538
  try {
4599
- if (await hasReadableCurrentIndex(coordinator)) return { ready: true };
5539
+ const readiness = await getSearchReadiness(coordinator);
5540
+ if (readiness.searchable) {
5541
+ return { ready: true };
5542
+ }
5543
+ if (readiness.blocked) return unavailableSnapshotResult(readiness.reason);
4600
5544
  } catch {
4601
5545
  }
4602
- const job = coordinator.start("retrieval") ?? coordinator.currentJob();
5546
+ const job = startRetrievalRefresh(projectRoot, host, coordinator);
4603
5547
  if (job) {
4604
5548
  await withTimeout(job, coordinator.getWaitMs());
5549
+ } else if (isBackgroundWorkerManaged(projectRoot, host)) {
5550
+ await waitForPublishedSnapshot(coordinator, coordinator.getWaitMs());
4605
5551
  }
4606
5552
  try {
4607
- if (await hasReadableCurrentIndex(coordinator)) return { ready: true };
5553
+ const readiness = await getSearchReadiness(coordinator);
5554
+ if (readiness.searchable) return { ready: true };
5555
+ if (readiness.blocked) return unavailableSnapshotResult(readiness.reason);
4608
5556
  } catch {
4609
5557
  }
4610
5558
  const status = coordinator.snapshot();
@@ -4625,18 +5573,52 @@ async function waitForAutoIndexForRetrieval(projectRoot, host) {
4625
5573
  text: `Automatic indexing is ${status.state}. Retry shortly or call index_status for progress. You can also run index_codebase explicitly.`
4626
5574
  };
4627
5575
  }
4628
- async function hasReadableCurrentIndex(coordinator) {
5576
+ async function stopAutoIndexForBackgroundWorker(projectRoot, host, waitForCompletion = false) {
5577
+ const coordinator = getCoordinator(projectRoot, host);
5578
+ if (!coordinator) {
5579
+ return { completed: true, completion: Promise.resolve() };
5580
+ }
5581
+ return coordinator.stop(waitForCompletion);
5582
+ }
5583
+ async function getSearchReadiness(coordinator) {
4629
5584
  const indexer = coordinator.getIndexer();
4630
5585
  if (indexer.getIndexFreshness) {
4631
5586
  const freshness = await indexer.getIndexFreshness();
4632
- return freshness.readable && freshness.current;
5587
+ const searchable = freshness.readable && freshness.current && freshness.reason === "current";
5588
+ return {
5589
+ blocked: freshness.reason === "unreadable" || freshness.reason === "incompatible" || freshness.reason === "failed-batches" || freshness.reason === "migration-required",
5590
+ reason: freshness.reason,
5591
+ searchable
5592
+ };
5593
+ }
5594
+ const indexed = (await indexer.getStatus()).indexed;
5595
+ return { blocked: false, searchable: indexed };
5596
+ }
5597
+ function unavailableSnapshotResult(reason) {
5598
+ 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.";
5599
+ return {
5600
+ ready: false,
5601
+ text: `${detail} Run index_codebase before retrying retrieval.`
5602
+ };
5603
+ }
5604
+ function startRetrievalRefresh(projectRoot, host, coordinator) {
5605
+ if (isBackgroundWorkerManaged(projectRoot, host)) {
5606
+ requestBackgroundWorkerRefresh(projectRoot, host, true);
5607
+ return isBackgroundWorkerLeader(projectRoot, host) ? coordinator.currentJob() : null;
5608
+ }
5609
+ return coordinator.start("retrieval") ?? coordinator.currentJob();
5610
+ }
5611
+ async function waitForPublishedSnapshot(coordinator, waitMs) {
5612
+ const deadline = Date.now() + waitMs;
5613
+ while (Date.now() < deadline) {
5614
+ if ((await getSearchReadiness(coordinator)).searchable) return;
5615
+ await new Promise((resolve18) => setTimeout(resolve18, Math.min(250, deadline - Date.now())));
4633
5616
  }
4634
- return (await indexer.getStatus()).indexed;
4635
5617
  }
4636
5618
 
4637
5619
  // src/tools/config-state.ts
4638
5620
  var import_fs8 = require("fs");
4639
- var path12 = __toESM(require("path"), 1);
5621
+ var path13 = __toESM(require("path"), 1);
4640
5622
  function normalizeKnowledgeBasePaths(config, projectRoot) {
4641
5623
  const normalized = { ...config };
4642
5624
  if (Array.isArray(normalized.knowledgeBases)) {
@@ -4663,8 +5645,8 @@ function loadEditableConfig(projectRoot, host) {
4663
5645
  }
4664
5646
  function saveConfig(projectRoot, config, host) {
4665
5647
  const configPath = getConfigPath(projectRoot, host);
4666
- const configDir = path12.dirname(configPath);
4667
- const configBaseDir = path12.dirname(configDir);
5648
+ const configDir = path13.dirname(configPath);
5649
+ const configBaseDir = path13.dirname(configDir);
4668
5650
  if (!(0, import_fs8.existsSync)(configDir)) {
4669
5651
  (0, import_fs8.mkdirSync)(configDir, { recursive: true });
4670
5652
  }
@@ -4679,7 +5661,7 @@ function saveConfig(projectRoot, config, host) {
4679
5661
 
4680
5662
  // src/indexer/index.ts
4681
5663
  var import_fs12 = require("fs");
4682
- var path19 = __toESM(require("path"), 1);
5664
+ var path20 = __toESM(require("path"), 1);
4683
5665
  var import_perf_hooks = require("perf_hooks");
4684
5666
  var import_child_process4 = require("child_process");
4685
5667
  var import_util4 = require("util");
@@ -4706,7 +5688,7 @@ function pTimeout(promise, options) {
4706
5688
  } = options;
4707
5689
  let timer;
4708
5690
  let abortHandler;
4709
- const wrappedPromise = new Promise((resolve17, reject) => {
5691
+ const wrappedPromise = new Promise((resolve18, reject) => {
4710
5692
  if (typeof milliseconds !== "number" || Math.sign(milliseconds) !== 1) {
4711
5693
  throw new TypeError(`Expected \`milliseconds\` to be a positive number, got \`${milliseconds}\``);
4712
5694
  }
@@ -4720,7 +5702,7 @@ function pTimeout(promise, options) {
4720
5702
  };
4721
5703
  signal.addEventListener("abort", abortHandler, { once: true });
4722
5704
  }
4723
- promise.then(resolve17, reject);
5705
+ promise.then(resolve18, reject);
4724
5706
  if (milliseconds === Number.POSITIVE_INFINITY) {
4725
5707
  return;
4726
5708
  }
@@ -4728,7 +5710,7 @@ function pTimeout(promise, options) {
4728
5710
  timer = customTimers.setTimeout.call(void 0, () => {
4729
5711
  if (fallback) {
4730
5712
  try {
4731
- resolve17(fallback());
5713
+ resolve18(fallback());
4732
5714
  } catch (error) {
4733
5715
  reject(error);
4734
5716
  }
@@ -4738,7 +5720,7 @@ function pTimeout(promise, options) {
4738
5720
  promise.cancel();
4739
5721
  }
4740
5722
  if (message === false) {
4741
- resolve17();
5723
+ resolve18();
4742
5724
  } else if (message instanceof Error) {
4743
5725
  reject(message);
4744
5726
  } else {
@@ -5140,7 +6122,7 @@ var PQueue = class extends import_index.default {
5140
6122
  // Assign unique ID if not provided
5141
6123
  id: options.id ?? (this.#idAssigner++).toString()
5142
6124
  };
5143
- return new Promise((resolve17, reject) => {
6125
+ return new Promise((resolve18, reject) => {
5144
6126
  const taskSymbol = /* @__PURE__ */ Symbol(`task-${options.id}`);
5145
6127
  let cleanupQueueAbortHandler = () => void 0;
5146
6128
  const run = async () => {
@@ -5180,7 +6162,7 @@ var PQueue = class extends import_index.default {
5180
6162
  })]);
5181
6163
  }
5182
6164
  const result = await operation;
5183
- resolve17(result);
6165
+ resolve18(result);
5184
6166
  this.emit("completed", result);
5185
6167
  } catch (error) {
5186
6168
  reject(error);
@@ -5368,13 +6350,13 @@ var PQueue = class extends import_index.default {
5368
6350
  });
5369
6351
  }
5370
6352
  async #onEvent(event, filter) {
5371
- return new Promise((resolve17) => {
6353
+ return new Promise((resolve18) => {
5372
6354
  const listener = () => {
5373
6355
  if (filter && !filter()) {
5374
6356
  return;
5375
6357
  }
5376
6358
  this.off(event, listener);
5377
- resolve17();
6359
+ resolve18();
5378
6360
  };
5379
6361
  this.on(event, listener);
5380
6362
  });
@@ -5660,7 +6642,7 @@ async function onAttemptFailure({ error, attemptNumber, retriesConsumed, startTi
5660
6642
  const finalDelay = Math.min(delayTime, remainingTime);
5661
6643
  options.signal?.throwIfAborted();
5662
6644
  if (finalDelay > 0) {
5663
- await new Promise((resolve17, reject) => {
6645
+ await new Promise((resolve18, reject) => {
5664
6646
  const onAbort = () => {
5665
6647
  clearTimeout(timeoutToken);
5666
6648
  options.signal?.removeEventListener("abort", onAbort);
@@ -5668,7 +6650,7 @@ async function onAttemptFailure({ error, attemptNumber, retriesConsumed, startTi
5668
6650
  };
5669
6651
  const timeoutToken = setTimeout(() => {
5670
6652
  options.signal?.removeEventListener("abort", onAbort);
5671
- resolve17();
6653
+ resolve18();
5672
6654
  }, finalDelay);
5673
6655
  if (options.unref) {
5674
6656
  timeoutToken.unref?.();
@@ -5730,10 +6712,10 @@ async function pRetry(input, options = {}) {
5730
6712
 
5731
6713
  // src/embeddings/detector.ts
5732
6714
  var import_fs9 = require("fs");
5733
- var path13 = __toESM(require("path"), 1);
5734
- var os4 = __toESM(require("os"), 1);
6715
+ var path14 = __toESM(require("path"), 1);
6716
+ var os5 = __toESM(require("os"), 1);
5735
6717
  function getOpenCodeAuthPath() {
5736
- return path13.join(os4.homedir(), ".local", "share", "opencode", "auth.json");
6718
+ return path14.join(os5.homedir(), ".local", "share", "opencode", "auth.json");
5737
6719
  }
5738
6720
  function loadOpenCodeAuth() {
5739
6721
  const authPath = getOpenCodeAuthPath();
@@ -6030,17 +7012,17 @@ function validateExternalUrl(urlString) {
6030
7012
  if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
6031
7013
  return { valid: false, reason: `Blocked protocol: ${parsed.protocol}` };
6032
7014
  }
6033
- const hostname2 = parsed.hostname.toLowerCase();
6034
- if (BLOCKED_HOSTNAMES.has(hostname2)) {
6035
- return { valid: false, reason: `Blocked: cloud metadata service (${hostname2})` };
7015
+ const hostname3 = parsed.hostname.toLowerCase();
7016
+ if (BLOCKED_HOSTNAMES.has(hostname3)) {
7017
+ return { valid: false, reason: `Blocked: cloud metadata service (${hostname3})` };
6036
7018
  }
6037
7019
  for (const pattern of BLOCKED_METADATA_IPS) {
6038
- if (pattern.test(hostname2)) {
6039
- return { valid: false, reason: `Blocked: cloud metadata IP (${hostname2})` };
7020
+ if (pattern.test(hostname3)) {
7021
+ return { valid: false, reason: `Blocked: cloud metadata IP (${hostname3})` };
6040
7022
  }
6041
7023
  }
6042
- if (/^169\.254\./.test(hostname2)) {
6043
- return { valid: false, reason: `Blocked: link-local address (${hostname2})` };
7024
+ if (/^169\.254\./.test(hostname3)) {
7025
+ return { valid: false, reason: `Blocked: link-local address (${hostname3})` };
6044
7026
  }
6045
7027
  return { valid: true };
6046
7028
  }
@@ -7132,8 +8114,8 @@ function extractParamNames(params) {
7132
8114
  }
7133
8115
 
7134
8116
  // src/native/binding.ts
7135
- var os5 = __toESM(require("os"), 1);
7136
- var path14 = __toESM(require("path"), 1);
8117
+ var os6 = __toESM(require("os"), 1);
8118
+ var path15 = __toESM(require("path"), 1);
7137
8119
  var module2 = __toESM(require("module"), 1);
7138
8120
  var import_node_url = require("url");
7139
8121
 
@@ -7170,7 +8152,7 @@ var STABLE_NATIVE_BINARY_NAME = IDENTITY_CATALOG.native.binaryName;
7170
8152
 
7171
8153
  // src/native/binding.ts
7172
8154
  var import_meta = {};
7173
- function getNativeBindingFilename(platform2 = os5.platform(), arch2 = os5.arch()) {
8155
+ function getNativeBindingFilename(platform2 = os6.platform(), arch2 = os6.arch()) {
7174
8156
  if (platform2 === "darwin" && arch2 === "arm64") {
7175
8157
  return `${STABLE_NATIVE_BINARY_NAME}.darwin-arm64.node`;
7176
8158
  }
@@ -7188,25 +8170,25 @@ function getNativeBindingFilename(platform2 = os5.platform(), arch2 = os5.arch()
7188
8170
  }
7189
8171
  throw new Error(`Unsupported platform: ${platform2}-${arch2}`);
7190
8172
  }
7191
- function resolveNativeBindingPath(packageRoot, platform2 = os5.platform(), arch2 = os5.arch()) {
7192
- return path14.join(packageRoot, "native", getNativeBindingFilename(platform2, arch2));
8173
+ function resolveNativeBindingPath(packageRoot, platform2 = os6.platform(), arch2 = os6.arch()) {
8174
+ return path15.join(packageRoot, "native", getNativeBindingFilename(platform2, arch2));
7193
8175
  }
7194
8176
  function getNativeBinding() {
7195
8177
  let currentDir;
7196
8178
  let requireTarget;
7197
8179
  if (typeof import_meta !== "undefined" && import_meta.url) {
7198
- currentDir = path14.dirname((0, import_node_url.fileURLToPath)(import_meta.url));
8180
+ currentDir = path15.dirname((0, import_node_url.fileURLToPath)(import_meta.url));
7199
8181
  requireTarget = import_meta.url;
7200
8182
  } else if (typeof __dirname !== "undefined") {
7201
8183
  currentDir = __dirname;
7202
8184
  requireTarget = __filename;
7203
8185
  } else {
7204
8186
  currentDir = process.cwd();
7205
- requireTarget = path14.join(currentDir, "index.js");
8187
+ requireTarget = path15.join(currentDir, "index.js");
7206
8188
  }
7207
8189
  const normalizedDir = currentDir.replace(/\\/g, "/");
7208
- const isDevMode = normalizedDir.includes("/src/native") || currentDir.includes(path14.join("src", "native"));
7209
- const packageRoot = isDevMode ? path14.resolve(currentDir, "../..") : path14.resolve(currentDir, "..");
8190
+ const isDevMode = normalizedDir.includes("/src/native") || currentDir.includes(path15.join("src", "native"));
8191
+ const packageRoot = isDevMode ? path15.resolve(currentDir, "../..") : path15.resolve(currentDir, "..");
7210
8192
  const nativePath = resolveNativeBindingPath(packageRoot);
7211
8193
  const require2 = module2.createRequire(requireTarget);
7212
8194
  return require2(nativePath);
@@ -7790,8 +8772,8 @@ var Database = class _Database {
7790
8772
 
7791
8773
  // src/git/branch-materialization.ts
7792
8774
  var import_fs10 = require("fs");
7793
- var os6 = __toESM(require("os"), 1);
7794
- var path15 = __toESM(require("path"), 1);
8775
+ var os7 = __toESM(require("os"), 1);
8776
+ var path16 = __toESM(require("path"), 1);
7795
8777
 
7796
8778
  // src/git/branch-resolution.ts
7797
8779
  var import_child_process = require("child_process");
@@ -8110,13 +9092,13 @@ async function isWorktreeRegistered(projectRoot, worktreePath) {
8110
9092
  return false;
8111
9093
  }
8112
9094
  function isPathWithinRoot(filePath, rootPath) {
8113
- const relative14 = path15.relative(path15.resolve(rootPath), path15.resolve(filePath));
8114
- return relative14 === "" || !relative14.startsWith(`..${path15.sep}`) && relative14 !== ".." && !path15.isAbsolute(relative14);
9095
+ const relative14 = path16.relative(path16.resolve(rootPath), path16.resolve(filePath));
9096
+ return relative14 === "" || !relative14.startsWith(`..${path16.sep}`) && relative14 !== ".." && !path16.isAbsolute(relative14);
8115
9097
  }
8116
9098
  async function pruneExactMissingWorktreeRegistration(projectRoot, worktreePath) {
8117
9099
  if (await pathExists(worktreePath)) return false;
8118
9100
  const commonDir = await runGit(projectRoot, ["rev-parse", "--path-format=absolute", "--git-common-dir"]);
8119
- const registrationsRoot = path15.join(commonDir, "worktrees");
9101
+ const registrationsRoot = path16.join(commonDir, "worktrees");
8120
9102
  let entries;
8121
9103
  try {
8122
9104
  entries = await import_fs10.promises.readdir(registrationsRoot, { withFileTypes: true });
@@ -8127,16 +9109,16 @@ async function pruneExactMissingWorktreeRegistration(projectRoot, worktreePath)
8127
9109
  const target = canonicalizePathForComparison(worktreePath);
8128
9110
  for (const entry of entries) {
8129
9111
  if (!entry.isDirectory()) continue;
8130
- const registrationPath = path15.join(registrationsRoot, entry.name);
9112
+ const registrationPath = path16.join(registrationsRoot, entry.name);
8131
9113
  if (!isPathWithinRoot(registrationPath, registrationsRoot)) continue;
8132
9114
  let gitdirPath;
8133
9115
  try {
8134
- gitdirPath = (await import_fs10.promises.readFile(path15.join(registrationPath, "gitdir"), "utf8")).trim();
9116
+ gitdirPath = (await import_fs10.promises.readFile(path16.join(registrationPath, "gitdir"), "utf8")).trim();
8135
9117
  } catch {
8136
9118
  continue;
8137
9119
  }
8138
- const resolvedGitdirPath = path15.isAbsolute(gitdirPath) ? gitdirPath : path15.resolve(registrationPath, gitdirPath);
8139
- if (canonicalizePathForComparison(path15.dirname(resolvedGitdirPath)) !== target) continue;
9120
+ const resolvedGitdirPath = path16.isAbsolute(gitdirPath) ? gitdirPath : path16.resolve(registrationPath, gitdirPath);
9121
+ if (canonicalizePathForComparison(path16.dirname(resolvedGitdirPath)) !== target) continue;
8140
9122
  await import_fs10.promises.rm(registrationPath, { recursive: true, force: true });
8141
9123
  return true;
8142
9124
  }
@@ -8154,7 +9136,7 @@ async function removeWorktree(projectRoot, worktreePath) {
8154
9136
  registered = await isWorktreeRegistered(projectRoot, worktreePath);
8155
9137
  } catch (error) {
8156
9138
  errors.push(asError(error));
8157
- throw new AggregateError(errors, `Could not verify temporary worktree deregistration; preserved ${path15.dirname(worktreePath)}`);
9139
+ throw new AggregateError(errors, `Could not verify temporary worktree deregistration; preserved ${path16.dirname(worktreePath)}`);
8158
9140
  }
8159
9141
  if (registered) {
8160
9142
  try {
@@ -8170,7 +9152,7 @@ async function removeWorktree(projectRoot, worktreePath) {
8170
9152
  registered = await isWorktreeRegistered(projectRoot, worktreePath);
8171
9153
  } catch (error) {
8172
9154
  errors.push(asError(error));
8173
- throw new AggregateError(errors, `Could not verify temporary worktree deregistration; preserved ${path15.dirname(worktreePath)}`);
9155
+ throw new AggregateError(errors, `Could not verify temporary worktree deregistration; preserved ${path16.dirname(worktreePath)}`);
8174
9156
  }
8175
9157
  }
8176
9158
  if (registered && !await pathExists(worktreePath)) {
@@ -8183,13 +9165,13 @@ async function removeWorktree(projectRoot, worktreePath) {
8183
9165
  }
8184
9166
  if (registered) {
8185
9167
  errors.push(new Error(`Temporary worktree remains registered: ${worktreePath}`));
8186
- throw new AggregateError(errors, `Failed to deregister temporary worktree; preserved ${path15.dirname(worktreePath)}`);
9168
+ throw new AggregateError(errors, `Failed to deregister temporary worktree; preserved ${path16.dirname(worktreePath)}`);
8187
9169
  }
8188
9170
  try {
8189
- await import_fs10.promises.rm(path15.dirname(worktreePath), { recursive: true, force: true });
9171
+ await import_fs10.promises.rm(path16.dirname(worktreePath), { recursive: true, force: true });
8190
9172
  } catch (error) {
8191
9173
  errors.push(asError(error));
8192
- throw new AggregateError(errors, `Deregistered the temporary worktree but could not remove ${path15.dirname(worktreePath)}`);
9174
+ throw new AggregateError(errors, `Deregistered the temporary worktree but could not remove ${path16.dirname(worktreePath)}`);
8193
9175
  }
8194
9176
  }
8195
9177
  async function cleanupTemporaryWorktree(projectRoot, worktreePath, temporaryRoot) {
@@ -8225,9 +9207,9 @@ async function withMaterializedBranch(request, callback) {
8225
9207
  `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.`
8226
9208
  );
8227
9209
  }
8228
- const temporaryRoot = await import_fs10.promises.mkdtemp(path15.join(os6.tmpdir(), "codebase-index-branch-"));
8229
- const worktreePath = path15.join(temporaryRoot, "worktree");
8230
- const hooksPath = path15.join(temporaryRoot, "hooks");
9210
+ const temporaryRoot = await import_fs10.promises.mkdtemp(path16.join(os7.tmpdir(), "codebase-index-branch-"));
9211
+ const worktreePath = path16.join(temporaryRoot, "worktree");
9212
+ const hooksPath = path16.join(temporaryRoot, "hooks");
8231
9213
  await import_fs10.promises.mkdir(hooksPath);
8232
9214
  const info = {
8233
9215
  branch: request.branch,
@@ -8279,7 +9261,7 @@ async function withMaterializedBranch(request, callback) {
8279
9261
  // src/tools/changed-files.ts
8280
9262
  var import_child_process2 = require("child_process");
8281
9263
  var import_fs11 = require("fs");
8282
- var path16 = __toESM(require("path"), 1);
9264
+ var path17 = __toESM(require("path"), 1);
8283
9265
  var import_util2 = require("util");
8284
9266
  var execFileAsync2 = (0, import_util2.promisify)(import_child_process2.execFile);
8285
9267
  var GH_PR_VIEW_FIELDS = [
@@ -8421,7 +9403,7 @@ function getHeadRepositoryIdentity(data, host) {
8421
9403
  return `${host}/${owner.toLowerCase()}/${repository.replace(/\.git$/i, "").toLowerCase()}`;
8422
9404
  }
8423
9405
  function getLocalRepositoryIdentity(projectRoot) {
8424
- let canonicalRoot = path16.resolve(projectRoot);
9406
+ let canonicalRoot = path17.resolve(projectRoot);
8425
9407
  try {
8426
9408
  canonicalRoot = import_fs11.realpathSync.native(canonicalRoot);
8427
9409
  } catch {
@@ -8482,17 +9464,17 @@ async function getMergeBase(projectRoot, baseCommit, headCommit) {
8482
9464
  return commit;
8483
9465
  }
8484
9466
  function normalizeFiles(rawFiles, projectRoot) {
8485
- const root = path16.resolve(projectRoot);
9467
+ const root = path17.resolve(projectRoot);
8486
9468
  const seen = /* @__PURE__ */ new Set();
8487
9469
  const result = [];
8488
9470
  for (const raw of rawFiles) {
8489
9471
  if (raw.length === 0) continue;
8490
- const absolute = path16.resolve(root, raw);
8491
- const relative14 = path16.relative(root, absolute);
8492
- if (path16.isAbsolute(raw) || relative14 === ".." || relative14.startsWith(`..${path16.sep}`) || path16.isAbsolute(relative14)) {
9472
+ const absolute = path17.resolve(root, raw);
9473
+ const relative14 = path17.relative(root, absolute);
9474
+ if (path17.isAbsolute(raw) || relative14 === ".." || relative14.startsWith(`..${path17.sep}`) || path17.isAbsolute(relative14)) {
8493
9475
  throw new Error(`Changed file escapes the project root: ${JSON.stringify(raw)}`);
8494
9476
  }
8495
- const cleaned = relative14.startsWith(`.${path16.sep}`) ? relative14.slice(2) : relative14;
9477
+ const cleaned = relative14.startsWith(`.${path17.sep}`) ? relative14.slice(2) : relative14;
8496
9478
  if (!seen.has(cleaned)) {
8497
9479
  seen.add(cleaned);
8498
9480
  result.push(cleaned);
@@ -8503,7 +9485,7 @@ function normalizeFiles(rawFiles, projectRoot) {
8503
9485
 
8504
9486
  // src/indexer/git-blame.ts
8505
9487
  var import_child_process3 = require("child_process");
8506
- var path17 = __toESM(require("path"), 1);
9488
+ var path18 = __toESM(require("path"), 1);
8507
9489
  var import_util3 = require("util");
8508
9490
  var execFileAsync3 = (0, import_util3.promisify)(import_child_process3.execFile);
8509
9491
  function parseGitBlamePorcelain(output) {
@@ -8541,7 +9523,7 @@ function parseGitBlamePorcelain(output) {
8541
9523
  return Array.from(commits.values()).filter((commit) => commit.lines > 0).sort((a, b) => b.lines - a.lines || b.committedAt - a.committedAt)[0];
8542
9524
  }
8543
9525
  async function getChunkGitBlame(projectRoot, filePath, startLine, endLine) {
8544
- const relativePath = path17.relative(projectRoot, filePath);
9526
+ const relativePath = path18.relative(projectRoot, filePath);
8545
9527
  try {
8546
9528
  const { stdout } = await execFileAsync3(
8547
9529
  "git",
@@ -9120,8 +10102,8 @@ function pathSegmentsForAffinityMatch(filePath) {
9120
10102
  if (segments.length === 0) {
9121
10103
  return [];
9122
10104
  }
9123
- const basename9 = segments[segments.length - 1] ?? "";
9124
- const basenameWithoutExt = basename9.replace(/\.[^/.]+$/u, "");
10105
+ const basename10 = segments[segments.length - 1] ?? "";
10106
+ const basenameWithoutExt = basename10.replace(/\.[^/.]+$/u, "");
9125
10107
  const normalizedSegments = segments.map((segment) => segment.toLowerCase());
9126
10108
  return Array.from(/* @__PURE__ */ new Set([
9127
10109
  ...normalizedSegments,
@@ -9430,8 +10412,8 @@ function hasAllEmbeddingParts(parts, expectedPartCount) {
9430
10412
 
9431
10413
  // src/indexer/failed-state-persistence.ts
9432
10414
  var fs2 = __toESM(require("fs"), 1);
9433
- var import_node_crypto = require("crypto");
9434
- var path18 = __toESM(require("path"), 1);
10415
+ var import_node_crypto2 = require("crypto");
10416
+ var path19 = __toESM(require("path"), 1);
9435
10417
  var import_node_string_decoder = require("string_decoder");
9436
10418
  var CURRENT_FAILED_BATCH_VERSION = 1;
9437
10419
  var DEFAULT_MALFORMED_LINE_ACTION = "skip";
@@ -9449,7 +10431,7 @@ function* readFailedBatchRecords(filePath, options = {}) {
9449
10431
  function createFailedBatchWriter(targetPath) {
9450
10432
  const temporaryPath = createTemporaryPath(targetPath);
9451
10433
  let finalized = false;
9452
- fs2.mkdirSync(path18.dirname(targetPath), { recursive: true });
10434
+ fs2.mkdirSync(path19.dirname(targetPath), { recursive: true });
9453
10435
  fs2.closeSync(fs2.openSync(temporaryPath, "w"));
9454
10436
  const write = (record) => {
9455
10437
  if (finalized) {
@@ -9468,7 +10450,7 @@ function createFailedBatchWriter(targetPath) {
9468
10450
  if (lines.length === 0) {
9469
10451
  return;
9470
10452
  }
9471
- fs2.mkdirSync(path18.dirname(targetPath), { recursive: true });
10453
+ fs2.mkdirSync(path19.dirname(targetPath), { recursive: true });
9472
10454
  fs2.appendFileSync(temporaryPath, `${lines.join("\n")}
9473
10455
  `, "utf-8");
9474
10456
  };
@@ -9476,7 +10458,7 @@ function createFailedBatchWriter(targetPath) {
9476
10458
  if (finalized) {
9477
10459
  return;
9478
10460
  }
9479
- fs2.mkdirSync(path18.dirname(targetPath), { recursive: true });
10461
+ fs2.mkdirSync(path19.dirname(targetPath), { recursive: true });
9480
10462
  fs2.renameSync(temporaryPath, targetPath);
9481
10463
  finalized = true;
9482
10464
  };
@@ -9622,10 +10604,10 @@ function stripLeadingBomAndWhitespace(value) {
9622
10604
  return result;
9623
10605
  }
9624
10606
  function createTemporaryPath(targetPath) {
9625
- const randomId = (0, import_node_crypto.createHash)("sha1").update(`${Date.now()}:${(0, import_node_crypto.randomBytes)(8).toString("hex")}`).digest("hex");
9626
- const targetDir = path18.dirname(targetPath);
9627
- const baseName = path18.basename(targetPath);
9628
- return path18.join(targetDir, `.${baseName}.${randomId}.tmp`);
10607
+ const randomId = (0, import_node_crypto2.createHash)("sha1").update(`${Date.now()}:${(0, import_node_crypto2.randomBytes)(8).toString("hex")}`).digest("hex");
10608
+ const targetDir = path19.dirname(targetPath);
10609
+ const baseName = path19.basename(targetPath);
10610
+ return path19.join(targetDir, `.${baseName}.${randomId}.tmp`);
9629
10611
  }
9630
10612
  function handleMalformedLine(filePath, lineNumber, line, error, options) {
9631
10613
  const action = options.malformedLineAction ?? DEFAULT_MALFORMED_LINE_ACTION;
@@ -9871,9 +10853,9 @@ var SWIFT_PARSER_VERSION = "1";
9871
10853
  var METAL_PARSER_VERSION = "1";
9872
10854
  var SYMBOL_EXTRACTOR_VERSION = "1";
9873
10855
  function isPathWithinRoot2(filePath, rootPath) {
9874
- const normalizedFilePath = path19.resolve(filePath);
9875
- const normalizedRoot = path19.resolve(rootPath);
9876
- return normalizedFilePath === normalizedRoot || normalizedFilePath.startsWith(`${normalizedRoot}${path19.sep}`);
10856
+ const normalizedFilePath = path20.resolve(filePath);
10857
+ const normalizedRoot = path20.resolve(rootPath);
10858
+ return normalizedFilePath === normalizedRoot || normalizedFilePath.startsWith(`${normalizedRoot}${path20.sep}`);
9877
10859
  }
9878
10860
  function promoteIdentifierMatches(query, combined, semanticCandidates, keywordCandidates, database, branchChunkIds, prioritizeSourcePaths = classifyQueryIntentRaw(query) === "source") {
9879
10861
  if (combined.length === 0) {
@@ -10204,10 +11186,10 @@ function matchesHardSearchFilters(candidate, options, projectRoot) {
10204
11186
  }
10205
11187
  if (options?.directory) {
10206
11188
  const candidatePath = canonicalizePathForComparison(
10207
- path19.resolve(projectRoot, candidate.metadata.filePath.replace(/\\/g, path19.sep))
11189
+ path20.resolve(projectRoot, candidate.metadata.filePath.replace(/\\/g, path20.sep))
10208
11190
  );
10209
11191
  const directoryPath = canonicalizePathForComparison(
10210
- path19.resolve(projectRoot, options.directory.trim().replace(/\\/g, path19.sep))
11192
+ path20.resolve(projectRoot, options.directory.trim().replace(/\\/g, path20.sep))
10211
11193
  );
10212
11194
  if (!isPathWithinRoot2(candidatePath, directoryPath)) return false;
10213
11195
  }
@@ -10320,26 +11302,37 @@ var Indexer = class _Indexer {
10320
11302
  return this.indexPathOverride ?? resolveProjectIndexPath(this.projectRoot, this.config.scope, this.host);
10321
11303
  }
10322
11304
  toCanonicalFilePath(filePath) {
10323
- if (!path19.isAbsolute(filePath)) {
11305
+ if (!path20.isAbsolute(filePath)) {
10324
11306
  return this.resolveStoredFilePath(filePath, this.projectRoot);
10325
11307
  }
10326
- if (path19.resolve(this.materializedProjectRoot) === path19.resolve(this.projectRoot) || !isPathWithinRoot2(filePath, this.materializedProjectRoot)) {
11308
+ if (path20.resolve(this.materializedProjectRoot) === path20.resolve(this.projectRoot) || !isPathWithinRoot2(filePath, this.materializedProjectRoot)) {
10327
11309
  return filePath;
10328
11310
  }
10329
- return path19.resolve(this.projectRoot, path19.relative(this.materializedProjectRoot, filePath));
11311
+ return path20.resolve(this.projectRoot, path20.relative(this.materializedProjectRoot, filePath));
10330
11312
  }
10331
11313
  toStoredFilePath(filePath) {
10332
11314
  const canonicalFilePath = this.toCanonicalFilePath(filePath);
10333
11315
  if (this.config.scope !== "project" || !isPathWithinRoot2(canonicalFilePath, this.projectRoot)) {
10334
11316
  return canonicalFilePath;
10335
11317
  }
10336
- return path19.relative(this.projectRoot, canonicalFilePath).split(path19.sep).join("/");
11318
+ return path20.relative(this.projectRoot, canonicalFilePath).split(path20.sep).join("/");
11319
+ }
11320
+ isStoredPathExcluded(storedPath) {
11321
+ let matchPath = storedPath.split(path20.sep).join("/");
11322
+ if (path20.isAbsolute(storedPath)) {
11323
+ const relativePath = path20.relative(this.projectRoot, storedPath).split(path20.sep).join("/");
11324
+ if (relativePath.startsWith("..") || path20.isAbsolute(relativePath)) {
11325
+ return false;
11326
+ }
11327
+ matchPath = relativePath;
11328
+ }
11329
+ return isExcludedByPatterns(matchPath, this.config.exclude);
10337
11330
  }
10338
11331
  resolveStoredFilePath(filePath, rootPath = this.projectRoot) {
10339
- if (path19.isAbsolute(filePath)) {
11332
+ if (path20.isAbsolute(filePath)) {
10340
11333
  return filePath;
10341
11334
  }
10342
- const resolvedPath = path19.resolve(rootPath, ...filePath.split("/"));
11335
+ const resolvedPath = path20.resolve(rootPath, ...filePath.split("/"));
10343
11336
  if (!isPathWithinRoot2(resolvedPath, rootPath)) {
10344
11337
  throw new Error(`Stored project path escapes project root: ${JSON.stringify(filePath)}`);
10345
11338
  }
@@ -10363,7 +11356,7 @@ var Indexer = class _Indexer {
10363
11356
  }
10364
11357
  toMaterializedFilePath(filePath) {
10365
11358
  const storedFilePath = this.toStoredFilePath(filePath);
10366
- if (path19.isAbsolute(storedFilePath)) {
11359
+ if (path20.isAbsolute(storedFilePath)) {
10367
11360
  return storedFilePath;
10368
11361
  }
10369
11362
  return this.resolveStoredFilePath(storedFilePath, this.materializedProjectRoot);
@@ -10380,10 +11373,10 @@ var Indexer = class _Indexer {
10380
11373
  }
10381
11374
  getRuntimeArtifactPath(fileName) {
10382
11375
  const namespace = this.getRuntimeArtifactNamespace();
10383
- if (!namespace) return path19.join(this.indexPath, fileName);
10384
- const extension = path19.extname(fileName);
11376
+ if (!namespace) return path20.join(this.indexPath, fileName);
11377
+ const extension = path20.extname(fileName);
10385
11378
  const baseName = fileName.slice(0, fileName.length - extension.length);
10386
- return path19.join(this.indexPath, `${baseName}.${namespace}${extension}`);
11379
+ return path20.join(this.indexPath, `${baseName}.${namespace}${extension}`);
10387
11380
  }
10388
11381
  refreshRuntimeArtifactPaths() {
10389
11382
  this.fileHashCachePath = this.getRuntimeArtifactPath("file-hashes.json");
@@ -10396,14 +11389,14 @@ var Indexer = class _Indexer {
10396
11389
  getMaterializedKnowledgeBases() {
10397
11390
  const canonicalProjectRoot = this.getCanonicalPath(this.projectRoot);
10398
11391
  return this.config.knowledgeBases.map((knowledgeBase) => {
10399
- const configuredPath = path19.isAbsolute(knowledgeBase) ? knowledgeBase : path19.resolve(this.projectRoot, knowledgeBase);
11392
+ const configuredPath = path20.isAbsolute(knowledgeBase) ? knowledgeBase : path20.resolve(this.projectRoot, knowledgeBase);
10400
11393
  const canonicalPath = this.getCanonicalPath(configuredPath);
10401
11394
  if (!isPathWithinRoot2(canonicalPath, canonicalProjectRoot)) {
10402
11395
  return canonicalPath;
10403
11396
  }
10404
- return path19.resolve(
11397
+ return path20.resolve(
10405
11398
  this.materializedProjectRoot,
10406
- path19.relative(canonicalProjectRoot, canonicalPath)
11399
+ path20.relative(canonicalProjectRoot, canonicalPath)
10407
11400
  );
10408
11401
  });
10409
11402
  }
@@ -10411,7 +11404,7 @@ var Indexer = class _Indexer {
10411
11404
  try {
10412
11405
  return canonicalizePathForComparison(targetPath);
10413
11406
  } catch {
10414
- return path19.resolve(targetPath);
11407
+ return path20.resolve(targetPath);
10415
11408
  }
10416
11409
  }
10417
11410
  getProjectIdentityHash(projectRoot) {
@@ -10537,7 +11530,7 @@ var Indexer = class _Indexer {
10537
11530
  atomicWriteSync(targetPath, data) {
10538
11531
  const lease = this.requireActiveLease();
10539
11532
  const tempPath = createLeaseTemporaryPath(targetPath, lease.owner, "tmp");
10540
- (0, import_fs12.mkdirSync)(path19.dirname(targetPath), { recursive: true });
11533
+ (0, import_fs12.mkdirSync)(path20.dirname(targetPath), { recursive: true });
10541
11534
  try {
10542
11535
  (0, import_fs12.writeFileSync)(tempPath, data);
10543
11536
  (0, import_fs12.renameSync)(tempPath, targetPath);
@@ -10547,14 +11540,14 @@ var Indexer = class _Indexer {
10547
11540
  }
10548
11541
  saveInvertedIndex(invertedIndex) {
10549
11542
  this.atomicWriteSync(
10550
- path19.join(this.indexPath, "inverted-index.json"),
11543
+ path20.join(this.indexPath, "inverted-index.json"),
10551
11544
  invertedIndex.serialize()
10552
11545
  );
10553
11546
  }
10554
11547
  getScopedRoots(projectRoot = this.projectRoot) {
10555
11548
  const roots = /* @__PURE__ */ new Set([this.getCanonicalPath(projectRoot)]);
10556
11549
  for (const kbRoot of this.config.knowledgeBases) {
10557
- roots.add(this.getCanonicalPath(path19.resolve(projectRoot, kbRoot)));
11550
+ roots.add(this.getCanonicalPath(path20.resolve(projectRoot, kbRoot)));
10558
11551
  }
10559
11552
  return Array.from(roots);
10560
11553
  }
@@ -10971,7 +11964,7 @@ var Indexer = class _Indexer {
10971
11964
  return configuredProviderInfo !== null && recovery.embeddingProvider === configuredProviderInfo.provider && recovery.embeddingModel === configuredProviderInfo.modelInfo.model && recovery.embeddingDimensions === configuredProviderInfo.modelInfo.dimensions && recovery.embeddingStrategyVersion === EMBEDDING_STRATEGY_VERSION;
10972
11965
  }
10973
11966
  hasUnknownLegacyForceIndexClear(owner) {
10974
- return owner.operation === "force-index" && owner.clearRecovery === void 0 && owner.recoveryProtocolVersion !== 1 && (0, import_fs12.existsSync)(path19.join(this.indexPath, "force-index-phase"));
11967
+ return owner.operation === "force-index" && owner.clearRecovery === void 0 && owner.recoveryProtocolVersion !== 1 && (0, import_fs12.existsSync)(path20.join(this.indexPath, "force-index-phase"));
10975
11968
  }
10976
11969
  async recoverFromInterruptedIndexingUnlocked(owners) {
10977
11970
  for (const owner of owners) {
@@ -11359,7 +12352,7 @@ var Indexer = class _Indexer {
11359
12352
  await options.queue.onSizeLessThan(Math.max(1, options.providerRateLimits.concurrency));
11360
12353
  const task = options.queue.add(async () => {
11361
12354
  if (options.rateLimitState.backoffMs > 0) {
11362
- await new Promise((resolve17) => setTimeout(resolve17, options.rateLimitState.backoffMs));
12355
+ await new Promise((resolve18) => setTimeout(resolve18, options.rateLimitState.backoffMs));
11363
12356
  }
11364
12357
  try {
11365
12358
  const embeddingResult = await pRetry(
@@ -11778,12 +12771,12 @@ var Indexer = class _Indexer {
11778
12771
  }
11779
12772
  }
11780
12773
  captureReaderArtifactFingerprint() {
11781
- const storePath = path19.join(this.indexPath, "vectors");
12774
+ const storePath = path20.join(this.indexPath, "vectors");
11782
12775
  return {
11783
12776
  vectors: `${this.getReaderFileFingerprint(storePath)}|${this.getReaderFileFingerprint(`${storePath}.meta.json`)}`,
11784
- keyword: this.getReaderFileFingerprint(path19.join(this.indexPath, "inverted-index.json")),
11785
- database: this.getReaderFileFingerprint(path19.join(this.indexPath, "codebase.db")),
11786
- databaseIdentity: this.getReaderFileFingerprint(path19.join(this.indexPath, "codebase.db"), true)
12777
+ keyword: this.getReaderFileFingerprint(path20.join(this.indexPath, "inverted-index.json")),
12778
+ database: this.getReaderFileFingerprint(path20.join(this.indexPath, "codebase.db")),
12779
+ databaseIdentity: this.getReaderFileFingerprint(path20.join(this.indexPath, "codebase.db"), true)
11787
12780
  };
11788
12781
  }
11789
12782
  refreshReaderArtifacts() {
@@ -11808,10 +12801,10 @@ var Indexer = class _Indexer {
11808
12801
  issues.set(component, this.createReadIssue(component, message));
11809
12802
  this.readerArtifactRetryAfter.set(component, Date.now() + READER_ARTIFACT_RETRY_INTERVAL_MS);
11810
12803
  };
11811
- const storePath = path19.join(this.indexPath, "vectors");
12804
+ const storePath = path20.join(this.indexPath, "vectors");
11812
12805
  const vectorMetadataPath = `${storePath}.meta.json`;
11813
- const invertedIndexPath = path19.join(this.indexPath, "inverted-index.json");
11814
- const dbPath = path19.join(this.indexPath, "codebase.db");
12806
+ const invertedIndexPath = path20.join(this.indexPath, "inverted-index.json");
12807
+ const dbPath = path20.join(this.indexPath, "codebase.db");
11815
12808
  if (vectorsChanged || retryDue("vectors")) {
11816
12809
  const vectorStoreExists = (0, import_fs12.existsSync)(storePath);
11817
12810
  const vectorMetadataExists = (0, import_fs12.existsSync)(vectorMetadataPath);
@@ -11927,10 +12920,10 @@ var Indexer = class _Indexer {
11927
12920
  });
11928
12921
  this.provider = createEmbeddingProvider(this.configuredProviderInfo);
11929
12922
  const dimensions = this.configuredProviderInfo.modelInfo.dimensions;
11930
- const storePath = path19.join(this.indexPath, "vectors");
12923
+ const storePath = path20.join(this.indexPath, "vectors");
11931
12924
  const vectorMetadataPath = `${storePath}.meta.json`;
11932
- const invertedIndexPath = path19.join(this.indexPath, "inverted-index.json");
11933
- const dbPath = path19.join(this.indexPath, "codebase.db");
12925
+ const invertedIndexPath = path20.join(this.indexPath, "inverted-index.json");
12926
+ const dbPath = path20.join(this.indexPath, "codebase.db");
11934
12927
  let dbIsNew = !(0, import_fs12.existsSync)(dbPath);
11935
12928
  const readerArtifactFingerprint = mode === "reader" ? this.captureReaderArtifactFingerprint() : null;
11936
12929
  if (mode === "writer") {
@@ -12108,7 +13101,7 @@ var Indexer = class _Indexer {
12108
13101
  if (await this.tryResetCorruptedIndex("running automatic orphan garbage collection", error)) {
12109
13102
  return {
12110
13103
  resetCorruptedIndex: true,
12111
- warning: this.getCorruptedIndexWarning(path19.join(this.indexPath, "codebase.db"))
13104
+ warning: this.getCorruptedIndexWarning(path20.join(this.indexPath, "codebase.db"))
12112
13105
  };
12113
13106
  }
12114
13107
  throw error;
@@ -12123,7 +13116,7 @@ var Indexer = class _Indexer {
12123
13116
  return;
12124
13117
  }
12125
13118
  const retainedEntries = store.getAllMetadata().filter(({ key }) => !excludedSet.has(key));
12126
- const storeBasePath = path19.join(this.indexPath, "vectors");
13119
+ const storeBasePath = path20.join(this.indexPath, "vectors");
12127
13120
  const storeIndexPath = storeBasePath;
12128
13121
  const storeMetadataPath = `${storeBasePath}.meta.json`;
12129
13122
  const lease = this.requireActiveLease();
@@ -12210,7 +13203,7 @@ var Indexer = class _Indexer {
12210
13203
  const names = await import_fs12.promises.readdir(this.indexPath);
12211
13204
  const runtimeStatePattern = /^(?:file-hashes|failed-batches)(?:\.[a-f0-9]{16})?\.json$/;
12212
13205
  await Promise.all(
12213
- names.filter((name) => runtimeStatePattern.test(name)).map((name) => import_fs12.promises.rm(path19.join(this.indexPath, name), { force: true }))
13206
+ names.filter((name) => runtimeStatePattern.test(name)).map((name) => import_fs12.promises.rm(path20.join(this.indexPath, name), { force: true }))
12214
13207
  );
12215
13208
  }
12216
13209
  async resetLocalIndexArtifacts() {
@@ -12226,13 +13219,13 @@ var Indexer = class _Indexer {
12226
13219
  this.readerArtifactRetryAfter.clear();
12227
13220
  this.fileHashCache.clear();
12228
13221
  const resetPaths = [
12229
- path19.join(this.indexPath, "codebase.db"),
12230
- path19.join(this.indexPath, "codebase.db-shm"),
12231
- path19.join(this.indexPath, "codebase.db-wal"),
12232
- path19.join(this.indexPath, "vectors"),
12233
- path19.join(this.indexPath, "vectors.usearch"),
12234
- path19.join(this.indexPath, "vectors.meta.json"),
12235
- path19.join(this.indexPath, "inverted-index.json")
13222
+ path20.join(this.indexPath, "codebase.db"),
13223
+ path20.join(this.indexPath, "codebase.db-shm"),
13224
+ path20.join(this.indexPath, "codebase.db-wal"),
13225
+ path20.join(this.indexPath, "vectors"),
13226
+ path20.join(this.indexPath, "vectors.usearch"),
13227
+ path20.join(this.indexPath, "vectors.meta.json"),
13228
+ path20.join(this.indexPath, "inverted-index.json")
12236
13229
  ];
12237
13230
  await Promise.all(resetPaths.map((targetPath) => import_fs12.promises.rm(targetPath, { recursive: true, force: true })));
12238
13231
  await this.removeProjectRuntimeStateArtifacts();
@@ -12242,7 +13235,7 @@ var Indexer = class _Indexer {
12242
13235
  if (!isSqliteCorruptionError(error)) {
12243
13236
  return false;
12244
13237
  }
12245
- const dbPath = path19.join(this.indexPath, "codebase.db");
13238
+ const dbPath = path20.join(this.indexPath, "codebase.db");
12246
13239
  const warning = this.getCorruptedIndexWarning(dbPath);
12247
13240
  const errorMessage = getErrorMessage4(error);
12248
13241
  if (this.config.scope === "global") {
@@ -12629,10 +13622,10 @@ var Indexer = class _Indexer {
12629
13622
  const reparseCachedMetalFiles = database.getMetadata(metalParserMetadataKey) !== METAL_PARSER_VERSION;
12630
13623
  const symbolExtractorMetadataKey = this.getSymbolExtractorVersionMetadataKey();
12631
13624
  const refreshCachedSymbols = database.getMetadata(symbolExtractorMetadataKey) !== SYMBOL_EXTRACTOR_VERSION;
12632
- if (reparseCachedSwiftFiles && Array.from(this.fileHashCache.keys()).some((filePath) => path19.extname(filePath).toLowerCase() === ".swift")) {
13625
+ if (reparseCachedSwiftFiles && Array.from(this.fileHashCache.keys()).some((filePath) => path20.extname(filePath).toLowerCase() === ".swift")) {
12633
13626
  this.logger.info("Reindexing cached Swift files for parser support");
12634
13627
  }
12635
- if (reparseCachedMetalFiles && Array.from(this.fileHashCache.keys()).some((filePath) => path19.extname(filePath).toLowerCase() === ".metal")) {
13628
+ if (reparseCachedMetalFiles && Array.from(this.fileHashCache.keys()).some((filePath) => path20.extname(filePath).toLowerCase() === ".metal")) {
12636
13629
  this.logger.info("Reindexing cached Metal files for parser support");
12637
13630
  }
12638
13631
  const includePatterns = [...this.config.include, ...this.config.additionalInclude];
@@ -12676,8 +13669,8 @@ var Indexer = class _Indexer {
12676
13669
  const needsCallGraphRefresh = cachedHashMatches && needsCallGraphResolutionMigration && database.getChunksByFile(storedPath).some(
12677
13670
  (chunk) => chunk.language === "php" || chunk.language === "c" || chunk.language === "cpp"
12678
13671
  );
12679
- const requiresSwiftParserUpgrade = reparseCachedSwiftFiles && path19.extname(storedPath).toLowerCase() === ".swift";
12680
- const requiresMetalParserUpgrade = reparseCachedMetalFiles && path19.extname(storedPath).toLowerCase() === ".metal";
13672
+ const requiresSwiftParserUpgrade = reparseCachedSwiftFiles && path20.extname(storedPath).toLowerCase() === ".swift";
13673
+ const requiresMetalParserUpgrade = reparseCachedMetalFiles && path20.extname(storedPath).toLowerCase() === ".metal";
12681
13674
  const inMigrationScope = forceScopedReembed && scopedRoots !== null && this.isFileInCurrentScope(storedPath, scopedRoots);
12682
13675
  if (cachedHashMatches && !inMigrationScope && !needsCallGraphRefresh && !requiresSwiftParserUpgrade && !requiresMetalParserUpgrade && !refreshCachedSymbols) {
12683
13676
  unchangedFilePaths.add(storedPath);
@@ -12736,7 +13729,7 @@ var Indexer = class _Indexer {
12736
13729
  }
12737
13730
  }
12738
13731
  }
12739
- const shouldRetryFailedPath = (filePath) => filePath !== null && currentFileHashes.has(filePath) && unchangedFilePaths.has(filePath);
13732
+ const shouldRetryFailedPath = (filePath) => filePath !== null && !this.isStoredPathExcluded(filePath) && currentFileHashes.has(filePath) && unchangedFilePaths.has(filePath);
12740
13733
  const failedProcessing = this.prepareFailedBatchProcessing(scopedRoots, shouldRetryFailedPath);
12741
13734
  const maxChunkTokens = getSafeEmbeddingChunkTokenLimit(configuredProviderInfo);
12742
13735
  const providerRateLimits = this.getProviderRateLimits(configuredProviderInfo.provider);
@@ -12840,7 +13833,7 @@ var Indexer = class _Indexer {
12840
13833
  throw new Error(`Parsed file was not present in its source batch: ${parsed.path}`);
12841
13834
  }
12842
13835
  if (parsed.chunks.length === 0) {
12843
- stats.parseFailures.push(path19.isAbsolute(parsed.path) ? path19.relative(this.projectRoot, parsed.path) : parsed.path);
13836
+ stats.parseFailures.push(path20.isAbsolute(parsed.path) ? path20.relative(this.projectRoot, parsed.path) : parsed.path);
12844
13837
  }
12845
13838
  let chunksToProcess = parsed.chunks;
12846
13839
  if (this.config.indexing.fallbackToTextOnMaxChunks && chunksToProcess.length > this.config.indexing.maxChunksPerFile) {
@@ -13175,7 +14168,7 @@ var Indexer = class _Indexer {
13175
14168
  previousBranchSymbolIds,
13176
14169
  Array.from(allSymbolIds)
13177
14170
  );
13178
- const vectorPath = path19.join(this.indexPath, "vectors");
14171
+ const vectorPath = path20.join(this.indexPath, "vectors");
13179
14172
  const shouldFingerprintLegacyPair = !store.hasFingerprint() && (0, import_fs12.existsSync)(vectorPath) && (0, import_fs12.existsSync)(`${vectorPath}.meta.json`);
13180
14173
  if (backfilledBlameMetadata || shouldFingerprintLegacyPair || removedStoredChunks) {
13181
14174
  store.save();
@@ -14034,7 +15027,7 @@ var Indexer = class _Indexer {
14034
15027
  gcOrphanSymbols: 0,
14035
15028
  gcOrphanCallEdges: 0,
14036
15029
  resetCorruptedIndex: true,
14037
- warning: this.getCorruptedIndexWarning(path19.join(this.indexPath, "codebase.db"))
15030
+ warning: this.getCorruptedIndexWarning(path20.join(this.indexPath, "codebase.db"))
14038
15031
  };
14039
15032
  }
14040
15033
  this.logger.recordGc(removedCount, gcOrphanChunks, gcOrphanEmbeddings);
@@ -14064,7 +15057,8 @@ var Indexer = class _Indexer {
14064
15057
  const maxChunkTokens = getSafeEmbeddingChunkTokenLimit(configuredProviderInfo);
14065
15058
  const providerRateLimits = this.getProviderRateLimits(configuredProviderInfo.provider);
14066
15059
  const roots = this.config.scope === "global" ? this.getScopedRoots() : null;
14067
- const failedProcessing = this.prepareFailedBatchProcessing(roots, () => true);
15060
+ const shouldProcessFailedPath = (filePath) => filePath === null || !this.isStoredPathExcluded(filePath);
15061
+ const failedProcessing = this.prepareFailedBatchProcessing(roots, shouldProcessFailedPath);
14068
15062
  if (failedProcessing.latestById.size === 0) {
14069
15063
  this.finalizeFailedBatchWriteState(failedProcessing.state);
14070
15064
  return { succeeded: 0, failed: 0, remaining: 0 };
@@ -14077,7 +15071,7 @@ var Indexer = class _Indexer {
14077
15071
  const retryableChunks = this.iterateLatestFailedChunks(
14078
15072
  failedProcessing.latestById,
14079
15073
  roots,
14080
- () => true,
15074
+ shouldProcessFailedPath,
14081
15075
  maxChunkTokens
14082
15076
  );
14083
15077
  for (const retryBatch of iterateOrderedFileBatches(
@@ -14347,9 +15341,9 @@ var Indexer = class _Indexer {
14347
15341
  this.requireReadableComponents(readIssues, "database");
14348
15342
  let shortest = [];
14349
15343
  for (const branchKey of this.getBranchCatalogKeys()) {
14350
- const path30 = database.findShortestPath(fromName, toName, branchKey, maxDepth);
14351
- if (path30.length > 0 && (shortest.length === 0 || path30.length < shortest.length)) {
14352
- shortest = path30;
15344
+ const path31 = database.findShortestPath(fromName, toName, branchKey, maxDepth);
15345
+ if (path31.length > 0 && (shortest.length === 0 || path31.length < shortest.length)) {
15346
+ shortest = path31;
14353
15347
  }
14354
15348
  }
14355
15349
  return shortest.map((hop) => this.resolveFilePathRecord(hop));
@@ -14397,13 +15391,13 @@ var Indexer = class _Indexer {
14397
15391
  }
14398
15392
  }
14399
15393
  if (!found) continue;
14400
- const path30 = [];
15394
+ const path31 = [];
14401
15395
  let currentSymbolId = toSymbolId;
14402
15396
  while (true) {
14403
15397
  const symbol = symbolsById.get(currentSymbolId);
14404
15398
  if (!symbol) break;
14405
15399
  const parent = parentBySymbolId.get(currentSymbolId);
14406
- path30.push({
15400
+ path31.push({
14407
15401
  symbolId: symbol.id,
14408
15402
  symbolName: symbol.name,
14409
15403
  filePath: symbol.filePath,
@@ -14413,9 +15407,9 @@ var Indexer = class _Indexer {
14413
15407
  if (!parent) break;
14414
15408
  currentSymbolId = parent.parentId;
14415
15409
  }
14416
- path30.reverse();
14417
- if (path30.length > 0 && (shortest.length === 0 || path30.length < shortest.length)) {
14418
- shortest = path30;
15410
+ path31.reverse();
15411
+ if (path31.length > 0 && (shortest.length === 0 || path31.length < shortest.length)) {
15412
+ shortest = path31;
14419
15413
  }
14420
15414
  }
14421
15415
  return shortest.map((hop) => this.resolveFilePathRecord(hop));
@@ -14566,7 +15560,7 @@ var Indexer = class _Indexer {
14566
15560
  );
14567
15561
  }
14568
15562
  }
14569
- const toStoredChangedFiles = (filePaths) => filePaths.map((filePath) => this.toStoredFilePath(path19.resolve(this.projectRoot, filePath)));
15563
+ const toStoredChangedFiles = (filePaths) => filePaths.map((filePath) => this.toStoredFilePath(path20.resolve(this.projectRoot, filePath)));
14570
15564
  const storedChangedFiles = toStoredChangedFiles(changedFiles);
14571
15565
  const directSymbols = database.getSymbolsForFiles(storedChangedFiles, branchKey);
14572
15566
  const directIds = directSymbols.map((s) => s.id);
@@ -14715,12 +15709,12 @@ var Indexer = class _Indexer {
14715
15709
  if (meta.filePath) filePaths.add(meta.filePath);
14716
15710
  }
14717
15711
  const directory = options?.directory?.replace(/\/$/, "");
14718
- const absoluteDirectoryFilter = directory ? path19.resolve(this.projectRoot, directory) : void 0;
15712
+ const absoluteDirectoryFilter = directory ? path20.resolve(this.projectRoot, directory) : void 0;
14719
15713
  for (const filePath of filePaths) {
14720
15714
  if (directory) {
14721
15715
  const absoluteFilePath = this.resolveStoredFilePath(filePath);
14722
15716
  const matchesRelative = filePath === directory || filePath.startsWith(directory + "/");
14723
- const matchesProjectRelative = absoluteDirectoryFilter !== void 0 && (absoluteFilePath === absoluteDirectoryFilter || absoluteFilePath.startsWith(absoluteDirectoryFilter + path19.sep));
15717
+ const matchesProjectRelative = absoluteDirectoryFilter !== void 0 && (absoluteFilePath === absoluteDirectoryFilter || absoluteFilePath.startsWith(absoluteDirectoryFilter + path20.sep));
14724
15718
  if (!matchesRelative && !matchesProjectRelative) {
14725
15719
  continue;
14726
15720
  }
@@ -14837,15 +15831,24 @@ function getOrCreateIndexer(projectRoot, host) {
14837
15831
  }
14838
15832
  const indexer = new Indexer(projectRoot, config, host);
14839
15833
  indexerCache.set(key, indexer);
14840
- configureAutoIndex(projectRoot, host, config, () => getOrCreateIndexer(projectRoot, host));
15834
+ configureAutoIndex(projectRoot, host, config, () => getOrCreateIndexer(projectRoot, host), {
15835
+ preserveManagedWorker: true,
15836
+ synchronizeBackgroundWorker: false
15837
+ });
14841
15838
  return indexer;
14842
15839
  }
14843
- function initializeTools(projectRoot, config, host) {
15840
+ function initializeTools(projectRoot, config, host, options = {}) {
14844
15841
  defaultProjectRoots.set(host, projectRoot);
14845
15842
  const key = getIndexerCacheKey(projectRoot, host);
15843
+ if (options.preserveManagedWorker === true && isBackgroundWorkerManaged(projectRoot, host) && indexerCache.has(key)) {
15844
+ return;
15845
+ }
14846
15846
  configCache.set(key, config);
14847
15847
  indexerCache.set(key, new Indexer(projectRoot, config, host));
14848
- configureAutoIndex(projectRoot, host, config, () => getOrCreateIndexer(projectRoot, host));
15848
+ configureAutoIndex(projectRoot, host, config, () => getOrCreateIndexer(projectRoot, host), {
15849
+ preserveManagedWorker: options.preserveManagedWorker,
15850
+ synchronizeBackgroundWorker: false
15851
+ });
14849
15852
  }
14850
15853
  function getIndexerForProject(projectRoot, host) {
14851
15854
  const root = getProjectRoot(projectRoot, host);
@@ -14859,7 +15862,9 @@ function refreshIndexerForDirectory(projectRoot, host, config = parseConfig(load
14859
15862
  const key = getIndexerCacheKey(projectRoot, host);
14860
15863
  configCache.set(key, config);
14861
15864
  indexerCache.set(key, new Indexer(projectRoot, config, host));
14862
- configureAutoIndex(projectRoot, host, config, () => getOrCreateIndexer(projectRoot, host));
15865
+ configureAutoIndex(projectRoot, host, config, () => getOrCreateIndexer(projectRoot, host), {
15866
+ synchronizeBackgroundWorker: true
15867
+ });
14863
15868
  return config;
14864
15869
  }
14865
15870
  var AutoIndexRetrievalUnavailableError = class extends Error {
@@ -14886,7 +15891,7 @@ function trimOrUndefined(value) {
14886
15891
  return normalized || void 0;
14887
15892
  }
14888
15893
  function normalizeCallGraphPath(value) {
14889
- let normalized = path20.posix.normalize(value.trim().replaceAll("\\", "/"));
15894
+ let normalized = path21.posix.normalize(value.trim().replaceAll("\\", "/"));
14890
15895
  if (normalized.startsWith("./")) {
14891
15896
  normalized = normalized.slice(2);
14892
15897
  }
@@ -15079,12 +16084,12 @@ async function getCallGraphPath(projectRoot, host, from, to, maxDepth, fromFileP
15079
16084
  if (fromResolution.status !== "resolved" || toResolution.status !== "resolved") {
15080
16085
  return { from: fromResolution, to: toResolution, path: [] };
15081
16086
  }
15082
- const path30 = await indexer.findCallPathBySymbolIds(
16087
+ const path31 = await indexer.findCallPathBySymbolIds(
15083
16088
  fromResolution.symbolId,
15084
16089
  toResolution.symbolId,
15085
16090
  maxDepth
15086
16091
  );
15087
- return { from: fromResolution, to: toResolution, path: path30 };
16092
+ return { from: fromResolution, to: toResolution, path: path31 };
15088
16093
  }
15089
16094
  async function runIndexCodebase(projectRoot, host, args, onProgress) {
15090
16095
  const root = getProjectRoot(projectRoot, host);
@@ -15270,8 +16275,8 @@ async function getIndexLogs(projectRoot, host, args) {
15270
16275
  function addKnowledgeBase(projectRoot, host, knowledgeBasePath) {
15271
16276
  const root = getProjectRoot(projectRoot, host);
15272
16277
  const inputPath = knowledgeBasePath.trim();
15273
- const normalizedPath2 = path20.resolve(
15274
- path20.isAbsolute(inputPath) ? inputPath : resolveKnowledgeBasePath(inputPath, root)
16278
+ const normalizedPath2 = path21.resolve(
16279
+ path21.isAbsolute(inputPath) ? inputPath : resolveKnowledgeBasePath(inputPath, root)
15275
16280
  );
15276
16281
  if (!(0, import_fs13.existsSync)(normalizedPath2)) {
15277
16282
  return `Error: Directory does not exist: ${normalizedPath2}`;
@@ -15307,7 +16312,7 @@ function addKnowledgeBase(projectRoot, host, knowledgeBasePath) {
15307
16312
  }
15308
16313
  }
15309
16314
  for (const dotDir of sensitiveDotDirs) {
15310
- const sensitiveDir = path20.join(homeDir, dotDir);
16315
+ const sensitiveDir = path21.join(homeDir, dotDir);
15311
16316
  if (sensitiveDir && (realPath === sensitiveDir || realPath.startsWith(`${sensitiveDir}/`))) {
15312
16317
  return `Error: Adding sensitive directory as knowledge base is not allowed: ${normalizedPath2}`;
15313
16318
  }
@@ -15370,7 +16375,7 @@ function listKnowledgeBases(projectRoot, host) {
15370
16375
  }
15371
16376
  result += "\n";
15372
16377
  }
15373
- const hasHostConfig = (0, import_fs13.existsSync)(path20.join(root, getHostProjectConfigRelativePath(host)));
16378
+ const hasHostConfig = (0, import_fs13.existsSync)(path21.join(root, getHostProjectConfigRelativePath(host)));
15374
16379
  if (hasHostConfig) {
15375
16380
  result += `
15376
16381
  Config sources: 1 file(s).`;
@@ -15408,7 +16413,7 @@ var import_fs14 = require("fs");
15408
16413
 
15409
16414
  // node_modules/chokidar/index.js
15410
16415
  var import_node_events = require("events");
15411
- var import_node_fs2 = require("fs");
16416
+ var import_node_fs3 = require("fs");
15412
16417
  var import_promises3 = require("fs/promises");
15413
16418
  var sp2 = __toESM(require("path"), 1);
15414
16419
 
@@ -15496,7 +16501,7 @@ var ReaddirpStream = class extends import_node_stream.Readable {
15496
16501
  this._directoryFilter = normalizeFilter(opts.directoryFilter);
15497
16502
  const statMethod = opts.lstat ? import_promises.lstat : import_promises.stat;
15498
16503
  if (wantBigintFsStats) {
15499
- this._stat = (path30) => statMethod(path30, { bigint: true });
16504
+ this._stat = (path31) => statMethod(path31, { bigint: true });
15500
16505
  } else {
15501
16506
  this._stat = statMethod;
15502
16507
  }
@@ -15521,8 +16526,8 @@ var ReaddirpStream = class extends import_node_stream.Readable {
15521
16526
  const par = this.parent;
15522
16527
  const fil = par && par.files;
15523
16528
  if (fil && fil.length > 0) {
15524
- const { path: path30, depth } = par;
15525
- const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path30));
16529
+ const { path: path31, depth } = par;
16530
+ const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path31));
15526
16531
  const awaited = await Promise.all(slice);
15527
16532
  for (const entry of awaited) {
15528
16533
  if (!entry)
@@ -15562,21 +16567,21 @@ var ReaddirpStream = class extends import_node_stream.Readable {
15562
16567
  this.reading = false;
15563
16568
  }
15564
16569
  }
15565
- async _exploreDir(path30, depth) {
16570
+ async _exploreDir(path31, depth) {
15566
16571
  let files;
15567
16572
  try {
15568
- files = await (0, import_promises.readdir)(path30, this._rdOptions);
16573
+ files = await (0, import_promises.readdir)(path31, this._rdOptions);
15569
16574
  } catch (error) {
15570
16575
  this._onError(error);
15571
16576
  }
15572
- return { files, depth, path: path30 };
16577
+ return { files, depth, path: path31 };
15573
16578
  }
15574
- async _formatEntry(dirent, path30) {
16579
+ async _formatEntry(dirent, path31) {
15575
16580
  let entry;
15576
- const basename9 = this._isDirent ? dirent.name : dirent;
16581
+ const basename10 = this._isDirent ? dirent.name : dirent;
15577
16582
  try {
15578
- const fullPath = (0, import_node_path.resolve)((0, import_node_path.join)(path30, basename9));
15579
- entry = { path: (0, import_node_path.relative)(this._root, fullPath), fullPath, basename: basename9 };
16583
+ const fullPath = (0, import_node_path.resolve)((0, import_node_path.join)(path31, basename10));
16584
+ entry = { path: (0, import_node_path.relative)(this._root, fullPath), fullPath, basename: basename10 };
15580
16585
  entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
15581
16586
  } catch (err) {
15582
16587
  this._onError(err);
@@ -15646,7 +16651,7 @@ function readdirp(root, options = {}) {
15646
16651
  }
15647
16652
 
15648
16653
  // node_modules/chokidar/handler.js
15649
- var import_node_fs = require("fs");
16654
+ var import_node_fs2 = require("fs");
15650
16655
  var import_promises2 = require("fs/promises");
15651
16656
  var import_node_os = require("os");
15652
16657
  var sp = __toESM(require("path"), 1);
@@ -15975,16 +16980,16 @@ var delFromSet = (main, prop, item) => {
15975
16980
  };
15976
16981
  var isEmptySet = (val) => val instanceof Set ? val.size === 0 : !val;
15977
16982
  var FsWatchInstances = /* @__PURE__ */ new Map();
15978
- function createFsWatchInstance(path30, options, listener, errHandler, emitRaw) {
16983
+ function createFsWatchInstance(path31, options, listener, errHandler, emitRaw) {
15979
16984
  const handleEvent = (rawEvent, evPath) => {
15980
- listener(path30);
15981
- emitRaw(rawEvent, evPath, { watchedPath: path30 });
15982
- if (evPath && path30 !== evPath) {
15983
- fsWatchBroadcast(sp.resolve(path30, evPath), KEY_LISTENERS, sp.join(path30, evPath));
16985
+ listener(path31);
16986
+ emitRaw(rawEvent, evPath, { watchedPath: path31 });
16987
+ if (evPath && path31 !== evPath) {
16988
+ fsWatchBroadcast(sp.resolve(path31, evPath), KEY_LISTENERS, sp.join(path31, evPath));
15984
16989
  }
15985
16990
  };
15986
16991
  try {
15987
- return (0, import_node_fs.watch)(path30, {
16992
+ return (0, import_node_fs2.watch)(path31, {
15988
16993
  persistent: options.persistent
15989
16994
  }, handleEvent);
15990
16995
  } catch (error) {
@@ -16000,12 +17005,12 @@ var fsWatchBroadcast = (fullPath, listenerType, val1, val2, val3) => {
16000
17005
  listener(val1, val2, val3);
16001
17006
  });
16002
17007
  };
16003
- var setFsWatchListener = (path30, fullPath, options, handlers) => {
17008
+ var setFsWatchListener = (path31, fullPath, options, handlers) => {
16004
17009
  const { listener, errHandler, rawEmitter } = handlers;
16005
17010
  let cont = FsWatchInstances.get(fullPath);
16006
17011
  let watcher;
16007
17012
  if (!options.persistent) {
16008
- watcher = createFsWatchInstance(path30, options, listener, errHandler, rawEmitter);
17013
+ watcher = createFsWatchInstance(path31, options, listener, errHandler, rawEmitter);
16009
17014
  if (!watcher)
16010
17015
  return;
16011
17016
  return watcher.close.bind(watcher);
@@ -16016,7 +17021,7 @@ var setFsWatchListener = (path30, fullPath, options, handlers) => {
16016
17021
  addAndConvert(cont, KEY_RAW, rawEmitter);
16017
17022
  } else {
16018
17023
  watcher = createFsWatchInstance(
16019
- path30,
17024
+ path31,
16020
17025
  options,
16021
17026
  fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS),
16022
17027
  errHandler,
@@ -16031,7 +17036,7 @@ var setFsWatchListener = (path30, fullPath, options, handlers) => {
16031
17036
  cont.watcherUnusable = true;
16032
17037
  if (isWindows && error.code === "EPERM") {
16033
17038
  try {
16034
- const fd = await (0, import_promises2.open)(path30, "r");
17039
+ const fd = await (0, import_promises2.open)(path31, "r");
16035
17040
  await fd.close();
16036
17041
  broadcastErr(error);
16037
17042
  } catch (err) {
@@ -16062,12 +17067,12 @@ var setFsWatchListener = (path30, fullPath, options, handlers) => {
16062
17067
  };
16063
17068
  };
16064
17069
  var FsWatchFileInstances = /* @__PURE__ */ new Map();
16065
- var setFsWatchFileListener = (path30, fullPath, options, handlers) => {
17070
+ var setFsWatchFileListener = (path31, fullPath, options, handlers) => {
16066
17071
  const { listener, rawEmitter } = handlers;
16067
17072
  let cont = FsWatchFileInstances.get(fullPath);
16068
17073
  const copts = cont && cont.options;
16069
17074
  if (copts && (copts.persistent < options.persistent || copts.interval > options.interval)) {
16070
- (0, import_node_fs.unwatchFile)(fullPath);
17075
+ (0, import_node_fs2.unwatchFile)(fullPath);
16071
17076
  cont = void 0;
16072
17077
  }
16073
17078
  if (cont) {
@@ -16078,13 +17083,13 @@ var setFsWatchFileListener = (path30, fullPath, options, handlers) => {
16078
17083
  listeners: listener,
16079
17084
  rawEmitters: rawEmitter,
16080
17085
  options,
16081
- watcher: (0, import_node_fs.watchFile)(fullPath, options, (curr, prev) => {
17086
+ watcher: (0, import_node_fs2.watchFile)(fullPath, options, (curr, prev) => {
16082
17087
  foreach(cont.rawEmitters, (rawEmitter2) => {
16083
17088
  rawEmitter2(EV.CHANGE, fullPath, { curr, prev });
16084
17089
  });
16085
17090
  const currmtime = curr.mtimeMs;
16086
17091
  if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {
16087
- foreach(cont.listeners, (listener2) => listener2(path30, curr));
17092
+ foreach(cont.listeners, (listener2) => listener2(path31, curr));
16088
17093
  }
16089
17094
  })
16090
17095
  };
@@ -16095,7 +17100,7 @@ var setFsWatchFileListener = (path30, fullPath, options, handlers) => {
16095
17100
  delFromSet(cont, KEY_RAW, rawEmitter);
16096
17101
  if (isEmptySet(cont.listeners)) {
16097
17102
  FsWatchFileInstances.delete(fullPath);
16098
- (0, import_node_fs.unwatchFile)(fullPath);
17103
+ (0, import_node_fs2.unwatchFile)(fullPath);
16099
17104
  cont.options = cont.watcher = void 0;
16100
17105
  Object.freeze(cont);
16101
17106
  }
@@ -16114,13 +17119,13 @@ var NodeFsHandler = class {
16114
17119
  * @param listener on fs change
16115
17120
  * @returns closer for the watcher instance
16116
17121
  */
16117
- _watchWithNodeFs(path30, listener) {
17122
+ _watchWithNodeFs(path31, listener) {
16118
17123
  const opts = this.fsw.options;
16119
- const directory = sp.dirname(path30);
16120
- const basename9 = sp.basename(path30);
17124
+ const directory = sp.dirname(path31);
17125
+ const basename10 = sp.basename(path31);
16121
17126
  const parent = this.fsw._getWatchedDir(directory);
16122
- parent.add(basename9);
16123
- const absolutePath = sp.resolve(path30);
17127
+ parent.add(basename10);
17128
+ const absolutePath = sp.resolve(path31);
16124
17129
  const options = {
16125
17130
  persistent: opts.persistent
16126
17131
  };
@@ -16129,13 +17134,13 @@ var NodeFsHandler = class {
16129
17134
  let closer;
16130
17135
  if (opts.usePolling) {
16131
17136
  const enableBin = opts.interval !== opts.binaryInterval;
16132
- options.interval = enableBin && isBinaryPath(basename9) ? opts.binaryInterval : opts.interval;
16133
- closer = setFsWatchFileListener(path30, absolutePath, options, {
17137
+ options.interval = enableBin && isBinaryPath(basename10) ? opts.binaryInterval : opts.interval;
17138
+ closer = setFsWatchFileListener(path31, absolutePath, options, {
16134
17139
  listener,
16135
17140
  rawEmitter: this.fsw._emitRaw
16136
17141
  });
16137
17142
  } else {
16138
- closer = setFsWatchListener(path30, absolutePath, options, {
17143
+ closer = setFsWatchListener(path31, absolutePath, options, {
16139
17144
  listener,
16140
17145
  errHandler: this._boundHandleError,
16141
17146
  rawEmitter: this.fsw._emitRaw
@@ -16151,13 +17156,13 @@ var NodeFsHandler = class {
16151
17156
  if (this.fsw.closed) {
16152
17157
  return;
16153
17158
  }
16154
- const dirname15 = sp.dirname(file);
16155
- const basename9 = sp.basename(file);
16156
- const parent = this.fsw._getWatchedDir(dirname15);
17159
+ const dirname16 = sp.dirname(file);
17160
+ const basename10 = sp.basename(file);
17161
+ const parent = this.fsw._getWatchedDir(dirname16);
16157
17162
  let prevStats = stats;
16158
- if (parent.has(basename9))
17163
+ if (parent.has(basename10))
16159
17164
  return;
16160
- const listener = async (path30, newStats) => {
17165
+ const listener = async (path31, newStats) => {
16161
17166
  if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5))
16162
17167
  return;
16163
17168
  if (!newStats || newStats.mtimeMs === 0) {
@@ -16171,18 +17176,18 @@ var NodeFsHandler = class {
16171
17176
  this.fsw._emit(EV.CHANGE, file, newStats2);
16172
17177
  }
16173
17178
  if ((isMacos || isLinux || isFreeBSD) && prevStats.ino !== newStats2.ino) {
16174
- this.fsw._closeFile(path30);
17179
+ this.fsw._closeFile(path31);
16175
17180
  prevStats = newStats2;
16176
17181
  const closer2 = this._watchWithNodeFs(file, listener);
16177
17182
  if (closer2)
16178
- this.fsw._addPathCloser(path30, closer2);
17183
+ this.fsw._addPathCloser(path31, closer2);
16179
17184
  } else {
16180
17185
  prevStats = newStats2;
16181
17186
  }
16182
17187
  } catch (error) {
16183
- this.fsw._remove(dirname15, basename9);
17188
+ this.fsw._remove(dirname16, basename10);
16184
17189
  }
16185
- } else if (parent.has(basename9)) {
17190
+ } else if (parent.has(basename10)) {
16186
17191
  const at = newStats.atimeMs;
16187
17192
  const mt = newStats.mtimeMs;
16188
17193
  if (!at || at <= mt || mt !== prevStats.mtimeMs) {
@@ -16207,7 +17212,7 @@ var NodeFsHandler = class {
16207
17212
  * @param item basename of this item
16208
17213
  * @returns true if no more processing is needed for this entry.
16209
17214
  */
16210
- async _handleSymlink(entry, directory, path30, item) {
17215
+ async _handleSymlink(entry, directory, path31, item) {
16211
17216
  if (this.fsw.closed) {
16212
17217
  return;
16213
17218
  }
@@ -16217,7 +17222,7 @@ var NodeFsHandler = class {
16217
17222
  this.fsw._incrReadyCount();
16218
17223
  let linkPath;
16219
17224
  try {
16220
- linkPath = await (0, import_promises2.realpath)(path30);
17225
+ linkPath = await (0, import_promises2.realpath)(path31);
16221
17226
  } catch (e) {
16222
17227
  this.fsw._emitReady();
16223
17228
  return true;
@@ -16227,12 +17232,12 @@ var NodeFsHandler = class {
16227
17232
  if (dir.has(item)) {
16228
17233
  if (this.fsw._symlinkPaths.get(full) !== linkPath) {
16229
17234
  this.fsw._symlinkPaths.set(full, linkPath);
16230
- this.fsw._emit(EV.CHANGE, path30, entry.stats);
17235
+ this.fsw._emit(EV.CHANGE, path31, entry.stats);
16231
17236
  }
16232
17237
  } else {
16233
17238
  dir.add(item);
16234
17239
  this.fsw._symlinkPaths.set(full, linkPath);
16235
- this.fsw._emit(EV.ADD, path30, entry.stats);
17240
+ this.fsw._emit(EV.ADD, path31, entry.stats);
16236
17241
  }
16237
17242
  this.fsw._emitReady();
16238
17243
  return true;
@@ -16262,9 +17267,9 @@ var NodeFsHandler = class {
16262
17267
  return;
16263
17268
  }
16264
17269
  const item = entry.path;
16265
- let path30 = sp.join(directory, item);
17270
+ let path31 = sp.join(directory, item);
16266
17271
  current.add(item);
16267
- if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path30, item)) {
17272
+ if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path31, item)) {
16268
17273
  return;
16269
17274
  }
16270
17275
  if (this.fsw.closed) {
@@ -16273,11 +17278,11 @@ var NodeFsHandler = class {
16273
17278
  }
16274
17279
  if (item === target || !target && !previous.has(item)) {
16275
17280
  this.fsw._incrReadyCount();
16276
- path30 = sp.join(dir, sp.relative(dir, path30));
16277
- this._addToNodeFs(path30, initialAdd, wh, depth + 1);
17281
+ path31 = sp.join(dir, sp.relative(dir, path31));
17282
+ this._addToNodeFs(path31, initialAdd, wh, depth + 1);
16278
17283
  }
16279
17284
  }).on(EV.ERROR, this._boundHandleError);
16280
- return new Promise((resolve17, reject) => {
17285
+ return new Promise((resolve18, reject) => {
16281
17286
  if (!stream)
16282
17287
  return reject();
16283
17288
  stream.once(STR_END, () => {
@@ -16286,7 +17291,7 @@ var NodeFsHandler = class {
16286
17291
  return;
16287
17292
  }
16288
17293
  const wasThrottled = throttler ? throttler.clear() : false;
16289
- resolve17(void 0);
17294
+ resolve18(void 0);
16290
17295
  previous.getChildren().filter((item) => {
16291
17296
  return item !== directory && !current.has(item);
16292
17297
  }).forEach((item) => {
@@ -16343,13 +17348,13 @@ var NodeFsHandler = class {
16343
17348
  * @param depth Child path actually targeted for watch
16344
17349
  * @param target Child path actually targeted for watch
16345
17350
  */
16346
- async _addToNodeFs(path30, initialAdd, priorWh, depth, target) {
17351
+ async _addToNodeFs(path31, initialAdd, priorWh, depth, target) {
16347
17352
  const ready = this.fsw._emitReady;
16348
- if (this.fsw._isIgnored(path30) || this.fsw.closed) {
17353
+ if (this.fsw._isIgnored(path31) || this.fsw.closed) {
16349
17354
  ready();
16350
17355
  return false;
16351
17356
  }
16352
- const wh = this.fsw._getWatchHelpers(path30);
17357
+ const wh = this.fsw._getWatchHelpers(path31);
16353
17358
  if (priorWh) {
16354
17359
  wh.filterPath = (entry) => priorWh.filterPath(entry);
16355
17360
  wh.filterDir = (entry) => priorWh.filterDir(entry);
@@ -16365,8 +17370,8 @@ var NodeFsHandler = class {
16365
17370
  const follow = this.fsw.options.followSymlinks;
16366
17371
  let closer;
16367
17372
  if (stats.isDirectory()) {
16368
- const absPath = sp.resolve(path30);
16369
- const targetPath = follow ? await (0, import_promises2.realpath)(path30) : path30;
17373
+ const absPath = sp.resolve(path31);
17374
+ const targetPath = follow ? await (0, import_promises2.realpath)(path31) : path31;
16370
17375
  if (this.fsw.closed)
16371
17376
  return;
16372
17377
  closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
@@ -16376,29 +17381,29 @@ var NodeFsHandler = class {
16376
17381
  this.fsw._symlinkPaths.set(absPath, targetPath);
16377
17382
  }
16378
17383
  } else if (stats.isSymbolicLink()) {
16379
- const targetPath = follow ? await (0, import_promises2.realpath)(path30) : path30;
17384
+ const targetPath = follow ? await (0, import_promises2.realpath)(path31) : path31;
16380
17385
  if (this.fsw.closed)
16381
17386
  return;
16382
17387
  const parent = sp.dirname(wh.watchPath);
16383
17388
  this.fsw._getWatchedDir(parent).add(wh.watchPath);
16384
17389
  this.fsw._emit(EV.ADD, wh.watchPath, stats);
16385
- closer = await this._handleDir(parent, stats, initialAdd, depth, path30, wh, targetPath);
17390
+ closer = await this._handleDir(parent, stats, initialAdd, depth, path31, wh, targetPath);
16386
17391
  if (this.fsw.closed)
16387
17392
  return;
16388
17393
  if (targetPath !== void 0) {
16389
- this.fsw._symlinkPaths.set(sp.resolve(path30), targetPath);
17394
+ this.fsw._symlinkPaths.set(sp.resolve(path31), targetPath);
16390
17395
  }
16391
17396
  } else {
16392
17397
  closer = this._handleFile(wh.watchPath, stats, initialAdd);
16393
17398
  }
16394
17399
  ready();
16395
17400
  if (closer)
16396
- this.fsw._addPathCloser(path30, closer);
17401
+ this.fsw._addPathCloser(path31, closer);
16397
17402
  return false;
16398
17403
  } catch (error) {
16399
17404
  if (this.fsw._handleError(error)) {
16400
17405
  ready();
16401
- return path30;
17406
+ return path31;
16402
17407
  }
16403
17408
  }
16404
17409
  }
@@ -16441,24 +17446,24 @@ function createPattern(matcher) {
16441
17446
  }
16442
17447
  return () => false;
16443
17448
  }
16444
- function normalizePath2(path30) {
16445
- if (typeof path30 !== "string")
17449
+ function normalizePath2(path31) {
17450
+ if (typeof path31 !== "string")
16446
17451
  throw new Error("string expected");
16447
- path30 = sp2.normalize(path30);
16448
- path30 = path30.replace(/\\/g, "/");
17452
+ path31 = sp2.normalize(path31);
17453
+ path31 = path31.replace(/\\/g, "/");
16449
17454
  let prepend = false;
16450
- if (path30.startsWith("//"))
17455
+ if (path31.startsWith("//"))
16451
17456
  prepend = true;
16452
- path30 = path30.replace(DOUBLE_SLASH_RE, "/");
17457
+ path31 = path31.replace(DOUBLE_SLASH_RE, "/");
16453
17458
  if (prepend)
16454
- path30 = "/" + path30;
16455
- return path30;
17459
+ path31 = "/" + path31;
17460
+ return path31;
16456
17461
  }
16457
17462
  function matchPatterns(patterns, testString, stats) {
16458
- const path30 = normalizePath2(testString);
17463
+ const path31 = normalizePath2(testString);
16459
17464
  for (let index = 0; index < patterns.length; index++) {
16460
17465
  const pattern = patterns[index];
16461
- if (pattern(path30, stats)) {
17466
+ if (pattern(path31, stats)) {
16462
17467
  return true;
16463
17468
  }
16464
17469
  }
@@ -16496,19 +17501,19 @@ var toUnix = (string) => {
16496
17501
  }
16497
17502
  return str;
16498
17503
  };
16499
- var normalizePathToUnix = (path30) => toUnix(sp2.normalize(toUnix(path30)));
16500
- var normalizeIgnored = (cwd = "") => (path30) => {
16501
- if (typeof path30 === "string") {
16502
- return normalizePathToUnix(sp2.isAbsolute(path30) ? path30 : sp2.join(cwd, path30));
17504
+ var normalizePathToUnix = (path31) => toUnix(sp2.normalize(toUnix(path31)));
17505
+ var normalizeIgnored = (cwd = "") => (path31) => {
17506
+ if (typeof path31 === "string") {
17507
+ return normalizePathToUnix(sp2.isAbsolute(path31) ? path31 : sp2.join(cwd, path31));
16503
17508
  } else {
16504
- return path30;
17509
+ return path31;
16505
17510
  }
16506
17511
  };
16507
- var getAbsolutePath = (path30, cwd) => {
16508
- if (sp2.isAbsolute(path30)) {
16509
- return path30;
17512
+ var getAbsolutePath = (path31, cwd) => {
17513
+ if (sp2.isAbsolute(path31)) {
17514
+ return path31;
16510
17515
  }
16511
- return sp2.join(cwd, path30);
17516
+ return sp2.join(cwd, path31);
16512
17517
  };
16513
17518
  var EMPTY_SET = Object.freeze(/* @__PURE__ */ new Set());
16514
17519
  var DirEntry = class {
@@ -16573,10 +17578,10 @@ var WatchHelper = class {
16573
17578
  dirParts;
16574
17579
  followSymlinks;
16575
17580
  statMethod;
16576
- constructor(path30, follow, fsw) {
17581
+ constructor(path31, follow, fsw) {
16577
17582
  this.fsw = fsw;
16578
- const watchPath = path30;
16579
- this.path = path30 = path30.replace(REPLACER_RE, "");
17583
+ const watchPath = path31;
17584
+ this.path = path31 = path31.replace(REPLACER_RE, "");
16580
17585
  this.watchPath = watchPath;
16581
17586
  this.fullWatchPath = sp2.resolve(watchPath);
16582
17587
  this.dirParts = [];
@@ -16716,20 +17721,20 @@ var FSWatcher = class extends import_node_events.EventEmitter {
16716
17721
  this._closePromise = void 0;
16717
17722
  let paths = unifyPaths(paths_);
16718
17723
  if (cwd) {
16719
- paths = paths.map((path30) => {
16720
- const absPath = getAbsolutePath(path30, cwd);
17724
+ paths = paths.map((path31) => {
17725
+ const absPath = getAbsolutePath(path31, cwd);
16721
17726
  return absPath;
16722
17727
  });
16723
17728
  }
16724
- paths.forEach((path30) => {
16725
- this._removeIgnoredPath(path30);
17729
+ paths.forEach((path31) => {
17730
+ this._removeIgnoredPath(path31);
16726
17731
  });
16727
17732
  this._userIgnored = void 0;
16728
17733
  if (!this._readyCount)
16729
17734
  this._readyCount = 0;
16730
17735
  this._readyCount += paths.length;
16731
- Promise.all(paths.map(async (path30) => {
16732
- const res = await this._nodeFsHandler._addToNodeFs(path30, !_internal, void 0, 0, _origAdd);
17736
+ Promise.all(paths.map(async (path31) => {
17737
+ const res = await this._nodeFsHandler._addToNodeFs(path31, !_internal, void 0, 0, _origAdd);
16733
17738
  if (res)
16734
17739
  this._emitReady();
16735
17740
  return res;
@@ -16751,17 +17756,17 @@ var FSWatcher = class extends import_node_events.EventEmitter {
16751
17756
  return this;
16752
17757
  const paths = unifyPaths(paths_);
16753
17758
  const { cwd } = this.options;
16754
- paths.forEach((path30) => {
16755
- if (!sp2.isAbsolute(path30) && !this._closers.has(path30)) {
17759
+ paths.forEach((path31) => {
17760
+ if (!sp2.isAbsolute(path31) && !this._closers.has(path31)) {
16756
17761
  if (cwd)
16757
- path30 = sp2.join(cwd, path30);
16758
- path30 = sp2.resolve(path30);
17762
+ path31 = sp2.join(cwd, path31);
17763
+ path31 = sp2.resolve(path31);
16759
17764
  }
16760
- this._closePath(path30);
16761
- this._addIgnoredPath(path30);
16762
- if (this._watched.has(path30)) {
17765
+ this._closePath(path31);
17766
+ this._addIgnoredPath(path31);
17767
+ if (this._watched.has(path31)) {
16763
17768
  this._addIgnoredPath({
16764
- path: path30,
17769
+ path: path31,
16765
17770
  recursive: true
16766
17771
  });
16767
17772
  }
@@ -16825,38 +17830,38 @@ var FSWatcher = class extends import_node_events.EventEmitter {
16825
17830
  * @param stats arguments to be passed with event
16826
17831
  * @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag
16827
17832
  */
16828
- async _emit(event, path30, stats) {
17833
+ async _emit(event, path31, stats) {
16829
17834
  if (this.closed)
16830
17835
  return;
16831
17836
  const opts = this.options;
16832
17837
  if (isWindows)
16833
- path30 = sp2.normalize(path30);
17838
+ path31 = sp2.normalize(path31);
16834
17839
  if (opts.cwd)
16835
- path30 = sp2.relative(opts.cwd, path30);
16836
- const args = [path30];
17840
+ path31 = sp2.relative(opts.cwd, path31);
17841
+ const args = [path31];
16837
17842
  if (stats != null)
16838
17843
  args.push(stats);
16839
17844
  const awf = opts.awaitWriteFinish;
16840
17845
  let pw;
16841
- if (awf && (pw = this._pendingWrites.get(path30))) {
17846
+ if (awf && (pw = this._pendingWrites.get(path31))) {
16842
17847
  pw.lastChange = /* @__PURE__ */ new Date();
16843
17848
  return this;
16844
17849
  }
16845
17850
  if (opts.atomic) {
16846
17851
  if (event === EVENTS.UNLINK) {
16847
- this._pendingUnlinks.set(path30, [event, ...args]);
17852
+ this._pendingUnlinks.set(path31, [event, ...args]);
16848
17853
  setTimeout(() => {
16849
- this._pendingUnlinks.forEach((entry, path31) => {
17854
+ this._pendingUnlinks.forEach((entry, path32) => {
16850
17855
  this.emit(...entry);
16851
17856
  this.emit(EVENTS.ALL, ...entry);
16852
- this._pendingUnlinks.delete(path31);
17857
+ this._pendingUnlinks.delete(path32);
16853
17858
  });
16854
17859
  }, typeof opts.atomic === "number" ? opts.atomic : 100);
16855
17860
  return this;
16856
17861
  }
16857
- if (event === EVENTS.ADD && this._pendingUnlinks.has(path30)) {
17862
+ if (event === EVENTS.ADD && this._pendingUnlinks.has(path31)) {
16858
17863
  event = EVENTS.CHANGE;
16859
- this._pendingUnlinks.delete(path30);
17864
+ this._pendingUnlinks.delete(path31);
16860
17865
  }
16861
17866
  }
16862
17867
  if (awf && (event === EVENTS.ADD || event === EVENTS.CHANGE) && this._readyEmitted) {
@@ -16874,16 +17879,16 @@ var FSWatcher = class extends import_node_events.EventEmitter {
16874
17879
  this.emitWithAll(event, args);
16875
17880
  }
16876
17881
  };
16877
- this._awaitWriteFinish(path30, awf.stabilityThreshold, event, awfEmit);
17882
+ this._awaitWriteFinish(path31, awf.stabilityThreshold, event, awfEmit);
16878
17883
  return this;
16879
17884
  }
16880
17885
  if (event === EVENTS.CHANGE) {
16881
- const isThrottled = !this._throttle(EVENTS.CHANGE, path30, 50);
17886
+ const isThrottled = !this._throttle(EVENTS.CHANGE, path31, 50);
16882
17887
  if (isThrottled)
16883
17888
  return this;
16884
17889
  }
16885
17890
  if (opts.alwaysStat && stats === void 0 && (event === EVENTS.ADD || event === EVENTS.ADD_DIR || event === EVENTS.CHANGE)) {
16886
- const fullPath = opts.cwd ? sp2.join(opts.cwd, path30) : path30;
17891
+ const fullPath = opts.cwd ? sp2.join(opts.cwd, path31) : path31;
16887
17892
  let stats2;
16888
17893
  try {
16889
17894
  stats2 = await (0, import_promises3.stat)(fullPath);
@@ -16914,23 +17919,23 @@ var FSWatcher = class extends import_node_events.EventEmitter {
16914
17919
  * @param timeout duration of time to suppress duplicate actions
16915
17920
  * @returns tracking object or false if action should be suppressed
16916
17921
  */
16917
- _throttle(actionType, path30, timeout) {
17922
+ _throttle(actionType, path31, timeout) {
16918
17923
  if (!this._throttled.has(actionType)) {
16919
17924
  this._throttled.set(actionType, /* @__PURE__ */ new Map());
16920
17925
  }
16921
17926
  const action = this._throttled.get(actionType);
16922
17927
  if (!action)
16923
17928
  throw new Error("invalid throttle");
16924
- const actionPath = action.get(path30);
17929
+ const actionPath = action.get(path31);
16925
17930
  if (actionPath) {
16926
17931
  actionPath.count++;
16927
17932
  return false;
16928
17933
  }
16929
17934
  let timeoutObject;
16930
17935
  const clear = () => {
16931
- const item = action.get(path30);
17936
+ const item = action.get(path31);
16932
17937
  const count = item ? item.count : 0;
16933
- action.delete(path30);
17938
+ action.delete(path31);
16934
17939
  clearTimeout(timeoutObject);
16935
17940
  if (item)
16936
17941
  clearTimeout(item.timeoutObject);
@@ -16938,7 +17943,7 @@ var FSWatcher = class extends import_node_events.EventEmitter {
16938
17943
  };
16939
17944
  timeoutObject = setTimeout(clear, timeout);
16940
17945
  const thr = { timeoutObject, clear, count: 0 };
16941
- action.set(path30, thr);
17946
+ action.set(path31, thr);
16942
17947
  return thr;
16943
17948
  }
16944
17949
  _incrReadyCount() {
@@ -16952,44 +17957,44 @@ var FSWatcher = class extends import_node_events.EventEmitter {
16952
17957
  * @param event
16953
17958
  * @param awfEmit Callback to be called when ready for event to be emitted.
16954
17959
  */
16955
- _awaitWriteFinish(path30, threshold, event, awfEmit) {
17960
+ _awaitWriteFinish(path31, threshold, event, awfEmit) {
16956
17961
  const awf = this.options.awaitWriteFinish;
16957
17962
  if (typeof awf !== "object")
16958
17963
  return;
16959
17964
  const pollInterval = awf.pollInterval;
16960
17965
  let timeoutHandler;
16961
- let fullPath = path30;
16962
- if (this.options.cwd && !sp2.isAbsolute(path30)) {
16963
- fullPath = sp2.join(this.options.cwd, path30);
17966
+ let fullPath = path31;
17967
+ if (this.options.cwd && !sp2.isAbsolute(path31)) {
17968
+ fullPath = sp2.join(this.options.cwd, path31);
16964
17969
  }
16965
17970
  const now2 = /* @__PURE__ */ new Date();
16966
17971
  const writes = this._pendingWrites;
16967
17972
  function awaitWriteFinishFn(prevStat) {
16968
- (0, import_node_fs2.stat)(fullPath, (err, curStat) => {
16969
- if (err || !writes.has(path30)) {
17973
+ (0, import_node_fs3.stat)(fullPath, (err, curStat) => {
17974
+ if (err || !writes.has(path31)) {
16970
17975
  if (err && err.code !== "ENOENT")
16971
17976
  awfEmit(err);
16972
17977
  return;
16973
17978
  }
16974
17979
  const now3 = Number(/* @__PURE__ */ new Date());
16975
17980
  if (prevStat && curStat.size !== prevStat.size) {
16976
- writes.get(path30).lastChange = now3;
17981
+ writes.get(path31).lastChange = now3;
16977
17982
  }
16978
- const pw = writes.get(path30);
17983
+ const pw = writes.get(path31);
16979
17984
  const df = now3 - pw.lastChange;
16980
17985
  if (df >= threshold) {
16981
- writes.delete(path30);
17986
+ writes.delete(path31);
16982
17987
  awfEmit(void 0, curStat);
16983
17988
  } else {
16984
17989
  timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat);
16985
17990
  }
16986
17991
  });
16987
17992
  }
16988
- if (!writes.has(path30)) {
16989
- writes.set(path30, {
17993
+ if (!writes.has(path31)) {
17994
+ writes.set(path31, {
16990
17995
  lastChange: now2,
16991
17996
  cancelWait: () => {
16992
- writes.delete(path30);
17997
+ writes.delete(path31);
16993
17998
  clearTimeout(timeoutHandler);
16994
17999
  return event;
16995
18000
  }
@@ -17000,8 +18005,8 @@ var FSWatcher = class extends import_node_events.EventEmitter {
17000
18005
  /**
17001
18006
  * Determines whether user has asked to ignore this path.
17002
18007
  */
17003
- _isIgnored(path30, stats) {
17004
- if (this.options.atomic && DOT_RE.test(path30))
18008
+ _isIgnored(path31, stats) {
18009
+ if (this.options.atomic && DOT_RE.test(path31))
17005
18010
  return true;
17006
18011
  if (!this._userIgnored) {
17007
18012
  const { cwd } = this.options;
@@ -17011,17 +18016,17 @@ var FSWatcher = class extends import_node_events.EventEmitter {
17011
18016
  const list = [...ignoredPaths.map(normalizeIgnored(cwd)), ...ignored];
17012
18017
  this._userIgnored = anymatch(list, void 0);
17013
18018
  }
17014
- return this._userIgnored(path30, stats);
18019
+ return this._userIgnored(path31, stats);
17015
18020
  }
17016
- _isntIgnored(path30, stat5) {
17017
- return !this._isIgnored(path30, stat5);
18021
+ _isntIgnored(path31, stat5) {
18022
+ return !this._isIgnored(path31, stat5);
17018
18023
  }
17019
18024
  /**
17020
18025
  * Provides a set of common helpers and properties relating to symlink handling.
17021
18026
  * @param path file or directory pattern being watched
17022
18027
  */
17023
- _getWatchHelpers(path30) {
17024
- return new WatchHelper(path30, this.options.followSymlinks, this);
18028
+ _getWatchHelpers(path31) {
18029
+ return new WatchHelper(path31, this.options.followSymlinks, this);
17025
18030
  }
17026
18031
  // Directory helpers
17027
18032
  // -----------------
@@ -17053,63 +18058,63 @@ var FSWatcher = class extends import_node_events.EventEmitter {
17053
18058
  * @param item base path of item/directory
17054
18059
  */
17055
18060
  _remove(directory, item, isDirectory) {
17056
- const path30 = sp2.join(directory, item);
17057
- const fullPath = sp2.resolve(path30);
17058
- isDirectory = isDirectory != null ? isDirectory : this._watched.has(path30) || this._watched.has(fullPath);
17059
- if (!this._throttle("remove", path30, 100))
18061
+ const path31 = sp2.join(directory, item);
18062
+ const fullPath = sp2.resolve(path31);
18063
+ isDirectory = isDirectory != null ? isDirectory : this._watched.has(path31) || this._watched.has(fullPath);
18064
+ if (!this._throttle("remove", path31, 100))
17060
18065
  return;
17061
18066
  if (!isDirectory && this._watched.size === 1) {
17062
18067
  this.add(directory, item, true);
17063
18068
  }
17064
- const wp = this._getWatchedDir(path30);
18069
+ const wp = this._getWatchedDir(path31);
17065
18070
  const nestedDirectoryChildren = wp.getChildren();
17066
- nestedDirectoryChildren.forEach((nested) => this._remove(path30, nested));
18071
+ nestedDirectoryChildren.forEach((nested) => this._remove(path31, nested));
17067
18072
  const parent = this._getWatchedDir(directory);
17068
18073
  const wasTracked = parent.has(item);
17069
18074
  parent.remove(item);
17070
18075
  if (this._symlinkPaths.has(fullPath)) {
17071
18076
  this._symlinkPaths.delete(fullPath);
17072
18077
  }
17073
- let relPath = path30;
18078
+ let relPath = path31;
17074
18079
  if (this.options.cwd)
17075
- relPath = sp2.relative(this.options.cwd, path30);
18080
+ relPath = sp2.relative(this.options.cwd, path31);
17076
18081
  if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
17077
18082
  const event = this._pendingWrites.get(relPath).cancelWait();
17078
18083
  if (event === EVENTS.ADD)
17079
18084
  return;
17080
18085
  }
17081
- this._watched.delete(path30);
18086
+ this._watched.delete(path31);
17082
18087
  this._watched.delete(fullPath);
17083
18088
  const eventName = isDirectory ? EVENTS.UNLINK_DIR : EVENTS.UNLINK;
17084
- if (wasTracked && !this._isIgnored(path30))
17085
- this._emit(eventName, path30);
17086
- this._closePath(path30);
18089
+ if (wasTracked && !this._isIgnored(path31))
18090
+ this._emit(eventName, path31);
18091
+ this._closePath(path31);
17087
18092
  }
17088
18093
  /**
17089
18094
  * Closes all watchers for a path
17090
18095
  */
17091
- _closePath(path30) {
17092
- this._closeFile(path30);
17093
- const dir = sp2.dirname(path30);
17094
- this._getWatchedDir(dir).remove(sp2.basename(path30));
18096
+ _closePath(path31) {
18097
+ this._closeFile(path31);
18098
+ const dir = sp2.dirname(path31);
18099
+ this._getWatchedDir(dir).remove(sp2.basename(path31));
17095
18100
  }
17096
18101
  /**
17097
18102
  * Closes only file-specific watchers
17098
18103
  */
17099
- _closeFile(path30) {
17100
- const closers = this._closers.get(path30);
18104
+ _closeFile(path31) {
18105
+ const closers = this._closers.get(path31);
17101
18106
  if (!closers)
17102
18107
  return;
17103
18108
  closers.forEach((closer) => closer());
17104
- this._closers.delete(path30);
18109
+ this._closers.delete(path31);
17105
18110
  }
17106
- _addPathCloser(path30, closer) {
18111
+ _addPathCloser(path31, closer) {
17107
18112
  if (!closer)
17108
18113
  return;
17109
- let list = this._closers.get(path30);
18114
+ let list = this._closers.get(path31);
17110
18115
  if (!list) {
17111
18116
  list = [];
17112
- this._closers.set(path30, list);
18117
+ this._closers.set(path31, list);
17113
18118
  }
17114
18119
  list.push(closer);
17115
18120
  }
@@ -17139,11 +18144,11 @@ function watch(paths, options = {}) {
17139
18144
  var chokidar_default = { watch, FSWatcher };
17140
18145
 
17141
18146
  // src/watcher/file-watcher.ts
17142
- var path23 = __toESM(require("path"), 1);
18147
+ var path24 = __toESM(require("path"), 1);
17143
18148
 
17144
18149
  // src/watcher/native-recursive-watcher.ts
17145
- var import_node_fs3 = require("fs");
17146
- var path21 = __toESM(require("path"), 1);
18150
+ var import_node_fs4 = require("fs");
18151
+ var path22 = __toESM(require("path"), 1);
17147
18152
  var NativeRecursiveWatcher = class {
17148
18153
  constructor(root, onChange, options = {}) {
17149
18154
  this.root = root;
@@ -17191,26 +18196,26 @@ var NativeRecursiveWatcher = class {
17191
18196
  toAbsolutePath(filename) {
17192
18197
  if (filename == null) return null;
17193
18198
  const normalizedFilename = typeof filename === "string" ? filename : filename.toString();
17194
- const absolutePath = path21.resolve(this.root, normalizedFilename);
17195
- const relativePath = path21.relative(this.root, absolutePath);
17196
- const outsideRoot = relativePath === ".." || relativePath.startsWith(`..${path21.sep}`) || path21.isAbsolute(relativePath);
18199
+ const absolutePath = path22.resolve(this.root, normalizedFilename);
18200
+ const relativePath = path22.relative(this.root, absolutePath);
18201
+ const outsideRoot = relativePath === ".." || relativePath.startsWith(`..${path22.sep}`) || path22.isAbsolute(relativePath);
17197
18202
  return outsideRoot ? null : absolutePath;
17198
18203
  }
17199
- defaultWatchFactory = (root, listener, options) => (0, import_node_fs3.watch)(root, options, listener);
18204
+ defaultWatchFactory = (root, listener, options) => (0, import_node_fs4.watch)(root, options, listener);
17200
18205
  };
17201
18206
 
17202
18207
  // src/watcher/snapshot.ts
17203
18208
  var fsPromises4 = __toESM(require("fs/promises"), 1);
17204
- var path22 = __toESM(require("path"), 1);
18209
+ var path23 = __toESM(require("path"), 1);
17205
18210
  async function buildFileSnapshotScan(projectRoot, config, configPaths = []) {
17206
- const normalizedProjectRoot = path22.resolve(projectRoot);
18211
+ const normalizedProjectRoot = path23.resolve(projectRoot);
17207
18212
  const ignoreFilter = createIgnoreFilter(normalizedProjectRoot);
17208
18213
  const includePatterns = [...config.include, ...config.additionalInclude ?? []];
17209
18214
  const maxDepth = config.indexing?.maxDepth ?? -1;
17210
18215
  const snapshot = /* @__PURE__ */ new Map();
17211
18216
  const unreadablePrefixes = /* @__PURE__ */ new Set();
17212
18217
  const includeFile = async (filePath) => {
17213
- const normalizedPath2 = path22.resolve(filePath);
18218
+ const normalizedPath2 = path23.resolve(filePath);
17214
18219
  if (!shouldIncludeFile(normalizedPath2, normalizedProjectRoot, includePatterns, config.exclude, ignoreFilter)) return;
17215
18220
  const stat5 = await readStatIfFile(normalizedPath2, unreadablePrefixes);
17216
18221
  if (stat5) snapshot.set(normalizedPath2, { size: stat5.size, mtimeMs: stat5.mtimeMs });
@@ -17222,16 +18227,16 @@ async function buildFileSnapshotScan(projectRoot, config, configPaths = []) {
17222
18227
  } catch (error) {
17223
18228
  if (isMissingFsError(error)) return;
17224
18229
  if (isPermissionFsError(error)) {
17225
- unreadablePrefixes.add(path22.resolve(directoryPath));
18230
+ unreadablePrefixes.add(path23.resolve(directoryPath));
17226
18231
  return;
17227
18232
  }
17228
18233
  throw error;
17229
18234
  }
17230
18235
  for (const entry of entries) {
17231
- const fullPath = path22.join(directoryPath, entry.name);
17232
- const relativePath = path22.relative(normalizedProjectRoot, fullPath);
18236
+ const fullPath = path23.join(directoryPath, entry.name);
18237
+ const relativePath = path23.relative(normalizedProjectRoot, fullPath);
17233
18238
  if (entry.isDirectory()) {
17234
- if (hasFilteredPathSegment(relativePath, path22.sep) || isRestrictedDirectory(relativePath, path22.sep)) continue;
18239
+ if (hasFilteredPathSegment(relativePath, path23.sep) || isRestrictedDirectory(relativePath, path23.sep)) continue;
17235
18240
  if (ignoreFilter.ignores(relativePath)) continue;
17236
18241
  if (maxDepth === -1 || depth < maxDepth) await walk(fullPath, depth + 1);
17237
18242
  } else if (entry.isFile()) {
@@ -17244,19 +18249,19 @@ async function buildFileSnapshotScan(projectRoot, config, configPaths = []) {
17244
18249
  return { entries: snapshot, unreadablePrefixes };
17245
18250
  }
17246
18251
  async function buildFileSnapshotForPathScan(projectRoot, config, configPaths, targetPath) {
17247
- const normalizedProjectRoot = path22.resolve(projectRoot);
17248
- const normalizedTargetPath = path22.resolve(targetPath);
18252
+ const normalizedProjectRoot = path23.resolve(projectRoot);
18253
+ const normalizedTargetPath = path23.resolve(targetPath);
17249
18254
  if (!isWithinPath(normalizedProjectRoot, normalizedTargetPath)) {
17250
18255
  return { entries: /* @__PURE__ */ new Map(), unreadablePrefixes: /* @__PURE__ */ new Set() };
17251
18256
  }
17252
18257
  const ignoreFilter = createIgnoreFilter(normalizedProjectRoot);
17253
18258
  const includePatterns = [...config.include, ...config.additionalInclude ?? []];
17254
18259
  const maxDepth = config.indexing?.maxDepth ?? -1;
17255
- const explicitConfigPaths = new Set(configPaths.map((configPath) => path22.resolve(configPath)));
18260
+ const explicitConfigPaths = new Set(configPaths.map((configPath) => path23.resolve(configPath)));
17256
18261
  const snapshot = /* @__PURE__ */ new Map();
17257
18262
  const unreadablePrefixes = /* @__PURE__ */ new Set();
17258
18263
  const includeFile = async (filePath) => {
17259
- const normalizedPath2 = path22.resolve(filePath);
18264
+ const normalizedPath2 = path23.resolve(filePath);
17260
18265
  if (!explicitConfigPaths.has(normalizedPath2) && !shouldIncludeFile(
17261
18266
  normalizedPath2,
17262
18267
  normalizedProjectRoot,
@@ -17274,16 +18279,16 @@ async function buildFileSnapshotForPathScan(projectRoot, config, configPaths, ta
17274
18279
  } catch (error) {
17275
18280
  if (isMissingFsError(error)) return;
17276
18281
  if (isPermissionFsError(error)) {
17277
- unreadablePrefixes.add(path22.resolve(directoryPath));
18282
+ unreadablePrefixes.add(path23.resolve(directoryPath));
17278
18283
  return;
17279
18284
  }
17280
18285
  throw error;
17281
18286
  }
17282
18287
  for (const entry of entries) {
17283
- const fullPath = path22.join(directoryPath, entry.name);
17284
- const relativePath = path22.relative(normalizedProjectRoot, fullPath);
18288
+ const fullPath = path23.join(directoryPath, entry.name);
18289
+ const relativePath = path23.relative(normalizedProjectRoot, fullPath);
17285
18290
  if (entry.isDirectory()) {
17286
- if (hasFilteredPathSegment(relativePath, path22.sep) || isRestrictedDirectory(relativePath, path22.sep)) continue;
18291
+ if (hasFilteredPathSegment(relativePath, path23.sep) || isRestrictedDirectory(relativePath, path23.sep)) continue;
17287
18292
  if (ignoreFilter.ignores(relativePath)) continue;
17288
18293
  if (maxDepth === -1 || depth < maxDepth) await walk(fullPath, depth + 1);
17289
18294
  } else if (entry.isFile()) {
@@ -17307,7 +18312,7 @@ function completeFileSnapshot(previous, scan) {
17307
18312
  return completed;
17308
18313
  }
17309
18314
  async function includeExplicitConfigPaths(snapshot, unreadablePrefixes, configPaths) {
17310
- for (const configPath of [...new Set(configPaths.map((value) => path22.resolve(value)))]) {
18315
+ for (const configPath of [...new Set(configPaths.map((value) => path23.resolve(value)))]) {
17311
18316
  if (snapshot.has(configPath)) continue;
17312
18317
  const stat5 = await readStatIfFile(configPath, unreadablePrefixes);
17313
18318
  if (stat5) snapshot.set(configPath, { size: stat5.size, mtimeMs: stat5.mtimeMs });
@@ -17317,12 +18322,12 @@ async function includeExplicitConfigPathsInPath(snapshot, unreadablePrefixes, co
17317
18322
  await includeExplicitConfigPaths(
17318
18323
  snapshot,
17319
18324
  unreadablePrefixes,
17320
- configPaths.filter((configPath) => isWithinPath(targetPath, path22.resolve(configPath)))
18325
+ configPaths.filter((configPath) => isWithinPath(targetPath, path23.resolve(configPath)))
17321
18326
  );
17322
18327
  }
17323
18328
  function isWithinPath(parentPath, childPath) {
17324
- const relativePath = path22.relative(parentPath, childPath);
17325
- return relativePath === "" || !relativePath.startsWith(`..${path22.sep}`) && relativePath !== ".." && !path22.isAbsolute(relativePath);
18329
+ const relativePath = path23.relative(parentPath, childPath);
18330
+ return relativePath === "" || !relativePath.startsWith(`..${path23.sep}`) && relativePath !== ".." && !path23.isAbsolute(relativePath);
17326
18331
  }
17327
18332
  async function readStatIfFile(filePath, unreadablePrefixes) {
17328
18333
  try {
@@ -17331,7 +18336,7 @@ async function readStatIfFile(filePath, unreadablePrefixes) {
17331
18336
  } catch (error) {
17332
18337
  if (isMissingFsError(error)) return null;
17333
18338
  if (isPermissionFsError(error)) {
17334
- unreadablePrefixes.add(path22.resolve(filePath));
18339
+ unreadablePrefixes.add(path23.resolve(filePath));
17335
18340
  return null;
17336
18341
  }
17337
18342
  throw error;
@@ -17468,8 +18473,8 @@ var FileWatcher = class {
17468
18473
  this.createWatcher();
17469
18474
  }
17470
18475
  resetReady() {
17471
- this.readyPromise = new Promise((resolve17) => {
17472
- this.resolveReady = resolve17;
18476
+ this.readyPromise = new Promise((resolve18) => {
18477
+ this.resolveReady = resolve18;
17473
18478
  });
17474
18479
  this.startupReadySignals = 1;
17475
18480
  }
@@ -17500,7 +18505,7 @@ var FileWatcher = class {
17500
18505
  const resolvedWatchTargets = watchTargets ?? this.getFullChokidarWatchTargets();
17501
18506
  const watcherOptions = {
17502
18507
  ignored: (filePath) => {
17503
- const relativePath = path23.relative(this.projectRoot, filePath);
18508
+ const relativePath = path24.relative(this.projectRoot, filePath);
17504
18509
  if (!relativePath) return false;
17505
18510
  if (this.isProjectConfigPathOrAncestor(relativePath)) {
17506
18511
  return false;
@@ -17508,10 +18513,10 @@ var FileWatcher = class {
17508
18513
  if (this.isOutsideProjectPath(relativePath)) {
17509
18514
  return true;
17510
18515
  }
17511
- if (hasFilteredPathSegment(relativePath, path23.sep)) {
18516
+ if (hasFilteredPathSegment(relativePath, path24.sep)) {
17512
18517
  return true;
17513
18518
  }
17514
- if (isRestrictedDirectory(relativePath, path23.sep)) {
18519
+ if (isRestrictedDirectory(relativePath, path24.sep)) {
17515
18520
  return true;
17516
18521
  }
17517
18522
  if (ignoreFilter.ignores(relativePath)) {
@@ -17602,13 +18607,13 @@ var FileWatcher = class {
17602
18607
  getExternalConfigWatchTargets() {
17603
18608
  return [...new Set(
17604
18609
  this.projectConfigPaths.filter((projectConfigPath) => {
17605
- const relativeConfigPath = path23.relative(this.projectRoot, projectConfigPath);
18610
+ const relativeConfigPath = path24.relative(this.projectRoot, projectConfigPath);
17606
18611
  return this.isOutsideProjectPath(relativeConfigPath);
17607
18612
  }).map((projectConfigPath) => {
17608
18613
  if ((0, import_fs14.existsSync)(projectConfigPath)) {
17609
18614
  return projectConfigPath;
17610
18615
  }
17611
- return this.getNearestExistingDirectory(path23.dirname(projectConfigPath));
18616
+ return this.getNearestExistingDirectory(path24.dirname(projectConfigPath));
17612
18617
  })
17613
18618
  )];
17614
18619
  }
@@ -17670,7 +18675,7 @@ var FileWatcher = class {
17670
18675
  }
17671
18676
  scheduleNativeReconciliation(generation, filePath) {
17672
18677
  if (!this.isCurrentNativeSetup(generation)) return;
17673
- const requiresFullReconciliation = filePath === path23.join(this.projectRoot, ".gitignore");
18678
+ const requiresFullReconciliation = filePath === path24.join(this.projectRoot, ".gitignore");
17674
18679
  const invalidatedPath = requiresFullReconciliation ? null : filePath;
17675
18680
  this.nativeInvalidatedPaths.set(invalidatedPath, invalidatedPath !== null);
17676
18681
  if (this.nativeReconcileTimer) {
@@ -17765,23 +18770,23 @@ var FileWatcher = class {
17765
18770
  this.scheduleFlush();
17766
18771
  }
17767
18772
  isProjectConfigPath(filePath) {
17768
- const relativePath = path23.relative(this.projectRoot, filePath);
17769
- const normalizedRelativePath = path23.normalize(relativePath);
18773
+ const relativePath = path24.relative(this.projectRoot, filePath);
18774
+ const normalizedRelativePath = path24.normalize(relativePath);
17770
18775
  return this.getProjectConfigRelativePaths().some((configPath) => configPath === normalizedRelativePath);
17771
18776
  }
17772
18777
  isProjectConfigPathOrAncestor(relativePath) {
17773
- const normalizedRelativePath = path23.normalize(relativePath);
18778
+ const normalizedRelativePath = path24.normalize(relativePath);
17774
18779
  return this.getProjectConfigRelativePaths().some(
17775
- (configPath) => configPath === normalizedRelativePath || configPath.startsWith(`${normalizedRelativePath}${path23.sep}`)
18780
+ (configPath) => configPath === normalizedRelativePath || configPath.startsWith(`${normalizedRelativePath}${path24.sep}`)
17776
18781
  );
17777
18782
  }
17778
18783
  isOutsideProjectPath(relativePath) {
17779
- return relativePath === ".." || relativePath.startsWith(`..${path23.sep}`) || path23.isAbsolute(relativePath);
18784
+ return relativePath === ".." || relativePath.startsWith(`..${path24.sep}`) || path24.isAbsolute(relativePath);
17780
18785
  }
17781
18786
  getNearestExistingDirectory(directoryPath) {
17782
18787
  let candidate = directoryPath;
17783
18788
  while (!(0, import_fs14.existsSync)(candidate)) {
17784
- const parent = path23.dirname(candidate);
18789
+ const parent = path24.dirname(candidate);
17785
18790
  if (parent === candidate) break;
17786
18791
  candidate = parent;
17787
18792
  }
@@ -17789,7 +18794,7 @@ var FileWatcher = class {
17789
18794
  }
17790
18795
  getProjectConfigRelativePaths() {
17791
18796
  return this.projectConfigPaths.map(
17792
- (configPath) => path23.normalize(path23.relative(this.projectRoot, configPath))
18797
+ (configPath) => path24.normalize(path24.relative(this.projectRoot, configPath))
17793
18798
  );
17794
18799
  }
17795
18800
  getConfigPathStates() {
@@ -17847,7 +18852,7 @@ var FileWatcher = class {
17847
18852
  return;
17848
18853
  }
17849
18854
  const changes = Array.from(this.pendingChanges.entries()).map(
17850
- ([path30, type]) => ({ path: path30, type })
18855
+ ([path31, type]) => ({ path: path31, type })
17851
18856
  );
17852
18857
  this.pendingChanges.clear();
17853
18858
  try {
@@ -17893,7 +18898,7 @@ var FileWatcher = class {
17893
18898
  };
17894
18899
 
17895
18900
  // src/watcher/git-head-watcher.ts
17896
- var path24 = __toESM(require("path"), 1);
18901
+ var path25 = __toESM(require("path"), 1);
17897
18902
  var GitHeadWatcher = class {
17898
18903
  watcher = null;
17899
18904
  projectRoot;
@@ -17915,13 +18920,13 @@ var GitHeadWatcher = class {
17915
18920
  this.readyPromise = Promise.resolve();
17916
18921
  return;
17917
18922
  }
17918
- this.readyPromise = new Promise((resolve17) => {
17919
- this.resolveReady = resolve17;
18923
+ this.readyPromise = new Promise((resolve18) => {
18924
+ this.resolveReady = resolve18;
17920
18925
  });
17921
18926
  this.onBranchChange = handler;
17922
18927
  this.currentBranch = getCurrentBranch(this.projectRoot);
17923
18928
  const headPath = getHeadPath(this.projectRoot);
17924
- const refsPath = path24.join(this.projectRoot, ".git", "refs", "heads");
18929
+ const refsPath = path25.join(this.projectRoot, ".git", "refs", "heads");
17925
18930
  this.watcher = chokidar_default.watch([headPath, refsPath], {
17926
18931
  persistent: true,
17927
18932
  ignoreInitial: true,
@@ -17989,7 +18994,9 @@ var GitHeadWatcher = class {
17989
18994
  function createWatcherWithIndexer(getIndexer, projectRoot, config, host, options = {}) {
17990
18995
  const fileWatcher = new FileWatcher(projectRoot, config, host, options);
17991
18996
  const configPaths = getConfigPaths(projectRoot, host, options);
17992
- configureAutoIndex(projectRoot, host, parseConfig(config), getIndexer);
18997
+ configureAutoIndex(projectRoot, host, parseConfig(config), getIndexer, {
18998
+ synchronizeBackgroundWorker: false
18999
+ });
17993
19000
  let stopped = false;
17994
19001
  const requestReindex = () => {
17995
19002
  if (stopped) return;
@@ -18009,7 +19016,9 @@ function createWatcherWithIndexer(getIndexer, projectRoot, config, host, options
18009
19016
  const parsedConfig = options.configPath ? parseConfig(loadConfigFile(options.configPath)) : void 0;
18010
19017
  const refreshedConfig = refreshIndexerForDirectory(projectRoot, host, parsedConfig);
18011
19018
  if (refreshedConfig) {
18012
- configureAutoIndex(projectRoot, host, refreshedConfig, getIndexer);
19019
+ configureAutoIndex(projectRoot, host, refreshedConfig, getIndexer, {
19020
+ synchronizeBackgroundWorker: false
19021
+ });
18013
19022
  }
18014
19023
  }
18015
19024
  requestReindex();
@@ -18785,7 +19794,7 @@ async function resolveCodebaseContextUnmeasured(projectRoot, host, input) {
18785
19794
  const directory = input.directory ?? void 0;
18786
19795
  const tokenBudget = input.tokenBudget ?? void 0;
18787
19796
  if (from && to) {
18788
- const path30 = await getCallGraphPath(
19797
+ const path31 = await getCallGraphPath(
18789
19798
  projectRoot,
18790
19799
  host,
18791
19800
  from,
@@ -18794,25 +19803,25 @@ async function resolveCodebaseContextUnmeasured(projectRoot, host, input) {
18794
19803
  fromFilePath,
18795
19804
  toFilePath
18796
19805
  );
18797
- const pathText = formatCallGraphPathResult(path30);
18798
- if (path30.path.length > 0) {
19806
+ const pathText = formatCallGraphPathResult(path31);
19807
+ if (path31.path.length > 0) {
18799
19808
  const fitted2 = fitTextToContextBudget(
18800
19809
  pathText,
18801
19810
  tokenBudget
18802
19811
  );
18803
19812
  return {
18804
19813
  text: fitted2.text,
18805
- details: fittedDetails("path", fitted2, path30.path.length)
19814
+ details: fittedDetails("path", fitted2, path31.path.length)
18806
19815
  };
18807
19816
  }
18808
- if (path30.from.status !== "resolved" || path30.to.status !== "resolved") {
19817
+ if (path31.from.status !== "resolved" || path31.to.status !== "resolved") {
18809
19818
  const fitted2 = fitTextToContextBudget(pathText, tokenBudget);
18810
19819
  return {
18811
19820
  text: fitted2.text,
18812
19821
  details: fittedDetails("path", fitted2, 0)
18813
19822
  };
18814
19823
  }
18815
- const resolvedFrom = path30.from;
19824
+ const resolvedFrom = path31.from;
18816
19825
  const { callers } = await getCallGraphData(projectRoot, host, {
18817
19826
  name: to,
18818
19827
  direction: "callers",
@@ -18973,7 +19982,7 @@ async function executeCallGraph(projectRoot, host, args) {
18973
19982
  return { text: formatCallGraphResult(await getCallGraphData(projectRoot, host, args)) };
18974
19983
  }
18975
19984
  async function executeCallGraphPath(projectRoot, host, args) {
18976
- const path30 = await getCallGraphPath(
19985
+ const path31 = await getCallGraphPath(
18977
19986
  projectRoot,
18978
19987
  host,
18979
19988
  args.from,
@@ -18982,7 +19991,7 @@ async function executeCallGraphPath(projectRoot, host, args) {
18982
19991
  args.fromFilePath,
18983
19992
  args.toFilePath
18984
19993
  );
18985
- return { text: formatCallGraphPathResult(path30) };
19994
+ return { text: formatCallGraphPathResult(path31) };
18986
19995
  }
18987
19996
  async function executeCodeCommunities(projectRoot, host, args) {
18988
19997
  const result = await getCodeCommunities(projectRoot, host, args);
@@ -18991,12 +20000,12 @@ async function executeCodeCommunities(projectRoot, host, args) {
18991
20000
 
18992
20001
  // src/adapters/opencode/tools.ts
18993
20002
  var import_fs15 = require("fs");
18994
- var os7 = __toESM(require("os"), 1);
18995
- var path27 = __toESM(require("path"), 1);
20003
+ var os8 = __toESM(require("os"), 1);
20004
+ var path28 = __toESM(require("path"), 1);
18996
20005
 
18997
20006
  // src/tools/visualize/activity.ts
18998
20007
  var import_child_process5 = require("child_process");
18999
- var path25 = __toESM(require("path"), 1);
20008
+ var path26 = __toESM(require("path"), 1);
19000
20009
  function attachRecentActivity(data, projectRoot) {
19001
20010
  const activity = readGitActivity(projectRoot);
19002
20011
  const changes = activity.size > 0 ? buildGitChanges(data, activity, projectRoot) : buildGraphChanges(data);
@@ -19158,7 +20167,7 @@ function normalizePath3(filePath) {
19158
20167
  return filePath.replace(/\\/g, "/");
19159
20168
  }
19160
20169
  function toGitRelativePath(projectRoot, filePath) {
19161
- const relativePath = path25.isAbsolute(filePath) ? path25.relative(projectRoot, filePath) : filePath;
20170
+ const relativePath = path26.isAbsolute(filePath) ? path26.relative(projectRoot, filePath) : filePath;
19162
20171
  return normalizePath3(relativePath);
19163
20172
  }
19164
20173
 
@@ -19416,7 +20425,7 @@ render();
19416
20425
  }
19417
20426
 
19418
20427
  // src/tools/visualize/transform.ts
19419
- var path26 = __toESM(require("path"), 1);
20428
+ var path27 = __toESM(require("path"), 1);
19420
20429
 
19421
20430
  // src/tools/visualize/modules.ts
19422
20431
  var MAX_MODULES = 18;
@@ -19676,7 +20685,7 @@ function transformForVisualization(symbols, edges, options = {}) {
19676
20685
  filePath: s.filePath,
19677
20686
  kind: s.kind,
19678
20687
  line: s.startLine,
19679
- directory: path26.dirname(s.filePath),
20688
+ directory: path27.dirname(s.filePath),
19680
20689
  moduleId: "",
19681
20690
  moduleLabel: ""
19682
20691
  }));
@@ -20005,7 +21014,7 @@ var index_visualize = tool({
20005
21014
  return "No connected symbols found for visualization. Try including orphans with includeOrphans=true, or check that the call graph has resolved edges.";
20006
21015
  }
20007
21016
  const html = generateVisualizationHtml(vizData);
20008
- const outputPath = path27.join(os7.tmpdir(), `call-graph-${Date.now()}.html`);
21017
+ const outputPath = path28.join(os8.tmpdir(), `call-graph-${Date.now()}.html`);
20009
21018
  (0, import_fs15.writeFileSync)(outputPath, html, "utf-8");
20010
21019
  let result = `Temporal call graph visualization generated: ${outputPath}
20011
21020
 
@@ -20118,7 +21127,7 @@ var MCP_TOOL_NAMES = [
20118
21127
 
20119
21128
  // src/commands/loader.ts
20120
21129
  var import_fs16 = require("fs");
20121
- var path28 = __toESM(require("path"), 1);
21130
+ var path29 = __toESM(require("path"), 1);
20122
21131
  function parseFrontmatter(content) {
20123
21132
  const frontmatterRegex = /^---\s*\n([\s\S]*?)\n---\s*\n([\s\S]*)$/;
20124
21133
  const match = content.match(frontmatterRegex);
@@ -20144,7 +21153,7 @@ function loadCommandsFromDirectory(commandsDir) {
20144
21153
  }
20145
21154
  const files = (0, import_fs16.readdirSync)(commandsDir).filter((f) => f.endsWith(".md"));
20146
21155
  for (const file of files) {
20147
- const filePath = path28.join(commandsDir, file);
21156
+ const filePath = path29.join(commandsDir, file);
20148
21157
  let content;
20149
21158
  try {
20150
21159
  content = (0, import_fs16.readFileSync)(filePath, "utf-8");
@@ -20153,7 +21162,7 @@ function loadCommandsFromDirectory(commandsDir) {
20153
21162
  throw new Error(`Failed to load command file ${filePath}: ${message}`);
20154
21163
  }
20155
21164
  const { frontmatter, body } = parseFrontmatter(content);
20156
- const name = path28.basename(file, ".md");
21165
+ const name = path29.basename(file, ".md");
20157
21166
  const description = frontmatter.description || `Run the ${name} command`;
20158
21167
  commands.set(name, {
20159
21168
  description,
@@ -20489,42 +21498,13 @@ var RoutingHintController = class {
20489
21498
 
20490
21499
  // src/adapters/opencode.ts
20491
21500
  var import_meta2 = {};
20492
- var activeWatchers = /* @__PURE__ */ new Map();
20493
- var watcherReplacementChains = /* @__PURE__ */ new Map();
20494
- async function replaceActiveWatcher(projectRoot, createNextWatcher) {
20495
- const chain = (watcherReplacementChains.get(projectRoot) ?? Promise.resolve()).catch(() => void 0).then(async () => {
20496
- const existing = activeWatchers.get(projectRoot);
20497
- if (existing) {
20498
- try {
20499
- await existing.stop();
20500
- } catch (error) {
20501
- console.error("[codebase-index] Failed to stop replaced watcher:", error);
20502
- throw error;
20503
- }
20504
- if (activeWatchers.get(projectRoot) === existing) {
20505
- activeWatchers.delete(projectRoot);
20506
- }
20507
- }
20508
- if (createNextWatcher) {
20509
- activeWatchers.set(projectRoot, createNextWatcher());
20510
- }
20511
- });
20512
- watcherReplacementChains.set(projectRoot, chain);
20513
- try {
20514
- await chain;
20515
- } finally {
20516
- if (watcherReplacementChains.get(projectRoot) === chain) {
20517
- watcherReplacementChains.delete(projectRoot);
20518
- }
20519
- }
20520
- }
20521
21501
  function getCommandsDir() {
20522
21502
  let currentDir = process.cwd();
20523
21503
  if (typeof import_meta2 !== "undefined" && import_meta2.url) {
20524
- currentDir = path29.dirname((0, import_url.fileURLToPath)(import_meta2.url));
21504
+ currentDir = path30.dirname((0, import_url.fileURLToPath)(import_meta2.url));
20525
21505
  }
20526
- const packageRoot = path29.basename(currentDir) === "adapters" ? path29.join(currentDir, "..", "..") : path29.join(currentDir, "..");
20527
- return path29.join(packageRoot, "commands");
21506
+ const packageRoot = path30.basename(currentDir) === "adapters" ? path30.join(currentDir, "..", "..") : path30.join(currentDir, "..");
21507
+ return path30.join(packageRoot, "commands");
20528
21508
  }
20529
21509
  function appendRoutingHints(output, hints, preferredRole) {
20530
21510
  const preferredBucket = preferredRole === "developer" ? output.developer : output.system;
@@ -20550,8 +21530,9 @@ var plugin = async ({ directory, worktree }) => {
20550
21530
  initializeTools2(projectRoot, config);
20551
21531
  const getProjectIndexer = () => getIndexerForProject2(projectRoot);
20552
21532
  const routingHints = config.search.routingHints ? new RoutingHintController(() => getProjectIndexer().getStatus(), 200, config.search.routingGraphHandoffHints) : null;
20553
- const isHomeDir = isHomeDirectory(projectRoot);
20554
- const isValidProject = !isHomeDir && (!config.indexing.requireProjectMarker || hasProjectMarker(projectRoot));
21533
+ const projectSafety = getProjectSafety(projectRoot, config);
21534
+ const isHomeDir = projectSafety.blockedReason === "home-directory";
21535
+ const isValidProject = projectSafety.safeToRun;
20555
21536
  if (isHomeDir) {
20556
21537
  console.warn(
20557
21538
  `[codebase-index] Refusing to watch or index home directory "${projectRoot}". Open a specific project directory instead.`
@@ -20561,16 +21542,24 @@ var plugin = async ({ directory, worktree }) => {
20561
21542
  `[codebase-index] Skipping file watching and auto-indexing: no project marker found in "${projectRoot}". Set "indexing.requireProjectMarker": false in config to override.`
20562
21543
  );
20563
21544
  }
20564
- if (config.indexing.autoIndex && isValidProject) {
20565
- startAutoIndex(projectRoot, "opencode", "startup");
20566
- }
20567
- if (config.indexing.watchFiles && isValidProject) {
20568
- await replaceActiveWatcher(
20569
- projectRoot,
20570
- () => createWatcherWithIndexer(getProjectIndexer, projectRoot, config, "opencode")
20571
- );
21545
+ if (!isValidProject) {
21546
+ await stopBackgroundWorker(projectRoot, "opencode").catch((error) => {
21547
+ console.error("[codebase-index] Failed to stop unsafe OpenCode background worker:", error);
21548
+ });
20572
21549
  } else {
20573
- await replaceActiveWatcher(projectRoot, null);
21550
+ const watcherFactoryForConfig = (refreshedConfig) => refreshedConfig.indexing.watchFiles ? () => createWatcherWithIndexer(getProjectIndexer, projectRoot, refreshedConfig, "opencode") : null;
21551
+ configureBackgroundWorker(projectRoot, "opencode", config, {
21552
+ startAutoIndex: (source, allowDisabledAutoIndex) => {
21553
+ startAutoIndexForBackgroundWorker(projectRoot, "opencode", source, allowDisabledAutoIndex);
21554
+ },
21555
+ stopAutoIndex: () => stopAutoIndexForBackgroundWorker(projectRoot, "opencode"),
21556
+ watcherFactory: watcherFactoryForConfig(config),
21557
+ watcherFactoryForConfig,
21558
+ replaceWatcher: true
21559
+ }, {
21560
+ restartAutoIndex: true
21561
+ });
21562
+ await waitForBackgroundWorkerStart(projectRoot, "opencode");
20574
21563
  }
20575
21564
  return {
20576
21565
  tool: {