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.
@@ -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(path25, checkUnignored, mode) {
336
+ test(path26, 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(path25);
345
+ const matched = rule[mode].test(path26);
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 = (path25, originalPath, doThrow) => {
367
- if (!isString(path25)) {
366
+ var checkPath = (path26, originalPath, doThrow) => {
367
+ if (!isString(path26)) {
368
368
  return doThrow(
369
369
  `path must be a string, but got \`${originalPath}\``,
370
370
  TypeError
371
371
  );
372
372
  }
373
- if (!path25) {
373
+ if (!path26) {
374
374
  return doThrow(`path must not be empty`, TypeError);
375
375
  }
376
- if (checkPath.isNotRelative(path25)) {
376
+ if (checkPath.isNotRelative(path26)) {
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 = (path25) => REGEX_TEST_INVALID_PATH.test(path25);
385
+ var isNotRelative = (path26) => REGEX_TEST_INVALID_PATH.test(path26);
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 path25 = originalPath && checkPath.convert(originalPath);
415
+ const path26 = originalPath && checkPath.convert(originalPath);
416
416
  checkPath(
417
- path25,
417
+ path26,
418
418
  originalPath,
419
419
  this._strictPathCheck ? throwError : RETURN_FALSE
420
420
  );
421
- return this._t(path25, cache, checkUnignored, slices);
421
+ return this._t(path26, cache, checkUnignored, slices);
422
422
  }
423
- checkIgnore(path25) {
424
- if (!REGEX_TEST_TRAILING_SLASH.test(path25)) {
425
- return this.test(path25);
423
+ checkIgnore(path26) {
424
+ if (!REGEX_TEST_TRAILING_SLASH.test(path26)) {
425
+ return this.test(path26);
426
426
  }
427
- const slices = path25.split(SLASH2).filter(Boolean);
427
+ const slices = path26.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(path25, false, MODE_CHECK_IGNORE);
440
+ return this._rules.test(path26, false, MODE_CHECK_IGNORE);
441
441
  }
442
- _t(path25, cache, checkUnignored, slices) {
443
- if (path25 in cache) {
444
- return cache[path25];
442
+ _t(path26, cache, checkUnignored, slices) {
443
+ if (path26 in cache) {
444
+ return cache[path26];
445
445
  }
446
446
  if (!slices) {
447
- slices = path25.split(SLASH2).filter(Boolean);
447
+ slices = path26.split(SLASH2).filter(Boolean);
448
448
  }
449
449
  slices.pop();
450
450
  if (!slices.length) {
451
- return cache[path25] = this._rules.test(path25, checkUnignored, MODE_IGNORE);
451
+ return cache[path26] = this._rules.test(path26, 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[path25] = parent.ignored ? parent : this._rules.test(path25, checkUnignored, MODE_IGNORE);
459
+ return cache[path26] = parent.ignored ? parent : this._rules.test(path26, checkUnignored, MODE_IGNORE);
460
460
  }
461
- ignores(path25) {
462
- return this._test(path25, this._ignoreCache, false).ignored;
461
+ ignores(path26) {
462
+ return this._test(path26, this._ignoreCache, false).ignored;
463
463
  }
464
464
  createFilter() {
465
- return (path25) => !this.ignores(path25);
465
+ return (path26) => !this.ignores(path26);
466
466
  }
467
467
  filter(paths) {
468
468
  return makeArray(paths).filter(this.createFilter());
469
469
  }
470
470
  // @returns {TestResult}
471
- test(path25) {
472
- return this._test(path25, this._testCache, true);
471
+ test(path26) {
472
+ return this._test(path26, this._testCache, true);
473
473
  }
474
474
  };
475
475
  var factory = (options) => new Ignore2(options);
476
- var isPathValid = (path25) => checkPath(path25 && checkPath.convert(path25), path25, RETURN_FALSE);
476
+ var isPathValid = (path26) => checkPath(path26 && checkPath.convert(path26), path26, 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 = (path25) => REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path25) || isNotRelative(path25);
481
+ checkPath.isNotRelative = (path26) => REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path26) || isNotRelative(path26);
482
482
  };
483
483
  if (
484
484
  // Detect `process` so that it can run in browsers.
@@ -2254,7 +2254,7 @@ function formatCodeCommunities(result) {
2254
2254
 
2255
2255
  // src/tools/operations.ts
2256
2256
  var import_fs13 = require("fs");
2257
- var path20 = __toESM(require("path"), 1);
2257
+ var path21 = __toESM(require("path"), 1);
2258
2258
 
2259
2259
  // src/tools/knowledge-base-paths.ts
2260
2260
  var path9 = __toESM(require("path"), 1);
@@ -2966,8 +2966,8 @@ function formatExactSearchHandoff(results) {
2966
2966
  }
2967
2967
  function formatContextEvidence(result, index) {
2968
2968
  const symbol = result.name ? ` ${JSON.stringify(compactEvidenceValue(result.name, 80))}` : "";
2969
- const path25 = compactEvidenceValue(result.filePath, 120);
2970
- return `[${index}] ${result.chunkType}${symbol} in ${path25}:${result.startLine}-${result.endLine} (score ${result.score.toFixed(2)})`;
2969
+ const path26 = compactEvidenceValue(result.filePath, 120);
2970
+ return `[${index}] ${result.chunkType}${symbol} in ${path26}:${result.startLine}-${result.endLine} (score ${result.score.toFixed(2)})`;
2971
2971
  }
2972
2972
  function formatContextPack(heading, selected, candidateCount, duplicateCount, limitOmittedCount, budgetOmittedCount, includeExactSearchHandoff) {
2973
2973
  const lines = selected.map((result, index) => formatContextEvidence(result, index + 1));
@@ -3610,8 +3610,8 @@ function formatEffectivenessMetrics(snapshot) {
3610
3610
 
3611
3611
  // src/utils/auto-index.ts
3612
3612
  var import_fs8 = require("fs");
3613
- var os4 = __toESM(require("os"), 1);
3614
- var path12 = __toESM(require("path"), 1);
3613
+ var os5 = __toESM(require("os"), 1);
3614
+ var path13 = __toESM(require("path"), 1);
3615
3615
 
3616
3616
  // src/indexer/index-lock.ts
3617
3617
  var import_crypto = require("crypto");
@@ -3858,7 +3858,7 @@ function removeDeadReclaimMarker(lockPath, expectedOwner) {
3858
3858
  return true;
3859
3859
  }
3860
3860
  function reclaimDeadOwner(indexPath, lockPath, expectedOwner) {
3861
- const reclaimPath = path10.join(lockPath, RECLAIM_DIRECTORY_NAME);
3861
+ const reclaimPath2 = path10.join(lockPath, RECLAIM_DIRECTORY_NAME);
3862
3862
  const reclaimOwner = {
3863
3863
  pid: process.pid,
3864
3864
  hostname: os3.hostname(),
@@ -3867,19 +3867,19 @@ function reclaimDeadOwner(indexPath, lockPath, expectedOwner) {
3867
3867
  expectedOwnerToken: expectedOwner.token
3868
3868
  };
3869
3869
  for (let attempt = 0; attempt < 2; attempt += 1) {
3870
- if (publishJsonDirectory(reclaimPath, reclaimOwner)) break;
3870
+ if (publishJsonDirectory(reclaimPath2, reclaimOwner)) break;
3871
3871
  if (attempt === 0 && removeDeadReclaimMarker(lockPath, expectedOwner)) continue;
3872
3872
  return false;
3873
3873
  }
3874
3874
  try {
3875
- const currentReclaimer = readReclaimOwner(reclaimPath);
3875
+ const currentReclaimer = readReclaimOwner(reclaimPath2);
3876
3876
  const currentOwner = readDirectoryOwner(lockPath);
3877
3877
  if (!currentReclaimer || !sameReclaimOwner(currentReclaimer, reclaimOwner) || !currentOwner || !sameOwner(currentOwner, expectedOwner) || getOwnerLiveness(currentOwner) !== "dead") {
3878
3878
  return false;
3879
3879
  }
3880
3880
  publishRecoveryMarker(indexPath, expectedOwner);
3881
3881
  const ownerBeforeQuarantine = readDirectoryOwner(lockPath);
3882
- const reclaimerBeforeQuarantine = readReclaimOwner(reclaimPath);
3882
+ const reclaimerBeforeQuarantine = readReclaimOwner(reclaimPath2);
3883
3883
  if (!ownerBeforeQuarantine || !sameOwner(ownerBeforeQuarantine, expectedOwner) || getOwnerLiveness(ownerBeforeQuarantine) !== "dead" || !reclaimerBeforeQuarantine || !sameReclaimOwner(reclaimerBeforeQuarantine, reclaimOwner)) {
3884
3884
  return false;
3885
3885
  }
@@ -4049,10 +4049,884 @@ function completeLeaseRecovery(lease) {
4049
4049
  }
4050
4050
  }
4051
4051
 
4052
+ // src/utils/background-worker.ts
4053
+ var import_node_crypto = require("crypto");
4054
+ var import_node_fs = require("fs");
4055
+ var os4 = __toESM(require("os"), 1);
4056
+ var path11 = __toESM(require("path"), 1);
4057
+ var OWNER_FILE_NAME2 = "owner.json";
4058
+ var HEARTBEAT_FILE_PREFIX = "heartbeat.";
4059
+ var RECLAIM_DIRECTORY_NAME2 = "reclaim";
4060
+ var REFRESH_REQUEST_FILE_NAME = "refresh-request.json";
4061
+ var HEARTBEAT_INTERVAL_MS = 5e3;
4062
+ var STALE_LEASE_MS = 3e4;
4063
+ var RETRY_DELAY_MS = 5e3;
4064
+ 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;
4065
+ var BackgroundWorkerStopError = class extends Error {
4066
+ constructor(watcherError, autoIndexError) {
4067
+ super("Failed to stop background worker");
4068
+ this.watcherError = watcherError;
4069
+ this.autoIndexError = autoIndexError;
4070
+ this.name = "BackgroundWorkerStopError";
4071
+ }
4072
+ watcherError;
4073
+ autoIndexError;
4074
+ };
4075
+ var workers = /* @__PURE__ */ new Map();
4076
+ var workerKeysByProject = /* @__PURE__ */ new Map();
4077
+ var workerReplacementBarriers = /* @__PURE__ */ new Map();
4078
+ function getErrorCode2(error) {
4079
+ return typeof error === "object" && error !== null && "code" in error ? String(error.code) : void 0;
4080
+ }
4081
+ function canonicalizePath(targetPath) {
4082
+ const resolved = path11.resolve(targetPath);
4083
+ if ((0, import_node_fs.existsSync)(resolved)) {
4084
+ try {
4085
+ return import_node_fs.realpathSync.native(resolved);
4086
+ } catch {
4087
+ return resolved;
4088
+ }
4089
+ }
4090
+ const parent = path11.dirname(resolved);
4091
+ if (parent === resolved) return resolved;
4092
+ return path11.join(canonicalizePath(parent), path11.basename(resolved));
4093
+ }
4094
+ function projectLookupKey(projectRoot3, host) {
4095
+ return `${host}::${canonicalizePath(projectRoot3)}`;
4096
+ }
4097
+ function resolveIdentity(projectRoot3, config, host) {
4098
+ const canonicalProjectRoot = canonicalizePath(projectRoot3);
4099
+ const canonicalIndexPath = canonicalizePath(resolveProjectIndexPath(projectRoot3, config.scope, host));
4100
+ return {
4101
+ canonicalIndexPath,
4102
+ canonicalProjectRoot,
4103
+ key: `${canonicalIndexPath}::${canonicalProjectRoot}`
4104
+ };
4105
+ }
4106
+ function controllerKey(identity, host) {
4107
+ return `${identity.key}::${host}`;
4108
+ }
4109
+ function leaseDirectoryName(identity) {
4110
+ const hash = (0, import_node_crypto.createHash)("sha256").update(identity.key).digest("hex").slice(0, 32);
4111
+ return `background-worker.${hash}.lease`;
4112
+ }
4113
+ function leasePathFor(identity) {
4114
+ return path11.join(identity.canonicalIndexPath, leaseDirectoryName(identity));
4115
+ }
4116
+ function parseOwner2(value) {
4117
+ if (typeof value !== "object" || value === null) return null;
4118
+ const candidate = value;
4119
+ if (candidate.version !== 1) return null;
4120
+ if (!Number.isInteger(candidate.pid) || (candidate.pid ?? 0) <= 0) return null;
4121
+ if (typeof candidate.hostname !== "string" || candidate.hostname.length === 0) return null;
4122
+ if (typeof candidate.startedAt !== "string" || Number.isNaN(Date.parse(candidate.startedAt))) return null;
4123
+ if (typeof candidate.heartbeatAt !== "string" || Number.isNaN(Date.parse(candidate.heartbeatAt))) return null;
4124
+ if (typeof candidate.projectRoot !== "string" || candidate.projectRoot.length === 0) return null;
4125
+ if (typeof candidate.indexPath !== "string" || candidate.indexPath.length === 0) return null;
4126
+ if (typeof candidate.token !== "string" || !UUID_PATTERN2.test(candidate.token)) return null;
4127
+ return candidate;
4128
+ }
4129
+ function parseHeartbeat(value, expectedToken) {
4130
+ if (typeof value !== "object" || value === null) return null;
4131
+ const candidate = value;
4132
+ if (candidate.version !== 1 || candidate.token !== expectedToken) return null;
4133
+ if (typeof candidate.heartbeatAt !== "string" || Number.isNaN(Date.parse(candidate.heartbeatAt))) return null;
4134
+ return candidate;
4135
+ }
4136
+ function parseReclaimOwner2(value) {
4137
+ if (typeof value !== "object" || value === null) return null;
4138
+ const candidate = value;
4139
+ if (candidate.version !== 1) return null;
4140
+ if (!Number.isInteger(candidate.pid) || (candidate.pid ?? 0) <= 0) return null;
4141
+ if (typeof candidate.hostname !== "string" || candidate.hostname.length === 0) return null;
4142
+ if (typeof candidate.startedAt !== "string" || Number.isNaN(Date.parse(candidate.startedAt))) return null;
4143
+ if (typeof candidate.token !== "string" || !UUID_PATTERN2.test(candidate.token)) return null;
4144
+ if (candidate.expectedOwnerToken !== null && (typeof candidate.expectedOwnerToken !== "string" || !UUID_PATTERN2.test(candidate.expectedOwnerToken))) return null;
4145
+ return candidate;
4146
+ }
4147
+ function heartbeatPath(leasePath, token) {
4148
+ return path11.join(leasePath, `${HEARTBEAT_FILE_PREFIX}${token}.json`);
4149
+ }
4150
+ function reclaimPath(leasePath) {
4151
+ return path11.join(leasePath, RECLAIM_DIRECTORY_NAME2);
4152
+ }
4153
+ function refreshRequestPath(leasePath) {
4154
+ return path11.join(leasePath, REFRESH_REQUEST_FILE_NAME);
4155
+ }
4156
+ function readLeaseOwner(leasePath) {
4157
+ try {
4158
+ return parseOwner2(JSON.parse((0, import_node_fs.readFileSync)(path11.join(leasePath, OWNER_FILE_NAME2), "utf-8")));
4159
+ } catch {
4160
+ return null;
4161
+ }
4162
+ }
4163
+ function readOwner(leasePath) {
4164
+ const owner = readLeaseOwner(leasePath);
4165
+ if (!owner) return null;
4166
+ try {
4167
+ const heartbeat = parseHeartbeat(
4168
+ JSON.parse((0, import_node_fs.readFileSync)(heartbeatPath(leasePath, owner.token), "utf-8")),
4169
+ owner.token
4170
+ );
4171
+ return heartbeat ? { ...owner, heartbeatAt: heartbeat.heartbeatAt } : owner;
4172
+ } catch {
4173
+ return owner;
4174
+ }
4175
+ }
4176
+ function readReclaimOwner2(leasePath) {
4177
+ try {
4178
+ return parseReclaimOwner2(JSON.parse((0, import_node_fs.readFileSync)(path11.join(reclaimPath(leasePath), OWNER_FILE_NAME2), "utf-8")));
4179
+ } catch {
4180
+ return null;
4181
+ }
4182
+ }
4183
+ function ownerLiveness(owner) {
4184
+ if (owner.hostname !== os4.hostname()) return "unknown";
4185
+ try {
4186
+ process.kill(owner.pid, 0);
4187
+ return "alive";
4188
+ } catch (error) {
4189
+ const code = getErrorCode2(error);
4190
+ if (code === "ESRCH") return "dead";
4191
+ if (code === "EPERM") return "alive";
4192
+ return "unknown";
4193
+ }
4194
+ }
4195
+ function isHeartbeatExpired(owner) {
4196
+ return Date.now() - Date.parse(owner.heartbeatAt) >= STALE_LEASE_MS;
4197
+ }
4198
+ function sameOwner2(left, right) {
4199
+ return left.pid === right.pid && left.hostname === right.hostname && left.token === right.token;
4200
+ }
4201
+ function writeHeartbeat(leasePath, owner) {
4202
+ const targetPath = heartbeatPath(leasePath, owner.token);
4203
+ const temporaryPath = `${targetPath}.tmp.${process.pid}.${owner.token}.${(0, import_node_crypto.randomUUID)()}`;
4204
+ const heartbeat = {
4205
+ version: 1,
4206
+ token: owner.token,
4207
+ heartbeatAt: owner.heartbeatAt
4208
+ };
4209
+ try {
4210
+ (0, import_node_fs.writeFileSync)(temporaryPath, JSON.stringify(heartbeat), {
4211
+ encoding: "utf-8",
4212
+ flag: "wx",
4213
+ mode: 384
4214
+ });
4215
+ (0, import_node_fs.renameSync)(temporaryPath, targetPath);
4216
+ const currentOwner = readLeaseOwner(leasePath);
4217
+ return currentOwner !== null && sameOwner2(currentOwner, owner);
4218
+ } finally {
4219
+ if ((0, import_node_fs.existsSync)(temporaryPath)) (0, import_node_fs.rmSync)(temporaryPath, { force: true });
4220
+ }
4221
+ }
4222
+ function requestRefreshFromLeader(leasePath, allowDisabledAutoIndex) {
4223
+ const requestPath = refreshRequestPath(leasePath);
4224
+ const temporaryPath = `${requestPath}.tmp.${process.pid}.${(0, import_node_crypto.randomUUID)()}`;
4225
+ try {
4226
+ const request = {
4227
+ allowDisabledAutoIndex,
4228
+ requestedAt: (/* @__PURE__ */ new Date()).toISOString(),
4229
+ version: 1
4230
+ };
4231
+ (0, import_node_fs.writeFileSync)(temporaryPath, JSON.stringify(request), {
4232
+ encoding: "utf-8",
4233
+ flag: "wx",
4234
+ mode: 384
4235
+ });
4236
+ (0, import_node_fs.renameSync)(temporaryPath, requestPath);
4237
+ } catch (error) {
4238
+ if (getErrorCode2(error) !== "ENOENT") {
4239
+ console.error("[codebase-index] Failed to request background index refresh from the project worker:", error);
4240
+ }
4241
+ } finally {
4242
+ if ((0, import_node_fs.existsSync)(temporaryPath)) (0, import_node_fs.rmSync)(temporaryPath, { force: true });
4243
+ }
4244
+ }
4245
+ function consumeRefreshRequest(leasePath) {
4246
+ const requestPath = refreshRequestPath(leasePath);
4247
+ const claimedPath = `${requestPath}.handling.${process.pid}.${(0, import_node_crypto.randomUUID)()}`;
4248
+ try {
4249
+ (0, import_node_fs.renameSync)(requestPath, claimedPath);
4250
+ } catch (error) {
4251
+ if (getErrorCode2(error) === "ENOENT") return null;
4252
+ throw error;
4253
+ }
4254
+ try {
4255
+ const value = JSON.parse((0, import_node_fs.readFileSync)(claimedPath, "utf-8"));
4256
+ return {
4257
+ allowDisabledAutoIndex: value.version === 1 && value.allowDisabledAutoIndex === true,
4258
+ requestedAt: typeof value.requestedAt === "string" ? value.requestedAt : (/* @__PURE__ */ new Date()).toISOString(),
4259
+ version: 1
4260
+ };
4261
+ } catch {
4262
+ return { allowDisabledAutoIndex: false, requestedAt: (/* @__PURE__ */ new Date()).toISOString(), version: 1 };
4263
+ } finally {
4264
+ (0, import_node_fs.rmSync)(claimedPath, { force: true });
4265
+ }
4266
+ }
4267
+ function publishLease(leasePath, owner) {
4268
+ const candidatePath = `${leasePath}.candidate.${process.pid}.${owner.token}`;
4269
+ try {
4270
+ (0, import_node_fs.mkdirSync)(candidatePath, { mode: 448 });
4271
+ } catch (error) {
4272
+ if (getErrorCode2(error) === "ENOENT") return false;
4273
+ throw error;
4274
+ }
4275
+ try {
4276
+ (0, import_node_fs.writeFileSync)(path11.join(candidatePath, OWNER_FILE_NAME2), JSON.stringify(owner), {
4277
+ encoding: "utf-8",
4278
+ flag: "wx",
4279
+ mode: 384
4280
+ });
4281
+ if ((0, import_node_fs.existsSync)(leasePath)) return false;
4282
+ try {
4283
+ (0, import_node_fs.renameSync)(candidatePath, leasePath);
4284
+ return true;
4285
+ } catch (error) {
4286
+ if ((0, import_node_fs.existsSync)(leasePath) || getErrorCode2(error) === "ENOENT") return false;
4287
+ throw error;
4288
+ }
4289
+ } finally {
4290
+ if ((0, import_node_fs.existsSync)(candidatePath)) (0, import_node_fs.rmSync)(candidatePath, { recursive: true, force: true });
4291
+ }
4292
+ }
4293
+ function sameReclaimOwner2(left, right) {
4294
+ return left.pid === right.pid && left.hostname === right.hostname && left.token === right.token && left.expectedOwnerToken === right.expectedOwnerToken;
4295
+ }
4296
+ function reclaimerLiveness(owner) {
4297
+ return ownerLiveness(owner);
4298
+ }
4299
+ function isReclaimMarkerExpired(leasePath, owner) {
4300
+ const startedAt = owner ? Date.parse(owner.startedAt) : (() => {
4301
+ try {
4302
+ return (0, import_node_fs.lstatSync)(reclaimPath(leasePath)).mtimeMs;
4303
+ } catch {
4304
+ return Date.now();
4305
+ }
4306
+ })();
4307
+ return Date.now() - startedAt >= STALE_LEASE_MS;
4308
+ }
4309
+ function hasActiveReclaimMarker(leasePath, owner) {
4310
+ const marker = readReclaimOwner2(leasePath);
4311
+ return marker !== null && marker.expectedOwnerToken === owner.token && (marker.hostname !== os4.hostname() || ownerLiveness(owner) !== "alive");
4312
+ }
4313
+ function publishReclaimMarker(leasePath, expectedOwner) {
4314
+ const markerPath = reclaimPath(leasePath);
4315
+ const owner = {
4316
+ version: 1,
4317
+ pid: process.pid,
4318
+ hostname: os4.hostname(),
4319
+ startedAt: (/* @__PURE__ */ new Date()).toISOString(),
4320
+ token: (0, import_node_crypto.randomUUID)(),
4321
+ expectedOwnerToken: expectedOwner?.token ?? null
4322
+ };
4323
+ try {
4324
+ (0, import_node_fs.mkdirSync)(markerPath, { mode: 448 });
4325
+ } catch (error) {
4326
+ if (getErrorCode2(error) === "EEXIST" || getErrorCode2(error) === "ENOENT") return null;
4327
+ throw error;
4328
+ }
4329
+ try {
4330
+ (0, import_node_fs.writeFileSync)(path11.join(markerPath, OWNER_FILE_NAME2), JSON.stringify(owner), {
4331
+ encoding: "utf-8",
4332
+ flag: "wx",
4333
+ mode: 384
4334
+ });
4335
+ return owner;
4336
+ } catch (error) {
4337
+ (0, import_node_fs.rmSync)(markerPath, { recursive: true, force: true });
4338
+ throw error;
4339
+ }
4340
+ }
4341
+ function removeExpiredReclaimMarker(leasePath, expectedOwner) {
4342
+ const marker = readReclaimOwner2(leasePath);
4343
+ const markerPath = reclaimPath(leasePath);
4344
+ if (!(0, import_node_fs.existsSync)(markerPath)) return false;
4345
+ if (marker && marker.expectedOwnerToken !== (expectedOwner?.token ?? null)) return false;
4346
+ if (marker && (reclaimerLiveness(marker) === "alive" || !isReclaimMarkerExpired(leasePath, marker))) return false;
4347
+ if (!marker && !isReclaimMarkerExpired(leasePath, null)) return false;
4348
+ const staleMarkerPath = `${markerPath}.stale.${marker?.pid ?? process.pid}.${marker?.token ?? (0, import_node_crypto.randomUUID)()}.${(0, import_node_crypto.randomUUID)()}`;
4349
+ try {
4350
+ (0, import_node_fs.renameSync)(markerPath, staleMarkerPath);
4351
+ } catch (error) {
4352
+ if (getErrorCode2(error) === "ENOENT") return false;
4353
+ throw error;
4354
+ }
4355
+ try {
4356
+ let claimedMarker = null;
4357
+ try {
4358
+ claimedMarker = parseReclaimOwner2(
4359
+ JSON.parse((0, import_node_fs.readFileSync)(path11.join(staleMarkerPath, OWNER_FILE_NAME2), "utf-8"))
4360
+ );
4361
+ } catch {
4362
+ claimedMarker = null;
4363
+ }
4364
+ const markerMatches = marker ? claimedMarker !== null && sameReclaimOwner2(claimedMarker, marker) : claimedMarker === null;
4365
+ if (!markerMatches || !canReclaimLease(leasePath, expectedOwner)) {
4366
+ if (!(0, import_node_fs.existsSync)(markerPath) && (0, import_node_fs.existsSync)(staleMarkerPath)) (0, import_node_fs.renameSync)(staleMarkerPath, markerPath);
4367
+ return false;
4368
+ }
4369
+ (0, import_node_fs.rmSync)(staleMarkerPath, { recursive: true, force: true });
4370
+ return true;
4371
+ } catch (error) {
4372
+ if (getErrorCode2(error) === "ENOENT") return false;
4373
+ throw error;
4374
+ }
4375
+ }
4376
+ function canReclaimLease(leasePath, expectedOwner) {
4377
+ if (!(0, import_node_fs.existsSync)(leasePath)) return false;
4378
+ if (!expectedOwner) return false;
4379
+ const currentOwner = readOwner(leasePath);
4380
+ if (!currentOwner || !sameOwner2(currentOwner, expectedOwner)) return false;
4381
+ if (currentOwner.hostname === os4.hostname()) {
4382
+ return ownerLiveness(currentOwner) === "dead";
4383
+ }
4384
+ return isHeartbeatExpired(currentOwner);
4385
+ }
4386
+ function reclaimLease(leasePath, expectedOwner) {
4387
+ let marker = null;
4388
+ for (let attempt = 0; attempt < 2; attempt += 1) {
4389
+ marker = publishReclaimMarker(leasePath, expectedOwner);
4390
+ if (marker) break;
4391
+ if (attempt === 0 && removeExpiredReclaimMarker(leasePath, expectedOwner)) continue;
4392
+ return false;
4393
+ }
4394
+ if (!marker) return false;
4395
+ const markerPath = reclaimPath(leasePath);
4396
+ try {
4397
+ const currentMarker = readReclaimOwner2(leasePath);
4398
+ if (!currentMarker || !sameReclaimOwner2(currentMarker, marker) || !canReclaimLease(leasePath, expectedOwner)) {
4399
+ return false;
4400
+ }
4401
+ const stalePath = `${leasePath}.stale.${process.pid}.${marker.token}`;
4402
+ (0, import_node_fs.renameSync)(leasePath, stalePath);
4403
+ const quarantinedOwner = readOwner(stalePath);
4404
+ const quarantinedMarker = readReclaimOwner2(stalePath);
4405
+ if (!quarantinedMarker || !sameReclaimOwner2(quarantinedMarker, marker) || expectedOwner !== null && (!quarantinedOwner || !sameOwner2(quarantinedOwner, expectedOwner))) {
4406
+ if (!(0, import_node_fs.existsSync)(leasePath) && (0, import_node_fs.existsSync)(stalePath)) (0, import_node_fs.renameSync)(stalePath, leasePath);
4407
+ return false;
4408
+ }
4409
+ (0, import_node_fs.rmSync)(stalePath, { recursive: true, force: true });
4410
+ return true;
4411
+ } catch (error) {
4412
+ if (getErrorCode2(error) === "ENOENT") return false;
4413
+ throw error;
4414
+ } finally {
4415
+ const currentMarker = readReclaimOwner2(leasePath);
4416
+ if (currentMarker && sameReclaimOwner2(currentMarker, marker)) {
4417
+ (0, import_node_fs.rmSync)(markerPath, { recursive: true, force: true });
4418
+ }
4419
+ }
4420
+ }
4421
+ function acquireLease(identity) {
4422
+ (0, import_node_fs.mkdirSync)(identity.canonicalIndexPath, { recursive: true, mode: 448 });
4423
+ const canonicalIndexPath = import_node_fs.realpathSync.native(identity.canonicalIndexPath);
4424
+ const leasePath = path11.join(canonicalIndexPath, leaseDirectoryName({ ...identity, canonicalIndexPath }));
4425
+ for (let attempt = 0; attempt < 4; attempt += 1) {
4426
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
4427
+ const owner = {
4428
+ version: 1,
4429
+ pid: process.pid,
4430
+ hostname: os4.hostname(),
4431
+ startedAt: timestamp,
4432
+ heartbeatAt: timestamp,
4433
+ projectRoot: identity.canonicalProjectRoot,
4434
+ indexPath: canonicalIndexPath,
4435
+ token: (0, import_node_crypto.randomUUID)()
4436
+ };
4437
+ if (publishLease(leasePath, owner)) {
4438
+ return { leasePath, owner };
4439
+ }
4440
+ const existingOwner = readOwner(leasePath);
4441
+ if (existingOwner) {
4442
+ if (canReclaimLease(leasePath, existingOwner) && reclaimLease(leasePath, existingOwner)) continue;
4443
+ return null;
4444
+ }
4445
+ return null;
4446
+ }
4447
+ return null;
4448
+ }
4449
+ function releaseLease(lease) {
4450
+ const currentOwner = readOwner(lease.leasePath);
4451
+ if (!currentOwner || !sameOwner2(currentOwner, lease.owner)) return false;
4452
+ const releasePath = `${lease.leasePath}.release.${lease.owner.pid}.${lease.owner.token}`;
4453
+ try {
4454
+ (0, import_node_fs.renameSync)(lease.leasePath, releasePath);
4455
+ } catch (error) {
4456
+ if (getErrorCode2(error) === "ENOENT") return false;
4457
+ throw error;
4458
+ }
4459
+ const claimedOwner = readOwner(releasePath);
4460
+ if (!claimedOwner || !sameOwner2(claimedOwner, lease.owner)) {
4461
+ if (!(0, import_node_fs.existsSync)(lease.leasePath) && (0, import_node_fs.existsSync)(releasePath)) {
4462
+ (0, import_node_fs.renameSync)(releasePath, lease.leasePath);
4463
+ }
4464
+ return false;
4465
+ }
4466
+ (0, import_node_fs.rmSync)(releasePath, { recursive: true, force: true });
4467
+ return true;
4468
+ }
4469
+ var BackgroundWorkerController = class {
4470
+ constructor(projectRoot3, host, config, hooks, identity) {
4471
+ this.projectRoot = projectRoot3;
4472
+ this.host = host;
4473
+ this.config = config;
4474
+ this.hooks = hooks;
4475
+ this.identity = identity;
4476
+ }
4477
+ projectRoot;
4478
+ host;
4479
+ config;
4480
+ hooks;
4481
+ identity;
4482
+ lease = null;
4483
+ watcher = null;
4484
+ leaderReady = Promise.resolve();
4485
+ heartbeatTimer = null;
4486
+ retryTimer = null;
4487
+ teardownRetryTimer = null;
4488
+ transition = Promise.resolve();
4489
+ stopPromise = null;
4490
+ stopped = false;
4491
+ stopping = false;
4492
+ losingLeadership = false;
4493
+ restartAfterStop = false;
4494
+ leaderWorkStopped = false;
4495
+ startingLeaderWork = false;
4496
+ stopAutoIndexOnTeardown = true;
4497
+ autoIndexStarted = false;
4498
+ reportedError = null;
4499
+ update(config, hooks, options) {
4500
+ const autoIndexWasEnabled = this.config.indexing.autoIndex;
4501
+ const shouldReplaceWatcher = this.watcher !== null && hooks.watcherFactory !== void 0 && (hooks.watcherFactory === null || hooks.replaceWatcher === true);
4502
+ this.config = config;
4503
+ this.hooks = {
4504
+ ...this.hooks,
4505
+ ...hooks,
4506
+ watcherFactory: hooks.watcherFactory === void 0 ? this.hooks.watcherFactory : hooks.watcherFactory,
4507
+ watcherFactoryForConfig: hooks.watcherFactoryForConfig === void 0 ? this.hooks.watcherFactoryForConfig : hooks.watcherFactoryForConfig
4508
+ };
4509
+ if (autoIndexWasEnabled && !config.indexing.autoIndex || options.restartAutoIndex === true && config.indexing.autoIndex && !this.startingLeaderWork) {
4510
+ this.autoIndexStarted = false;
4511
+ }
4512
+ if (!this.canRun()) {
4513
+ void this.stop().catch((error) => {
4514
+ console.error("[codebase-index] Failed to stop background worker after disabling automatic work:", error);
4515
+ });
4516
+ return;
4517
+ }
4518
+ if (shouldReplaceWatcher) {
4519
+ void this.enqueue(async () => {
4520
+ const watcher = this.watcher;
4521
+ if (watcher) {
4522
+ await watcher.stop();
4523
+ if (this.watcher === watcher) this.watcher = null;
4524
+ }
4525
+ if (this.lease && !this.stopped) this.startLeaderWork();
4526
+ }).catch((error) => {
4527
+ console.error("[codebase-index] Failed to replace background file watcher:", error);
4528
+ });
4529
+ }
4530
+ this.start();
4531
+ }
4532
+ startAfter(activation) {
4533
+ this.transition = activation.catch(() => void 0);
4534
+ this.start();
4535
+ }
4536
+ start() {
4537
+ if (!this.canRun() || this.losingLeadership) return;
4538
+ if (this.stopping) {
4539
+ this.restartAfterStop = true;
4540
+ return;
4541
+ }
4542
+ this.stopped = false;
4543
+ void this.enqueue(async () => {
4544
+ if (this.stopped || this.stopping || this.losingLeadership || !this.canRun()) return;
4545
+ if (!this.lease) {
4546
+ try {
4547
+ this.lease = acquireLease(this.identity);
4548
+ this.reportedError = null;
4549
+ } catch (error) {
4550
+ this.reportAcquireError(error);
4551
+ this.scheduleRetry();
4552
+ return;
4553
+ }
4554
+ }
4555
+ if (!this.lease) {
4556
+ this.scheduleRetry();
4557
+ return;
4558
+ }
4559
+ this.startHeartbeat();
4560
+ this.startLeaderWork();
4561
+ });
4562
+ }
4563
+ waitForStart() {
4564
+ return this.transition.catch(() => void 0).then(() => this.leaderReady);
4565
+ }
4566
+ requestRefresh(allowDisabledAutoIndex = false) {
4567
+ this.start();
4568
+ if (!this.isLeader()) {
4569
+ requestRefreshFromLeader(leasePathFor(this.identity), allowDisabledAutoIndex);
4570
+ return;
4571
+ }
4572
+ void this.enqueue(async () => {
4573
+ if (this.stopped || !this.lease) return;
4574
+ this.hooks.startAutoIndex("retrieval", allowDisabledAutoIndex);
4575
+ });
4576
+ }
4577
+ isLeader() {
4578
+ return this.lease !== null && !this.stopping && !this.losingLeadership;
4579
+ }
4580
+ isStopping() {
4581
+ return this.stopping;
4582
+ }
4583
+ getHooksForConfig(config) {
4584
+ const watcherFactoryForConfig = this.hooks.watcherFactoryForConfig;
4585
+ if (!watcherFactoryForConfig) return this.hooks;
4586
+ return {
4587
+ ...this.hooks,
4588
+ watcherFactory: watcherFactoryForConfig(config),
4589
+ replaceWatcher: true
4590
+ };
4591
+ }
4592
+ attachWatcher(watcherFactory, watcherFactoryForConfig) {
4593
+ if (this.hooks.watcherFactory !== void 0) return;
4594
+ this.hooks = {
4595
+ ...this.hooks,
4596
+ watcherFactory,
4597
+ watcherFactoryForConfig: watcherFactoryForConfig ?? this.hooks.watcherFactoryForConfig
4598
+ };
4599
+ this.start();
4600
+ }
4601
+ async stop(stopAutoIndex = true) {
4602
+ if (this.stopPromise) return this.stopPromise;
4603
+ this.stopped = true;
4604
+ this.stopping = true;
4605
+ this.stopAutoIndexOnTeardown &&= stopAutoIndex;
4606
+ this.clearRetryTimer();
4607
+ const attempt = this.enqueue(async () => {
4608
+ try {
4609
+ const lease = this.lease;
4610
+ if (this.leaderWorkStopped) {
4611
+ if (lease) {
4612
+ this.releaseStoppedLease(lease);
4613
+ } else {
4614
+ this.finishStoppedLease();
4615
+ }
4616
+ return;
4617
+ }
4618
+ const hadLeaderWork = lease !== null || this.watcher !== null || this.autoIndexStarted;
4619
+ const stopped = await this.stopLeaderWork(hadLeaderWork && this.stopAutoIndexOnTeardown);
4620
+ if (!lease) {
4621
+ this.finishStoppedLease();
4622
+ return;
4623
+ }
4624
+ if (!stopped.completed) {
4625
+ this.releaseLeaseWhenAutoIndexStops(lease, stopped.completion);
4626
+ return;
4627
+ }
4628
+ this.leaderWorkStopped = true;
4629
+ this.releaseStoppedLease(lease);
4630
+ } catch (error) {
4631
+ this.scheduleTeardownRetry();
4632
+ throw error;
4633
+ }
4634
+ });
4635
+ const completion = attempt.finally(() => {
4636
+ if (this.stopPromise === completion) this.stopPromise = null;
4637
+ });
4638
+ this.stopPromise = completion;
4639
+ return completion;
4640
+ }
4641
+ canRun() {
4642
+ return this.config.indexing.autoIndex || this.hooks.watcherFactory != null;
4643
+ }
4644
+ enqueue(operation) {
4645
+ const next = this.transition.catch(() => void 0).then(operation);
4646
+ this.transition = next;
4647
+ return next;
4648
+ }
4649
+ startLeaderWork() {
4650
+ if (this.stopped || this.stopping || this.losingLeadership) return;
4651
+ this.startingLeaderWork = true;
4652
+ try {
4653
+ if (this.config.indexing.autoIndex && !this.autoIndexStarted) {
4654
+ this.autoIndexStarted = true;
4655
+ this.hooks.startAutoIndex("startup");
4656
+ }
4657
+ if (!this.watcher && this.hooks.watcherFactory) {
4658
+ try {
4659
+ const watcher = this.hooks.watcherFactory();
4660
+ this.watcher = watcher;
4661
+ this.leaderReady = watcher.whenReady?.().catch((error) => {
4662
+ console.error("[codebase-index] Failed while waiting for background file watcher startup:", error);
4663
+ }) ?? Promise.resolve();
4664
+ } catch (error) {
4665
+ console.error("[codebase-index] Failed to start background file watcher:", error);
4666
+ this.leaderReady = Promise.resolve();
4667
+ }
4668
+ }
4669
+ } finally {
4670
+ this.startingLeaderWork = false;
4671
+ }
4672
+ }
4673
+ async stopLeaderWork(stopAutoIndex) {
4674
+ const watcher = this.watcher;
4675
+ let watcherError;
4676
+ if (watcher) {
4677
+ try {
4678
+ await watcher.stop();
4679
+ if (this.watcher === watcher) this.watcher = null;
4680
+ } catch (error) {
4681
+ watcherError = error;
4682
+ }
4683
+ }
4684
+ let autoIndexError;
4685
+ let autoIndexStop = {
4686
+ completed: true,
4687
+ completion: Promise.resolve()
4688
+ };
4689
+ if (stopAutoIndex) {
4690
+ try {
4691
+ autoIndexStop = await this.hooks.stopAutoIndex();
4692
+ this.autoIndexStarted = false;
4693
+ } catch (error) {
4694
+ autoIndexError = error;
4695
+ }
4696
+ }
4697
+ if (watcherError !== void 0 || autoIndexError !== void 0) {
4698
+ throw new BackgroundWorkerStopError(watcherError, autoIndexError);
4699
+ }
4700
+ return autoIndexStop;
4701
+ }
4702
+ releaseLeaseWhenAutoIndexStops(lease, completion) {
4703
+ void completion.then(
4704
+ () => {
4705
+ void this.enqueue(async () => {
4706
+ if (this.lease !== lease || !this.stopping) return;
4707
+ this.leaderWorkStopped = true;
4708
+ this.releaseStoppedLease(lease);
4709
+ }).catch((error) => {
4710
+ console.error("[codebase-index] Failed to release background worker lease after automatic indexing stopped:", error);
4711
+ this.scheduleTeardownRetry();
4712
+ });
4713
+ },
4714
+ (error) => {
4715
+ console.error("[codebase-index] Failed while waiting for automatic indexing to stop:", error);
4716
+ this.scheduleTeardownRetry();
4717
+ }
4718
+ );
4719
+ }
4720
+ releaseStoppedLease(lease) {
4721
+ if (this.lease !== lease) {
4722
+ this.finishStoppedLease();
4723
+ return;
4724
+ }
4725
+ releaseLease(lease);
4726
+ this.lease = null;
4727
+ this.finishStoppedLease();
4728
+ }
4729
+ finishStoppedLease() {
4730
+ this.leaderWorkStopped = false;
4731
+ this.stopAutoIndexOnTeardown = true;
4732
+ this.stopping = false;
4733
+ this.clearTimers();
4734
+ this.restartAfterTeardown();
4735
+ if (!this.stopped || this.stopping) return;
4736
+ const projectKey = projectLookupKey(this.projectRoot, this.host);
4737
+ const key = controllerKey(this.identity, this.host);
4738
+ if (workers.get(key) === this) workers.delete(key);
4739
+ if (workerKeysByProject.get(projectKey) === key) workerKeysByProject.delete(projectKey);
4740
+ }
4741
+ startHeartbeat() {
4742
+ if (this.heartbeatTimer) return;
4743
+ const heartbeat = () => {
4744
+ void this.heartbeat();
4745
+ };
4746
+ this.heartbeatTimer = setInterval(heartbeat, HEARTBEAT_INTERVAL_MS);
4747
+ this.heartbeatTimer.unref?.();
4748
+ }
4749
+ async heartbeat() {
4750
+ const lease = this.lease;
4751
+ if (!lease || this.losingLeadership || this.stopped && !this.stopping) return;
4752
+ if (hasActiveReclaimMarker(lease.leasePath, lease.owner)) {
4753
+ await this.loseLeadership();
4754
+ return;
4755
+ }
4756
+ const currentOwner = readOwner(lease.leasePath);
4757
+ if (!currentOwner || !sameOwner2(currentOwner, lease.owner)) {
4758
+ await this.loseLeadership();
4759
+ return;
4760
+ }
4761
+ try {
4762
+ const nextOwner = { ...lease.owner, heartbeatAt: (/* @__PURE__ */ new Date()).toISOString() };
4763
+ if (!writeHeartbeat(lease.leasePath, nextOwner)) {
4764
+ await this.loseLeadership();
4765
+ return;
4766
+ }
4767
+ lease.owner = nextOwner;
4768
+ const refreshRequest = !this.stopping ? consumeRefreshRequest(lease.leasePath) : null;
4769
+ if (refreshRequest) {
4770
+ this.hooks.startAutoIndex("retrieval", refreshRequest.allowDisabledAutoIndex);
4771
+ }
4772
+ } catch (error) {
4773
+ const ownerAfterError = readOwner(lease.leasePath);
4774
+ if (hasActiveReclaimMarker(lease.leasePath, lease.owner) || !ownerAfterError || !sameOwner2(ownerAfterError, lease.owner)) {
4775
+ await this.loseLeadership();
4776
+ return;
4777
+ }
4778
+ console.error("[codebase-index] Failed to renew background worker lease:", error);
4779
+ }
4780
+ }
4781
+ async loseLeadership() {
4782
+ if (this.losingLeadership) return;
4783
+ this.losingLeadership = true;
4784
+ this.clearHeartbeat();
4785
+ await this.enqueue(async () => this.stopAfterLeadershipLoss());
4786
+ }
4787
+ async stopAfterLeadershipLoss() {
4788
+ const lease = this.lease;
4789
+ if (!lease) {
4790
+ this.losingLeadership = false;
4791
+ return;
4792
+ }
4793
+ try {
4794
+ const stopped = await this.stopLeaderWork(true);
4795
+ this.lease = null;
4796
+ this.losingLeadership = false;
4797
+ if (stopped.completed) {
4798
+ this.scheduleRetry();
4799
+ } else {
4800
+ void stopped.completion.then(() => this.scheduleRetry());
4801
+ }
4802
+ } catch (error) {
4803
+ console.error("[codebase-index] Failed to stop background work after losing its lease:", error);
4804
+ this.scheduleLostLeadershipTeardownRetry();
4805
+ }
4806
+ }
4807
+ scheduleRetry() {
4808
+ if (this.stopped || !this.canRun() || this.retryTimer) return;
4809
+ this.retryTimer = setTimeout(() => {
4810
+ this.retryTimer = null;
4811
+ this.start();
4812
+ }, RETRY_DELAY_MS);
4813
+ this.retryTimer.unref?.();
4814
+ }
4815
+ scheduleTeardownRetry() {
4816
+ if (!this.stopping || this.teardownRetryTimer) return;
4817
+ this.teardownRetryTimer = setTimeout(() => {
4818
+ this.teardownRetryTimer = null;
4819
+ void this.stop(this.stopAutoIndexOnTeardown).catch((error) => {
4820
+ console.error("[codebase-index] Failed to retry background worker teardown:", error);
4821
+ });
4822
+ }, RETRY_DELAY_MS);
4823
+ this.teardownRetryTimer.unref?.();
4824
+ }
4825
+ restartAfterTeardown() {
4826
+ if (!this.restartAfterStop || !this.canRun() || this.losingLeadership) return;
4827
+ this.restartAfterStop = false;
4828
+ this.stopped = false;
4829
+ this.start();
4830
+ }
4831
+ scheduleLostLeadershipTeardownRetry() {
4832
+ if (this.stopped || !this.losingLeadership || this.retryTimer) return;
4833
+ this.retryTimer = setTimeout(() => {
4834
+ this.retryTimer = null;
4835
+ void this.enqueue(async () => this.stopAfterLeadershipLoss());
4836
+ }, RETRY_DELAY_MS);
4837
+ this.retryTimer.unref?.();
4838
+ }
4839
+ clearHeartbeat() {
4840
+ if (!this.heartbeatTimer) return;
4841
+ clearInterval(this.heartbeatTimer);
4842
+ this.heartbeatTimer = null;
4843
+ }
4844
+ clearTimers() {
4845
+ this.clearHeartbeat();
4846
+ this.clearRetryTimer();
4847
+ if (this.teardownRetryTimer) {
4848
+ clearTimeout(this.teardownRetryTimer);
4849
+ this.teardownRetryTimer = null;
4850
+ }
4851
+ }
4852
+ clearRetryTimer() {
4853
+ if (!this.retryTimer) return;
4854
+ clearTimeout(this.retryTimer);
4855
+ this.retryTimer = null;
4856
+ }
4857
+ reportAcquireError(error) {
4858
+ const message = error instanceof Error ? error.message : String(error);
4859
+ if (this.reportedError === message) return;
4860
+ this.reportedError = message;
4861
+ console.error("[codebase-index] Failed to acquire background worker lease:", error);
4862
+ }
4863
+ };
4864
+ function configureBackgroundWorker(projectRoot3, host, config, hooks, options = {}) {
4865
+ const projectKey = projectLookupKey(projectRoot3, host);
4866
+ const identity = resolveIdentity(projectRoot3, config, host);
4867
+ const key = controllerKey(identity, host);
4868
+ const previousKey = workerKeysByProject.get(projectKey);
4869
+ if (previousKey && previousKey !== key) {
4870
+ const previous = workers.get(previousKey);
4871
+ const previousBarrier = workerReplacementBarriers.get(projectKey) ?? Promise.resolve();
4872
+ const stopPrevious = previous?.stop(options.stopPreviousAutoIndex ?? true) ?? Promise.resolve();
4873
+ const activation = Promise.all([previousBarrier, stopPrevious]).then(() => void 0);
4874
+ workerReplacementBarriers.set(projectKey, activation);
4875
+ workers.delete(previousKey);
4876
+ const worker2 = new BackgroundWorkerController(projectRoot3, host, config, hooks, identity);
4877
+ worker2.startAfter(activation);
4878
+ workers.set(key, worker2);
4879
+ workerKeysByProject.set(projectKey, key);
4880
+ return;
4881
+ }
4882
+ let worker = workers.get(key);
4883
+ if (!worker) {
4884
+ worker = new BackgroundWorkerController(projectRoot3, host, config, hooks, identity);
4885
+ workers.set(key, worker);
4886
+ } else {
4887
+ worker.update(config, hooks, options);
4888
+ }
4889
+ workerKeysByProject.set(projectKey, key);
4890
+ worker.start();
4891
+ }
4892
+ function updateBackgroundWorkerConfig(projectRoot3, host, config) {
4893
+ const projectKey = projectLookupKey(projectRoot3, host);
4894
+ const key = workerKeysByProject.get(projectKey);
4895
+ const worker = key ? workers.get(key) : void 0;
4896
+ if (!worker) return;
4897
+ configureBackgroundWorker(projectRoot3, host, config, worker.getHooksForConfig(config), {
4898
+ stopPreviousAutoIndex: false,
4899
+ restartAutoIndex: true
4900
+ });
4901
+ }
4902
+ function waitForBackgroundWorkerStart(projectRoot3, host) {
4903
+ const key = workerKeysByProject.get(projectLookupKey(projectRoot3, host));
4904
+ return workers.get(key ?? "")?.waitForStart() ?? Promise.resolve();
4905
+ }
4906
+ function requestBackgroundWorkerRefresh(projectRoot3, host, allowDisabledAutoIndex = false) {
4907
+ const key = workerKeysByProject.get(projectLookupKey(projectRoot3, host));
4908
+ workers.get(key ?? "")?.requestRefresh(allowDisabledAutoIndex);
4909
+ }
4910
+ function isBackgroundWorkerManaged(projectRoot3, host) {
4911
+ const key = workerKeysByProject.get(projectLookupKey(projectRoot3, host));
4912
+ return key !== void 0 && workers.has(key);
4913
+ }
4914
+ function isBackgroundWorkerLeader(projectRoot3, host) {
4915
+ const key = workerKeysByProject.get(projectLookupKey(projectRoot3, host));
4916
+ return key !== void 0 && workers.get(key)?.isLeader() === true;
4917
+ }
4918
+ async function stopBackgroundWorker(projectRoot3, host) {
4919
+ const projectKey = projectLookupKey(projectRoot3, host);
4920
+ const key = workerKeysByProject.get(projectKey);
4921
+ const worker = key ? workers.get(key) : void 0;
4922
+ if (!worker) return;
4923
+ await worker.stop();
4924
+ }
4925
+
4052
4926
  // src/utils/files.ts
4053
4927
  var import_ignore = __toESM(require_ignore(), 1);
4054
4928
  var import_fs7 = require("fs");
4055
- var path11 = __toESM(require("path"), 1);
4929
+ var path12 = __toESM(require("path"), 1);
4056
4930
  var PROJECT_MARKERS = [
4057
4931
  ".git",
4058
4932
  "package.json",
@@ -4070,7 +4944,7 @@ var PROJECT_MARKERS = [
4070
4944
  ];
4071
4945
  function hasProjectMarker(projectRoot3) {
4072
4946
  for (const marker of PROJECT_MARKERS) {
4073
- if ((0, import_fs7.existsSync)(path11.join(projectRoot3, marker))) {
4947
+ if ((0, import_fs7.existsSync)(path12.join(projectRoot3, marker))) {
4074
4948
  return true;
4075
4949
  }
4076
4950
  }
@@ -4097,33 +4971,53 @@ function createIgnoreFilter(projectRoot3) {
4097
4971
  "**/*build*/**"
4098
4972
  ];
4099
4973
  ig.add(defaultIgnores);
4100
- const gitignorePath = path11.join(projectRoot3, ".gitignore");
4974
+ const gitignorePath = path12.join(projectRoot3, ".gitignore");
4101
4975
  if ((0, import_fs7.existsSync)(gitignorePath)) {
4102
4976
  const gitignoreContent = (0, import_fs7.readFileSync)(gitignorePath, "utf-8");
4103
4977
  ig.add(gitignoreContent);
4104
4978
  }
4105
4979
  return ig;
4106
4980
  }
4107
- function shouldIncludeFile(filePath, projectRoot3, includePatterns, excludePatterns, ignoreFilter) {
4108
- const relativePath = path11.relative(projectRoot3, filePath);
4109
- if (hasFilteredPathSegment(relativePath, path11.sep)) {
4110
- return false;
4111
- }
4112
- if (ignoreFilter.ignores(relativePath)) {
4113
- return false;
4981
+ function toPosixRelativePath(relativePath) {
4982
+ return relativePath.split(path12.sep).join("/");
4983
+ }
4984
+ function matchesAnyGlob(filePath, patterns) {
4985
+ const normalized = toPosixRelativePath(filePath);
4986
+ return patterns.some((pattern) => matchGlob(normalized, pattern));
4987
+ }
4988
+ function isExcludedByPatterns(relativePath, excludePatterns) {
4989
+ return matchesAnyGlob(relativePath, excludePatterns);
4990
+ }
4991
+ function isExcludedDirectory(relativePath, excludePatterns) {
4992
+ const normalized = toPosixRelativePath(relativePath);
4993
+ if (matchesAnyGlob(normalized, excludePatterns)) {
4994
+ return true;
4114
4995
  }
4115
4996
  for (const pattern of excludePatterns) {
4116
- if (matchGlob(relativePath, pattern)) {
4117
- return false;
4997
+ const posixPattern = toPosixRelativePath(pattern).replace(/\/+$/, "");
4998
+ if (!posixPattern.endsWith("/**")) {
4999
+ continue;
4118
5000
  }
4119
- }
4120
- for (const pattern of includePatterns) {
4121
- if (matchGlob(relativePath, pattern)) {
5001
+ const directoryPattern = posixPattern.slice(0, -3);
5002
+ if (directoryPattern && matchesAnyGlob(normalized, [directoryPattern])) {
4122
5003
  return true;
4123
5004
  }
4124
5005
  }
4125
5006
  return false;
4126
5007
  }
5008
+ function shouldIncludeFile(filePath, projectRoot3, includePatterns, excludePatterns, ignoreFilter) {
5009
+ const relativePath = toPosixRelativePath(path12.relative(projectRoot3, filePath));
5010
+ if (hasFilteredPathSegment(relativePath, "/")) {
5011
+ return false;
5012
+ }
5013
+ if (ignoreFilter.ignores(relativePath)) {
5014
+ return false;
5015
+ }
5016
+ if (isExcludedByPatterns(relativePath, excludePatterns)) {
5017
+ return false;
5018
+ }
5019
+ return matchesAnyGlob(relativePath, includePatterns);
5020
+ }
4127
5021
  function matchGlob(filePath, pattern) {
4128
5022
  if (pattern.startsWith("**/")) {
4129
5023
  const withoutPrefix = pattern.slice(3);
@@ -4144,8 +5038,8 @@ async function* walkDirectory(dir, projectRoot3, includePatterns, excludePattern
4144
5038
  const filesInDir = [];
4145
5039
  const subdirs = [];
4146
5040
  for (const entry of entries) {
4147
- const fullPath = path11.join(dir, entry.name);
4148
- const relativePath = path11.relative(projectRoot3, fullPath);
5041
+ const fullPath = path12.join(dir, entry.name);
5042
+ const relativePath = toPosixRelativePath(path12.relative(projectRoot3, fullPath));
4149
5043
  if (isHiddenPathSegment(entry.name)) {
4150
5044
  if (entry.isDirectory()) {
4151
5045
  skipped.push({ path: relativePath, reason: "excluded" });
@@ -4163,6 +5057,10 @@ async function* walkDirectory(dir, projectRoot3, includePatterns, excludePattern
4163
5057
  continue;
4164
5058
  }
4165
5059
  if (entry.isDirectory()) {
5060
+ if (isExcludedDirectory(relativePath, excludePatterns)) {
5061
+ skipped.push({ path: relativePath, reason: "excluded" });
5062
+ continue;
5063
+ }
4166
5064
  subdirs.push({ fullPath, relativePath });
4167
5065
  } else if (entry.isFile()) {
4168
5066
  const stat5 = await import_fs7.promises.stat(fullPath);
@@ -4170,20 +5068,11 @@ async function* walkDirectory(dir, projectRoot3, includePatterns, excludePattern
4170
5068
  skipped.push({ path: relativePath, reason: "too_large" });
4171
5069
  continue;
4172
5070
  }
4173
- for (const pattern of excludePatterns) {
4174
- if (matchGlob(relativePath, pattern)) {
4175
- skipped.push({ path: relativePath, reason: "excluded" });
4176
- continue;
4177
- }
4178
- }
4179
- let matched = false;
4180
- for (const pattern of includePatterns) {
4181
- if (matchGlob(relativePath, pattern)) {
4182
- matched = true;
4183
- break;
4184
- }
5071
+ if (isExcludedByPatterns(relativePath, excludePatterns)) {
5072
+ skipped.push({ path: relativePath, reason: "excluded" });
5073
+ continue;
4185
5074
  }
4186
- if (matched) {
5075
+ if (matchesAnyGlob(relativePath, includePatterns)) {
4187
5076
  filesInDir.push({ path: fullPath, size: stat5.size });
4188
5077
  }
4189
5078
  }
@@ -4194,7 +5083,7 @@ async function* walkDirectory(dir, projectRoot3, includePatterns, excludePattern
4194
5083
  yield f;
4195
5084
  }
4196
5085
  for (let i = options.maxFilesPerDirectory; i < filesInDir.length; i++) {
4197
- skipped.push({ path: path11.relative(projectRoot3, filesInDir[i].path), reason: "excluded" });
5086
+ skipped.push({ path: toPosixRelativePath(path12.relative(projectRoot3, filesInDir[i].path)), reason: "excluded" });
4198
5087
  }
4199
5088
  const canRecurse = options.maxDepth === -1 || currentDepth < options.maxDepth;
4200
5089
  if (canRecurse) {
@@ -4234,8 +5123,8 @@ async function collectFiles(projectRoot3, includePatterns, excludePatterns, maxF
4234
5123
  if (additionalRoots && additionalRoots.length > 0) {
4235
5124
  const normalizedRoots = /* @__PURE__ */ new Set();
4236
5125
  for (const kbRoot of additionalRoots) {
4237
- const resolved = path11.normalize(
4238
- path11.isAbsolute(kbRoot) ? kbRoot : path11.resolve(projectRoot3, kbRoot)
5126
+ const resolved = path12.normalize(
5127
+ path12.isAbsolute(kbRoot) ? kbRoot : path12.resolve(projectRoot3, kbRoot)
4239
5128
  );
4240
5129
  normalizedRoots.add(resolved);
4241
5130
  }
@@ -4276,7 +5165,7 @@ function getErrorMessage(error) {
4276
5165
  return error instanceof Error ? error.message : String(error);
4277
5166
  }
4278
5167
  function runCommand(file, args, options) {
4279
- return new Promise((resolve17, reject) => {
5168
+ return new Promise((resolve18, reject) => {
4280
5169
  childProcess.execFile(
4281
5170
  file,
4282
5171
  args,
@@ -4286,7 +5175,7 @@ function runCommand(file, args, options) {
4286
5175
  reject(error);
4287
5176
  return;
4288
5177
  }
4289
- resolve17(stdout);
5178
+ resolve18(stdout);
4290
5179
  }
4291
5180
  );
4292
5181
  });
@@ -4378,8 +5267,8 @@ var AutoIndexCancelledError = class extends Error {
4378
5267
  function now() {
4379
5268
  return (/* @__PURE__ */ new Date()).toISOString();
4380
5269
  }
4381
- function canonicalizePath(targetPath) {
4382
- const resolved = path12.resolve(targetPath);
5270
+ function canonicalizePath2(targetPath) {
5271
+ const resolved = path13.resolve(targetPath);
4383
5272
  if ((0, import_fs8.existsSync)(resolved)) {
4384
5273
  try {
4385
5274
  return import_fs8.realpathSync.native(resolved);
@@ -4387,20 +5276,20 @@ function canonicalizePath(targetPath) {
4387
5276
  return resolved;
4388
5277
  }
4389
5278
  }
4390
- const parent = path12.dirname(resolved);
5279
+ const parent = path13.dirname(resolved);
4391
5280
  if (parent === resolved) return resolved;
4392
- return path12.join(canonicalizePath(parent), path12.basename(resolved));
5281
+ return path13.join(canonicalizePath2(parent), path13.basename(resolved));
4393
5282
  }
4394
5283
  function isHomeDirectory(projectRoot3) {
4395
- return canonicalizePath(projectRoot3) === canonicalizePath(os4.homedir());
5284
+ return canonicalizePath2(projectRoot3) === canonicalizePath2(os5.homedir());
4396
5285
  }
4397
- function projectLookupKey(projectRoot3, host) {
4398
- return `${host}::${canonicalizePath(projectRoot3)}`;
5286
+ function projectLookupKey2(projectRoot3, host) {
5287
+ return `${host}::${canonicalizePath2(projectRoot3)}`;
4399
5288
  }
4400
5289
  function coordinatorKey(projectRoot3, config, host) {
4401
- const canonicalProjectRoot = canonicalizePath(projectRoot3);
5290
+ const canonicalProjectRoot = canonicalizePath2(projectRoot3);
4402
5291
  const indexPath = resolveProjectIndexPath(projectRoot3, config.scope, host);
4403
- return `${canonicalizePath(indexPath)}::${canonicalProjectRoot}`;
5292
+ return `${canonicalizePath2(indexPath)}::${canonicalProjectRoot}`;
4404
5293
  }
4405
5294
  function getProjectSafety(projectRoot3, config) {
4406
5295
  if (isHomeDirectory(projectRoot3)) {
@@ -4431,10 +5320,10 @@ function safeFailureMessage(error) {
4431
5320
  }
4432
5321
  function cancellableDelay(delayMs, signal) {
4433
5322
  if (signal.aborted) return Promise.reject(new AutoIndexCancelledError());
4434
- return new Promise((resolve17, reject) => {
5323
+ return new Promise((resolve18, reject) => {
4435
5324
  const timer = setTimeout(() => {
4436
5325
  signal.removeEventListener("abort", onAbort);
4437
- resolve17();
5326
+ resolve18();
4438
5327
  }, delayMs);
4439
5328
  timer.unref?.();
4440
5329
  const onAbort = () => {
@@ -4446,18 +5335,44 @@ function cancellableDelay(delayMs, signal) {
4446
5335
  }
4447
5336
  function withTimeout(promise, timeoutMs) {
4448
5337
  if (timeoutMs <= 0) return Promise.resolve(void 0);
4449
- return new Promise((resolve17) => {
4450
- const timer = setTimeout(() => resolve17(void 0), timeoutMs);
5338
+ return new Promise((resolve18) => {
5339
+ const timer = setTimeout(() => resolve18(void 0), timeoutMs);
4451
5340
  timer.unref?.();
4452
5341
  void promise.then((value) => {
4453
5342
  clearTimeout(timer);
4454
- resolve17(value);
5343
+ resolve18(value);
4455
5344
  }, () => {
4456
5345
  clearTimeout(timer);
4457
- resolve17(void 0);
5346
+ resolve18(void 0);
4458
5347
  });
4459
5348
  });
4460
5349
  }
5350
+ function settlesWithin(promise, timeoutMs) {
5351
+ if (timeoutMs <= 0) return Promise.resolve(false);
5352
+ return new Promise((resolve18) => {
5353
+ let settled = false;
5354
+ const timer = setTimeout(() => {
5355
+ if (settled) return;
5356
+ settled = true;
5357
+ resolve18(false);
5358
+ }, timeoutMs);
5359
+ timer.unref?.();
5360
+ void promise.then(
5361
+ () => {
5362
+ if (settled) return;
5363
+ settled = true;
5364
+ clearTimeout(timer);
5365
+ resolve18(true);
5366
+ },
5367
+ () => {
5368
+ if (settled) return;
5369
+ settled = true;
5370
+ clearTimeout(timer);
5371
+ resolve18(true);
5372
+ }
5373
+ );
5374
+ });
5375
+ }
4461
5376
  function requestPriority(request) {
4462
5377
  if (request.force) return 4;
4463
5378
  if (request.source === "manual") return 3;
@@ -4468,6 +5383,7 @@ function mergeRequests(current, next) {
4468
5383
  if (!current) return next;
4469
5384
  const preferred = requestPriority(next) > requestPriority(current) ? next : current;
4470
5385
  return {
5386
+ allowDisabledAutoIndex: current.allowDisabledAutoIndex || next.allowDisabledAutoIndex,
4471
5387
  checkFreshness: current.checkFreshness && next.checkFreshness,
4472
5388
  force: current.force || next.force,
4473
5389
  onProgress: next.onProgress ?? current.onProgress,
@@ -4529,11 +5445,11 @@ var AutoIndexCoordinator = class {
4529
5445
  progress: this.status.progress ? { ...this.status.progress } : void 0
4530
5446
  };
4531
5447
  }
4532
- start(source) {
5448
+ start(source, allowDisabledAutoIndex = false) {
4533
5449
  this.refreshSafety();
4534
- if (!this.registration.config.indexing.autoIndex || !this.registration.safeToRun) return null;
5450
+ if (!this.registration.config.indexing.autoIndex && !allowDisabledAutoIndex || !this.registration.safeToRun) return null;
4535
5451
  if (this.status.state === "failed") return this.inFlight;
4536
- return this.request({ checkFreshness: true, force: false, source });
5452
+ return this.request({ allowDisabledAutoIndex, checkFreshness: true, force: false, source });
4537
5453
  }
4538
5454
  request(request) {
4539
5455
  if (this.stopped) {
@@ -4608,13 +5524,15 @@ var AutoIndexCoordinator = class {
4608
5524
  retryAttempt: void 0
4609
5525
  });
4610
5526
  const inFlight = this.inFlight;
4611
- if (inFlight) {
4612
- if (waitForCompletion) {
4613
- await inFlight;
4614
- } else {
4615
- await withTimeout(inFlight, SHUTDOWN_WAIT_MS);
4616
- }
5527
+ const completion = inFlight ? inFlight.then(() => void 0, () => void 0) : Promise.resolve();
5528
+ if (!inFlight) {
5529
+ return { completed: true, completion };
5530
+ }
5531
+ if (waitForCompletion) {
5532
+ await completion;
5533
+ return { completed: true, completion };
4617
5534
  }
5535
+ return { completed: await settlesWithin(completion, SHUTDOWN_WAIT_MS), completion };
4618
5536
  }
4619
5537
  startRequest(request) {
4620
5538
  if (this.stopped || !this.canRun(request)) {
@@ -4803,7 +5721,7 @@ var AutoIndexCoordinator = class {
4803
5721
  if (request.source === "manual" || request.source === "watcher") {
4804
5722
  return true;
4805
5723
  }
4806
- return this.registration.safeToRun && this.registration.config.indexing.autoIndex;
5724
+ return this.registration.safeToRun && (this.registration.config.indexing.autoIndex || request.allowDisabledAutoIndex === true);
4807
5725
  }
4808
5726
  shouldDeferForBattery(request) {
4809
5727
  return this.registration.backgroundIndexingPolicy !== null && (request.source === "startup" || request.source === "watcher");
@@ -4836,17 +5754,17 @@ var AutoIndexCoordinator = class {
4836
5754
  }
4837
5755
  }
4838
5756
  waitForBatteryRetry(delayMs) {
4839
- return new Promise((resolve17) => {
5757
+ return new Promise((resolve18) => {
4840
5758
  const timer = setTimeout(() => {
4841
5759
  if (this.batteryRetryTimer === timer) {
4842
5760
  this.batteryRetryTimer = null;
4843
5761
  this.resolveBatteryRetry = null;
4844
5762
  }
4845
- resolve17();
5763
+ resolve18();
4846
5764
  }, delayMs);
4847
5765
  timer.unref?.();
4848
5766
  this.batteryRetryTimer = timer;
4849
- this.resolveBatteryRetry = resolve17;
5767
+ this.resolveBatteryRetry = resolve18;
4850
5768
  });
4851
5769
  }
4852
5770
  cancelBatteryRetry() {
@@ -4854,9 +5772,9 @@ var AutoIndexCoordinator = class {
4854
5772
  clearTimeout(this.batteryRetryTimer);
4855
5773
  this.batteryRetryTimer = null;
4856
5774
  }
4857
- const resolve17 = this.resolveBatteryRetry;
5775
+ const resolve18 = this.resolveBatteryRetry;
4858
5776
  this.resolveBatteryRetry = null;
4859
- resolve17?.();
5777
+ resolve18?.();
4860
5778
  }
4861
5779
  finishBatteryCheck(batteryCheck) {
4862
5780
  if (this.batteryCheck !== batteryCheck) return;
@@ -4869,12 +5787,25 @@ var AutoIndexCoordinator = class {
4869
5787
  }
4870
5788
  };
4871
5789
  function getCoordinator(projectRoot3, host) {
4872
- const key = coordinatorKeysByProject.get(projectLookupKey(projectRoot3, host));
5790
+ const key = coordinatorKeysByProject.get(projectLookupKey2(projectRoot3, host));
4873
5791
  return key ? coordinators.get(key) ?? null : null;
4874
5792
  }
4875
- function configureAutoIndex(projectRoot3, host, config, getIndexer) {
4876
- const projectKey = projectLookupKey(projectRoot3, host);
5793
+ function synchronizeBackgroundWorker(projectRoot3, host, config, safeToRun) {
5794
+ if (safeToRun) {
5795
+ updateBackgroundWorkerConfig(projectRoot3, host, config);
5796
+ return;
5797
+ }
5798
+ void stopBackgroundWorker(projectRoot3, host).catch((error) => {
5799
+ console.error("[codebase-index] Failed to stop background worker after project safety changed:", error);
5800
+ });
5801
+ }
5802
+ function configureAutoIndex(projectRoot3, host, config, getIndexer, options = {}) {
5803
+ const projectKey = projectLookupKey2(projectRoot3, host);
4877
5804
  const safety = getProjectSafety(projectRoot3, config);
5805
+ const synchronizeWorker = options.synchronizeBackgroundWorker ?? true;
5806
+ if (options.preserveManagedWorker === true && isBackgroundWorkerManaged(projectRoot3, host)) {
5807
+ return;
5808
+ }
4878
5809
  const registration = {
4879
5810
  backgroundIndexingPolicy: createBackgroundIndexingPolicy(
4880
5811
  config.indexing.pauseBackgroundIndexingOnBattery
@@ -4892,6 +5823,9 @@ function configureAutoIndex(projectRoot3, host, config, getIndexer) {
4892
5823
  const stopPrevious = previousCoordinator?.stop(true) ?? Promise.resolve();
4893
5824
  const activation = Promise.all([previousBarrier, stopPrevious]).then(() => void 0);
4894
5825
  coordinatorReplacementBarriers.set(projectKey, activation);
5826
+ if (synchronizeWorker) {
5827
+ synchronizeBackgroundWorker(projectRoot3, host, config, safety.safeToRun);
5828
+ }
4895
5829
  coordinators.delete(previousKey);
4896
5830
  const coordinator2 = new AutoIndexCoordinator(registration);
4897
5831
  coordinator2.activateAfter(activation);
@@ -4907,8 +5841,17 @@ function configureAutoIndex(projectRoot3, host, config, getIndexer) {
4907
5841
  coordinator.update(registration);
4908
5842
  }
4909
5843
  coordinatorKeysByProject.set(projectKey, key);
5844
+ if (synchronizeWorker) {
5845
+ synchronizeBackgroundWorker(projectRoot3, host, config, safety.safeToRun);
5846
+ }
5847
+ }
5848
+ function startAutoIndexForBackgroundWorker(projectRoot3, host, source = "startup", allowDisabledAutoIndex = false) {
5849
+ return getCoordinator(projectRoot3, host)?.start(source, allowDisabledAutoIndex) ?? null;
4910
5850
  }
4911
5851
  function requestBackgroundIndex(projectRoot3, host) {
5852
+ if (isBackgroundWorkerManaged(projectRoot3, host) && !isBackgroundWorkerLeader(projectRoot3, host)) {
5853
+ return null;
5854
+ }
4912
5855
  return getCoordinator(projectRoot3, host)?.request({
4913
5856
  checkFreshness: false,
4914
5857
  force: false,
@@ -4948,15 +5891,23 @@ async function waitForAutoIndexForRetrieval(projectRoot3, host) {
4948
5891
  };
4949
5892
  }
4950
5893
  try {
4951
- if (await hasReadableCurrentIndex(coordinator)) return { ready: true };
5894
+ const readiness = await getSearchReadiness(coordinator);
5895
+ if (readiness.searchable) {
5896
+ return { ready: true };
5897
+ }
5898
+ if (readiness.blocked) return unavailableSnapshotResult(readiness.reason);
4952
5899
  } catch {
4953
5900
  }
4954
- const job = coordinator.start("retrieval") ?? coordinator.currentJob();
5901
+ const job = startRetrievalRefresh(projectRoot3, host, coordinator);
4955
5902
  if (job) {
4956
5903
  await withTimeout(job, coordinator.getWaitMs());
5904
+ } else if (isBackgroundWorkerManaged(projectRoot3, host)) {
5905
+ await waitForPublishedSnapshot(coordinator, coordinator.getWaitMs());
4957
5906
  }
4958
5907
  try {
4959
- if (await hasReadableCurrentIndex(coordinator)) return { ready: true };
5908
+ const readiness = await getSearchReadiness(coordinator);
5909
+ if (readiness.searchable) return { ready: true };
5910
+ if (readiness.blocked) return unavailableSnapshotResult(readiness.reason);
4960
5911
  } catch {
4961
5912
  }
4962
5913
  const status = coordinator.snapshot();
@@ -4977,21 +5928,52 @@ async function waitForAutoIndexForRetrieval(projectRoot3, host) {
4977
5928
  text: `Automatic indexing is ${status.state}. Retry shortly or call index_status for progress. You can also run index_codebase explicitly.`
4978
5929
  };
4979
5930
  }
4980
- async function stopAutoIndex(projectRoot3, host) {
4981
- await getCoordinator(projectRoot3, host)?.stop();
5931
+ async function stopAutoIndexForBackgroundWorker(projectRoot3, host, waitForCompletion = false) {
5932
+ const coordinator = getCoordinator(projectRoot3, host);
5933
+ if (!coordinator) {
5934
+ return { completed: true, completion: Promise.resolve() };
5935
+ }
5936
+ return coordinator.stop(waitForCompletion);
4982
5937
  }
4983
- async function hasReadableCurrentIndex(coordinator) {
5938
+ async function getSearchReadiness(coordinator) {
4984
5939
  const indexer = coordinator.getIndexer();
4985
5940
  if (indexer.getIndexFreshness) {
4986
5941
  const freshness = await indexer.getIndexFreshness();
4987
- return freshness.readable && freshness.current;
5942
+ const searchable = freshness.readable && freshness.current && freshness.reason === "current";
5943
+ return {
5944
+ blocked: freshness.reason === "unreadable" || freshness.reason === "incompatible" || freshness.reason === "failed-batches" || freshness.reason === "migration-required",
5945
+ reason: freshness.reason,
5946
+ searchable
5947
+ };
5948
+ }
5949
+ const indexed = (await indexer.getStatus()).indexed;
5950
+ return { blocked: false, searchable: indexed };
5951
+ }
5952
+ function unavailableSnapshotResult(reason) {
5953
+ 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.";
5954
+ return {
5955
+ ready: false,
5956
+ text: `${detail} Run index_codebase before retrying retrieval.`
5957
+ };
5958
+ }
5959
+ function startRetrievalRefresh(projectRoot3, host, coordinator) {
5960
+ if (isBackgroundWorkerManaged(projectRoot3, host)) {
5961
+ requestBackgroundWorkerRefresh(projectRoot3, host, true);
5962
+ return isBackgroundWorkerLeader(projectRoot3, host) ? coordinator.currentJob() : null;
5963
+ }
5964
+ return coordinator.start("retrieval") ?? coordinator.currentJob();
5965
+ }
5966
+ async function waitForPublishedSnapshot(coordinator, waitMs) {
5967
+ const deadline = Date.now() + waitMs;
5968
+ while (Date.now() < deadline) {
5969
+ if ((await getSearchReadiness(coordinator)).searchable) return;
5970
+ await new Promise((resolve18) => setTimeout(resolve18, Math.min(250, deadline - Date.now())));
4988
5971
  }
4989
- return (await indexer.getStatus()).indexed;
4990
5972
  }
4991
5973
 
4992
5974
  // src/tools/config-state.ts
4993
5975
  var import_fs9 = require("fs");
4994
- var path13 = __toESM(require("path"), 1);
5976
+ var path14 = __toESM(require("path"), 1);
4995
5977
  function normalizeKnowledgeBasePaths(config, projectRoot3) {
4996
5978
  const normalized = { ...config };
4997
5979
  if (Array.isArray(normalized.knowledgeBases)) {
@@ -5018,8 +6000,8 @@ function loadEditableConfig(projectRoot3, host) {
5018
6000
  }
5019
6001
  function saveConfig(projectRoot3, config, host) {
5020
6002
  const configPath = getConfigPath(projectRoot3, host);
5021
- const configDir = path13.dirname(configPath);
5022
- const configBaseDir = path13.dirname(configDir);
6003
+ const configDir = path14.dirname(configPath);
6004
+ const configBaseDir = path14.dirname(configDir);
5023
6005
  if (!(0, import_fs9.existsSync)(configDir)) {
5024
6006
  (0, import_fs9.mkdirSync)(configDir, { recursive: true });
5025
6007
  }
@@ -5034,7 +6016,7 @@ function saveConfig(projectRoot3, config, host) {
5034
6016
 
5035
6017
  // src/indexer/index.ts
5036
6018
  var import_fs12 = require("fs");
5037
- var path19 = __toESM(require("path"), 1);
6019
+ var path20 = __toESM(require("path"), 1);
5038
6020
  var import_perf_hooks = require("perf_hooks");
5039
6021
  var import_child_process4 = require("child_process");
5040
6022
  var import_util4 = require("util");
@@ -5061,7 +6043,7 @@ function pTimeout(promise, options) {
5061
6043
  } = options;
5062
6044
  let timer;
5063
6045
  let abortHandler;
5064
- const wrappedPromise = new Promise((resolve17, reject) => {
6046
+ const wrappedPromise = new Promise((resolve18, reject) => {
5065
6047
  if (typeof milliseconds !== "number" || Math.sign(milliseconds) !== 1) {
5066
6048
  throw new TypeError(`Expected \`milliseconds\` to be a positive number, got \`${milliseconds}\``);
5067
6049
  }
@@ -5075,7 +6057,7 @@ function pTimeout(promise, options) {
5075
6057
  };
5076
6058
  signal.addEventListener("abort", abortHandler, { once: true });
5077
6059
  }
5078
- promise.then(resolve17, reject);
6060
+ promise.then(resolve18, reject);
5079
6061
  if (milliseconds === Number.POSITIVE_INFINITY) {
5080
6062
  return;
5081
6063
  }
@@ -5083,7 +6065,7 @@ function pTimeout(promise, options) {
5083
6065
  timer = customTimers.setTimeout.call(void 0, () => {
5084
6066
  if (fallback) {
5085
6067
  try {
5086
- resolve17(fallback());
6068
+ resolve18(fallback());
5087
6069
  } catch (error) {
5088
6070
  reject(error);
5089
6071
  }
@@ -5093,7 +6075,7 @@ function pTimeout(promise, options) {
5093
6075
  promise.cancel();
5094
6076
  }
5095
6077
  if (message === false) {
5096
- resolve17();
6078
+ resolve18();
5097
6079
  } else if (message instanceof Error) {
5098
6080
  reject(message);
5099
6081
  } else {
@@ -5495,7 +6477,7 @@ var PQueue = class extends import_index.default {
5495
6477
  // Assign unique ID if not provided
5496
6478
  id: options.id ?? (this.#idAssigner++).toString()
5497
6479
  };
5498
- return new Promise((resolve17, reject) => {
6480
+ return new Promise((resolve18, reject) => {
5499
6481
  const taskSymbol = /* @__PURE__ */ Symbol(`task-${options.id}`);
5500
6482
  let cleanupQueueAbortHandler = () => void 0;
5501
6483
  const run = async () => {
@@ -5535,7 +6517,7 @@ var PQueue = class extends import_index.default {
5535
6517
  })]);
5536
6518
  }
5537
6519
  const result = await operation;
5538
- resolve17(result);
6520
+ resolve18(result);
5539
6521
  this.emit("completed", result);
5540
6522
  } catch (error) {
5541
6523
  reject(error);
@@ -5723,13 +6705,13 @@ var PQueue = class extends import_index.default {
5723
6705
  });
5724
6706
  }
5725
6707
  async #onEvent(event, filter) {
5726
- return new Promise((resolve17) => {
6708
+ return new Promise((resolve18) => {
5727
6709
  const listener = () => {
5728
6710
  if (filter && !filter()) {
5729
6711
  return;
5730
6712
  }
5731
6713
  this.off(event, listener);
5732
- resolve17();
6714
+ resolve18();
5733
6715
  };
5734
6716
  this.on(event, listener);
5735
6717
  });
@@ -6015,7 +6997,7 @@ async function onAttemptFailure({ error, attemptNumber, retriesConsumed, startTi
6015
6997
  const finalDelay = Math.min(delayTime, remainingTime);
6016
6998
  options.signal?.throwIfAborted();
6017
6999
  if (finalDelay > 0) {
6018
- await new Promise((resolve17, reject) => {
7000
+ await new Promise((resolve18, reject) => {
6019
7001
  const onAbort = () => {
6020
7002
  clearTimeout(timeoutToken);
6021
7003
  options.signal?.removeEventListener("abort", onAbort);
@@ -6023,7 +7005,7 @@ async function onAttemptFailure({ error, attemptNumber, retriesConsumed, startTi
6023
7005
  };
6024
7006
  const timeoutToken = setTimeout(() => {
6025
7007
  options.signal?.removeEventListener("abort", onAbort);
6026
- resolve17();
7008
+ resolve18();
6027
7009
  }, finalDelay);
6028
7010
  if (options.unref) {
6029
7011
  timeoutToken.unref?.();
@@ -6141,17 +7123,17 @@ function validateExternalUrl(urlString) {
6141
7123
  if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
6142
7124
  return { valid: false, reason: `Blocked protocol: ${parsed.protocol}` };
6143
7125
  }
6144
- const hostname2 = parsed.hostname.toLowerCase();
6145
- if (BLOCKED_HOSTNAMES.has(hostname2)) {
6146
- return { valid: false, reason: `Blocked: cloud metadata service (${hostname2})` };
7126
+ const hostname3 = parsed.hostname.toLowerCase();
7127
+ if (BLOCKED_HOSTNAMES.has(hostname3)) {
7128
+ return { valid: false, reason: `Blocked: cloud metadata service (${hostname3})` };
6147
7129
  }
6148
7130
  for (const pattern of BLOCKED_METADATA_IPS) {
6149
- if (pattern.test(hostname2)) {
6150
- return { valid: false, reason: `Blocked: cloud metadata IP (${hostname2})` };
7131
+ if (pattern.test(hostname3)) {
7132
+ return { valid: false, reason: `Blocked: cloud metadata IP (${hostname3})` };
6151
7133
  }
6152
7134
  }
6153
- if (/^169\.254\./.test(hostname2)) {
6154
- return { valid: false, reason: `Blocked: link-local address (${hostname2})` };
7135
+ if (/^169\.254\./.test(hostname3)) {
7136
+ return { valid: false, reason: `Blocked: link-local address (${hostname3})` };
6155
7137
  }
6156
7138
  return { valid: true };
6157
7139
  }
@@ -7163,8 +8145,8 @@ function extractParamNames(params) {
7163
8145
  }
7164
8146
 
7165
8147
  // src/native/binding.ts
7166
- var os5 = __toESM(require("os"), 1);
7167
- var path14 = __toESM(require("path"), 1);
8148
+ var os6 = __toESM(require("os"), 1);
8149
+ var path15 = __toESM(require("path"), 1);
7168
8150
  var module2 = __toESM(require("module"), 1);
7169
8151
  var import_node_url = require("url");
7170
8152
 
@@ -7201,7 +8183,7 @@ var STABLE_NATIVE_BINARY_NAME = IDENTITY_CATALOG.native.binaryName;
7201
8183
 
7202
8184
  // src/native/binding.ts
7203
8185
  var import_meta = {};
7204
- function getNativeBindingFilename(platform2 = os5.platform(), arch2 = os5.arch()) {
8186
+ function getNativeBindingFilename(platform2 = os6.platform(), arch2 = os6.arch()) {
7205
8187
  if (platform2 === "darwin" && arch2 === "arm64") {
7206
8188
  return `${STABLE_NATIVE_BINARY_NAME}.darwin-arm64.node`;
7207
8189
  }
@@ -7219,25 +8201,25 @@ function getNativeBindingFilename(platform2 = os5.platform(), arch2 = os5.arch()
7219
8201
  }
7220
8202
  throw new Error(`Unsupported platform: ${platform2}-${arch2}`);
7221
8203
  }
7222
- function resolveNativeBindingPath(packageRoot, platform2 = os5.platform(), arch2 = os5.arch()) {
7223
- return path14.join(packageRoot, "native", getNativeBindingFilename(platform2, arch2));
8204
+ function resolveNativeBindingPath(packageRoot, platform2 = os6.platform(), arch2 = os6.arch()) {
8205
+ return path15.join(packageRoot, "native", getNativeBindingFilename(platform2, arch2));
7224
8206
  }
7225
8207
  function getNativeBinding() {
7226
8208
  let currentDir;
7227
8209
  let requireTarget;
7228
8210
  if (typeof import_meta !== "undefined" && import_meta.url) {
7229
- currentDir = path14.dirname((0, import_node_url.fileURLToPath)(import_meta.url));
8211
+ currentDir = path15.dirname((0, import_node_url.fileURLToPath)(import_meta.url));
7230
8212
  requireTarget = import_meta.url;
7231
8213
  } else if (typeof __dirname !== "undefined") {
7232
8214
  currentDir = __dirname;
7233
8215
  requireTarget = __filename;
7234
8216
  } else {
7235
8217
  currentDir = process.cwd();
7236
- requireTarget = path14.join(currentDir, "index.js");
8218
+ requireTarget = path15.join(currentDir, "index.js");
7237
8219
  }
7238
8220
  const normalizedDir = currentDir.replace(/\\/g, "/");
7239
- const isDevMode = normalizedDir.includes("/src/native") || currentDir.includes(path14.join("src", "native"));
7240
- const packageRoot = isDevMode ? path14.resolve(currentDir, "../..") : path14.resolve(currentDir, "..");
8221
+ const isDevMode = normalizedDir.includes("/src/native") || currentDir.includes(path15.join("src", "native"));
8222
+ const packageRoot = isDevMode ? path15.resolve(currentDir, "../..") : path15.resolve(currentDir, "..");
7241
8223
  const nativePath = resolveNativeBindingPath(packageRoot);
7242
8224
  const require2 = module2.createRequire(requireTarget);
7243
8225
  return require2(nativePath);
@@ -7821,8 +8803,8 @@ var Database = class _Database {
7821
8803
 
7822
8804
  // src/git/branch-materialization.ts
7823
8805
  var import_fs10 = require("fs");
7824
- var os6 = __toESM(require("os"), 1);
7825
- var path15 = __toESM(require("path"), 1);
8806
+ var os7 = __toESM(require("os"), 1);
8807
+ var path16 = __toESM(require("path"), 1);
7826
8808
 
7827
8809
  // src/git/branch-resolution.ts
7828
8810
  var import_child_process = require("child_process");
@@ -8141,13 +9123,13 @@ async function isWorktreeRegistered(projectRoot3, worktreePath) {
8141
9123
  return false;
8142
9124
  }
8143
9125
  function isPathWithinRoot(filePath, rootPath) {
8144
- const relative13 = path15.relative(path15.resolve(rootPath), path15.resolve(filePath));
8145
- return relative13 === "" || !relative13.startsWith(`..${path15.sep}`) && relative13 !== ".." && !path15.isAbsolute(relative13);
9126
+ const relative13 = path16.relative(path16.resolve(rootPath), path16.resolve(filePath));
9127
+ return relative13 === "" || !relative13.startsWith(`..${path16.sep}`) && relative13 !== ".." && !path16.isAbsolute(relative13);
8146
9128
  }
8147
9129
  async function pruneExactMissingWorktreeRegistration(projectRoot3, worktreePath) {
8148
9130
  if (await pathExists(worktreePath)) return false;
8149
9131
  const commonDir = await runGit(projectRoot3, ["rev-parse", "--path-format=absolute", "--git-common-dir"]);
8150
- const registrationsRoot = path15.join(commonDir, "worktrees");
9132
+ const registrationsRoot = path16.join(commonDir, "worktrees");
8151
9133
  let entries;
8152
9134
  try {
8153
9135
  entries = await import_fs10.promises.readdir(registrationsRoot, { withFileTypes: true });
@@ -8158,16 +9140,16 @@ async function pruneExactMissingWorktreeRegistration(projectRoot3, worktreePath)
8158
9140
  const target = canonicalizePathForComparison(worktreePath);
8159
9141
  for (const entry of entries) {
8160
9142
  if (!entry.isDirectory()) continue;
8161
- const registrationPath = path15.join(registrationsRoot, entry.name);
9143
+ const registrationPath = path16.join(registrationsRoot, entry.name);
8162
9144
  if (!isPathWithinRoot(registrationPath, registrationsRoot)) continue;
8163
9145
  let gitdirPath;
8164
9146
  try {
8165
- gitdirPath = (await import_fs10.promises.readFile(path15.join(registrationPath, "gitdir"), "utf8")).trim();
9147
+ gitdirPath = (await import_fs10.promises.readFile(path16.join(registrationPath, "gitdir"), "utf8")).trim();
8166
9148
  } catch {
8167
9149
  continue;
8168
9150
  }
8169
- const resolvedGitdirPath = path15.isAbsolute(gitdirPath) ? gitdirPath : path15.resolve(registrationPath, gitdirPath);
8170
- if (canonicalizePathForComparison(path15.dirname(resolvedGitdirPath)) !== target) continue;
9151
+ const resolvedGitdirPath = path16.isAbsolute(gitdirPath) ? gitdirPath : path16.resolve(registrationPath, gitdirPath);
9152
+ if (canonicalizePathForComparison(path16.dirname(resolvedGitdirPath)) !== target) continue;
8171
9153
  await import_fs10.promises.rm(registrationPath, { recursive: true, force: true });
8172
9154
  return true;
8173
9155
  }
@@ -8185,7 +9167,7 @@ async function removeWorktree(projectRoot3, worktreePath) {
8185
9167
  registered = await isWorktreeRegistered(projectRoot3, worktreePath);
8186
9168
  } catch (error) {
8187
9169
  errors.push(asError(error));
8188
- throw new AggregateError(errors, `Could not verify temporary worktree deregistration; preserved ${path15.dirname(worktreePath)}`);
9170
+ throw new AggregateError(errors, `Could not verify temporary worktree deregistration; preserved ${path16.dirname(worktreePath)}`);
8189
9171
  }
8190
9172
  if (registered) {
8191
9173
  try {
@@ -8201,7 +9183,7 @@ async function removeWorktree(projectRoot3, worktreePath) {
8201
9183
  registered = await isWorktreeRegistered(projectRoot3, worktreePath);
8202
9184
  } catch (error) {
8203
9185
  errors.push(asError(error));
8204
- throw new AggregateError(errors, `Could not verify temporary worktree deregistration; preserved ${path15.dirname(worktreePath)}`);
9186
+ throw new AggregateError(errors, `Could not verify temporary worktree deregistration; preserved ${path16.dirname(worktreePath)}`);
8205
9187
  }
8206
9188
  }
8207
9189
  if (registered && !await pathExists(worktreePath)) {
@@ -8214,13 +9196,13 @@ async function removeWorktree(projectRoot3, worktreePath) {
8214
9196
  }
8215
9197
  if (registered) {
8216
9198
  errors.push(new Error(`Temporary worktree remains registered: ${worktreePath}`));
8217
- throw new AggregateError(errors, `Failed to deregister temporary worktree; preserved ${path15.dirname(worktreePath)}`);
9199
+ throw new AggregateError(errors, `Failed to deregister temporary worktree; preserved ${path16.dirname(worktreePath)}`);
8218
9200
  }
8219
9201
  try {
8220
- await import_fs10.promises.rm(path15.dirname(worktreePath), { recursive: true, force: true });
9202
+ await import_fs10.promises.rm(path16.dirname(worktreePath), { recursive: true, force: true });
8221
9203
  } catch (error) {
8222
9204
  errors.push(asError(error));
8223
- throw new AggregateError(errors, `Deregistered the temporary worktree but could not remove ${path15.dirname(worktreePath)}`);
9205
+ throw new AggregateError(errors, `Deregistered the temporary worktree but could not remove ${path16.dirname(worktreePath)}`);
8224
9206
  }
8225
9207
  }
8226
9208
  async function cleanupTemporaryWorktree(projectRoot3, worktreePath, temporaryRoot) {
@@ -8256,9 +9238,9 @@ async function withMaterializedBranch(request, callback) {
8256
9238
  `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.`
8257
9239
  );
8258
9240
  }
8259
- const temporaryRoot = await import_fs10.promises.mkdtemp(path15.join(os6.tmpdir(), "codebase-index-branch-"));
8260
- const worktreePath = path15.join(temporaryRoot, "worktree");
8261
- const hooksPath = path15.join(temporaryRoot, "hooks");
9241
+ const temporaryRoot = await import_fs10.promises.mkdtemp(path16.join(os7.tmpdir(), "codebase-index-branch-"));
9242
+ const worktreePath = path16.join(temporaryRoot, "worktree");
9243
+ const hooksPath = path16.join(temporaryRoot, "hooks");
8262
9244
  await import_fs10.promises.mkdir(hooksPath);
8263
9245
  const info = {
8264
9246
  branch: request.branch,
@@ -8310,7 +9292,7 @@ async function withMaterializedBranch(request, callback) {
8310
9292
  // src/tools/changed-files.ts
8311
9293
  var import_child_process2 = require("child_process");
8312
9294
  var import_fs11 = require("fs");
8313
- var path16 = __toESM(require("path"), 1);
9295
+ var path17 = __toESM(require("path"), 1);
8314
9296
  var import_util2 = require("util");
8315
9297
  var execFileAsync2 = (0, import_util2.promisify)(import_child_process2.execFile);
8316
9298
  var GH_PR_VIEW_FIELDS = [
@@ -8452,7 +9434,7 @@ function getHeadRepositoryIdentity(data, host) {
8452
9434
  return `${host}/${owner.toLowerCase()}/${repository.replace(/\.git$/i, "").toLowerCase()}`;
8453
9435
  }
8454
9436
  function getLocalRepositoryIdentity(projectRoot3) {
8455
- let canonicalRoot = path16.resolve(projectRoot3);
9437
+ let canonicalRoot = path17.resolve(projectRoot3);
8456
9438
  try {
8457
9439
  canonicalRoot = import_fs11.realpathSync.native(canonicalRoot);
8458
9440
  } catch {
@@ -8513,17 +9495,17 @@ async function getMergeBase(projectRoot3, baseCommit, headCommit) {
8513
9495
  return commit;
8514
9496
  }
8515
9497
  function normalizeFiles(rawFiles, projectRoot3) {
8516
- const root = path16.resolve(projectRoot3);
9498
+ const root = path17.resolve(projectRoot3);
8517
9499
  const seen = /* @__PURE__ */ new Set();
8518
9500
  const result = [];
8519
9501
  for (const raw of rawFiles) {
8520
9502
  if (raw.length === 0) continue;
8521
- const absolute = path16.resolve(root, raw);
8522
- const relative13 = path16.relative(root, absolute);
8523
- if (path16.isAbsolute(raw) || relative13 === ".." || relative13.startsWith(`..${path16.sep}`) || path16.isAbsolute(relative13)) {
9503
+ const absolute = path17.resolve(root, raw);
9504
+ const relative13 = path17.relative(root, absolute);
9505
+ if (path17.isAbsolute(raw) || relative13 === ".." || relative13.startsWith(`..${path17.sep}`) || path17.isAbsolute(relative13)) {
8524
9506
  throw new Error(`Changed file escapes the project root: ${JSON.stringify(raw)}`);
8525
9507
  }
8526
- const cleaned = relative13.startsWith(`.${path16.sep}`) ? relative13.slice(2) : relative13;
9508
+ const cleaned = relative13.startsWith(`.${path17.sep}`) ? relative13.slice(2) : relative13;
8527
9509
  if (!seen.has(cleaned)) {
8528
9510
  seen.add(cleaned);
8529
9511
  result.push(cleaned);
@@ -8534,7 +9516,7 @@ function normalizeFiles(rawFiles, projectRoot3) {
8534
9516
 
8535
9517
  // src/indexer/git-blame.ts
8536
9518
  var import_child_process3 = require("child_process");
8537
- var path17 = __toESM(require("path"), 1);
9519
+ var path18 = __toESM(require("path"), 1);
8538
9520
  var import_util3 = require("util");
8539
9521
  var execFileAsync3 = (0, import_util3.promisify)(import_child_process3.execFile);
8540
9522
  function parseGitBlamePorcelain(output) {
@@ -8572,7 +9554,7 @@ function parseGitBlamePorcelain(output) {
8572
9554
  return Array.from(commits.values()).filter((commit) => commit.lines > 0).sort((a, b) => b.lines - a.lines || b.committedAt - a.committedAt)[0];
8573
9555
  }
8574
9556
  async function getChunkGitBlame(projectRoot3, filePath, startLine, endLine) {
8575
- const relativePath = path17.relative(projectRoot3, filePath);
9557
+ const relativePath = path18.relative(projectRoot3, filePath);
8576
9558
  try {
8577
9559
  const { stdout } = await execFileAsync3(
8578
9560
  "git",
@@ -9151,8 +10133,8 @@ function pathSegmentsForAffinityMatch(filePath) {
9151
10133
  if (segments.length === 0) {
9152
10134
  return [];
9153
10135
  }
9154
- const basename7 = segments[segments.length - 1] ?? "";
9155
- const basenameWithoutExt = basename7.replace(/\.[^/.]+$/u, "");
10136
+ const basename8 = segments[segments.length - 1] ?? "";
10137
+ const basenameWithoutExt = basename8.replace(/\.[^/.]+$/u, "");
9156
10138
  const normalizedSegments = segments.map((segment) => segment.toLowerCase());
9157
10139
  return Array.from(/* @__PURE__ */ new Set([
9158
10140
  ...normalizedSegments,
@@ -9461,8 +10443,8 @@ function hasAllEmbeddingParts(parts, expectedPartCount) {
9461
10443
 
9462
10444
  // src/indexer/failed-state-persistence.ts
9463
10445
  var fs2 = __toESM(require("fs"), 1);
9464
- var import_node_crypto = require("crypto");
9465
- var path18 = __toESM(require("path"), 1);
10446
+ var import_node_crypto2 = require("crypto");
10447
+ var path19 = __toESM(require("path"), 1);
9466
10448
  var import_node_string_decoder = require("string_decoder");
9467
10449
  var CURRENT_FAILED_BATCH_VERSION = 1;
9468
10450
  var DEFAULT_MALFORMED_LINE_ACTION = "skip";
@@ -9480,7 +10462,7 @@ function* readFailedBatchRecords(filePath, options = {}) {
9480
10462
  function createFailedBatchWriter(targetPath) {
9481
10463
  const temporaryPath = createTemporaryPath(targetPath);
9482
10464
  let finalized = false;
9483
- fs2.mkdirSync(path18.dirname(targetPath), { recursive: true });
10465
+ fs2.mkdirSync(path19.dirname(targetPath), { recursive: true });
9484
10466
  fs2.closeSync(fs2.openSync(temporaryPath, "w"));
9485
10467
  const write = (record) => {
9486
10468
  if (finalized) {
@@ -9499,7 +10481,7 @@ function createFailedBatchWriter(targetPath) {
9499
10481
  if (lines.length === 0) {
9500
10482
  return;
9501
10483
  }
9502
- fs2.mkdirSync(path18.dirname(targetPath), { recursive: true });
10484
+ fs2.mkdirSync(path19.dirname(targetPath), { recursive: true });
9503
10485
  fs2.appendFileSync(temporaryPath, `${lines.join("\n")}
9504
10486
  `, "utf-8");
9505
10487
  };
@@ -9507,7 +10489,7 @@ function createFailedBatchWriter(targetPath) {
9507
10489
  if (finalized) {
9508
10490
  return;
9509
10491
  }
9510
- fs2.mkdirSync(path18.dirname(targetPath), { recursive: true });
10492
+ fs2.mkdirSync(path19.dirname(targetPath), { recursive: true });
9511
10493
  fs2.renameSync(temporaryPath, targetPath);
9512
10494
  finalized = true;
9513
10495
  };
@@ -9653,10 +10635,10 @@ function stripLeadingBomAndWhitespace(value) {
9653
10635
  return result;
9654
10636
  }
9655
10637
  function createTemporaryPath(targetPath) {
9656
- const randomId = (0, import_node_crypto.createHash)("sha1").update(`${Date.now()}:${(0, import_node_crypto.randomBytes)(8).toString("hex")}`).digest("hex");
9657
- const targetDir = path18.dirname(targetPath);
9658
- const baseName = path18.basename(targetPath);
9659
- return path18.join(targetDir, `.${baseName}.${randomId}.tmp`);
10638
+ const randomId = (0, import_node_crypto2.createHash)("sha1").update(`${Date.now()}:${(0, import_node_crypto2.randomBytes)(8).toString("hex")}`).digest("hex");
10639
+ const targetDir = path19.dirname(targetPath);
10640
+ const baseName = path19.basename(targetPath);
10641
+ return path19.join(targetDir, `.${baseName}.${randomId}.tmp`);
9660
10642
  }
9661
10643
  function handleMalformedLine(filePath, lineNumber, line, error, options) {
9662
10644
  const action = options.malformedLineAction ?? DEFAULT_MALFORMED_LINE_ACTION;
@@ -9902,9 +10884,9 @@ var SWIFT_PARSER_VERSION = "1";
9902
10884
  var METAL_PARSER_VERSION = "1";
9903
10885
  var SYMBOL_EXTRACTOR_VERSION = "1";
9904
10886
  function isPathWithinRoot2(filePath, rootPath) {
9905
- const normalizedFilePath = path19.resolve(filePath);
9906
- const normalizedRoot = path19.resolve(rootPath);
9907
- return normalizedFilePath === normalizedRoot || normalizedFilePath.startsWith(`${normalizedRoot}${path19.sep}`);
10887
+ const normalizedFilePath = path20.resolve(filePath);
10888
+ const normalizedRoot = path20.resolve(rootPath);
10889
+ return normalizedFilePath === normalizedRoot || normalizedFilePath.startsWith(`${normalizedRoot}${path20.sep}`);
9908
10890
  }
9909
10891
  function promoteIdentifierMatches(query, combined, semanticCandidates, keywordCandidates, database, branchChunkIds, prioritizeSourcePaths = classifyQueryIntentRaw(query) === "source") {
9910
10892
  if (combined.length === 0) {
@@ -10235,10 +11217,10 @@ function matchesHardSearchFilters(candidate, options, projectRoot3) {
10235
11217
  }
10236
11218
  if (options?.directory) {
10237
11219
  const candidatePath = canonicalizePathForComparison(
10238
- path19.resolve(projectRoot3, candidate.metadata.filePath.replace(/\\/g, path19.sep))
11220
+ path20.resolve(projectRoot3, candidate.metadata.filePath.replace(/\\/g, path20.sep))
10239
11221
  );
10240
11222
  const directoryPath = canonicalizePathForComparison(
10241
- path19.resolve(projectRoot3, options.directory.trim().replace(/\\/g, path19.sep))
11223
+ path20.resolve(projectRoot3, options.directory.trim().replace(/\\/g, path20.sep))
10242
11224
  );
10243
11225
  if (!isPathWithinRoot2(candidatePath, directoryPath)) return false;
10244
11226
  }
@@ -10351,26 +11333,37 @@ var Indexer = class _Indexer {
10351
11333
  return this.indexPathOverride ?? resolveProjectIndexPath(this.projectRoot, this.config.scope, this.host);
10352
11334
  }
10353
11335
  toCanonicalFilePath(filePath) {
10354
- if (!path19.isAbsolute(filePath)) {
11336
+ if (!path20.isAbsolute(filePath)) {
10355
11337
  return this.resolveStoredFilePath(filePath, this.projectRoot);
10356
11338
  }
10357
- if (path19.resolve(this.materializedProjectRoot) === path19.resolve(this.projectRoot) || !isPathWithinRoot2(filePath, this.materializedProjectRoot)) {
11339
+ if (path20.resolve(this.materializedProjectRoot) === path20.resolve(this.projectRoot) || !isPathWithinRoot2(filePath, this.materializedProjectRoot)) {
10358
11340
  return filePath;
10359
11341
  }
10360
- return path19.resolve(this.projectRoot, path19.relative(this.materializedProjectRoot, filePath));
11342
+ return path20.resolve(this.projectRoot, path20.relative(this.materializedProjectRoot, filePath));
10361
11343
  }
10362
11344
  toStoredFilePath(filePath) {
10363
11345
  const canonicalFilePath = this.toCanonicalFilePath(filePath);
10364
11346
  if (this.config.scope !== "project" || !isPathWithinRoot2(canonicalFilePath, this.projectRoot)) {
10365
11347
  return canonicalFilePath;
10366
11348
  }
10367
- return path19.relative(this.projectRoot, canonicalFilePath).split(path19.sep).join("/");
11349
+ return path20.relative(this.projectRoot, canonicalFilePath).split(path20.sep).join("/");
11350
+ }
11351
+ isStoredPathExcluded(storedPath) {
11352
+ let matchPath = storedPath.split(path20.sep).join("/");
11353
+ if (path20.isAbsolute(storedPath)) {
11354
+ const relativePath = path20.relative(this.projectRoot, storedPath).split(path20.sep).join("/");
11355
+ if (relativePath.startsWith("..") || path20.isAbsolute(relativePath)) {
11356
+ return false;
11357
+ }
11358
+ matchPath = relativePath;
11359
+ }
11360
+ return isExcludedByPatterns(matchPath, this.config.exclude);
10368
11361
  }
10369
11362
  resolveStoredFilePath(filePath, rootPath = this.projectRoot) {
10370
- if (path19.isAbsolute(filePath)) {
11363
+ if (path20.isAbsolute(filePath)) {
10371
11364
  return filePath;
10372
11365
  }
10373
- const resolvedPath = path19.resolve(rootPath, ...filePath.split("/"));
11366
+ const resolvedPath = path20.resolve(rootPath, ...filePath.split("/"));
10374
11367
  if (!isPathWithinRoot2(resolvedPath, rootPath)) {
10375
11368
  throw new Error(`Stored project path escapes project root: ${JSON.stringify(filePath)}`);
10376
11369
  }
@@ -10394,7 +11387,7 @@ var Indexer = class _Indexer {
10394
11387
  }
10395
11388
  toMaterializedFilePath(filePath) {
10396
11389
  const storedFilePath = this.toStoredFilePath(filePath);
10397
- if (path19.isAbsolute(storedFilePath)) {
11390
+ if (path20.isAbsolute(storedFilePath)) {
10398
11391
  return storedFilePath;
10399
11392
  }
10400
11393
  return this.resolveStoredFilePath(storedFilePath, this.materializedProjectRoot);
@@ -10411,10 +11404,10 @@ var Indexer = class _Indexer {
10411
11404
  }
10412
11405
  getRuntimeArtifactPath(fileName) {
10413
11406
  const namespace = this.getRuntimeArtifactNamespace();
10414
- if (!namespace) return path19.join(this.indexPath, fileName);
10415
- const extension = path19.extname(fileName);
11407
+ if (!namespace) return path20.join(this.indexPath, fileName);
11408
+ const extension = path20.extname(fileName);
10416
11409
  const baseName = fileName.slice(0, fileName.length - extension.length);
10417
- return path19.join(this.indexPath, `${baseName}.${namespace}${extension}`);
11410
+ return path20.join(this.indexPath, `${baseName}.${namespace}${extension}`);
10418
11411
  }
10419
11412
  refreshRuntimeArtifactPaths() {
10420
11413
  this.fileHashCachePath = this.getRuntimeArtifactPath("file-hashes.json");
@@ -10427,14 +11420,14 @@ var Indexer = class _Indexer {
10427
11420
  getMaterializedKnowledgeBases() {
10428
11421
  const canonicalProjectRoot = this.getCanonicalPath(this.projectRoot);
10429
11422
  return this.config.knowledgeBases.map((knowledgeBase) => {
10430
- const configuredPath = path19.isAbsolute(knowledgeBase) ? knowledgeBase : path19.resolve(this.projectRoot, knowledgeBase);
11423
+ const configuredPath = path20.isAbsolute(knowledgeBase) ? knowledgeBase : path20.resolve(this.projectRoot, knowledgeBase);
10431
11424
  const canonicalPath = this.getCanonicalPath(configuredPath);
10432
11425
  if (!isPathWithinRoot2(canonicalPath, canonicalProjectRoot)) {
10433
11426
  return canonicalPath;
10434
11427
  }
10435
- return path19.resolve(
11428
+ return path20.resolve(
10436
11429
  this.materializedProjectRoot,
10437
- path19.relative(canonicalProjectRoot, canonicalPath)
11430
+ path20.relative(canonicalProjectRoot, canonicalPath)
10438
11431
  );
10439
11432
  });
10440
11433
  }
@@ -10442,7 +11435,7 @@ var Indexer = class _Indexer {
10442
11435
  try {
10443
11436
  return canonicalizePathForComparison(targetPath);
10444
11437
  } catch {
10445
- return path19.resolve(targetPath);
11438
+ return path20.resolve(targetPath);
10446
11439
  }
10447
11440
  }
10448
11441
  getProjectIdentityHash(projectRoot3) {
@@ -10568,7 +11561,7 @@ var Indexer = class _Indexer {
10568
11561
  atomicWriteSync(targetPath, data) {
10569
11562
  const lease = this.requireActiveLease();
10570
11563
  const tempPath = createLeaseTemporaryPath(targetPath, lease.owner, "tmp");
10571
- (0, import_fs12.mkdirSync)(path19.dirname(targetPath), { recursive: true });
11564
+ (0, import_fs12.mkdirSync)(path20.dirname(targetPath), { recursive: true });
10572
11565
  try {
10573
11566
  (0, import_fs12.writeFileSync)(tempPath, data);
10574
11567
  (0, import_fs12.renameSync)(tempPath, targetPath);
@@ -10578,14 +11571,14 @@ var Indexer = class _Indexer {
10578
11571
  }
10579
11572
  saveInvertedIndex(invertedIndex) {
10580
11573
  this.atomicWriteSync(
10581
- path19.join(this.indexPath, "inverted-index.json"),
11574
+ path20.join(this.indexPath, "inverted-index.json"),
10582
11575
  invertedIndex.serialize()
10583
11576
  );
10584
11577
  }
10585
11578
  getScopedRoots(projectRoot3 = this.projectRoot) {
10586
11579
  const roots = /* @__PURE__ */ new Set([this.getCanonicalPath(projectRoot3)]);
10587
11580
  for (const kbRoot of this.config.knowledgeBases) {
10588
- roots.add(this.getCanonicalPath(path19.resolve(projectRoot3, kbRoot)));
11581
+ roots.add(this.getCanonicalPath(path20.resolve(projectRoot3, kbRoot)));
10589
11582
  }
10590
11583
  return Array.from(roots);
10591
11584
  }
@@ -11002,7 +11995,7 @@ var Indexer = class _Indexer {
11002
11995
  return configuredProviderInfo !== null && recovery.embeddingProvider === configuredProviderInfo.provider && recovery.embeddingModel === configuredProviderInfo.modelInfo.model && recovery.embeddingDimensions === configuredProviderInfo.modelInfo.dimensions && recovery.embeddingStrategyVersion === EMBEDDING_STRATEGY_VERSION;
11003
11996
  }
11004
11997
  hasUnknownLegacyForceIndexClear(owner) {
11005
- return owner.operation === "force-index" && owner.clearRecovery === void 0 && owner.recoveryProtocolVersion !== 1 && (0, import_fs12.existsSync)(path19.join(this.indexPath, "force-index-phase"));
11998
+ return owner.operation === "force-index" && owner.clearRecovery === void 0 && owner.recoveryProtocolVersion !== 1 && (0, import_fs12.existsSync)(path20.join(this.indexPath, "force-index-phase"));
11006
11999
  }
11007
12000
  async recoverFromInterruptedIndexingUnlocked(owners) {
11008
12001
  for (const owner of owners) {
@@ -11390,7 +12383,7 @@ var Indexer = class _Indexer {
11390
12383
  await options.queue.onSizeLessThan(Math.max(1, options.providerRateLimits.concurrency));
11391
12384
  const task = options.queue.add(async () => {
11392
12385
  if (options.rateLimitState.backoffMs > 0) {
11393
- await new Promise((resolve17) => setTimeout(resolve17, options.rateLimitState.backoffMs));
12386
+ await new Promise((resolve18) => setTimeout(resolve18, options.rateLimitState.backoffMs));
11394
12387
  }
11395
12388
  try {
11396
12389
  const embeddingResult = await pRetry(
@@ -11809,12 +12802,12 @@ var Indexer = class _Indexer {
11809
12802
  }
11810
12803
  }
11811
12804
  captureReaderArtifactFingerprint() {
11812
- const storePath = path19.join(this.indexPath, "vectors");
12805
+ const storePath = path20.join(this.indexPath, "vectors");
11813
12806
  return {
11814
12807
  vectors: `${this.getReaderFileFingerprint(storePath)}|${this.getReaderFileFingerprint(`${storePath}.meta.json`)}`,
11815
- keyword: this.getReaderFileFingerprint(path19.join(this.indexPath, "inverted-index.json")),
11816
- database: this.getReaderFileFingerprint(path19.join(this.indexPath, "codebase.db")),
11817
- databaseIdentity: this.getReaderFileFingerprint(path19.join(this.indexPath, "codebase.db"), true)
12808
+ keyword: this.getReaderFileFingerprint(path20.join(this.indexPath, "inverted-index.json")),
12809
+ database: this.getReaderFileFingerprint(path20.join(this.indexPath, "codebase.db")),
12810
+ databaseIdentity: this.getReaderFileFingerprint(path20.join(this.indexPath, "codebase.db"), true)
11818
12811
  };
11819
12812
  }
11820
12813
  refreshReaderArtifacts() {
@@ -11839,10 +12832,10 @@ var Indexer = class _Indexer {
11839
12832
  issues.set(component, this.createReadIssue(component, message));
11840
12833
  this.readerArtifactRetryAfter.set(component, Date.now() + READER_ARTIFACT_RETRY_INTERVAL_MS);
11841
12834
  };
11842
- const storePath = path19.join(this.indexPath, "vectors");
12835
+ const storePath = path20.join(this.indexPath, "vectors");
11843
12836
  const vectorMetadataPath = `${storePath}.meta.json`;
11844
- const invertedIndexPath = path19.join(this.indexPath, "inverted-index.json");
11845
- const dbPath = path19.join(this.indexPath, "codebase.db");
12837
+ const invertedIndexPath = path20.join(this.indexPath, "inverted-index.json");
12838
+ const dbPath = path20.join(this.indexPath, "codebase.db");
11846
12839
  if (vectorsChanged || retryDue("vectors")) {
11847
12840
  const vectorStoreExists = (0, import_fs12.existsSync)(storePath);
11848
12841
  const vectorMetadataExists = (0, import_fs12.existsSync)(vectorMetadataPath);
@@ -11958,10 +12951,10 @@ var Indexer = class _Indexer {
11958
12951
  });
11959
12952
  this.provider = createEmbeddingProvider(this.configuredProviderInfo);
11960
12953
  const dimensions = this.configuredProviderInfo.modelInfo.dimensions;
11961
- const storePath = path19.join(this.indexPath, "vectors");
12954
+ const storePath = path20.join(this.indexPath, "vectors");
11962
12955
  const vectorMetadataPath = `${storePath}.meta.json`;
11963
- const invertedIndexPath = path19.join(this.indexPath, "inverted-index.json");
11964
- const dbPath = path19.join(this.indexPath, "codebase.db");
12956
+ const invertedIndexPath = path20.join(this.indexPath, "inverted-index.json");
12957
+ const dbPath = path20.join(this.indexPath, "codebase.db");
11965
12958
  let dbIsNew = !(0, import_fs12.existsSync)(dbPath);
11966
12959
  const readerArtifactFingerprint = mode === "reader" ? this.captureReaderArtifactFingerprint() : null;
11967
12960
  if (mode === "writer") {
@@ -12139,7 +13132,7 @@ var Indexer = class _Indexer {
12139
13132
  if (await this.tryResetCorruptedIndex("running automatic orphan garbage collection", error)) {
12140
13133
  return {
12141
13134
  resetCorruptedIndex: true,
12142
- warning: this.getCorruptedIndexWarning(path19.join(this.indexPath, "codebase.db"))
13135
+ warning: this.getCorruptedIndexWarning(path20.join(this.indexPath, "codebase.db"))
12143
13136
  };
12144
13137
  }
12145
13138
  throw error;
@@ -12154,7 +13147,7 @@ var Indexer = class _Indexer {
12154
13147
  return;
12155
13148
  }
12156
13149
  const retainedEntries = store.getAllMetadata().filter(({ key }) => !excludedSet.has(key));
12157
- const storeBasePath = path19.join(this.indexPath, "vectors");
13150
+ const storeBasePath = path20.join(this.indexPath, "vectors");
12158
13151
  const storeIndexPath = storeBasePath;
12159
13152
  const storeMetadataPath = `${storeBasePath}.meta.json`;
12160
13153
  const lease = this.requireActiveLease();
@@ -12241,7 +13234,7 @@ var Indexer = class _Indexer {
12241
13234
  const names = await import_fs12.promises.readdir(this.indexPath);
12242
13235
  const runtimeStatePattern = /^(?:file-hashes|failed-batches)(?:\.[a-f0-9]{16})?\.json$/;
12243
13236
  await Promise.all(
12244
- names.filter((name) => runtimeStatePattern.test(name)).map((name) => import_fs12.promises.rm(path19.join(this.indexPath, name), { force: true }))
13237
+ names.filter((name) => runtimeStatePattern.test(name)).map((name) => import_fs12.promises.rm(path20.join(this.indexPath, name), { force: true }))
12245
13238
  );
12246
13239
  }
12247
13240
  async resetLocalIndexArtifacts() {
@@ -12257,13 +13250,13 @@ var Indexer = class _Indexer {
12257
13250
  this.readerArtifactRetryAfter.clear();
12258
13251
  this.fileHashCache.clear();
12259
13252
  const resetPaths = [
12260
- path19.join(this.indexPath, "codebase.db"),
12261
- path19.join(this.indexPath, "codebase.db-shm"),
12262
- path19.join(this.indexPath, "codebase.db-wal"),
12263
- path19.join(this.indexPath, "vectors"),
12264
- path19.join(this.indexPath, "vectors.usearch"),
12265
- path19.join(this.indexPath, "vectors.meta.json"),
12266
- path19.join(this.indexPath, "inverted-index.json")
13253
+ path20.join(this.indexPath, "codebase.db"),
13254
+ path20.join(this.indexPath, "codebase.db-shm"),
13255
+ path20.join(this.indexPath, "codebase.db-wal"),
13256
+ path20.join(this.indexPath, "vectors"),
13257
+ path20.join(this.indexPath, "vectors.usearch"),
13258
+ path20.join(this.indexPath, "vectors.meta.json"),
13259
+ path20.join(this.indexPath, "inverted-index.json")
12267
13260
  ];
12268
13261
  await Promise.all(resetPaths.map((targetPath) => import_fs12.promises.rm(targetPath, { recursive: true, force: true })));
12269
13262
  await this.removeProjectRuntimeStateArtifacts();
@@ -12273,7 +13266,7 @@ var Indexer = class _Indexer {
12273
13266
  if (!isSqliteCorruptionError(error)) {
12274
13267
  return false;
12275
13268
  }
12276
- const dbPath = path19.join(this.indexPath, "codebase.db");
13269
+ const dbPath = path20.join(this.indexPath, "codebase.db");
12277
13270
  const warning = this.getCorruptedIndexWarning(dbPath);
12278
13271
  const errorMessage = getErrorMessage4(error);
12279
13272
  if (this.config.scope === "global") {
@@ -12660,10 +13653,10 @@ var Indexer = class _Indexer {
12660
13653
  const reparseCachedMetalFiles = database.getMetadata(metalParserMetadataKey) !== METAL_PARSER_VERSION;
12661
13654
  const symbolExtractorMetadataKey = this.getSymbolExtractorVersionMetadataKey();
12662
13655
  const refreshCachedSymbols = database.getMetadata(symbolExtractorMetadataKey) !== SYMBOL_EXTRACTOR_VERSION;
12663
- if (reparseCachedSwiftFiles && Array.from(this.fileHashCache.keys()).some((filePath) => path19.extname(filePath).toLowerCase() === ".swift")) {
13656
+ if (reparseCachedSwiftFiles && Array.from(this.fileHashCache.keys()).some((filePath) => path20.extname(filePath).toLowerCase() === ".swift")) {
12664
13657
  this.logger.info("Reindexing cached Swift files for parser support");
12665
13658
  }
12666
- if (reparseCachedMetalFiles && Array.from(this.fileHashCache.keys()).some((filePath) => path19.extname(filePath).toLowerCase() === ".metal")) {
13659
+ if (reparseCachedMetalFiles && Array.from(this.fileHashCache.keys()).some((filePath) => path20.extname(filePath).toLowerCase() === ".metal")) {
12667
13660
  this.logger.info("Reindexing cached Metal files for parser support");
12668
13661
  }
12669
13662
  const includePatterns = [...this.config.include, ...this.config.additionalInclude];
@@ -12707,8 +13700,8 @@ var Indexer = class _Indexer {
12707
13700
  const needsCallGraphRefresh = cachedHashMatches && needsCallGraphResolutionMigration && database.getChunksByFile(storedPath).some(
12708
13701
  (chunk) => chunk.language === "php" || chunk.language === "c" || chunk.language === "cpp"
12709
13702
  );
12710
- const requiresSwiftParserUpgrade = reparseCachedSwiftFiles && path19.extname(storedPath).toLowerCase() === ".swift";
12711
- const requiresMetalParserUpgrade = reparseCachedMetalFiles && path19.extname(storedPath).toLowerCase() === ".metal";
13703
+ const requiresSwiftParserUpgrade = reparseCachedSwiftFiles && path20.extname(storedPath).toLowerCase() === ".swift";
13704
+ const requiresMetalParserUpgrade = reparseCachedMetalFiles && path20.extname(storedPath).toLowerCase() === ".metal";
12712
13705
  const inMigrationScope = forceScopedReembed && scopedRoots !== null && this.isFileInCurrentScope(storedPath, scopedRoots);
12713
13706
  if (cachedHashMatches && !inMigrationScope && !needsCallGraphRefresh && !requiresSwiftParserUpgrade && !requiresMetalParserUpgrade && !refreshCachedSymbols) {
12714
13707
  unchangedFilePaths.add(storedPath);
@@ -12767,7 +13760,7 @@ var Indexer = class _Indexer {
12767
13760
  }
12768
13761
  }
12769
13762
  }
12770
- const shouldRetryFailedPath = (filePath) => filePath !== null && currentFileHashes.has(filePath) && unchangedFilePaths.has(filePath);
13763
+ const shouldRetryFailedPath = (filePath) => filePath !== null && !this.isStoredPathExcluded(filePath) && currentFileHashes.has(filePath) && unchangedFilePaths.has(filePath);
12771
13764
  const failedProcessing = this.prepareFailedBatchProcessing(scopedRoots, shouldRetryFailedPath);
12772
13765
  const maxChunkTokens = getSafeEmbeddingChunkTokenLimit(configuredProviderInfo);
12773
13766
  const providerRateLimits = this.getProviderRateLimits(configuredProviderInfo.provider);
@@ -12871,7 +13864,7 @@ var Indexer = class _Indexer {
12871
13864
  throw new Error(`Parsed file was not present in its source batch: ${parsed.path}`);
12872
13865
  }
12873
13866
  if (parsed.chunks.length === 0) {
12874
- stats.parseFailures.push(path19.isAbsolute(parsed.path) ? path19.relative(this.projectRoot, parsed.path) : parsed.path);
13867
+ stats.parseFailures.push(path20.isAbsolute(parsed.path) ? path20.relative(this.projectRoot, parsed.path) : parsed.path);
12875
13868
  }
12876
13869
  let chunksToProcess = parsed.chunks;
12877
13870
  if (this.config.indexing.fallbackToTextOnMaxChunks && chunksToProcess.length > this.config.indexing.maxChunksPerFile) {
@@ -13206,7 +14199,7 @@ var Indexer = class _Indexer {
13206
14199
  previousBranchSymbolIds,
13207
14200
  Array.from(allSymbolIds)
13208
14201
  );
13209
- const vectorPath = path19.join(this.indexPath, "vectors");
14202
+ const vectorPath = path20.join(this.indexPath, "vectors");
13210
14203
  const shouldFingerprintLegacyPair = !store.hasFingerprint() && (0, import_fs12.existsSync)(vectorPath) && (0, import_fs12.existsSync)(`${vectorPath}.meta.json`);
13211
14204
  if (backfilledBlameMetadata || shouldFingerprintLegacyPair || removedStoredChunks) {
13212
14205
  store.save();
@@ -14065,7 +15058,7 @@ var Indexer = class _Indexer {
14065
15058
  gcOrphanSymbols: 0,
14066
15059
  gcOrphanCallEdges: 0,
14067
15060
  resetCorruptedIndex: true,
14068
- warning: this.getCorruptedIndexWarning(path19.join(this.indexPath, "codebase.db"))
15061
+ warning: this.getCorruptedIndexWarning(path20.join(this.indexPath, "codebase.db"))
14069
15062
  };
14070
15063
  }
14071
15064
  this.logger.recordGc(removedCount, gcOrphanChunks, gcOrphanEmbeddings);
@@ -14095,7 +15088,8 @@ var Indexer = class _Indexer {
14095
15088
  const maxChunkTokens = getSafeEmbeddingChunkTokenLimit(configuredProviderInfo);
14096
15089
  const providerRateLimits = this.getProviderRateLimits(configuredProviderInfo.provider);
14097
15090
  const roots = this.config.scope === "global" ? this.getScopedRoots() : null;
14098
- const failedProcessing = this.prepareFailedBatchProcessing(roots, () => true);
15091
+ const shouldProcessFailedPath = (filePath) => filePath === null || !this.isStoredPathExcluded(filePath);
15092
+ const failedProcessing = this.prepareFailedBatchProcessing(roots, shouldProcessFailedPath);
14099
15093
  if (failedProcessing.latestById.size === 0) {
14100
15094
  this.finalizeFailedBatchWriteState(failedProcessing.state);
14101
15095
  return { succeeded: 0, failed: 0, remaining: 0 };
@@ -14108,7 +15102,7 @@ var Indexer = class _Indexer {
14108
15102
  const retryableChunks = this.iterateLatestFailedChunks(
14109
15103
  failedProcessing.latestById,
14110
15104
  roots,
14111
- () => true,
15105
+ shouldProcessFailedPath,
14112
15106
  maxChunkTokens
14113
15107
  );
14114
15108
  for (const retryBatch of iterateOrderedFileBatches(
@@ -14378,9 +15372,9 @@ var Indexer = class _Indexer {
14378
15372
  this.requireReadableComponents(readIssues, "database");
14379
15373
  let shortest = [];
14380
15374
  for (const branchKey of this.getBranchCatalogKeys()) {
14381
- const path25 = database.findShortestPath(fromName, toName, branchKey, maxDepth);
14382
- if (path25.length > 0 && (shortest.length === 0 || path25.length < shortest.length)) {
14383
- shortest = path25;
15375
+ const path26 = database.findShortestPath(fromName, toName, branchKey, maxDepth);
15376
+ if (path26.length > 0 && (shortest.length === 0 || path26.length < shortest.length)) {
15377
+ shortest = path26;
14384
15378
  }
14385
15379
  }
14386
15380
  return shortest.map((hop) => this.resolveFilePathRecord(hop));
@@ -14428,13 +15422,13 @@ var Indexer = class _Indexer {
14428
15422
  }
14429
15423
  }
14430
15424
  if (!found) continue;
14431
- const path25 = [];
15425
+ const path26 = [];
14432
15426
  let currentSymbolId = toSymbolId;
14433
15427
  while (true) {
14434
15428
  const symbol = symbolsById.get(currentSymbolId);
14435
15429
  if (!symbol) break;
14436
15430
  const parent = parentBySymbolId.get(currentSymbolId);
14437
- path25.push({
15431
+ path26.push({
14438
15432
  symbolId: symbol.id,
14439
15433
  symbolName: symbol.name,
14440
15434
  filePath: symbol.filePath,
@@ -14444,9 +15438,9 @@ var Indexer = class _Indexer {
14444
15438
  if (!parent) break;
14445
15439
  currentSymbolId = parent.parentId;
14446
15440
  }
14447
- path25.reverse();
14448
- if (path25.length > 0 && (shortest.length === 0 || path25.length < shortest.length)) {
14449
- shortest = path25;
15441
+ path26.reverse();
15442
+ if (path26.length > 0 && (shortest.length === 0 || path26.length < shortest.length)) {
15443
+ shortest = path26;
14450
15444
  }
14451
15445
  }
14452
15446
  return shortest.map((hop) => this.resolveFilePathRecord(hop));
@@ -14597,7 +15591,7 @@ var Indexer = class _Indexer {
14597
15591
  );
14598
15592
  }
14599
15593
  }
14600
- const toStoredChangedFiles = (filePaths) => filePaths.map((filePath) => this.toStoredFilePath(path19.resolve(this.projectRoot, filePath)));
15594
+ const toStoredChangedFiles = (filePaths) => filePaths.map((filePath) => this.toStoredFilePath(path20.resolve(this.projectRoot, filePath)));
14601
15595
  const storedChangedFiles = toStoredChangedFiles(changedFiles);
14602
15596
  const directSymbols = database.getSymbolsForFiles(storedChangedFiles, branchKey);
14603
15597
  const directIds = directSymbols.map((s) => s.id);
@@ -14746,12 +15740,12 @@ var Indexer = class _Indexer {
14746
15740
  if (meta.filePath) filePaths.add(meta.filePath);
14747
15741
  }
14748
15742
  const directory = options?.directory?.replace(/\/$/, "");
14749
- const absoluteDirectoryFilter = directory ? path19.resolve(this.projectRoot, directory) : void 0;
15743
+ const absoluteDirectoryFilter = directory ? path20.resolve(this.projectRoot, directory) : void 0;
14750
15744
  for (const filePath of filePaths) {
14751
15745
  if (directory) {
14752
15746
  const absoluteFilePath = this.resolveStoredFilePath(filePath);
14753
15747
  const matchesRelative = filePath === directory || filePath.startsWith(directory + "/");
14754
- const matchesProjectRelative = absoluteDirectoryFilter !== void 0 && (absoluteFilePath === absoluteDirectoryFilter || absoluteFilePath.startsWith(absoluteDirectoryFilter + path19.sep));
15748
+ const matchesProjectRelative = absoluteDirectoryFilter !== void 0 && (absoluteFilePath === absoluteDirectoryFilter || absoluteFilePath.startsWith(absoluteDirectoryFilter + path20.sep));
14755
15749
  if (!matchesRelative && !matchesProjectRelative) {
14756
15750
  continue;
14757
15751
  }
@@ -14868,7 +15862,10 @@ function getOrCreateIndexer(projectRoot3, host) {
14868
15862
  }
14869
15863
  const indexer = new Indexer(projectRoot3, config, host);
14870
15864
  indexerCache.set(key, indexer);
14871
- configureAutoIndex(projectRoot3, host, config, () => getOrCreateIndexer(projectRoot3, host));
15865
+ configureAutoIndex(projectRoot3, host, config, () => getOrCreateIndexer(projectRoot3, host), {
15866
+ preserveManagedWorker: true,
15867
+ synchronizeBackgroundWorker: false
15868
+ });
14872
15869
  return indexer;
14873
15870
  }
14874
15871
  function getIndexerForProject(projectRoot3, host) {
@@ -14883,7 +15880,9 @@ function refreshIndexerForDirectory(projectRoot3, host, config = parseConfig(loa
14883
15880
  const key = getIndexerCacheKey(projectRoot3, host);
14884
15881
  configCache.set(key, config);
14885
15882
  indexerCache.set(key, new Indexer(projectRoot3, config, host));
14886
- configureAutoIndex(projectRoot3, host, config, () => getOrCreateIndexer(projectRoot3, host));
15883
+ configureAutoIndex(projectRoot3, host, config, () => getOrCreateIndexer(projectRoot3, host), {
15884
+ synchronizeBackgroundWorker: true
15885
+ });
14887
15886
  return config;
14888
15887
  }
14889
15888
  var AutoIndexRetrievalUnavailableError = class extends Error {
@@ -14910,7 +15909,7 @@ function trimOrUndefined(value) {
14910
15909
  return normalized || void 0;
14911
15910
  }
14912
15911
  function normalizeCallGraphPath(value) {
14913
- let normalized = path20.posix.normalize(value.trim().replaceAll("\\", "/"));
15912
+ let normalized = path21.posix.normalize(value.trim().replaceAll("\\", "/"));
14914
15913
  if (normalized.startsWith("./")) {
14915
15914
  normalized = normalized.slice(2);
14916
15915
  }
@@ -15103,12 +16102,12 @@ async function getCallGraphPath(projectRoot3, host, from, to, maxDepth, fromFile
15103
16102
  if (fromResolution.status !== "resolved" || toResolution.status !== "resolved") {
15104
16103
  return { from: fromResolution, to: toResolution, path: [] };
15105
16104
  }
15106
- const path25 = await indexer.findCallPathBySymbolIds(
16105
+ const path26 = await indexer.findCallPathBySymbolIds(
15107
16106
  fromResolution.symbolId,
15108
16107
  toResolution.symbolId,
15109
16108
  maxDepth
15110
16109
  );
15111
- return { from: fromResolution, to: toResolution, path: path25 };
16110
+ return { from: fromResolution, to: toResolution, path: path26 };
15112
16111
  }
15113
16112
  async function runIndexCodebase(projectRoot3, host, args, onProgress) {
15114
16113
  const root = getProjectRoot(projectRoot3, host);
@@ -15306,8 +16305,8 @@ async function getIndexLogs(projectRoot3, host, args) {
15306
16305
  function addKnowledgeBase(projectRoot3, host, knowledgeBasePath) {
15307
16306
  const root = getProjectRoot(projectRoot3, host);
15308
16307
  const inputPath = knowledgeBasePath.trim();
15309
- const normalizedPath2 = path20.resolve(
15310
- path20.isAbsolute(inputPath) ? inputPath : resolveKnowledgeBasePath(inputPath, root)
16308
+ const normalizedPath2 = path21.resolve(
16309
+ path21.isAbsolute(inputPath) ? inputPath : resolveKnowledgeBasePath(inputPath, root)
15311
16310
  );
15312
16311
  if (!(0, import_fs13.existsSync)(normalizedPath2)) {
15313
16312
  return `Error: Directory does not exist: ${normalizedPath2}`;
@@ -15343,7 +16342,7 @@ function addKnowledgeBase(projectRoot3, host, knowledgeBasePath) {
15343
16342
  }
15344
16343
  }
15345
16344
  for (const dotDir of sensitiveDotDirs) {
15346
- const sensitiveDir = path20.join(homeDir, dotDir);
16345
+ const sensitiveDir = path21.join(homeDir, dotDir);
15347
16346
  if (sensitiveDir && (realPath === sensitiveDir || realPath.startsWith(`${sensitiveDir}/`))) {
15348
16347
  return `Error: Adding sensitive directory as knowledge base is not allowed: ${normalizedPath2}`;
15349
16348
  }
@@ -15406,7 +16405,7 @@ function listKnowledgeBases(projectRoot3, host) {
15406
16405
  }
15407
16406
  result += "\n";
15408
16407
  }
15409
- const hasHostConfig = (0, import_fs13.existsSync)(path20.join(root, getHostProjectConfigRelativePath(host)));
16408
+ const hasHostConfig = (0, import_fs13.existsSync)(path21.join(root, getHostProjectConfigRelativePath(host)));
15410
16409
  if (hasHostConfig) {
15411
16410
  result += `
15412
16411
  Config sources: 1 file(s).`;
@@ -15879,7 +16878,7 @@ async function resolveCodebaseContextUnmeasured(projectRoot3, host, input) {
15879
16878
  const directory = input.directory ?? void 0;
15880
16879
  const tokenBudget = input.tokenBudget ?? void 0;
15881
16880
  if (from && to) {
15882
- const path25 = await getCallGraphPath(
16881
+ const path26 = await getCallGraphPath(
15883
16882
  projectRoot3,
15884
16883
  host,
15885
16884
  from,
@@ -15888,25 +16887,25 @@ async function resolveCodebaseContextUnmeasured(projectRoot3, host, input) {
15888
16887
  fromFilePath,
15889
16888
  toFilePath
15890
16889
  );
15891
- const pathText = formatCallGraphPathResult(path25);
15892
- if (path25.path.length > 0) {
16890
+ const pathText = formatCallGraphPathResult(path26);
16891
+ if (path26.path.length > 0) {
15893
16892
  const fitted2 = fitTextToContextBudget(
15894
16893
  pathText,
15895
16894
  tokenBudget
15896
16895
  );
15897
16896
  return {
15898
16897
  text: fitted2.text,
15899
- details: fittedDetails("path", fitted2, path25.path.length)
16898
+ details: fittedDetails("path", fitted2, path26.path.length)
15900
16899
  };
15901
16900
  }
15902
- if (path25.from.status !== "resolved" || path25.to.status !== "resolved") {
16901
+ if (path26.from.status !== "resolved" || path26.to.status !== "resolved") {
15903
16902
  const fitted2 = fitTextToContextBudget(pathText, tokenBudget);
15904
16903
  return {
15905
16904
  text: fitted2.text,
15906
16905
  details: fittedDetails("path", fitted2, 0)
15907
16906
  };
15908
16907
  }
15909
- const resolvedFrom = path25.from;
16908
+ const resolvedFrom = path26.from;
15910
16909
  const { callers } = await getCallGraphData(projectRoot3, host, {
15911
16910
  name: to,
15912
16911
  direction: "callers",
@@ -16351,7 +17350,7 @@ var import_fs14 = require("fs");
16351
17350
 
16352
17351
  // node_modules/chokidar/index.js
16353
17352
  var import_node_events = require("events");
16354
- var import_node_fs2 = require("fs");
17353
+ var import_node_fs3 = require("fs");
16355
17354
  var import_promises3 = require("fs/promises");
16356
17355
  var sp2 = __toESM(require("path"), 1);
16357
17356
 
@@ -16439,7 +17438,7 @@ var ReaddirpStream = class extends import_node_stream.Readable {
16439
17438
  this._directoryFilter = normalizeFilter(opts.directoryFilter);
16440
17439
  const statMethod = opts.lstat ? import_promises.lstat : import_promises.stat;
16441
17440
  if (wantBigintFsStats) {
16442
- this._stat = (path25) => statMethod(path25, { bigint: true });
17441
+ this._stat = (path26) => statMethod(path26, { bigint: true });
16443
17442
  } else {
16444
17443
  this._stat = statMethod;
16445
17444
  }
@@ -16464,8 +17463,8 @@ var ReaddirpStream = class extends import_node_stream.Readable {
16464
17463
  const par = this.parent;
16465
17464
  const fil = par && par.files;
16466
17465
  if (fil && fil.length > 0) {
16467
- const { path: path25, depth } = par;
16468
- const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path25));
17466
+ const { path: path26, depth } = par;
17467
+ const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path26));
16469
17468
  const awaited = await Promise.all(slice);
16470
17469
  for (const entry of awaited) {
16471
17470
  if (!entry)
@@ -16505,21 +17504,21 @@ var ReaddirpStream = class extends import_node_stream.Readable {
16505
17504
  this.reading = false;
16506
17505
  }
16507
17506
  }
16508
- async _exploreDir(path25, depth) {
17507
+ async _exploreDir(path26, depth) {
16509
17508
  let files;
16510
17509
  try {
16511
- files = await (0, import_promises.readdir)(path25, this._rdOptions);
17510
+ files = await (0, import_promises.readdir)(path26, this._rdOptions);
16512
17511
  } catch (error) {
16513
17512
  this._onError(error);
16514
17513
  }
16515
- return { files, depth, path: path25 };
17514
+ return { files, depth, path: path26 };
16516
17515
  }
16517
- async _formatEntry(dirent, path25) {
17516
+ async _formatEntry(dirent, path26) {
16518
17517
  let entry;
16519
- const basename7 = this._isDirent ? dirent.name : dirent;
17518
+ const basename8 = this._isDirent ? dirent.name : dirent;
16520
17519
  try {
16521
- const fullPath = (0, import_node_path.resolve)((0, import_node_path.join)(path25, basename7));
16522
- entry = { path: (0, import_node_path.relative)(this._root, fullPath), fullPath, basename: basename7 };
17520
+ const fullPath = (0, import_node_path.resolve)((0, import_node_path.join)(path26, basename8));
17521
+ entry = { path: (0, import_node_path.relative)(this._root, fullPath), fullPath, basename: basename8 };
16523
17522
  entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
16524
17523
  } catch (err) {
16525
17524
  this._onError(err);
@@ -16589,7 +17588,7 @@ function readdirp(root, options = {}) {
16589
17588
  }
16590
17589
 
16591
17590
  // node_modules/chokidar/handler.js
16592
- var import_node_fs = require("fs");
17591
+ var import_node_fs2 = require("fs");
16593
17592
  var import_promises2 = require("fs/promises");
16594
17593
  var import_node_os = require("os");
16595
17594
  var sp = __toESM(require("path"), 1);
@@ -16918,16 +17917,16 @@ var delFromSet = (main, prop, item) => {
16918
17917
  };
16919
17918
  var isEmptySet = (val) => val instanceof Set ? val.size === 0 : !val;
16920
17919
  var FsWatchInstances = /* @__PURE__ */ new Map();
16921
- function createFsWatchInstance(path25, options, listener, errHandler, emitRaw) {
17920
+ function createFsWatchInstance(path26, options, listener, errHandler, emitRaw) {
16922
17921
  const handleEvent = (rawEvent, evPath) => {
16923
- listener(path25);
16924
- emitRaw(rawEvent, evPath, { watchedPath: path25 });
16925
- if (evPath && path25 !== evPath) {
16926
- fsWatchBroadcast(sp.resolve(path25, evPath), KEY_LISTENERS, sp.join(path25, evPath));
17922
+ listener(path26);
17923
+ emitRaw(rawEvent, evPath, { watchedPath: path26 });
17924
+ if (evPath && path26 !== evPath) {
17925
+ fsWatchBroadcast(sp.resolve(path26, evPath), KEY_LISTENERS, sp.join(path26, evPath));
16927
17926
  }
16928
17927
  };
16929
17928
  try {
16930
- return (0, import_node_fs.watch)(path25, {
17929
+ return (0, import_node_fs2.watch)(path26, {
16931
17930
  persistent: options.persistent
16932
17931
  }, handleEvent);
16933
17932
  } catch (error) {
@@ -16943,12 +17942,12 @@ var fsWatchBroadcast = (fullPath, listenerType, val1, val2, val3) => {
16943
17942
  listener(val1, val2, val3);
16944
17943
  });
16945
17944
  };
16946
- var setFsWatchListener = (path25, fullPath, options, handlers) => {
17945
+ var setFsWatchListener = (path26, fullPath, options, handlers) => {
16947
17946
  const { listener, errHandler, rawEmitter } = handlers;
16948
17947
  let cont = FsWatchInstances.get(fullPath);
16949
17948
  let watcher;
16950
17949
  if (!options.persistent) {
16951
- watcher = createFsWatchInstance(path25, options, listener, errHandler, rawEmitter);
17950
+ watcher = createFsWatchInstance(path26, options, listener, errHandler, rawEmitter);
16952
17951
  if (!watcher)
16953
17952
  return;
16954
17953
  return watcher.close.bind(watcher);
@@ -16959,7 +17958,7 @@ var setFsWatchListener = (path25, fullPath, options, handlers) => {
16959
17958
  addAndConvert(cont, KEY_RAW, rawEmitter);
16960
17959
  } else {
16961
17960
  watcher = createFsWatchInstance(
16962
- path25,
17961
+ path26,
16963
17962
  options,
16964
17963
  fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS),
16965
17964
  errHandler,
@@ -16974,7 +17973,7 @@ var setFsWatchListener = (path25, fullPath, options, handlers) => {
16974
17973
  cont.watcherUnusable = true;
16975
17974
  if (isWindows && error.code === "EPERM") {
16976
17975
  try {
16977
- const fd = await (0, import_promises2.open)(path25, "r");
17976
+ const fd = await (0, import_promises2.open)(path26, "r");
16978
17977
  await fd.close();
16979
17978
  broadcastErr(error);
16980
17979
  } catch (err) {
@@ -17005,12 +18004,12 @@ var setFsWatchListener = (path25, fullPath, options, handlers) => {
17005
18004
  };
17006
18005
  };
17007
18006
  var FsWatchFileInstances = /* @__PURE__ */ new Map();
17008
- var setFsWatchFileListener = (path25, fullPath, options, handlers) => {
18007
+ var setFsWatchFileListener = (path26, fullPath, options, handlers) => {
17009
18008
  const { listener, rawEmitter } = handlers;
17010
18009
  let cont = FsWatchFileInstances.get(fullPath);
17011
18010
  const copts = cont && cont.options;
17012
18011
  if (copts && (copts.persistent < options.persistent || copts.interval > options.interval)) {
17013
- (0, import_node_fs.unwatchFile)(fullPath);
18012
+ (0, import_node_fs2.unwatchFile)(fullPath);
17014
18013
  cont = void 0;
17015
18014
  }
17016
18015
  if (cont) {
@@ -17021,13 +18020,13 @@ var setFsWatchFileListener = (path25, fullPath, options, handlers) => {
17021
18020
  listeners: listener,
17022
18021
  rawEmitters: rawEmitter,
17023
18022
  options,
17024
- watcher: (0, import_node_fs.watchFile)(fullPath, options, (curr, prev) => {
18023
+ watcher: (0, import_node_fs2.watchFile)(fullPath, options, (curr, prev) => {
17025
18024
  foreach(cont.rawEmitters, (rawEmitter2) => {
17026
18025
  rawEmitter2(EV.CHANGE, fullPath, { curr, prev });
17027
18026
  });
17028
18027
  const currmtime = curr.mtimeMs;
17029
18028
  if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {
17030
- foreach(cont.listeners, (listener2) => listener2(path25, curr));
18029
+ foreach(cont.listeners, (listener2) => listener2(path26, curr));
17031
18030
  }
17032
18031
  })
17033
18032
  };
@@ -17038,7 +18037,7 @@ var setFsWatchFileListener = (path25, fullPath, options, handlers) => {
17038
18037
  delFromSet(cont, KEY_RAW, rawEmitter);
17039
18038
  if (isEmptySet(cont.listeners)) {
17040
18039
  FsWatchFileInstances.delete(fullPath);
17041
- (0, import_node_fs.unwatchFile)(fullPath);
18040
+ (0, import_node_fs2.unwatchFile)(fullPath);
17042
18041
  cont.options = cont.watcher = void 0;
17043
18042
  Object.freeze(cont);
17044
18043
  }
@@ -17057,13 +18056,13 @@ var NodeFsHandler = class {
17057
18056
  * @param listener on fs change
17058
18057
  * @returns closer for the watcher instance
17059
18058
  */
17060
- _watchWithNodeFs(path25, listener) {
18059
+ _watchWithNodeFs(path26, listener) {
17061
18060
  const opts = this.fsw.options;
17062
- const directory = sp.dirname(path25);
17063
- const basename7 = sp.basename(path25);
18061
+ const directory = sp.dirname(path26);
18062
+ const basename8 = sp.basename(path26);
17064
18063
  const parent = this.fsw._getWatchedDir(directory);
17065
- parent.add(basename7);
17066
- const absolutePath = sp.resolve(path25);
18064
+ parent.add(basename8);
18065
+ const absolutePath = sp.resolve(path26);
17067
18066
  const options = {
17068
18067
  persistent: opts.persistent
17069
18068
  };
@@ -17072,13 +18071,13 @@ var NodeFsHandler = class {
17072
18071
  let closer;
17073
18072
  if (opts.usePolling) {
17074
18073
  const enableBin = opts.interval !== opts.binaryInterval;
17075
- options.interval = enableBin && isBinaryPath(basename7) ? opts.binaryInterval : opts.interval;
17076
- closer = setFsWatchFileListener(path25, absolutePath, options, {
18074
+ options.interval = enableBin && isBinaryPath(basename8) ? opts.binaryInterval : opts.interval;
18075
+ closer = setFsWatchFileListener(path26, absolutePath, options, {
17077
18076
  listener,
17078
18077
  rawEmitter: this.fsw._emitRaw
17079
18078
  });
17080
18079
  } else {
17081
- closer = setFsWatchListener(path25, absolutePath, options, {
18080
+ closer = setFsWatchListener(path26, absolutePath, options, {
17082
18081
  listener,
17083
18082
  errHandler: this._boundHandleError,
17084
18083
  rawEmitter: this.fsw._emitRaw
@@ -17094,13 +18093,13 @@ var NodeFsHandler = class {
17094
18093
  if (this.fsw.closed) {
17095
18094
  return;
17096
18095
  }
17097
- const dirname13 = sp.dirname(file);
17098
- const basename7 = sp.basename(file);
17099
- const parent = this.fsw._getWatchedDir(dirname13);
18096
+ const dirname14 = sp.dirname(file);
18097
+ const basename8 = sp.basename(file);
18098
+ const parent = this.fsw._getWatchedDir(dirname14);
17100
18099
  let prevStats = stats;
17101
- if (parent.has(basename7))
18100
+ if (parent.has(basename8))
17102
18101
  return;
17103
- const listener = async (path25, newStats) => {
18102
+ const listener = async (path26, newStats) => {
17104
18103
  if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5))
17105
18104
  return;
17106
18105
  if (!newStats || newStats.mtimeMs === 0) {
@@ -17114,18 +18113,18 @@ var NodeFsHandler = class {
17114
18113
  this.fsw._emit(EV.CHANGE, file, newStats2);
17115
18114
  }
17116
18115
  if ((isMacos || isLinux || isFreeBSD) && prevStats.ino !== newStats2.ino) {
17117
- this.fsw._closeFile(path25);
18116
+ this.fsw._closeFile(path26);
17118
18117
  prevStats = newStats2;
17119
18118
  const closer2 = this._watchWithNodeFs(file, listener);
17120
18119
  if (closer2)
17121
- this.fsw._addPathCloser(path25, closer2);
18120
+ this.fsw._addPathCloser(path26, closer2);
17122
18121
  } else {
17123
18122
  prevStats = newStats2;
17124
18123
  }
17125
18124
  } catch (error) {
17126
- this.fsw._remove(dirname13, basename7);
18125
+ this.fsw._remove(dirname14, basename8);
17127
18126
  }
17128
- } else if (parent.has(basename7)) {
18127
+ } else if (parent.has(basename8)) {
17129
18128
  const at = newStats.atimeMs;
17130
18129
  const mt = newStats.mtimeMs;
17131
18130
  if (!at || at <= mt || mt !== prevStats.mtimeMs) {
@@ -17150,7 +18149,7 @@ var NodeFsHandler = class {
17150
18149
  * @param item basename of this item
17151
18150
  * @returns true if no more processing is needed for this entry.
17152
18151
  */
17153
- async _handleSymlink(entry, directory, path25, item) {
18152
+ async _handleSymlink(entry, directory, path26, item) {
17154
18153
  if (this.fsw.closed) {
17155
18154
  return;
17156
18155
  }
@@ -17160,7 +18159,7 @@ var NodeFsHandler = class {
17160
18159
  this.fsw._incrReadyCount();
17161
18160
  let linkPath;
17162
18161
  try {
17163
- linkPath = await (0, import_promises2.realpath)(path25);
18162
+ linkPath = await (0, import_promises2.realpath)(path26);
17164
18163
  } catch (e) {
17165
18164
  this.fsw._emitReady();
17166
18165
  return true;
@@ -17170,12 +18169,12 @@ var NodeFsHandler = class {
17170
18169
  if (dir.has(item)) {
17171
18170
  if (this.fsw._symlinkPaths.get(full) !== linkPath) {
17172
18171
  this.fsw._symlinkPaths.set(full, linkPath);
17173
- this.fsw._emit(EV.CHANGE, path25, entry.stats);
18172
+ this.fsw._emit(EV.CHANGE, path26, entry.stats);
17174
18173
  }
17175
18174
  } else {
17176
18175
  dir.add(item);
17177
18176
  this.fsw._symlinkPaths.set(full, linkPath);
17178
- this.fsw._emit(EV.ADD, path25, entry.stats);
18177
+ this.fsw._emit(EV.ADD, path26, entry.stats);
17179
18178
  }
17180
18179
  this.fsw._emitReady();
17181
18180
  return true;
@@ -17205,9 +18204,9 @@ var NodeFsHandler = class {
17205
18204
  return;
17206
18205
  }
17207
18206
  const item = entry.path;
17208
- let path25 = sp.join(directory, item);
18207
+ let path26 = sp.join(directory, item);
17209
18208
  current.add(item);
17210
- if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path25, item)) {
18209
+ if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path26, item)) {
17211
18210
  return;
17212
18211
  }
17213
18212
  if (this.fsw.closed) {
@@ -17216,11 +18215,11 @@ var NodeFsHandler = class {
17216
18215
  }
17217
18216
  if (item === target || !target && !previous.has(item)) {
17218
18217
  this.fsw._incrReadyCount();
17219
- path25 = sp.join(dir, sp.relative(dir, path25));
17220
- this._addToNodeFs(path25, initialAdd, wh, depth + 1);
18218
+ path26 = sp.join(dir, sp.relative(dir, path26));
18219
+ this._addToNodeFs(path26, initialAdd, wh, depth + 1);
17221
18220
  }
17222
18221
  }).on(EV.ERROR, this._boundHandleError);
17223
- return new Promise((resolve17, reject) => {
18222
+ return new Promise((resolve18, reject) => {
17224
18223
  if (!stream)
17225
18224
  return reject();
17226
18225
  stream.once(STR_END, () => {
@@ -17229,7 +18228,7 @@ var NodeFsHandler = class {
17229
18228
  return;
17230
18229
  }
17231
18230
  const wasThrottled = throttler ? throttler.clear() : false;
17232
- resolve17(void 0);
18231
+ resolve18(void 0);
17233
18232
  previous.getChildren().filter((item) => {
17234
18233
  return item !== directory && !current.has(item);
17235
18234
  }).forEach((item) => {
@@ -17286,13 +18285,13 @@ var NodeFsHandler = class {
17286
18285
  * @param depth Child path actually targeted for watch
17287
18286
  * @param target Child path actually targeted for watch
17288
18287
  */
17289
- async _addToNodeFs(path25, initialAdd, priorWh, depth, target) {
18288
+ async _addToNodeFs(path26, initialAdd, priorWh, depth, target) {
17290
18289
  const ready = this.fsw._emitReady;
17291
- if (this.fsw._isIgnored(path25) || this.fsw.closed) {
18290
+ if (this.fsw._isIgnored(path26) || this.fsw.closed) {
17292
18291
  ready();
17293
18292
  return false;
17294
18293
  }
17295
- const wh = this.fsw._getWatchHelpers(path25);
18294
+ const wh = this.fsw._getWatchHelpers(path26);
17296
18295
  if (priorWh) {
17297
18296
  wh.filterPath = (entry) => priorWh.filterPath(entry);
17298
18297
  wh.filterDir = (entry) => priorWh.filterDir(entry);
@@ -17308,8 +18307,8 @@ var NodeFsHandler = class {
17308
18307
  const follow = this.fsw.options.followSymlinks;
17309
18308
  let closer;
17310
18309
  if (stats.isDirectory()) {
17311
- const absPath = sp.resolve(path25);
17312
- const targetPath = follow ? await (0, import_promises2.realpath)(path25) : path25;
18310
+ const absPath = sp.resolve(path26);
18311
+ const targetPath = follow ? await (0, import_promises2.realpath)(path26) : path26;
17313
18312
  if (this.fsw.closed)
17314
18313
  return;
17315
18314
  closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
@@ -17319,29 +18318,29 @@ var NodeFsHandler = class {
17319
18318
  this.fsw._symlinkPaths.set(absPath, targetPath);
17320
18319
  }
17321
18320
  } else if (stats.isSymbolicLink()) {
17322
- const targetPath = follow ? await (0, import_promises2.realpath)(path25) : path25;
18321
+ const targetPath = follow ? await (0, import_promises2.realpath)(path26) : path26;
17323
18322
  if (this.fsw.closed)
17324
18323
  return;
17325
18324
  const parent = sp.dirname(wh.watchPath);
17326
18325
  this.fsw._getWatchedDir(parent).add(wh.watchPath);
17327
18326
  this.fsw._emit(EV.ADD, wh.watchPath, stats);
17328
- closer = await this._handleDir(parent, stats, initialAdd, depth, path25, wh, targetPath);
18327
+ closer = await this._handleDir(parent, stats, initialAdd, depth, path26, wh, targetPath);
17329
18328
  if (this.fsw.closed)
17330
18329
  return;
17331
18330
  if (targetPath !== void 0) {
17332
- this.fsw._symlinkPaths.set(sp.resolve(path25), targetPath);
18331
+ this.fsw._symlinkPaths.set(sp.resolve(path26), targetPath);
17333
18332
  }
17334
18333
  } else {
17335
18334
  closer = this._handleFile(wh.watchPath, stats, initialAdd);
17336
18335
  }
17337
18336
  ready();
17338
18337
  if (closer)
17339
- this.fsw._addPathCloser(path25, closer);
18338
+ this.fsw._addPathCloser(path26, closer);
17340
18339
  return false;
17341
18340
  } catch (error) {
17342
18341
  if (this.fsw._handleError(error)) {
17343
18342
  ready();
17344
- return path25;
18343
+ return path26;
17345
18344
  }
17346
18345
  }
17347
18346
  }
@@ -17384,24 +18383,24 @@ function createPattern(matcher) {
17384
18383
  }
17385
18384
  return () => false;
17386
18385
  }
17387
- function normalizePath2(path25) {
17388
- if (typeof path25 !== "string")
18386
+ function normalizePath2(path26) {
18387
+ if (typeof path26 !== "string")
17389
18388
  throw new Error("string expected");
17390
- path25 = sp2.normalize(path25);
17391
- path25 = path25.replace(/\\/g, "/");
18389
+ path26 = sp2.normalize(path26);
18390
+ path26 = path26.replace(/\\/g, "/");
17392
18391
  let prepend = false;
17393
- if (path25.startsWith("//"))
18392
+ if (path26.startsWith("//"))
17394
18393
  prepend = true;
17395
- path25 = path25.replace(DOUBLE_SLASH_RE, "/");
18394
+ path26 = path26.replace(DOUBLE_SLASH_RE, "/");
17396
18395
  if (prepend)
17397
- path25 = "/" + path25;
17398
- return path25;
18396
+ path26 = "/" + path26;
18397
+ return path26;
17399
18398
  }
17400
18399
  function matchPatterns(patterns, testString, stats) {
17401
- const path25 = normalizePath2(testString);
18400
+ const path26 = normalizePath2(testString);
17402
18401
  for (let index = 0; index < patterns.length; index++) {
17403
18402
  const pattern = patterns[index];
17404
- if (pattern(path25, stats)) {
18403
+ if (pattern(path26, stats)) {
17405
18404
  return true;
17406
18405
  }
17407
18406
  }
@@ -17439,19 +18438,19 @@ var toUnix = (string) => {
17439
18438
  }
17440
18439
  return str;
17441
18440
  };
17442
- var normalizePathToUnix = (path25) => toUnix(sp2.normalize(toUnix(path25)));
17443
- var normalizeIgnored = (cwd = "") => (path25) => {
17444
- if (typeof path25 === "string") {
17445
- return normalizePathToUnix(sp2.isAbsolute(path25) ? path25 : sp2.join(cwd, path25));
18441
+ var normalizePathToUnix = (path26) => toUnix(sp2.normalize(toUnix(path26)));
18442
+ var normalizeIgnored = (cwd = "") => (path26) => {
18443
+ if (typeof path26 === "string") {
18444
+ return normalizePathToUnix(sp2.isAbsolute(path26) ? path26 : sp2.join(cwd, path26));
17446
18445
  } else {
17447
- return path25;
18446
+ return path26;
17448
18447
  }
17449
18448
  };
17450
- var getAbsolutePath = (path25, cwd) => {
17451
- if (sp2.isAbsolute(path25)) {
17452
- return path25;
18449
+ var getAbsolutePath = (path26, cwd) => {
18450
+ if (sp2.isAbsolute(path26)) {
18451
+ return path26;
17453
18452
  }
17454
- return sp2.join(cwd, path25);
18453
+ return sp2.join(cwd, path26);
17455
18454
  };
17456
18455
  var EMPTY_SET = Object.freeze(/* @__PURE__ */ new Set());
17457
18456
  var DirEntry = class {
@@ -17516,10 +18515,10 @@ var WatchHelper = class {
17516
18515
  dirParts;
17517
18516
  followSymlinks;
17518
18517
  statMethod;
17519
- constructor(path25, follow, fsw) {
18518
+ constructor(path26, follow, fsw) {
17520
18519
  this.fsw = fsw;
17521
- const watchPath = path25;
17522
- this.path = path25 = path25.replace(REPLACER_RE, "");
18520
+ const watchPath = path26;
18521
+ this.path = path26 = path26.replace(REPLACER_RE, "");
17523
18522
  this.watchPath = watchPath;
17524
18523
  this.fullWatchPath = sp2.resolve(watchPath);
17525
18524
  this.dirParts = [];
@@ -17659,20 +18658,20 @@ var FSWatcher = class extends import_node_events.EventEmitter {
17659
18658
  this._closePromise = void 0;
17660
18659
  let paths = unifyPaths(paths_);
17661
18660
  if (cwd) {
17662
- paths = paths.map((path25) => {
17663
- const absPath = getAbsolutePath(path25, cwd);
18661
+ paths = paths.map((path26) => {
18662
+ const absPath = getAbsolutePath(path26, cwd);
17664
18663
  return absPath;
17665
18664
  });
17666
18665
  }
17667
- paths.forEach((path25) => {
17668
- this._removeIgnoredPath(path25);
18666
+ paths.forEach((path26) => {
18667
+ this._removeIgnoredPath(path26);
17669
18668
  });
17670
18669
  this._userIgnored = void 0;
17671
18670
  if (!this._readyCount)
17672
18671
  this._readyCount = 0;
17673
18672
  this._readyCount += paths.length;
17674
- Promise.all(paths.map(async (path25) => {
17675
- const res = await this._nodeFsHandler._addToNodeFs(path25, !_internal, void 0, 0, _origAdd);
18673
+ Promise.all(paths.map(async (path26) => {
18674
+ const res = await this._nodeFsHandler._addToNodeFs(path26, !_internal, void 0, 0, _origAdd);
17676
18675
  if (res)
17677
18676
  this._emitReady();
17678
18677
  return res;
@@ -17694,17 +18693,17 @@ var FSWatcher = class extends import_node_events.EventEmitter {
17694
18693
  return this;
17695
18694
  const paths = unifyPaths(paths_);
17696
18695
  const { cwd } = this.options;
17697
- paths.forEach((path25) => {
17698
- if (!sp2.isAbsolute(path25) && !this._closers.has(path25)) {
18696
+ paths.forEach((path26) => {
18697
+ if (!sp2.isAbsolute(path26) && !this._closers.has(path26)) {
17699
18698
  if (cwd)
17700
- path25 = sp2.join(cwd, path25);
17701
- path25 = sp2.resolve(path25);
18699
+ path26 = sp2.join(cwd, path26);
18700
+ path26 = sp2.resolve(path26);
17702
18701
  }
17703
- this._closePath(path25);
17704
- this._addIgnoredPath(path25);
17705
- if (this._watched.has(path25)) {
18702
+ this._closePath(path26);
18703
+ this._addIgnoredPath(path26);
18704
+ if (this._watched.has(path26)) {
17706
18705
  this._addIgnoredPath({
17707
- path: path25,
18706
+ path: path26,
17708
18707
  recursive: true
17709
18708
  });
17710
18709
  }
@@ -17768,38 +18767,38 @@ var FSWatcher = class extends import_node_events.EventEmitter {
17768
18767
  * @param stats arguments to be passed with event
17769
18768
  * @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag
17770
18769
  */
17771
- async _emit(event, path25, stats) {
18770
+ async _emit(event, path26, stats) {
17772
18771
  if (this.closed)
17773
18772
  return;
17774
18773
  const opts = this.options;
17775
18774
  if (isWindows)
17776
- path25 = sp2.normalize(path25);
18775
+ path26 = sp2.normalize(path26);
17777
18776
  if (opts.cwd)
17778
- path25 = sp2.relative(opts.cwd, path25);
17779
- const args = [path25];
18777
+ path26 = sp2.relative(opts.cwd, path26);
18778
+ const args = [path26];
17780
18779
  if (stats != null)
17781
18780
  args.push(stats);
17782
18781
  const awf = opts.awaitWriteFinish;
17783
18782
  let pw;
17784
- if (awf && (pw = this._pendingWrites.get(path25))) {
18783
+ if (awf && (pw = this._pendingWrites.get(path26))) {
17785
18784
  pw.lastChange = /* @__PURE__ */ new Date();
17786
18785
  return this;
17787
18786
  }
17788
18787
  if (opts.atomic) {
17789
18788
  if (event === EVENTS.UNLINK) {
17790
- this._pendingUnlinks.set(path25, [event, ...args]);
18789
+ this._pendingUnlinks.set(path26, [event, ...args]);
17791
18790
  setTimeout(() => {
17792
- this._pendingUnlinks.forEach((entry, path26) => {
18791
+ this._pendingUnlinks.forEach((entry, path27) => {
17793
18792
  this.emit(...entry);
17794
18793
  this.emit(EVENTS.ALL, ...entry);
17795
- this._pendingUnlinks.delete(path26);
18794
+ this._pendingUnlinks.delete(path27);
17796
18795
  });
17797
18796
  }, typeof opts.atomic === "number" ? opts.atomic : 100);
17798
18797
  return this;
17799
18798
  }
17800
- if (event === EVENTS.ADD && this._pendingUnlinks.has(path25)) {
18799
+ if (event === EVENTS.ADD && this._pendingUnlinks.has(path26)) {
17801
18800
  event = EVENTS.CHANGE;
17802
- this._pendingUnlinks.delete(path25);
18801
+ this._pendingUnlinks.delete(path26);
17803
18802
  }
17804
18803
  }
17805
18804
  if (awf && (event === EVENTS.ADD || event === EVENTS.CHANGE) && this._readyEmitted) {
@@ -17817,16 +18816,16 @@ var FSWatcher = class extends import_node_events.EventEmitter {
17817
18816
  this.emitWithAll(event, args);
17818
18817
  }
17819
18818
  };
17820
- this._awaitWriteFinish(path25, awf.stabilityThreshold, event, awfEmit);
18819
+ this._awaitWriteFinish(path26, awf.stabilityThreshold, event, awfEmit);
17821
18820
  return this;
17822
18821
  }
17823
18822
  if (event === EVENTS.CHANGE) {
17824
- const isThrottled = !this._throttle(EVENTS.CHANGE, path25, 50);
18823
+ const isThrottled = !this._throttle(EVENTS.CHANGE, path26, 50);
17825
18824
  if (isThrottled)
17826
18825
  return this;
17827
18826
  }
17828
18827
  if (opts.alwaysStat && stats === void 0 && (event === EVENTS.ADD || event === EVENTS.ADD_DIR || event === EVENTS.CHANGE)) {
17829
- const fullPath = opts.cwd ? sp2.join(opts.cwd, path25) : path25;
18828
+ const fullPath = opts.cwd ? sp2.join(opts.cwd, path26) : path26;
17830
18829
  let stats2;
17831
18830
  try {
17832
18831
  stats2 = await (0, import_promises3.stat)(fullPath);
@@ -17857,23 +18856,23 @@ var FSWatcher = class extends import_node_events.EventEmitter {
17857
18856
  * @param timeout duration of time to suppress duplicate actions
17858
18857
  * @returns tracking object or false if action should be suppressed
17859
18858
  */
17860
- _throttle(actionType, path25, timeout) {
18859
+ _throttle(actionType, path26, timeout) {
17861
18860
  if (!this._throttled.has(actionType)) {
17862
18861
  this._throttled.set(actionType, /* @__PURE__ */ new Map());
17863
18862
  }
17864
18863
  const action = this._throttled.get(actionType);
17865
18864
  if (!action)
17866
18865
  throw new Error("invalid throttle");
17867
- const actionPath = action.get(path25);
18866
+ const actionPath = action.get(path26);
17868
18867
  if (actionPath) {
17869
18868
  actionPath.count++;
17870
18869
  return false;
17871
18870
  }
17872
18871
  let timeoutObject;
17873
18872
  const clear = () => {
17874
- const item = action.get(path25);
18873
+ const item = action.get(path26);
17875
18874
  const count = item ? item.count : 0;
17876
- action.delete(path25);
18875
+ action.delete(path26);
17877
18876
  clearTimeout(timeoutObject);
17878
18877
  if (item)
17879
18878
  clearTimeout(item.timeoutObject);
@@ -17881,7 +18880,7 @@ var FSWatcher = class extends import_node_events.EventEmitter {
17881
18880
  };
17882
18881
  timeoutObject = setTimeout(clear, timeout);
17883
18882
  const thr = { timeoutObject, clear, count: 0 };
17884
- action.set(path25, thr);
18883
+ action.set(path26, thr);
17885
18884
  return thr;
17886
18885
  }
17887
18886
  _incrReadyCount() {
@@ -17895,44 +18894,44 @@ var FSWatcher = class extends import_node_events.EventEmitter {
17895
18894
  * @param event
17896
18895
  * @param awfEmit Callback to be called when ready for event to be emitted.
17897
18896
  */
17898
- _awaitWriteFinish(path25, threshold, event, awfEmit) {
18897
+ _awaitWriteFinish(path26, threshold, event, awfEmit) {
17899
18898
  const awf = this.options.awaitWriteFinish;
17900
18899
  if (typeof awf !== "object")
17901
18900
  return;
17902
18901
  const pollInterval = awf.pollInterval;
17903
18902
  let timeoutHandler;
17904
- let fullPath = path25;
17905
- if (this.options.cwd && !sp2.isAbsolute(path25)) {
17906
- fullPath = sp2.join(this.options.cwd, path25);
18903
+ let fullPath = path26;
18904
+ if (this.options.cwd && !sp2.isAbsolute(path26)) {
18905
+ fullPath = sp2.join(this.options.cwd, path26);
17907
18906
  }
17908
18907
  const now2 = /* @__PURE__ */ new Date();
17909
18908
  const writes = this._pendingWrites;
17910
18909
  function awaitWriteFinishFn(prevStat) {
17911
- (0, import_node_fs2.stat)(fullPath, (err, curStat) => {
17912
- if (err || !writes.has(path25)) {
18910
+ (0, import_node_fs3.stat)(fullPath, (err, curStat) => {
18911
+ if (err || !writes.has(path26)) {
17913
18912
  if (err && err.code !== "ENOENT")
17914
18913
  awfEmit(err);
17915
18914
  return;
17916
18915
  }
17917
18916
  const now3 = Number(/* @__PURE__ */ new Date());
17918
18917
  if (prevStat && curStat.size !== prevStat.size) {
17919
- writes.get(path25).lastChange = now3;
18918
+ writes.get(path26).lastChange = now3;
17920
18919
  }
17921
- const pw = writes.get(path25);
18920
+ const pw = writes.get(path26);
17922
18921
  const df = now3 - pw.lastChange;
17923
18922
  if (df >= threshold) {
17924
- writes.delete(path25);
18923
+ writes.delete(path26);
17925
18924
  awfEmit(void 0, curStat);
17926
18925
  } else {
17927
18926
  timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat);
17928
18927
  }
17929
18928
  });
17930
18929
  }
17931
- if (!writes.has(path25)) {
17932
- writes.set(path25, {
18930
+ if (!writes.has(path26)) {
18931
+ writes.set(path26, {
17933
18932
  lastChange: now2,
17934
18933
  cancelWait: () => {
17935
- writes.delete(path25);
18934
+ writes.delete(path26);
17936
18935
  clearTimeout(timeoutHandler);
17937
18936
  return event;
17938
18937
  }
@@ -17943,8 +18942,8 @@ var FSWatcher = class extends import_node_events.EventEmitter {
17943
18942
  /**
17944
18943
  * Determines whether user has asked to ignore this path.
17945
18944
  */
17946
- _isIgnored(path25, stats) {
17947
- if (this.options.atomic && DOT_RE.test(path25))
18945
+ _isIgnored(path26, stats) {
18946
+ if (this.options.atomic && DOT_RE.test(path26))
17948
18947
  return true;
17949
18948
  if (!this._userIgnored) {
17950
18949
  const { cwd } = this.options;
@@ -17954,17 +18953,17 @@ var FSWatcher = class extends import_node_events.EventEmitter {
17954
18953
  const list = [...ignoredPaths.map(normalizeIgnored(cwd)), ...ignored];
17955
18954
  this._userIgnored = anymatch(list, void 0);
17956
18955
  }
17957
- return this._userIgnored(path25, stats);
18956
+ return this._userIgnored(path26, stats);
17958
18957
  }
17959
- _isntIgnored(path25, stat5) {
17960
- return !this._isIgnored(path25, stat5);
18958
+ _isntIgnored(path26, stat5) {
18959
+ return !this._isIgnored(path26, stat5);
17961
18960
  }
17962
18961
  /**
17963
18962
  * Provides a set of common helpers and properties relating to symlink handling.
17964
18963
  * @param path file or directory pattern being watched
17965
18964
  */
17966
- _getWatchHelpers(path25) {
17967
- return new WatchHelper(path25, this.options.followSymlinks, this);
18965
+ _getWatchHelpers(path26) {
18966
+ return new WatchHelper(path26, this.options.followSymlinks, this);
17968
18967
  }
17969
18968
  // Directory helpers
17970
18969
  // -----------------
@@ -17996,63 +18995,63 @@ var FSWatcher = class extends import_node_events.EventEmitter {
17996
18995
  * @param item base path of item/directory
17997
18996
  */
17998
18997
  _remove(directory, item, isDirectory) {
17999
- const path25 = sp2.join(directory, item);
18000
- const fullPath = sp2.resolve(path25);
18001
- isDirectory = isDirectory != null ? isDirectory : this._watched.has(path25) || this._watched.has(fullPath);
18002
- if (!this._throttle("remove", path25, 100))
18998
+ const path26 = sp2.join(directory, item);
18999
+ const fullPath = sp2.resolve(path26);
19000
+ isDirectory = isDirectory != null ? isDirectory : this._watched.has(path26) || this._watched.has(fullPath);
19001
+ if (!this._throttle("remove", path26, 100))
18003
19002
  return;
18004
19003
  if (!isDirectory && this._watched.size === 1) {
18005
19004
  this.add(directory, item, true);
18006
19005
  }
18007
- const wp = this._getWatchedDir(path25);
19006
+ const wp = this._getWatchedDir(path26);
18008
19007
  const nestedDirectoryChildren = wp.getChildren();
18009
- nestedDirectoryChildren.forEach((nested) => this._remove(path25, nested));
19008
+ nestedDirectoryChildren.forEach((nested) => this._remove(path26, nested));
18010
19009
  const parent = this._getWatchedDir(directory);
18011
19010
  const wasTracked = parent.has(item);
18012
19011
  parent.remove(item);
18013
19012
  if (this._symlinkPaths.has(fullPath)) {
18014
19013
  this._symlinkPaths.delete(fullPath);
18015
19014
  }
18016
- let relPath = path25;
19015
+ let relPath = path26;
18017
19016
  if (this.options.cwd)
18018
- relPath = sp2.relative(this.options.cwd, path25);
19017
+ relPath = sp2.relative(this.options.cwd, path26);
18019
19018
  if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
18020
19019
  const event = this._pendingWrites.get(relPath).cancelWait();
18021
19020
  if (event === EVENTS.ADD)
18022
19021
  return;
18023
19022
  }
18024
- this._watched.delete(path25);
19023
+ this._watched.delete(path26);
18025
19024
  this._watched.delete(fullPath);
18026
19025
  const eventName = isDirectory ? EVENTS.UNLINK_DIR : EVENTS.UNLINK;
18027
- if (wasTracked && !this._isIgnored(path25))
18028
- this._emit(eventName, path25);
18029
- this._closePath(path25);
19026
+ if (wasTracked && !this._isIgnored(path26))
19027
+ this._emit(eventName, path26);
19028
+ this._closePath(path26);
18030
19029
  }
18031
19030
  /**
18032
19031
  * Closes all watchers for a path
18033
19032
  */
18034
- _closePath(path25) {
18035
- this._closeFile(path25);
18036
- const dir = sp2.dirname(path25);
18037
- this._getWatchedDir(dir).remove(sp2.basename(path25));
19033
+ _closePath(path26) {
19034
+ this._closeFile(path26);
19035
+ const dir = sp2.dirname(path26);
19036
+ this._getWatchedDir(dir).remove(sp2.basename(path26));
18038
19037
  }
18039
19038
  /**
18040
19039
  * Closes only file-specific watchers
18041
19040
  */
18042
- _closeFile(path25) {
18043
- const closers = this._closers.get(path25);
19041
+ _closeFile(path26) {
19042
+ const closers = this._closers.get(path26);
18044
19043
  if (!closers)
18045
19044
  return;
18046
19045
  closers.forEach((closer) => closer());
18047
- this._closers.delete(path25);
19046
+ this._closers.delete(path26);
18048
19047
  }
18049
- _addPathCloser(path25, closer) {
19048
+ _addPathCloser(path26, closer) {
18050
19049
  if (!closer)
18051
19050
  return;
18052
- let list = this._closers.get(path25);
19051
+ let list = this._closers.get(path26);
18053
19052
  if (!list) {
18054
19053
  list = [];
18055
- this._closers.set(path25, list);
19054
+ this._closers.set(path26, list);
18056
19055
  }
18057
19056
  list.push(closer);
18058
19057
  }
@@ -18082,11 +19081,11 @@ function watch(paths, options = {}) {
18082
19081
  var chokidar_default = { watch, FSWatcher };
18083
19082
 
18084
19083
  // src/watcher/file-watcher.ts
18085
- var path23 = __toESM(require("path"), 1);
19084
+ var path24 = __toESM(require("path"), 1);
18086
19085
 
18087
19086
  // src/watcher/native-recursive-watcher.ts
18088
- var import_node_fs3 = require("fs");
18089
- var path21 = __toESM(require("path"), 1);
19087
+ var import_node_fs4 = require("fs");
19088
+ var path22 = __toESM(require("path"), 1);
18090
19089
  var NativeRecursiveWatcher = class {
18091
19090
  constructor(root, onChange, options = {}) {
18092
19091
  this.root = root;
@@ -18134,26 +19133,26 @@ var NativeRecursiveWatcher = class {
18134
19133
  toAbsolutePath(filename) {
18135
19134
  if (filename == null) return null;
18136
19135
  const normalizedFilename = typeof filename === "string" ? filename : filename.toString();
18137
- const absolutePath = path21.resolve(this.root, normalizedFilename);
18138
- const relativePath = path21.relative(this.root, absolutePath);
18139
- const outsideRoot = relativePath === ".." || relativePath.startsWith(`..${path21.sep}`) || path21.isAbsolute(relativePath);
19136
+ const absolutePath = path22.resolve(this.root, normalizedFilename);
19137
+ const relativePath = path22.relative(this.root, absolutePath);
19138
+ const outsideRoot = relativePath === ".." || relativePath.startsWith(`..${path22.sep}`) || path22.isAbsolute(relativePath);
18140
19139
  return outsideRoot ? null : absolutePath;
18141
19140
  }
18142
- defaultWatchFactory = (root, listener, options) => (0, import_node_fs3.watch)(root, options, listener);
19141
+ defaultWatchFactory = (root, listener, options) => (0, import_node_fs4.watch)(root, options, listener);
18143
19142
  };
18144
19143
 
18145
19144
  // src/watcher/snapshot.ts
18146
19145
  var fsPromises4 = __toESM(require("fs/promises"), 1);
18147
- var path22 = __toESM(require("path"), 1);
19146
+ var path23 = __toESM(require("path"), 1);
18148
19147
  async function buildFileSnapshotScan(projectRoot3, config, configPaths = []) {
18149
- const normalizedProjectRoot = path22.resolve(projectRoot3);
19148
+ const normalizedProjectRoot = path23.resolve(projectRoot3);
18150
19149
  const ignoreFilter = createIgnoreFilter(normalizedProjectRoot);
18151
19150
  const includePatterns = [...config.include, ...config.additionalInclude ?? []];
18152
19151
  const maxDepth = config.indexing?.maxDepth ?? -1;
18153
19152
  const snapshot = /* @__PURE__ */ new Map();
18154
19153
  const unreadablePrefixes = /* @__PURE__ */ new Set();
18155
19154
  const includeFile = async (filePath) => {
18156
- const normalizedPath2 = path22.resolve(filePath);
19155
+ const normalizedPath2 = path23.resolve(filePath);
18157
19156
  if (!shouldIncludeFile(normalizedPath2, normalizedProjectRoot, includePatterns, config.exclude, ignoreFilter)) return;
18158
19157
  const stat5 = await readStatIfFile(normalizedPath2, unreadablePrefixes);
18159
19158
  if (stat5) snapshot.set(normalizedPath2, { size: stat5.size, mtimeMs: stat5.mtimeMs });
@@ -18165,16 +19164,16 @@ async function buildFileSnapshotScan(projectRoot3, config, configPaths = []) {
18165
19164
  } catch (error) {
18166
19165
  if (isMissingFsError(error)) return;
18167
19166
  if (isPermissionFsError(error)) {
18168
- unreadablePrefixes.add(path22.resolve(directoryPath));
19167
+ unreadablePrefixes.add(path23.resolve(directoryPath));
18169
19168
  return;
18170
19169
  }
18171
19170
  throw error;
18172
19171
  }
18173
19172
  for (const entry of entries) {
18174
- const fullPath = path22.join(directoryPath, entry.name);
18175
- const relativePath = path22.relative(normalizedProjectRoot, fullPath);
19173
+ const fullPath = path23.join(directoryPath, entry.name);
19174
+ const relativePath = path23.relative(normalizedProjectRoot, fullPath);
18176
19175
  if (entry.isDirectory()) {
18177
- if (hasFilteredPathSegment(relativePath, path22.sep) || isRestrictedDirectory(relativePath, path22.sep)) continue;
19176
+ if (hasFilteredPathSegment(relativePath, path23.sep) || isRestrictedDirectory(relativePath, path23.sep)) continue;
18178
19177
  if (ignoreFilter.ignores(relativePath)) continue;
18179
19178
  if (maxDepth === -1 || depth < maxDepth) await walk(fullPath, depth + 1);
18180
19179
  } else if (entry.isFile()) {
@@ -18187,19 +19186,19 @@ async function buildFileSnapshotScan(projectRoot3, config, configPaths = []) {
18187
19186
  return { entries: snapshot, unreadablePrefixes };
18188
19187
  }
18189
19188
  async function buildFileSnapshotForPathScan(projectRoot3, config, configPaths, targetPath) {
18190
- const normalizedProjectRoot = path22.resolve(projectRoot3);
18191
- const normalizedTargetPath = path22.resolve(targetPath);
19189
+ const normalizedProjectRoot = path23.resolve(projectRoot3);
19190
+ const normalizedTargetPath = path23.resolve(targetPath);
18192
19191
  if (!isWithinPath(normalizedProjectRoot, normalizedTargetPath)) {
18193
19192
  return { entries: /* @__PURE__ */ new Map(), unreadablePrefixes: /* @__PURE__ */ new Set() };
18194
19193
  }
18195
19194
  const ignoreFilter = createIgnoreFilter(normalizedProjectRoot);
18196
19195
  const includePatterns = [...config.include, ...config.additionalInclude ?? []];
18197
19196
  const maxDepth = config.indexing?.maxDepth ?? -1;
18198
- const explicitConfigPaths = new Set(configPaths.map((configPath) => path22.resolve(configPath)));
19197
+ const explicitConfigPaths = new Set(configPaths.map((configPath) => path23.resolve(configPath)));
18199
19198
  const snapshot = /* @__PURE__ */ new Map();
18200
19199
  const unreadablePrefixes = /* @__PURE__ */ new Set();
18201
19200
  const includeFile = async (filePath) => {
18202
- const normalizedPath2 = path22.resolve(filePath);
19201
+ const normalizedPath2 = path23.resolve(filePath);
18203
19202
  if (!explicitConfigPaths.has(normalizedPath2) && !shouldIncludeFile(
18204
19203
  normalizedPath2,
18205
19204
  normalizedProjectRoot,
@@ -18217,16 +19216,16 @@ async function buildFileSnapshotForPathScan(projectRoot3, config, configPaths, t
18217
19216
  } catch (error) {
18218
19217
  if (isMissingFsError(error)) return;
18219
19218
  if (isPermissionFsError(error)) {
18220
- unreadablePrefixes.add(path22.resolve(directoryPath));
19219
+ unreadablePrefixes.add(path23.resolve(directoryPath));
18221
19220
  return;
18222
19221
  }
18223
19222
  throw error;
18224
19223
  }
18225
19224
  for (const entry of entries) {
18226
- const fullPath = path22.join(directoryPath, entry.name);
18227
- const relativePath = path22.relative(normalizedProjectRoot, fullPath);
19225
+ const fullPath = path23.join(directoryPath, entry.name);
19226
+ const relativePath = path23.relative(normalizedProjectRoot, fullPath);
18228
19227
  if (entry.isDirectory()) {
18229
- if (hasFilteredPathSegment(relativePath, path22.sep) || isRestrictedDirectory(relativePath, path22.sep)) continue;
19228
+ if (hasFilteredPathSegment(relativePath, path23.sep) || isRestrictedDirectory(relativePath, path23.sep)) continue;
18230
19229
  if (ignoreFilter.ignores(relativePath)) continue;
18231
19230
  if (maxDepth === -1 || depth < maxDepth) await walk(fullPath, depth + 1);
18232
19231
  } else if (entry.isFile()) {
@@ -18250,7 +19249,7 @@ function completeFileSnapshot(previous, scan) {
18250
19249
  return completed;
18251
19250
  }
18252
19251
  async function includeExplicitConfigPaths(snapshot, unreadablePrefixes, configPaths) {
18253
- for (const configPath of [...new Set(configPaths.map((value) => path22.resolve(value)))]) {
19252
+ for (const configPath of [...new Set(configPaths.map((value) => path23.resolve(value)))]) {
18254
19253
  if (snapshot.has(configPath)) continue;
18255
19254
  const stat5 = await readStatIfFile(configPath, unreadablePrefixes);
18256
19255
  if (stat5) snapshot.set(configPath, { size: stat5.size, mtimeMs: stat5.mtimeMs });
@@ -18260,12 +19259,12 @@ async function includeExplicitConfigPathsInPath(snapshot, unreadablePrefixes, co
18260
19259
  await includeExplicitConfigPaths(
18261
19260
  snapshot,
18262
19261
  unreadablePrefixes,
18263
- configPaths.filter((configPath) => isWithinPath(targetPath, path22.resolve(configPath)))
19262
+ configPaths.filter((configPath) => isWithinPath(targetPath, path23.resolve(configPath)))
18264
19263
  );
18265
19264
  }
18266
19265
  function isWithinPath(parentPath, childPath) {
18267
- const relativePath = path22.relative(parentPath, childPath);
18268
- return relativePath === "" || !relativePath.startsWith(`..${path22.sep}`) && relativePath !== ".." && !path22.isAbsolute(relativePath);
19266
+ const relativePath = path23.relative(parentPath, childPath);
19267
+ return relativePath === "" || !relativePath.startsWith(`..${path23.sep}`) && relativePath !== ".." && !path23.isAbsolute(relativePath);
18269
19268
  }
18270
19269
  async function readStatIfFile(filePath, unreadablePrefixes) {
18271
19270
  try {
@@ -18274,7 +19273,7 @@ async function readStatIfFile(filePath, unreadablePrefixes) {
18274
19273
  } catch (error) {
18275
19274
  if (isMissingFsError(error)) return null;
18276
19275
  if (isPermissionFsError(error)) {
18277
- unreadablePrefixes.add(path22.resolve(filePath));
19276
+ unreadablePrefixes.add(path23.resolve(filePath));
18278
19277
  return null;
18279
19278
  }
18280
19279
  throw error;
@@ -18411,8 +19410,8 @@ var FileWatcher = class {
18411
19410
  this.createWatcher();
18412
19411
  }
18413
19412
  resetReady() {
18414
- this.readyPromise = new Promise((resolve17) => {
18415
- this.resolveReady = resolve17;
19413
+ this.readyPromise = new Promise((resolve18) => {
19414
+ this.resolveReady = resolve18;
18416
19415
  });
18417
19416
  this.startupReadySignals = 1;
18418
19417
  }
@@ -18443,7 +19442,7 @@ var FileWatcher = class {
18443
19442
  const resolvedWatchTargets = watchTargets ?? this.getFullChokidarWatchTargets();
18444
19443
  const watcherOptions = {
18445
19444
  ignored: (filePath) => {
18446
- const relativePath = path23.relative(this.projectRoot, filePath);
19445
+ const relativePath = path24.relative(this.projectRoot, filePath);
18447
19446
  if (!relativePath) return false;
18448
19447
  if (this.isProjectConfigPathOrAncestor(relativePath)) {
18449
19448
  return false;
@@ -18451,10 +19450,10 @@ var FileWatcher = class {
18451
19450
  if (this.isOutsideProjectPath(relativePath)) {
18452
19451
  return true;
18453
19452
  }
18454
- if (hasFilteredPathSegment(relativePath, path23.sep)) {
19453
+ if (hasFilteredPathSegment(relativePath, path24.sep)) {
18455
19454
  return true;
18456
19455
  }
18457
- if (isRestrictedDirectory(relativePath, path23.sep)) {
19456
+ if (isRestrictedDirectory(relativePath, path24.sep)) {
18458
19457
  return true;
18459
19458
  }
18460
19459
  if (ignoreFilter.ignores(relativePath)) {
@@ -18545,13 +19544,13 @@ var FileWatcher = class {
18545
19544
  getExternalConfigWatchTargets() {
18546
19545
  return [...new Set(
18547
19546
  this.projectConfigPaths.filter((projectConfigPath) => {
18548
- const relativeConfigPath = path23.relative(this.projectRoot, projectConfigPath);
19547
+ const relativeConfigPath = path24.relative(this.projectRoot, projectConfigPath);
18549
19548
  return this.isOutsideProjectPath(relativeConfigPath);
18550
19549
  }).map((projectConfigPath) => {
18551
19550
  if ((0, import_fs14.existsSync)(projectConfigPath)) {
18552
19551
  return projectConfigPath;
18553
19552
  }
18554
- return this.getNearestExistingDirectory(path23.dirname(projectConfigPath));
19553
+ return this.getNearestExistingDirectory(path24.dirname(projectConfigPath));
18555
19554
  })
18556
19555
  )];
18557
19556
  }
@@ -18613,7 +19612,7 @@ var FileWatcher = class {
18613
19612
  }
18614
19613
  scheduleNativeReconciliation(generation, filePath) {
18615
19614
  if (!this.isCurrentNativeSetup(generation)) return;
18616
- const requiresFullReconciliation = filePath === path23.join(this.projectRoot, ".gitignore");
19615
+ const requiresFullReconciliation = filePath === path24.join(this.projectRoot, ".gitignore");
18617
19616
  const invalidatedPath = requiresFullReconciliation ? null : filePath;
18618
19617
  this.nativeInvalidatedPaths.set(invalidatedPath, invalidatedPath !== null);
18619
19618
  if (this.nativeReconcileTimer) {
@@ -18708,23 +19707,23 @@ var FileWatcher = class {
18708
19707
  this.scheduleFlush();
18709
19708
  }
18710
19709
  isProjectConfigPath(filePath) {
18711
- const relativePath = path23.relative(this.projectRoot, filePath);
18712
- const normalizedRelativePath = path23.normalize(relativePath);
19710
+ const relativePath = path24.relative(this.projectRoot, filePath);
19711
+ const normalizedRelativePath = path24.normalize(relativePath);
18713
19712
  return this.getProjectConfigRelativePaths().some((configPath) => configPath === normalizedRelativePath);
18714
19713
  }
18715
19714
  isProjectConfigPathOrAncestor(relativePath) {
18716
- const normalizedRelativePath = path23.normalize(relativePath);
19715
+ const normalizedRelativePath = path24.normalize(relativePath);
18717
19716
  return this.getProjectConfigRelativePaths().some(
18718
- (configPath) => configPath === normalizedRelativePath || configPath.startsWith(`${normalizedRelativePath}${path23.sep}`)
19717
+ (configPath) => configPath === normalizedRelativePath || configPath.startsWith(`${normalizedRelativePath}${path24.sep}`)
18719
19718
  );
18720
19719
  }
18721
19720
  isOutsideProjectPath(relativePath) {
18722
- return relativePath === ".." || relativePath.startsWith(`..${path23.sep}`) || path23.isAbsolute(relativePath);
19721
+ return relativePath === ".." || relativePath.startsWith(`..${path24.sep}`) || path24.isAbsolute(relativePath);
18723
19722
  }
18724
19723
  getNearestExistingDirectory(directoryPath) {
18725
19724
  let candidate = directoryPath;
18726
19725
  while (!(0, import_fs14.existsSync)(candidate)) {
18727
- const parent = path23.dirname(candidate);
19726
+ const parent = path24.dirname(candidate);
18728
19727
  if (parent === candidate) break;
18729
19728
  candidate = parent;
18730
19729
  }
@@ -18732,7 +19731,7 @@ var FileWatcher = class {
18732
19731
  }
18733
19732
  getProjectConfigRelativePaths() {
18734
19733
  return this.projectConfigPaths.map(
18735
- (configPath) => path23.normalize(path23.relative(this.projectRoot, configPath))
19734
+ (configPath) => path24.normalize(path24.relative(this.projectRoot, configPath))
18736
19735
  );
18737
19736
  }
18738
19737
  getConfigPathStates() {
@@ -18790,7 +19789,7 @@ var FileWatcher = class {
18790
19789
  return;
18791
19790
  }
18792
19791
  const changes = Array.from(this.pendingChanges.entries()).map(
18793
- ([path25, type]) => ({ path: path25, type })
19792
+ ([path26, type]) => ({ path: path26, type })
18794
19793
  );
18795
19794
  this.pendingChanges.clear();
18796
19795
  try {
@@ -18836,7 +19835,7 @@ var FileWatcher = class {
18836
19835
  };
18837
19836
 
18838
19837
  // src/watcher/git-head-watcher.ts
18839
- var path24 = __toESM(require("path"), 1);
19838
+ var path25 = __toESM(require("path"), 1);
18840
19839
  var GitHeadWatcher = class {
18841
19840
  watcher = null;
18842
19841
  projectRoot;
@@ -18858,13 +19857,13 @@ var GitHeadWatcher = class {
18858
19857
  this.readyPromise = Promise.resolve();
18859
19858
  return;
18860
19859
  }
18861
- this.readyPromise = new Promise((resolve17) => {
18862
- this.resolveReady = resolve17;
19860
+ this.readyPromise = new Promise((resolve18) => {
19861
+ this.resolveReady = resolve18;
18863
19862
  });
18864
19863
  this.onBranchChange = handler;
18865
19864
  this.currentBranch = getCurrentBranch(this.projectRoot);
18866
19865
  const headPath = getHeadPath(this.projectRoot);
18867
- const refsPath = path24.join(this.projectRoot, ".git", "refs", "heads");
19866
+ const refsPath = path25.join(this.projectRoot, ".git", "refs", "heads");
18868
19867
  this.watcher = chokidar_default.watch([headPath, refsPath], {
18869
19868
  persistent: true,
18870
19869
  ignoreInitial: true,
@@ -18932,7 +19931,9 @@ var GitHeadWatcher = class {
18932
19931
  function createWatcherWithIndexer(getIndexer, projectRoot3, config, host, options = {}) {
18933
19932
  const fileWatcher = new FileWatcher(projectRoot3, config, host, options);
18934
19933
  const configPaths = getConfigPaths(projectRoot3, host, options);
18935
- configureAutoIndex(projectRoot3, host, parseConfig(config), getIndexer);
19934
+ configureAutoIndex(projectRoot3, host, parseConfig(config), getIndexer, {
19935
+ synchronizeBackgroundWorker: false
19936
+ });
18936
19937
  let stopped = false;
18937
19938
  const requestReindex = () => {
18938
19939
  if (stopped) return;
@@ -18952,7 +19953,9 @@ function createWatcherWithIndexer(getIndexer, projectRoot3, config, host, option
18952
19953
  const parsedConfig = options.configPath ? parseConfig(loadConfigFile(options.configPath)) : void 0;
18953
19954
  const refreshedConfig = refreshIndexerForDirectory(projectRoot3, host, parsedConfig);
18954
19955
  if (refreshedConfig) {
18955
- configureAutoIndex(projectRoot3, host, refreshedConfig, getIndexer);
19956
+ configureAutoIndex(projectRoot3, host, refreshedConfig, getIndexer, {
19957
+ synchronizeBackgroundWorker: false
19958
+ });
18956
19959
  }
18957
19960
  }
18958
19961
  requestReindex();
@@ -19000,7 +20003,6 @@ function getConfigPaths(projectRoot3, host, options) {
19000
20003
 
19001
20004
  // src/adapters/pi/extension.ts
19002
20005
  var HOST2 = "pi";
19003
- var activeWatchers = /* @__PURE__ */ new Map();
19004
20006
  var ChunkType = import_typebox2.Type.Union([
19005
20007
  import_typebox2.Type.Literal("function"),
19006
20008
  import_typebox2.Type.Literal("class"),
@@ -19019,24 +20021,30 @@ function projectRoot2(ctx) {
19019
20021
  function isValidProject(projectRoot3, requireProjectMarker) {
19020
20022
  return !isHomeDirectory(projectRoot3) && (!requireProjectMarker || hasProjectMarker(projectRoot3));
19021
20023
  }
19022
- function ensureWatcher(projectRoot3) {
19023
- if (activeWatchers.has(projectRoot3)) return;
20024
+ async function ensureWatcher(projectRoot3) {
19024
20025
  const config = parseConfig(loadMergedConfig(projectRoot3, HOST2));
19025
- if (!config.indexing.watchFiles || !isValidProject(projectRoot3, config.indexing.requireProjectMarker)) {
20026
+ if (!isValidProject(projectRoot3, config.indexing.requireProjectMarker)) {
20027
+ await stopBackgroundWorker(projectRoot3, HOST2).catch((error) => {
20028
+ console.error("[codebase-index] Failed to stop Pi background worker:", error);
20029
+ });
19026
20030
  return;
19027
20031
  }
19028
- activeWatchers.set(projectRoot3, createWatcherWithIndexer(
20032
+ getIndexerForProject(projectRoot3, HOST2);
20033
+ const watcherFactoryForConfig = (refreshedConfig) => refreshedConfig.indexing.watchFiles ? () => createWatcherWithIndexer(
19029
20034
  () => getIndexerForProject(projectRoot3, HOST2),
19030
20035
  projectRoot3,
19031
- config,
20036
+ refreshedConfig,
19032
20037
  HOST2
19033
- ));
19034
- }
19035
- async function stopWatcher(projectRoot3) {
19036
- const watcher = activeWatchers.get(projectRoot3);
19037
- if (!watcher) return;
19038
- activeWatchers.delete(projectRoot3);
19039
- await watcher.stop();
20038
+ ) : null;
20039
+ configureBackgroundWorker(projectRoot3, HOST2, config, {
20040
+ startAutoIndex: (source, allowDisabledAutoIndex) => {
20041
+ startAutoIndexForBackgroundWorker(projectRoot3, HOST2, source, allowDisabledAutoIndex);
20042
+ },
20043
+ stopAutoIndex: () => stopAutoIndexForBackgroundWorker(projectRoot3, HOST2),
20044
+ watcherFactory: watcherFactoryForConfig(config),
20045
+ watcherFactoryForConfig
20046
+ });
20047
+ await waitForBackgroundWorkerStart(projectRoot3, HOST2);
19040
20048
  }
19041
20049
  function codebaseIndexPiExtension(pi) {
19042
20050
  pi.registerTool({
@@ -19269,7 +20277,7 @@ function codebaseIndexPiExtension(pi) {
19269
20277
  });
19270
20278
  registerPiCallGraphTools(pi);
19271
20279
  pi.on("before_agent_start", async (event, ctx) => {
19272
- ensureWatcher(projectRoot2(ctx));
20280
+ await ensureWatcher(projectRoot2(ctx));
19273
20281
  return {
19274
20282
  systemPrompt: `${event.systemPrompt}
19275
20283
 
@@ -19278,7 +20286,7 @@ Check index_status first when index readiness is unknown. Use codebase_context o
19278
20286
  });
19279
20287
  pi.on("session_shutdown", async (_event, ctx) => {
19280
20288
  const root = projectRoot2(ctx);
19281
- await Promise.all([stopWatcher(root), stopAutoIndex(root, HOST2)]);
20289
+ await stopBackgroundWorker(root, HOST2);
19282
20290
  });
19283
20291
  pi.registerTool({
19284
20292
  name: TOOL_NAME.PR_IMPACT,