opencode-codebase-index 0.24.0 → 0.25.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/README.md +10 -0
- package/dist/cbi.cjs +15788 -0
- package/dist/cbi.cjs.map +1 -0
- package/dist/cbi.js +15791 -0
- package/dist/cbi.js.map +1 -0
- package/dist/cli.cjs +1847 -660
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +1881 -685
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +1673 -590
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1680 -588
- package/dist/index.js.map +1 -1
- package/dist/pi-extension.cjs +1585 -485
- package/dist/pi-extension.cjs.map +1 -1
- package/dist/pi-extension.js +1641 -532
- package/dist/pi-extension.js.map +1 -1
- package/native/codebase-index-native.darwin-arm64.node +0 -0
- package/native/codebase-index-native.darwin-x64.node +0 -0
- package/native/codebase-index-native.linux-arm64-gnu.node +0 -0
- package/native/codebase-index-native.linux-x64-gnu.node +0 -0
- package/native/codebase-index-native.win32-x64-msvc.node +0 -0
- package/package.json +3 -2
package/dist/index.cjs
CHANGED
|
@@ -333,7 +333,7 @@ var require_ignore = __commonJS({
|
|
|
333
333
|
// path matching.
|
|
334
334
|
// - check `string` either `MODE_IGNORE` or `MODE_CHECK_IGNORE`
|
|
335
335
|
// @returns {TestResult} true if a file is ignored
|
|
336
|
-
test(
|
|
336
|
+
test(path31, checkUnignored, mode) {
|
|
337
337
|
let ignored = false;
|
|
338
338
|
let unignored = false;
|
|
339
339
|
let matchedRule;
|
|
@@ -342,7 +342,7 @@ var require_ignore = __commonJS({
|
|
|
342
342
|
if (unignored === negative && ignored !== unignored || negative && !ignored && !unignored && !checkUnignored) {
|
|
343
343
|
return;
|
|
344
344
|
}
|
|
345
|
-
const matched = rule[mode].test(
|
|
345
|
+
const matched = rule[mode].test(path31);
|
|
346
346
|
if (!matched) {
|
|
347
347
|
return;
|
|
348
348
|
}
|
|
@@ -363,17 +363,17 @@ var require_ignore = __commonJS({
|
|
|
363
363
|
var throwError = (message, Ctor) => {
|
|
364
364
|
throw new Ctor(message);
|
|
365
365
|
};
|
|
366
|
-
var checkPath = (
|
|
367
|
-
if (!isString(
|
|
366
|
+
var checkPath = (path31, originalPath, doThrow) => {
|
|
367
|
+
if (!isString(path31)) {
|
|
368
368
|
return doThrow(
|
|
369
369
|
`path must be a string, but got \`${originalPath}\``,
|
|
370
370
|
TypeError
|
|
371
371
|
);
|
|
372
372
|
}
|
|
373
|
-
if (!
|
|
373
|
+
if (!path31) {
|
|
374
374
|
return doThrow(`path must not be empty`, TypeError);
|
|
375
375
|
}
|
|
376
|
-
if (checkPath.isNotRelative(
|
|
376
|
+
if (checkPath.isNotRelative(path31)) {
|
|
377
377
|
const r = "`path.relative()`d";
|
|
378
378
|
return doThrow(
|
|
379
379
|
`path should be a ${r} string, but got "${originalPath}"`,
|
|
@@ -382,7 +382,7 @@ var require_ignore = __commonJS({
|
|
|
382
382
|
}
|
|
383
383
|
return true;
|
|
384
384
|
};
|
|
385
|
-
var isNotRelative = (
|
|
385
|
+
var isNotRelative = (path31) => REGEX_TEST_INVALID_PATH.test(path31);
|
|
386
386
|
checkPath.isNotRelative = isNotRelative;
|
|
387
387
|
checkPath.convert = (p) => p;
|
|
388
388
|
var Ignore2 = class {
|
|
@@ -412,19 +412,19 @@ var require_ignore = __commonJS({
|
|
|
412
412
|
}
|
|
413
413
|
// @returns {TestResult}
|
|
414
414
|
_test(originalPath, cache, checkUnignored, slices) {
|
|
415
|
-
const
|
|
415
|
+
const path31 = originalPath && checkPath.convert(originalPath);
|
|
416
416
|
checkPath(
|
|
417
|
-
|
|
417
|
+
path31,
|
|
418
418
|
originalPath,
|
|
419
419
|
this._strictPathCheck ? throwError : RETURN_FALSE
|
|
420
420
|
);
|
|
421
|
-
return this._t(
|
|
421
|
+
return this._t(path31, cache, checkUnignored, slices);
|
|
422
422
|
}
|
|
423
|
-
checkIgnore(
|
|
424
|
-
if (!REGEX_TEST_TRAILING_SLASH.test(
|
|
425
|
-
return this.test(
|
|
423
|
+
checkIgnore(path31) {
|
|
424
|
+
if (!REGEX_TEST_TRAILING_SLASH.test(path31)) {
|
|
425
|
+
return this.test(path31);
|
|
426
426
|
}
|
|
427
|
-
const slices =
|
|
427
|
+
const slices = path31.split(SLASH2).filter(Boolean);
|
|
428
428
|
slices.pop();
|
|
429
429
|
if (slices.length) {
|
|
430
430
|
const parent = this._t(
|
|
@@ -437,18 +437,18 @@ var require_ignore = __commonJS({
|
|
|
437
437
|
return parent;
|
|
438
438
|
}
|
|
439
439
|
}
|
|
440
|
-
return this._rules.test(
|
|
440
|
+
return this._rules.test(path31, false, MODE_CHECK_IGNORE);
|
|
441
441
|
}
|
|
442
|
-
_t(
|
|
443
|
-
if (
|
|
444
|
-
return cache[
|
|
442
|
+
_t(path31, cache, checkUnignored, slices) {
|
|
443
|
+
if (path31 in cache) {
|
|
444
|
+
return cache[path31];
|
|
445
445
|
}
|
|
446
446
|
if (!slices) {
|
|
447
|
-
slices =
|
|
447
|
+
slices = path31.split(SLASH2).filter(Boolean);
|
|
448
448
|
}
|
|
449
449
|
slices.pop();
|
|
450
450
|
if (!slices.length) {
|
|
451
|
-
return cache[
|
|
451
|
+
return cache[path31] = this._rules.test(path31, checkUnignored, MODE_IGNORE);
|
|
452
452
|
}
|
|
453
453
|
const parent = this._t(
|
|
454
454
|
slices.join(SLASH2) + SLASH2,
|
|
@@ -456,29 +456,29 @@ var require_ignore = __commonJS({
|
|
|
456
456
|
checkUnignored,
|
|
457
457
|
slices
|
|
458
458
|
);
|
|
459
|
-
return cache[
|
|
459
|
+
return cache[path31] = parent.ignored ? parent : this._rules.test(path31, checkUnignored, MODE_IGNORE);
|
|
460
460
|
}
|
|
461
|
-
ignores(
|
|
462
|
-
return this._test(
|
|
461
|
+
ignores(path31) {
|
|
462
|
+
return this._test(path31, this._ignoreCache, false).ignored;
|
|
463
463
|
}
|
|
464
464
|
createFilter() {
|
|
465
|
-
return (
|
|
465
|
+
return (path31) => !this.ignores(path31);
|
|
466
466
|
}
|
|
467
467
|
filter(paths) {
|
|
468
468
|
return makeArray(paths).filter(this.createFilter());
|
|
469
469
|
}
|
|
470
470
|
// @returns {TestResult}
|
|
471
|
-
test(
|
|
472
|
-
return this._test(
|
|
471
|
+
test(path31) {
|
|
472
|
+
return this._test(path31, this._testCache, true);
|
|
473
473
|
}
|
|
474
474
|
};
|
|
475
475
|
var factory = (options) => new Ignore2(options);
|
|
476
|
-
var isPathValid = (
|
|
476
|
+
var isPathValid = (path31) => checkPath(path31 && checkPath.convert(path31), path31, RETURN_FALSE);
|
|
477
477
|
var setupWindows = () => {
|
|
478
478
|
const makePosix = (str) => /^\\\\\?\\/.test(str) || /["<>|\u0000-\u001F]+/u.test(str) ? str : str.replace(/\\/g, "/");
|
|
479
479
|
checkPath.convert = makePosix;
|
|
480
480
|
const REGEX_TEST_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i;
|
|
481
|
-
checkPath.isNotRelative = (
|
|
481
|
+
checkPath.isNotRelative = (path31) => REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path31) || isNotRelative(path31);
|
|
482
482
|
};
|
|
483
483
|
if (
|
|
484
484
|
// Detect `process` so that it can run in browsers.
|
|
@@ -663,7 +663,7 @@ __export(index_exports, {
|
|
|
663
663
|
module.exports = __toCommonJS(index_exports);
|
|
664
664
|
|
|
665
665
|
// src/adapters/opencode.ts
|
|
666
|
-
var
|
|
666
|
+
var path30 = __toESM(require("path"), 1);
|
|
667
667
|
var import_url = require("url");
|
|
668
668
|
|
|
669
669
|
// src/config/constants.ts
|
|
@@ -1762,7 +1762,7 @@ function loadMergedConfig(projectRoot, host) {
|
|
|
1762
1762
|
|
|
1763
1763
|
// src/tools/operations.ts
|
|
1764
1764
|
var import_fs13 = require("fs");
|
|
1765
|
-
var
|
|
1765
|
+
var path21 = __toESM(require("path"), 1);
|
|
1766
1766
|
|
|
1767
1767
|
// src/tools/knowledge-base-paths.ts
|
|
1768
1768
|
var path8 = __toESM(require("path"), 1);
|
|
@@ -2611,8 +2611,8 @@ function formatExactSearchHandoff(results) {
|
|
|
2611
2611
|
}
|
|
2612
2612
|
function formatContextEvidence(result, index) {
|
|
2613
2613
|
const symbol = result.name ? ` ${JSON.stringify(compactEvidenceValue(result.name, 80))}` : "";
|
|
2614
|
-
const
|
|
2615
|
-
return `[${index}] ${result.chunkType}${symbol} in ${
|
|
2614
|
+
const path31 = compactEvidenceValue(result.filePath, 120);
|
|
2615
|
+
return `[${index}] ${result.chunkType}${symbol} in ${path31}:${result.startLine}-${result.endLine} (score ${result.score.toFixed(2)})`;
|
|
2616
2616
|
}
|
|
2617
2617
|
function formatContextPack(heading, selected, candidateCount, duplicateCount, limitOmittedCount, budgetOmittedCount, includeExactSearchHandoff) {
|
|
2618
2618
|
const lines = selected.map((result, index) => formatContextEvidence(result, index + 1));
|
|
@@ -3255,8 +3255,8 @@ function formatEffectivenessMetrics(snapshot) {
|
|
|
3255
3255
|
|
|
3256
3256
|
// src/utils/auto-index.ts
|
|
3257
3257
|
var import_fs7 = require("fs");
|
|
3258
|
-
var
|
|
3259
|
-
var
|
|
3258
|
+
var os4 = __toESM(require("os"), 1);
|
|
3259
|
+
var path12 = __toESM(require("path"), 1);
|
|
3260
3260
|
|
|
3261
3261
|
// src/indexer/index-lock.ts
|
|
3262
3262
|
var import_crypto = require("crypto");
|
|
@@ -3503,7 +3503,7 @@ function removeDeadReclaimMarker(lockPath, expectedOwner) {
|
|
|
3503
3503
|
return true;
|
|
3504
3504
|
}
|
|
3505
3505
|
function reclaimDeadOwner(indexPath, lockPath, expectedOwner) {
|
|
3506
|
-
const
|
|
3506
|
+
const reclaimPath2 = path9.join(lockPath, RECLAIM_DIRECTORY_NAME);
|
|
3507
3507
|
const reclaimOwner = {
|
|
3508
3508
|
pid: process.pid,
|
|
3509
3509
|
hostname: os2.hostname(),
|
|
@@ -3512,19 +3512,19 @@ function reclaimDeadOwner(indexPath, lockPath, expectedOwner) {
|
|
|
3512
3512
|
expectedOwnerToken: expectedOwner.token
|
|
3513
3513
|
};
|
|
3514
3514
|
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
3515
|
-
if (publishJsonDirectory(
|
|
3515
|
+
if (publishJsonDirectory(reclaimPath2, reclaimOwner)) break;
|
|
3516
3516
|
if (attempt === 0 && removeDeadReclaimMarker(lockPath, expectedOwner)) continue;
|
|
3517
3517
|
return false;
|
|
3518
3518
|
}
|
|
3519
3519
|
try {
|
|
3520
|
-
const currentReclaimer = readReclaimOwner(
|
|
3520
|
+
const currentReclaimer = readReclaimOwner(reclaimPath2);
|
|
3521
3521
|
const currentOwner = readDirectoryOwner(lockPath);
|
|
3522
3522
|
if (!currentReclaimer || !sameReclaimOwner(currentReclaimer, reclaimOwner) || !currentOwner || !sameOwner(currentOwner, expectedOwner) || getOwnerLiveness(currentOwner) !== "dead") {
|
|
3523
3523
|
return false;
|
|
3524
3524
|
}
|
|
3525
3525
|
publishRecoveryMarker(indexPath, expectedOwner);
|
|
3526
3526
|
const ownerBeforeQuarantine = readDirectoryOwner(lockPath);
|
|
3527
|
-
const reclaimerBeforeQuarantine = readReclaimOwner(
|
|
3527
|
+
const reclaimerBeforeQuarantine = readReclaimOwner(reclaimPath2);
|
|
3528
3528
|
if (!ownerBeforeQuarantine || !sameOwner(ownerBeforeQuarantine, expectedOwner) || getOwnerLiveness(ownerBeforeQuarantine) !== "dead" || !reclaimerBeforeQuarantine || !sameReclaimOwner(reclaimerBeforeQuarantine, reclaimOwner)) {
|
|
3529
3529
|
return false;
|
|
3530
3530
|
}
|
|
@@ -3627,77 +3627,951 @@ function releaseIndexLock(lease) {
|
|
|
3627
3627
|
}
|
|
3628
3628
|
return false;
|
|
3629
3629
|
}
|
|
3630
|
-
try {
|
|
3631
|
-
retryTransientFilesystemOperation(() => (0, import_fs5.rmSync)(releasePath, { recursive: true, force: true }));
|
|
3632
|
-
} catch (error) {
|
|
3633
|
-
console.error(`[codebase-index] Lease released but tombstone cleanup failed: ${releasePath}`, error);
|
|
3630
|
+
try {
|
|
3631
|
+
retryTransientFilesystemOperation(() => (0, import_fs5.rmSync)(releasePath, { recursive: true, force: true }));
|
|
3632
|
+
} catch (error) {
|
|
3633
|
+
console.error(`[codebase-index] Lease released but tombstone cleanup failed: ${releasePath}`, error);
|
|
3634
|
+
}
|
|
3635
|
+
return true;
|
|
3636
|
+
}
|
|
3637
|
+
function setIndexLockClearRecoveryState(lease, clearRecovery) {
|
|
3638
|
+
const currentOwner = readDirectoryOwner(lease.lockPath);
|
|
3639
|
+
if (!currentOwner || !sameOwner(currentOwner, lease.owner)) {
|
|
3640
|
+
throw new Error(`Lost ownership of index mutation lease ${lease.owner.token}`);
|
|
3641
|
+
}
|
|
3642
|
+
const nextOwner = { ...currentOwner };
|
|
3643
|
+
if (clearRecovery === null) {
|
|
3644
|
+
delete nextOwner.clearRecovery;
|
|
3645
|
+
} else {
|
|
3646
|
+
nextOwner.clearRecovery = clearRecovery;
|
|
3647
|
+
}
|
|
3648
|
+
const ownerPath = path9.join(lease.lockPath, OWNER_FILE_NAME);
|
|
3649
|
+
const temporaryPath = path9.join(
|
|
3650
|
+
lease.lockPath,
|
|
3651
|
+
`${OWNER_FILE_NAME}.tmp.${lease.owner.pid}.${lease.owner.token}.${(0, import_crypto.randomUUID)()}`
|
|
3652
|
+
);
|
|
3653
|
+
try {
|
|
3654
|
+
(0, import_fs5.writeFileSync)(temporaryPath, JSON.stringify(nextOwner), {
|
|
3655
|
+
encoding: "utf-8",
|
|
3656
|
+
flag: "wx",
|
|
3657
|
+
mode: 384
|
|
3658
|
+
});
|
|
3659
|
+
retryTransientFilesystemOperation(() => (0, import_fs5.renameSync)(temporaryPath, ownerPath));
|
|
3660
|
+
} finally {
|
|
3661
|
+
if ((0, import_fs5.existsSync)(temporaryPath)) (0, import_fs5.rmSync)(temporaryPath, { force: true });
|
|
3662
|
+
}
|
|
3663
|
+
}
|
|
3664
|
+
function createLeaseTemporaryPath(targetPath, owner, kind = "tmp") {
|
|
3665
|
+
if (kind === "bak") return `${targetPath}.bak.${owner.pid}.${owner.token}`;
|
|
3666
|
+
temporaryCounter += 1;
|
|
3667
|
+
return `${targetPath}.tmp.${owner.pid}.${owner.token}.${temporaryCounter}`;
|
|
3668
|
+
}
|
|
3669
|
+
function removeLeaseTemporaryPath(temporaryPath) {
|
|
3670
|
+
if ((0, import_fs5.existsSync)(temporaryPath)) (0, import_fs5.rmSync)(temporaryPath, { recursive: true, force: true });
|
|
3671
|
+
}
|
|
3672
|
+
function recoverLeaseArtifacts(indexPath, owner, backupTargets) {
|
|
3673
|
+
for (const targetPath of backupTargets) {
|
|
3674
|
+
const backupPath = createLeaseTemporaryPath(targetPath, owner, "bak");
|
|
3675
|
+
if (!(0, import_fs5.existsSync)(backupPath)) continue;
|
|
3676
|
+
if ((0, import_fs5.existsSync)(targetPath)) (0, import_fs5.rmSync)(targetPath, { recursive: true, force: true });
|
|
3677
|
+
(0, import_fs5.renameSync)(backupPath, targetPath);
|
|
3678
|
+
}
|
|
3679
|
+
const temporaryOwnerMarker = `.tmp.${owner.pid}.${owner.token}.`;
|
|
3680
|
+
for (const entry of (0, import_fs5.readdirSync)(indexPath)) {
|
|
3681
|
+
if (!entry.includes(temporaryOwnerMarker)) continue;
|
|
3682
|
+
(0, import_fs5.rmSync)(path9.join(indexPath, entry), { recursive: true, force: true });
|
|
3683
|
+
}
|
|
3684
|
+
}
|
|
3685
|
+
function completeLeaseRecovery(lease) {
|
|
3686
|
+
for (const recovery of lease.recoveries) {
|
|
3687
|
+
const markerOwner = readRecoveryOwner(recovery.markerPath);
|
|
3688
|
+
if (!markerOwner || !sameOwner(markerOwner, recovery.owner)) {
|
|
3689
|
+
throw new Error(`Recovery marker ownership changed: ${recovery.markerPath}`);
|
|
3690
|
+
}
|
|
3691
|
+
}
|
|
3692
|
+
for (const recovery of lease.recoveries) {
|
|
3693
|
+
(0, import_fs5.rmSync)(recovery.markerPath, { recursive: true, force: true });
|
|
3694
|
+
}
|
|
3695
|
+
}
|
|
3696
|
+
|
|
3697
|
+
// src/utils/background-worker.ts
|
|
3698
|
+
var import_node_crypto = require("crypto");
|
|
3699
|
+
var import_node_fs = require("fs");
|
|
3700
|
+
var os3 = __toESM(require("os"), 1);
|
|
3701
|
+
var path10 = __toESM(require("path"), 1);
|
|
3702
|
+
var OWNER_FILE_NAME2 = "owner.json";
|
|
3703
|
+
var HEARTBEAT_FILE_PREFIX = "heartbeat.";
|
|
3704
|
+
var RECLAIM_DIRECTORY_NAME2 = "reclaim";
|
|
3705
|
+
var REFRESH_REQUEST_FILE_NAME = "refresh-request.json";
|
|
3706
|
+
var HEARTBEAT_INTERVAL_MS = 5e3;
|
|
3707
|
+
var STALE_LEASE_MS = 3e4;
|
|
3708
|
+
var RETRY_DELAY_MS = 5e3;
|
|
3709
|
+
var UUID_PATTERN2 = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
3710
|
+
var BackgroundWorkerStopError = class extends Error {
|
|
3711
|
+
constructor(watcherError, autoIndexError) {
|
|
3712
|
+
super("Failed to stop background worker");
|
|
3713
|
+
this.watcherError = watcherError;
|
|
3714
|
+
this.autoIndexError = autoIndexError;
|
|
3715
|
+
this.name = "BackgroundWorkerStopError";
|
|
3716
|
+
}
|
|
3717
|
+
watcherError;
|
|
3718
|
+
autoIndexError;
|
|
3719
|
+
};
|
|
3720
|
+
var workers = /* @__PURE__ */ new Map();
|
|
3721
|
+
var workerKeysByProject = /* @__PURE__ */ new Map();
|
|
3722
|
+
var workerReplacementBarriers = /* @__PURE__ */ new Map();
|
|
3723
|
+
function getErrorCode2(error) {
|
|
3724
|
+
return typeof error === "object" && error !== null && "code" in error ? String(error.code) : void 0;
|
|
3725
|
+
}
|
|
3726
|
+
function canonicalizePath(targetPath) {
|
|
3727
|
+
const resolved = path10.resolve(targetPath);
|
|
3728
|
+
if ((0, import_node_fs.existsSync)(resolved)) {
|
|
3729
|
+
try {
|
|
3730
|
+
return import_node_fs.realpathSync.native(resolved);
|
|
3731
|
+
} catch {
|
|
3732
|
+
return resolved;
|
|
3733
|
+
}
|
|
3734
|
+
}
|
|
3735
|
+
const parent = path10.dirname(resolved);
|
|
3736
|
+
if (parent === resolved) return resolved;
|
|
3737
|
+
return path10.join(canonicalizePath(parent), path10.basename(resolved));
|
|
3738
|
+
}
|
|
3739
|
+
function projectLookupKey(projectRoot, host) {
|
|
3740
|
+
return `${host}::${canonicalizePath(projectRoot)}`;
|
|
3741
|
+
}
|
|
3742
|
+
function resolveIdentity(projectRoot, config, host) {
|
|
3743
|
+
const canonicalProjectRoot = canonicalizePath(projectRoot);
|
|
3744
|
+
const canonicalIndexPath = canonicalizePath(resolveProjectIndexPath(projectRoot, config.scope, host));
|
|
3745
|
+
return {
|
|
3746
|
+
canonicalIndexPath,
|
|
3747
|
+
canonicalProjectRoot,
|
|
3748
|
+
key: `${canonicalIndexPath}::${canonicalProjectRoot}`
|
|
3749
|
+
};
|
|
3750
|
+
}
|
|
3751
|
+
function controllerKey(identity, host) {
|
|
3752
|
+
return `${identity.key}::${host}`;
|
|
3753
|
+
}
|
|
3754
|
+
function leaseDirectoryName(identity) {
|
|
3755
|
+
const hash = (0, import_node_crypto.createHash)("sha256").update(identity.key).digest("hex").slice(0, 32);
|
|
3756
|
+
return `background-worker.${hash}.lease`;
|
|
3757
|
+
}
|
|
3758
|
+
function leasePathFor(identity) {
|
|
3759
|
+
return path10.join(identity.canonicalIndexPath, leaseDirectoryName(identity));
|
|
3760
|
+
}
|
|
3761
|
+
function parseOwner2(value) {
|
|
3762
|
+
if (typeof value !== "object" || value === null) return null;
|
|
3763
|
+
const candidate = value;
|
|
3764
|
+
if (candidate.version !== 1) return null;
|
|
3765
|
+
if (!Number.isInteger(candidate.pid) || (candidate.pid ?? 0) <= 0) return null;
|
|
3766
|
+
if (typeof candidate.hostname !== "string" || candidate.hostname.length === 0) return null;
|
|
3767
|
+
if (typeof candidate.startedAt !== "string" || Number.isNaN(Date.parse(candidate.startedAt))) return null;
|
|
3768
|
+
if (typeof candidate.heartbeatAt !== "string" || Number.isNaN(Date.parse(candidate.heartbeatAt))) return null;
|
|
3769
|
+
if (typeof candidate.projectRoot !== "string" || candidate.projectRoot.length === 0) return null;
|
|
3770
|
+
if (typeof candidate.indexPath !== "string" || candidate.indexPath.length === 0) return null;
|
|
3771
|
+
if (typeof candidate.token !== "string" || !UUID_PATTERN2.test(candidate.token)) return null;
|
|
3772
|
+
return candidate;
|
|
3773
|
+
}
|
|
3774
|
+
function parseHeartbeat(value, expectedToken) {
|
|
3775
|
+
if (typeof value !== "object" || value === null) return null;
|
|
3776
|
+
const candidate = value;
|
|
3777
|
+
if (candidate.version !== 1 || candidate.token !== expectedToken) return null;
|
|
3778
|
+
if (typeof candidate.heartbeatAt !== "string" || Number.isNaN(Date.parse(candidate.heartbeatAt))) return null;
|
|
3779
|
+
return candidate;
|
|
3780
|
+
}
|
|
3781
|
+
function parseReclaimOwner2(value) {
|
|
3782
|
+
if (typeof value !== "object" || value === null) return null;
|
|
3783
|
+
const candidate = value;
|
|
3784
|
+
if (candidate.version !== 1) return null;
|
|
3785
|
+
if (!Number.isInteger(candidate.pid) || (candidate.pid ?? 0) <= 0) return null;
|
|
3786
|
+
if (typeof candidate.hostname !== "string" || candidate.hostname.length === 0) return null;
|
|
3787
|
+
if (typeof candidate.startedAt !== "string" || Number.isNaN(Date.parse(candidate.startedAt))) return null;
|
|
3788
|
+
if (typeof candidate.token !== "string" || !UUID_PATTERN2.test(candidate.token)) return null;
|
|
3789
|
+
if (candidate.expectedOwnerToken !== null && (typeof candidate.expectedOwnerToken !== "string" || !UUID_PATTERN2.test(candidate.expectedOwnerToken))) return null;
|
|
3790
|
+
return candidate;
|
|
3791
|
+
}
|
|
3792
|
+
function heartbeatPath(leasePath, token) {
|
|
3793
|
+
return path10.join(leasePath, `${HEARTBEAT_FILE_PREFIX}${token}.json`);
|
|
3794
|
+
}
|
|
3795
|
+
function reclaimPath(leasePath) {
|
|
3796
|
+
return path10.join(leasePath, RECLAIM_DIRECTORY_NAME2);
|
|
3797
|
+
}
|
|
3798
|
+
function refreshRequestPath(leasePath) {
|
|
3799
|
+
return path10.join(leasePath, REFRESH_REQUEST_FILE_NAME);
|
|
3800
|
+
}
|
|
3801
|
+
function readLeaseOwner(leasePath) {
|
|
3802
|
+
try {
|
|
3803
|
+
return parseOwner2(JSON.parse((0, import_node_fs.readFileSync)(path10.join(leasePath, OWNER_FILE_NAME2), "utf-8")));
|
|
3804
|
+
} catch {
|
|
3805
|
+
return null;
|
|
3806
|
+
}
|
|
3807
|
+
}
|
|
3808
|
+
function readOwner(leasePath) {
|
|
3809
|
+
const owner = readLeaseOwner(leasePath);
|
|
3810
|
+
if (!owner) return null;
|
|
3811
|
+
try {
|
|
3812
|
+
const heartbeat = parseHeartbeat(
|
|
3813
|
+
JSON.parse((0, import_node_fs.readFileSync)(heartbeatPath(leasePath, owner.token), "utf-8")),
|
|
3814
|
+
owner.token
|
|
3815
|
+
);
|
|
3816
|
+
return heartbeat ? { ...owner, heartbeatAt: heartbeat.heartbeatAt } : owner;
|
|
3817
|
+
} catch {
|
|
3818
|
+
return owner;
|
|
3819
|
+
}
|
|
3820
|
+
}
|
|
3821
|
+
function readReclaimOwner2(leasePath) {
|
|
3822
|
+
try {
|
|
3823
|
+
return parseReclaimOwner2(JSON.parse((0, import_node_fs.readFileSync)(path10.join(reclaimPath(leasePath), OWNER_FILE_NAME2), "utf-8")));
|
|
3824
|
+
} catch {
|
|
3825
|
+
return null;
|
|
3826
|
+
}
|
|
3827
|
+
}
|
|
3828
|
+
function ownerLiveness(owner) {
|
|
3829
|
+
if (owner.hostname !== os3.hostname()) return "unknown";
|
|
3830
|
+
try {
|
|
3831
|
+
process.kill(owner.pid, 0);
|
|
3832
|
+
return "alive";
|
|
3833
|
+
} catch (error) {
|
|
3834
|
+
const code = getErrorCode2(error);
|
|
3835
|
+
if (code === "ESRCH") return "dead";
|
|
3836
|
+
if (code === "EPERM") return "alive";
|
|
3837
|
+
return "unknown";
|
|
3838
|
+
}
|
|
3839
|
+
}
|
|
3840
|
+
function isHeartbeatExpired(owner) {
|
|
3841
|
+
return Date.now() - Date.parse(owner.heartbeatAt) >= STALE_LEASE_MS;
|
|
3842
|
+
}
|
|
3843
|
+
function sameOwner2(left, right) {
|
|
3844
|
+
return left.pid === right.pid && left.hostname === right.hostname && left.token === right.token;
|
|
3845
|
+
}
|
|
3846
|
+
function writeHeartbeat(leasePath, owner) {
|
|
3847
|
+
const targetPath = heartbeatPath(leasePath, owner.token);
|
|
3848
|
+
const temporaryPath = `${targetPath}.tmp.${process.pid}.${owner.token}.${(0, import_node_crypto.randomUUID)()}`;
|
|
3849
|
+
const heartbeat = {
|
|
3850
|
+
version: 1,
|
|
3851
|
+
token: owner.token,
|
|
3852
|
+
heartbeatAt: owner.heartbeatAt
|
|
3853
|
+
};
|
|
3854
|
+
try {
|
|
3855
|
+
(0, import_node_fs.writeFileSync)(temporaryPath, JSON.stringify(heartbeat), {
|
|
3856
|
+
encoding: "utf-8",
|
|
3857
|
+
flag: "wx",
|
|
3858
|
+
mode: 384
|
|
3859
|
+
});
|
|
3860
|
+
(0, import_node_fs.renameSync)(temporaryPath, targetPath);
|
|
3861
|
+
const currentOwner = readLeaseOwner(leasePath);
|
|
3862
|
+
return currentOwner !== null && sameOwner2(currentOwner, owner);
|
|
3863
|
+
} finally {
|
|
3864
|
+
if ((0, import_node_fs.existsSync)(temporaryPath)) (0, import_node_fs.rmSync)(temporaryPath, { force: true });
|
|
3865
|
+
}
|
|
3866
|
+
}
|
|
3867
|
+
function requestRefreshFromLeader(leasePath, allowDisabledAutoIndex) {
|
|
3868
|
+
const requestPath = refreshRequestPath(leasePath);
|
|
3869
|
+
const temporaryPath = `${requestPath}.tmp.${process.pid}.${(0, import_node_crypto.randomUUID)()}`;
|
|
3870
|
+
try {
|
|
3871
|
+
const request = {
|
|
3872
|
+
allowDisabledAutoIndex,
|
|
3873
|
+
requestedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3874
|
+
version: 1
|
|
3875
|
+
};
|
|
3876
|
+
(0, import_node_fs.writeFileSync)(temporaryPath, JSON.stringify(request), {
|
|
3877
|
+
encoding: "utf-8",
|
|
3878
|
+
flag: "wx",
|
|
3879
|
+
mode: 384
|
|
3880
|
+
});
|
|
3881
|
+
(0, import_node_fs.renameSync)(temporaryPath, requestPath);
|
|
3882
|
+
} catch (error) {
|
|
3883
|
+
if (getErrorCode2(error) !== "ENOENT") {
|
|
3884
|
+
console.error("[codebase-index] Failed to request background index refresh from the project worker:", error);
|
|
3885
|
+
}
|
|
3886
|
+
} finally {
|
|
3887
|
+
if ((0, import_node_fs.existsSync)(temporaryPath)) (0, import_node_fs.rmSync)(temporaryPath, { force: true });
|
|
3888
|
+
}
|
|
3889
|
+
}
|
|
3890
|
+
function consumeRefreshRequest(leasePath) {
|
|
3891
|
+
const requestPath = refreshRequestPath(leasePath);
|
|
3892
|
+
const claimedPath = `${requestPath}.handling.${process.pid}.${(0, import_node_crypto.randomUUID)()}`;
|
|
3893
|
+
try {
|
|
3894
|
+
(0, import_node_fs.renameSync)(requestPath, claimedPath);
|
|
3895
|
+
} catch (error) {
|
|
3896
|
+
if (getErrorCode2(error) === "ENOENT") return null;
|
|
3897
|
+
throw error;
|
|
3898
|
+
}
|
|
3899
|
+
try {
|
|
3900
|
+
const value = JSON.parse((0, import_node_fs.readFileSync)(claimedPath, "utf-8"));
|
|
3901
|
+
return {
|
|
3902
|
+
allowDisabledAutoIndex: value.version === 1 && value.allowDisabledAutoIndex === true,
|
|
3903
|
+
requestedAt: typeof value.requestedAt === "string" ? value.requestedAt : (/* @__PURE__ */ new Date()).toISOString(),
|
|
3904
|
+
version: 1
|
|
3905
|
+
};
|
|
3906
|
+
} catch {
|
|
3907
|
+
return { allowDisabledAutoIndex: false, requestedAt: (/* @__PURE__ */ new Date()).toISOString(), version: 1 };
|
|
3908
|
+
} finally {
|
|
3909
|
+
(0, import_node_fs.rmSync)(claimedPath, { force: true });
|
|
3910
|
+
}
|
|
3911
|
+
}
|
|
3912
|
+
function publishLease(leasePath, owner) {
|
|
3913
|
+
const candidatePath = `${leasePath}.candidate.${process.pid}.${owner.token}`;
|
|
3914
|
+
try {
|
|
3915
|
+
(0, import_node_fs.mkdirSync)(candidatePath, { mode: 448 });
|
|
3916
|
+
} catch (error) {
|
|
3917
|
+
if (getErrorCode2(error) === "ENOENT") return false;
|
|
3918
|
+
throw error;
|
|
3919
|
+
}
|
|
3920
|
+
try {
|
|
3921
|
+
(0, import_node_fs.writeFileSync)(path10.join(candidatePath, OWNER_FILE_NAME2), JSON.stringify(owner), {
|
|
3922
|
+
encoding: "utf-8",
|
|
3923
|
+
flag: "wx",
|
|
3924
|
+
mode: 384
|
|
3925
|
+
});
|
|
3926
|
+
if ((0, import_node_fs.existsSync)(leasePath)) return false;
|
|
3927
|
+
try {
|
|
3928
|
+
(0, import_node_fs.renameSync)(candidatePath, leasePath);
|
|
3929
|
+
return true;
|
|
3930
|
+
} catch (error) {
|
|
3931
|
+
if ((0, import_node_fs.existsSync)(leasePath) || getErrorCode2(error) === "ENOENT") return false;
|
|
3932
|
+
throw error;
|
|
3933
|
+
}
|
|
3934
|
+
} finally {
|
|
3935
|
+
if ((0, import_node_fs.existsSync)(candidatePath)) (0, import_node_fs.rmSync)(candidatePath, { recursive: true, force: true });
|
|
3936
|
+
}
|
|
3937
|
+
}
|
|
3938
|
+
function sameReclaimOwner2(left, right) {
|
|
3939
|
+
return left.pid === right.pid && left.hostname === right.hostname && left.token === right.token && left.expectedOwnerToken === right.expectedOwnerToken;
|
|
3940
|
+
}
|
|
3941
|
+
function reclaimerLiveness(owner) {
|
|
3942
|
+
return ownerLiveness(owner);
|
|
3943
|
+
}
|
|
3944
|
+
function isReclaimMarkerExpired(leasePath, owner) {
|
|
3945
|
+
const startedAt = owner ? Date.parse(owner.startedAt) : (() => {
|
|
3946
|
+
try {
|
|
3947
|
+
return (0, import_node_fs.lstatSync)(reclaimPath(leasePath)).mtimeMs;
|
|
3948
|
+
} catch {
|
|
3949
|
+
return Date.now();
|
|
3950
|
+
}
|
|
3951
|
+
})();
|
|
3952
|
+
return Date.now() - startedAt >= STALE_LEASE_MS;
|
|
3953
|
+
}
|
|
3954
|
+
function hasActiveReclaimMarker(leasePath, owner) {
|
|
3955
|
+
const marker = readReclaimOwner2(leasePath);
|
|
3956
|
+
return marker !== null && marker.expectedOwnerToken === owner.token && (marker.hostname !== os3.hostname() || ownerLiveness(owner) !== "alive");
|
|
3957
|
+
}
|
|
3958
|
+
function publishReclaimMarker(leasePath, expectedOwner) {
|
|
3959
|
+
const markerPath = reclaimPath(leasePath);
|
|
3960
|
+
const owner = {
|
|
3961
|
+
version: 1,
|
|
3962
|
+
pid: process.pid,
|
|
3963
|
+
hostname: os3.hostname(),
|
|
3964
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3965
|
+
token: (0, import_node_crypto.randomUUID)(),
|
|
3966
|
+
expectedOwnerToken: expectedOwner?.token ?? null
|
|
3967
|
+
};
|
|
3968
|
+
try {
|
|
3969
|
+
(0, import_node_fs.mkdirSync)(markerPath, { mode: 448 });
|
|
3970
|
+
} catch (error) {
|
|
3971
|
+
if (getErrorCode2(error) === "EEXIST" || getErrorCode2(error) === "ENOENT") return null;
|
|
3972
|
+
throw error;
|
|
3973
|
+
}
|
|
3974
|
+
try {
|
|
3975
|
+
(0, import_node_fs.writeFileSync)(path10.join(markerPath, OWNER_FILE_NAME2), JSON.stringify(owner), {
|
|
3976
|
+
encoding: "utf-8",
|
|
3977
|
+
flag: "wx",
|
|
3978
|
+
mode: 384
|
|
3979
|
+
});
|
|
3980
|
+
return owner;
|
|
3981
|
+
} catch (error) {
|
|
3982
|
+
(0, import_node_fs.rmSync)(markerPath, { recursive: true, force: true });
|
|
3983
|
+
throw error;
|
|
3984
|
+
}
|
|
3985
|
+
}
|
|
3986
|
+
function removeExpiredReclaimMarker(leasePath, expectedOwner) {
|
|
3987
|
+
const marker = readReclaimOwner2(leasePath);
|
|
3988
|
+
const markerPath = reclaimPath(leasePath);
|
|
3989
|
+
if (!(0, import_node_fs.existsSync)(markerPath)) return false;
|
|
3990
|
+
if (marker && marker.expectedOwnerToken !== (expectedOwner?.token ?? null)) return false;
|
|
3991
|
+
if (marker && (reclaimerLiveness(marker) === "alive" || !isReclaimMarkerExpired(leasePath, marker))) return false;
|
|
3992
|
+
if (!marker && !isReclaimMarkerExpired(leasePath, null)) return false;
|
|
3993
|
+
const staleMarkerPath = `${markerPath}.stale.${marker?.pid ?? process.pid}.${marker?.token ?? (0, import_node_crypto.randomUUID)()}.${(0, import_node_crypto.randomUUID)()}`;
|
|
3994
|
+
try {
|
|
3995
|
+
(0, import_node_fs.renameSync)(markerPath, staleMarkerPath);
|
|
3996
|
+
} catch (error) {
|
|
3997
|
+
if (getErrorCode2(error) === "ENOENT") return false;
|
|
3998
|
+
throw error;
|
|
3999
|
+
}
|
|
4000
|
+
try {
|
|
4001
|
+
let claimedMarker = null;
|
|
4002
|
+
try {
|
|
4003
|
+
claimedMarker = parseReclaimOwner2(
|
|
4004
|
+
JSON.parse((0, import_node_fs.readFileSync)(path10.join(staleMarkerPath, OWNER_FILE_NAME2), "utf-8"))
|
|
4005
|
+
);
|
|
4006
|
+
} catch {
|
|
4007
|
+
claimedMarker = null;
|
|
4008
|
+
}
|
|
4009
|
+
const markerMatches = marker ? claimedMarker !== null && sameReclaimOwner2(claimedMarker, marker) : claimedMarker === null;
|
|
4010
|
+
if (!markerMatches || !canReclaimLease(leasePath, expectedOwner)) {
|
|
4011
|
+
if (!(0, import_node_fs.existsSync)(markerPath) && (0, import_node_fs.existsSync)(staleMarkerPath)) (0, import_node_fs.renameSync)(staleMarkerPath, markerPath);
|
|
4012
|
+
return false;
|
|
4013
|
+
}
|
|
4014
|
+
(0, import_node_fs.rmSync)(staleMarkerPath, { recursive: true, force: true });
|
|
4015
|
+
return true;
|
|
4016
|
+
} catch (error) {
|
|
4017
|
+
if (getErrorCode2(error) === "ENOENT") return false;
|
|
4018
|
+
throw error;
|
|
4019
|
+
}
|
|
4020
|
+
}
|
|
4021
|
+
function canReclaimLease(leasePath, expectedOwner) {
|
|
4022
|
+
if (!(0, import_node_fs.existsSync)(leasePath)) return false;
|
|
4023
|
+
if (!expectedOwner) return false;
|
|
4024
|
+
const currentOwner = readOwner(leasePath);
|
|
4025
|
+
if (!currentOwner || !sameOwner2(currentOwner, expectedOwner)) return false;
|
|
4026
|
+
if (currentOwner.hostname === os3.hostname()) {
|
|
4027
|
+
return ownerLiveness(currentOwner) === "dead";
|
|
4028
|
+
}
|
|
4029
|
+
return isHeartbeatExpired(currentOwner);
|
|
4030
|
+
}
|
|
4031
|
+
function reclaimLease(leasePath, expectedOwner) {
|
|
4032
|
+
let marker = null;
|
|
4033
|
+
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
4034
|
+
marker = publishReclaimMarker(leasePath, expectedOwner);
|
|
4035
|
+
if (marker) break;
|
|
4036
|
+
if (attempt === 0 && removeExpiredReclaimMarker(leasePath, expectedOwner)) continue;
|
|
4037
|
+
return false;
|
|
4038
|
+
}
|
|
4039
|
+
if (!marker) return false;
|
|
4040
|
+
const markerPath = reclaimPath(leasePath);
|
|
4041
|
+
try {
|
|
4042
|
+
const currentMarker = readReclaimOwner2(leasePath);
|
|
4043
|
+
if (!currentMarker || !sameReclaimOwner2(currentMarker, marker) || !canReclaimLease(leasePath, expectedOwner)) {
|
|
4044
|
+
return false;
|
|
4045
|
+
}
|
|
4046
|
+
const stalePath = `${leasePath}.stale.${process.pid}.${marker.token}`;
|
|
4047
|
+
(0, import_node_fs.renameSync)(leasePath, stalePath);
|
|
4048
|
+
const quarantinedOwner = readOwner(stalePath);
|
|
4049
|
+
const quarantinedMarker = readReclaimOwner2(stalePath);
|
|
4050
|
+
if (!quarantinedMarker || !sameReclaimOwner2(quarantinedMarker, marker) || expectedOwner !== null && (!quarantinedOwner || !sameOwner2(quarantinedOwner, expectedOwner))) {
|
|
4051
|
+
if (!(0, import_node_fs.existsSync)(leasePath) && (0, import_node_fs.existsSync)(stalePath)) (0, import_node_fs.renameSync)(stalePath, leasePath);
|
|
4052
|
+
return false;
|
|
4053
|
+
}
|
|
4054
|
+
(0, import_node_fs.rmSync)(stalePath, { recursive: true, force: true });
|
|
4055
|
+
return true;
|
|
4056
|
+
} catch (error) {
|
|
4057
|
+
if (getErrorCode2(error) === "ENOENT") return false;
|
|
4058
|
+
throw error;
|
|
4059
|
+
} finally {
|
|
4060
|
+
const currentMarker = readReclaimOwner2(leasePath);
|
|
4061
|
+
if (currentMarker && sameReclaimOwner2(currentMarker, marker)) {
|
|
4062
|
+
(0, import_node_fs.rmSync)(markerPath, { recursive: true, force: true });
|
|
4063
|
+
}
|
|
4064
|
+
}
|
|
4065
|
+
}
|
|
4066
|
+
function acquireLease(identity) {
|
|
4067
|
+
(0, import_node_fs.mkdirSync)(identity.canonicalIndexPath, { recursive: true, mode: 448 });
|
|
4068
|
+
const canonicalIndexPath = import_node_fs.realpathSync.native(identity.canonicalIndexPath);
|
|
4069
|
+
const leasePath = path10.join(canonicalIndexPath, leaseDirectoryName({ ...identity, canonicalIndexPath }));
|
|
4070
|
+
for (let attempt = 0; attempt < 4; attempt += 1) {
|
|
4071
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
4072
|
+
const owner = {
|
|
4073
|
+
version: 1,
|
|
4074
|
+
pid: process.pid,
|
|
4075
|
+
hostname: os3.hostname(),
|
|
4076
|
+
startedAt: timestamp,
|
|
4077
|
+
heartbeatAt: timestamp,
|
|
4078
|
+
projectRoot: identity.canonicalProjectRoot,
|
|
4079
|
+
indexPath: canonicalIndexPath,
|
|
4080
|
+
token: (0, import_node_crypto.randomUUID)()
|
|
4081
|
+
};
|
|
4082
|
+
if (publishLease(leasePath, owner)) {
|
|
4083
|
+
return { leasePath, owner };
|
|
4084
|
+
}
|
|
4085
|
+
const existingOwner = readOwner(leasePath);
|
|
4086
|
+
if (existingOwner) {
|
|
4087
|
+
if (canReclaimLease(leasePath, existingOwner) && reclaimLease(leasePath, existingOwner)) continue;
|
|
4088
|
+
return null;
|
|
4089
|
+
}
|
|
4090
|
+
return null;
|
|
4091
|
+
}
|
|
4092
|
+
return null;
|
|
4093
|
+
}
|
|
4094
|
+
function releaseLease(lease) {
|
|
4095
|
+
const currentOwner = readOwner(lease.leasePath);
|
|
4096
|
+
if (!currentOwner || !sameOwner2(currentOwner, lease.owner)) return false;
|
|
4097
|
+
const releasePath = `${lease.leasePath}.release.${lease.owner.pid}.${lease.owner.token}`;
|
|
4098
|
+
try {
|
|
4099
|
+
(0, import_node_fs.renameSync)(lease.leasePath, releasePath);
|
|
4100
|
+
} catch (error) {
|
|
4101
|
+
if (getErrorCode2(error) === "ENOENT") return false;
|
|
4102
|
+
throw error;
|
|
4103
|
+
}
|
|
4104
|
+
const claimedOwner = readOwner(releasePath);
|
|
4105
|
+
if (!claimedOwner || !sameOwner2(claimedOwner, lease.owner)) {
|
|
4106
|
+
if (!(0, import_node_fs.existsSync)(lease.leasePath) && (0, import_node_fs.existsSync)(releasePath)) {
|
|
4107
|
+
(0, import_node_fs.renameSync)(releasePath, lease.leasePath);
|
|
4108
|
+
}
|
|
4109
|
+
return false;
|
|
4110
|
+
}
|
|
4111
|
+
(0, import_node_fs.rmSync)(releasePath, { recursive: true, force: true });
|
|
4112
|
+
return true;
|
|
4113
|
+
}
|
|
4114
|
+
var BackgroundWorkerController = class {
|
|
4115
|
+
constructor(projectRoot, host, config, hooks, identity) {
|
|
4116
|
+
this.projectRoot = projectRoot;
|
|
4117
|
+
this.host = host;
|
|
4118
|
+
this.config = config;
|
|
4119
|
+
this.hooks = hooks;
|
|
4120
|
+
this.identity = identity;
|
|
4121
|
+
}
|
|
4122
|
+
projectRoot;
|
|
4123
|
+
host;
|
|
4124
|
+
config;
|
|
4125
|
+
hooks;
|
|
4126
|
+
identity;
|
|
4127
|
+
lease = null;
|
|
4128
|
+
watcher = null;
|
|
4129
|
+
leaderReady = Promise.resolve();
|
|
4130
|
+
heartbeatTimer = null;
|
|
4131
|
+
retryTimer = null;
|
|
4132
|
+
teardownRetryTimer = null;
|
|
4133
|
+
transition = Promise.resolve();
|
|
4134
|
+
stopPromise = null;
|
|
4135
|
+
stopped = false;
|
|
4136
|
+
stopping = false;
|
|
4137
|
+
losingLeadership = false;
|
|
4138
|
+
restartAfterStop = false;
|
|
4139
|
+
leaderWorkStopped = false;
|
|
4140
|
+
startingLeaderWork = false;
|
|
4141
|
+
stopAutoIndexOnTeardown = true;
|
|
4142
|
+
autoIndexStarted = false;
|
|
4143
|
+
reportedError = null;
|
|
4144
|
+
update(config, hooks, options) {
|
|
4145
|
+
const autoIndexWasEnabled = this.config.indexing.autoIndex;
|
|
4146
|
+
const shouldReplaceWatcher = this.watcher !== null && hooks.watcherFactory !== void 0 && (hooks.watcherFactory === null || hooks.replaceWatcher === true);
|
|
4147
|
+
this.config = config;
|
|
4148
|
+
this.hooks = {
|
|
4149
|
+
...this.hooks,
|
|
4150
|
+
...hooks,
|
|
4151
|
+
watcherFactory: hooks.watcherFactory === void 0 ? this.hooks.watcherFactory : hooks.watcherFactory,
|
|
4152
|
+
watcherFactoryForConfig: hooks.watcherFactoryForConfig === void 0 ? this.hooks.watcherFactoryForConfig : hooks.watcherFactoryForConfig
|
|
4153
|
+
};
|
|
4154
|
+
if (autoIndexWasEnabled && !config.indexing.autoIndex || options.restartAutoIndex === true && config.indexing.autoIndex && !this.startingLeaderWork) {
|
|
4155
|
+
this.autoIndexStarted = false;
|
|
4156
|
+
}
|
|
4157
|
+
if (!this.canRun()) {
|
|
4158
|
+
void this.stop().catch((error) => {
|
|
4159
|
+
console.error("[codebase-index] Failed to stop background worker after disabling automatic work:", error);
|
|
4160
|
+
});
|
|
4161
|
+
return;
|
|
4162
|
+
}
|
|
4163
|
+
if (shouldReplaceWatcher) {
|
|
4164
|
+
void this.enqueue(async () => {
|
|
4165
|
+
const watcher = this.watcher;
|
|
4166
|
+
if (watcher) {
|
|
4167
|
+
await watcher.stop();
|
|
4168
|
+
if (this.watcher === watcher) this.watcher = null;
|
|
4169
|
+
}
|
|
4170
|
+
if (this.lease && !this.stopped) this.startLeaderWork();
|
|
4171
|
+
}).catch((error) => {
|
|
4172
|
+
console.error("[codebase-index] Failed to replace background file watcher:", error);
|
|
4173
|
+
});
|
|
4174
|
+
}
|
|
4175
|
+
this.start();
|
|
4176
|
+
}
|
|
4177
|
+
startAfter(activation) {
|
|
4178
|
+
this.transition = activation.catch(() => void 0);
|
|
4179
|
+
this.start();
|
|
4180
|
+
}
|
|
4181
|
+
start() {
|
|
4182
|
+
if (!this.canRun() || this.losingLeadership) return;
|
|
4183
|
+
if (this.stopping) {
|
|
4184
|
+
this.restartAfterStop = true;
|
|
4185
|
+
return;
|
|
4186
|
+
}
|
|
4187
|
+
this.stopped = false;
|
|
4188
|
+
void this.enqueue(async () => {
|
|
4189
|
+
if (this.stopped || this.stopping || this.losingLeadership || !this.canRun()) return;
|
|
4190
|
+
if (!this.lease) {
|
|
4191
|
+
try {
|
|
4192
|
+
this.lease = acquireLease(this.identity);
|
|
4193
|
+
this.reportedError = null;
|
|
4194
|
+
} catch (error) {
|
|
4195
|
+
this.reportAcquireError(error);
|
|
4196
|
+
this.scheduleRetry();
|
|
4197
|
+
return;
|
|
4198
|
+
}
|
|
4199
|
+
}
|
|
4200
|
+
if (!this.lease) {
|
|
4201
|
+
this.scheduleRetry();
|
|
4202
|
+
return;
|
|
4203
|
+
}
|
|
4204
|
+
this.startHeartbeat();
|
|
4205
|
+
this.startLeaderWork();
|
|
4206
|
+
});
|
|
4207
|
+
}
|
|
4208
|
+
waitForStart() {
|
|
4209
|
+
return this.transition.catch(() => void 0).then(() => this.leaderReady);
|
|
4210
|
+
}
|
|
4211
|
+
requestRefresh(allowDisabledAutoIndex = false) {
|
|
4212
|
+
this.start();
|
|
4213
|
+
if (!this.isLeader()) {
|
|
4214
|
+
requestRefreshFromLeader(leasePathFor(this.identity), allowDisabledAutoIndex);
|
|
4215
|
+
return;
|
|
4216
|
+
}
|
|
4217
|
+
void this.enqueue(async () => {
|
|
4218
|
+
if (this.stopped || !this.lease) return;
|
|
4219
|
+
this.hooks.startAutoIndex("retrieval", allowDisabledAutoIndex);
|
|
4220
|
+
});
|
|
4221
|
+
}
|
|
4222
|
+
isLeader() {
|
|
4223
|
+
return this.lease !== null && !this.stopping && !this.losingLeadership;
|
|
4224
|
+
}
|
|
4225
|
+
isStopping() {
|
|
4226
|
+
return this.stopping;
|
|
4227
|
+
}
|
|
4228
|
+
getHooksForConfig(config) {
|
|
4229
|
+
const watcherFactoryForConfig = this.hooks.watcherFactoryForConfig;
|
|
4230
|
+
if (!watcherFactoryForConfig) return this.hooks;
|
|
4231
|
+
return {
|
|
4232
|
+
...this.hooks,
|
|
4233
|
+
watcherFactory: watcherFactoryForConfig(config),
|
|
4234
|
+
replaceWatcher: true
|
|
4235
|
+
};
|
|
4236
|
+
}
|
|
4237
|
+
attachWatcher(watcherFactory, watcherFactoryForConfig) {
|
|
4238
|
+
if (this.hooks.watcherFactory !== void 0) return;
|
|
4239
|
+
this.hooks = {
|
|
4240
|
+
...this.hooks,
|
|
4241
|
+
watcherFactory,
|
|
4242
|
+
watcherFactoryForConfig: watcherFactoryForConfig ?? this.hooks.watcherFactoryForConfig
|
|
4243
|
+
};
|
|
4244
|
+
this.start();
|
|
4245
|
+
}
|
|
4246
|
+
async stop(stopAutoIndex = true) {
|
|
4247
|
+
if (this.stopPromise) return this.stopPromise;
|
|
4248
|
+
this.stopped = true;
|
|
4249
|
+
this.stopping = true;
|
|
4250
|
+
this.stopAutoIndexOnTeardown &&= stopAutoIndex;
|
|
4251
|
+
this.clearRetryTimer();
|
|
4252
|
+
const attempt = this.enqueue(async () => {
|
|
4253
|
+
try {
|
|
4254
|
+
const lease = this.lease;
|
|
4255
|
+
if (this.leaderWorkStopped) {
|
|
4256
|
+
if (lease) {
|
|
4257
|
+
this.releaseStoppedLease(lease);
|
|
4258
|
+
} else {
|
|
4259
|
+
this.finishStoppedLease();
|
|
4260
|
+
}
|
|
4261
|
+
return;
|
|
4262
|
+
}
|
|
4263
|
+
const hadLeaderWork = lease !== null || this.watcher !== null || this.autoIndexStarted;
|
|
4264
|
+
const stopped = await this.stopLeaderWork(hadLeaderWork && this.stopAutoIndexOnTeardown);
|
|
4265
|
+
if (!lease) {
|
|
4266
|
+
this.finishStoppedLease();
|
|
4267
|
+
return;
|
|
4268
|
+
}
|
|
4269
|
+
if (!stopped.completed) {
|
|
4270
|
+
this.releaseLeaseWhenAutoIndexStops(lease, stopped.completion);
|
|
4271
|
+
return;
|
|
4272
|
+
}
|
|
4273
|
+
this.leaderWorkStopped = true;
|
|
4274
|
+
this.releaseStoppedLease(lease);
|
|
4275
|
+
} catch (error) {
|
|
4276
|
+
this.scheduleTeardownRetry();
|
|
4277
|
+
throw error;
|
|
4278
|
+
}
|
|
4279
|
+
});
|
|
4280
|
+
const completion = attempt.finally(() => {
|
|
4281
|
+
if (this.stopPromise === completion) this.stopPromise = null;
|
|
4282
|
+
});
|
|
4283
|
+
this.stopPromise = completion;
|
|
4284
|
+
return completion;
|
|
4285
|
+
}
|
|
4286
|
+
canRun() {
|
|
4287
|
+
return this.config.indexing.autoIndex || this.hooks.watcherFactory != null;
|
|
4288
|
+
}
|
|
4289
|
+
enqueue(operation) {
|
|
4290
|
+
const next = this.transition.catch(() => void 0).then(operation);
|
|
4291
|
+
this.transition = next;
|
|
4292
|
+
return next;
|
|
4293
|
+
}
|
|
4294
|
+
startLeaderWork() {
|
|
4295
|
+
if (this.stopped || this.stopping || this.losingLeadership) return;
|
|
4296
|
+
this.startingLeaderWork = true;
|
|
4297
|
+
try {
|
|
4298
|
+
if (this.config.indexing.autoIndex && !this.autoIndexStarted) {
|
|
4299
|
+
this.autoIndexStarted = true;
|
|
4300
|
+
this.hooks.startAutoIndex("startup");
|
|
4301
|
+
}
|
|
4302
|
+
if (!this.watcher && this.hooks.watcherFactory) {
|
|
4303
|
+
try {
|
|
4304
|
+
const watcher = this.hooks.watcherFactory();
|
|
4305
|
+
this.watcher = watcher;
|
|
4306
|
+
this.leaderReady = watcher.whenReady?.().catch((error) => {
|
|
4307
|
+
console.error("[codebase-index] Failed while waiting for background file watcher startup:", error);
|
|
4308
|
+
}) ?? Promise.resolve();
|
|
4309
|
+
} catch (error) {
|
|
4310
|
+
console.error("[codebase-index] Failed to start background file watcher:", error);
|
|
4311
|
+
this.leaderReady = Promise.resolve();
|
|
4312
|
+
}
|
|
4313
|
+
}
|
|
4314
|
+
} finally {
|
|
4315
|
+
this.startingLeaderWork = false;
|
|
4316
|
+
}
|
|
4317
|
+
}
|
|
4318
|
+
async stopLeaderWork(stopAutoIndex) {
|
|
4319
|
+
const watcher = this.watcher;
|
|
4320
|
+
let watcherError;
|
|
4321
|
+
if (watcher) {
|
|
4322
|
+
try {
|
|
4323
|
+
await watcher.stop();
|
|
4324
|
+
if (this.watcher === watcher) this.watcher = null;
|
|
4325
|
+
} catch (error) {
|
|
4326
|
+
watcherError = error;
|
|
4327
|
+
}
|
|
4328
|
+
}
|
|
4329
|
+
let autoIndexError;
|
|
4330
|
+
let autoIndexStop = {
|
|
4331
|
+
completed: true,
|
|
4332
|
+
completion: Promise.resolve()
|
|
4333
|
+
};
|
|
4334
|
+
if (stopAutoIndex) {
|
|
4335
|
+
try {
|
|
4336
|
+
autoIndexStop = await this.hooks.stopAutoIndex();
|
|
4337
|
+
this.autoIndexStarted = false;
|
|
4338
|
+
} catch (error) {
|
|
4339
|
+
autoIndexError = error;
|
|
4340
|
+
}
|
|
4341
|
+
}
|
|
4342
|
+
if (watcherError !== void 0 || autoIndexError !== void 0) {
|
|
4343
|
+
throw new BackgroundWorkerStopError(watcherError, autoIndexError);
|
|
4344
|
+
}
|
|
4345
|
+
return autoIndexStop;
|
|
4346
|
+
}
|
|
4347
|
+
releaseLeaseWhenAutoIndexStops(lease, completion) {
|
|
4348
|
+
void completion.then(
|
|
4349
|
+
() => {
|
|
4350
|
+
void this.enqueue(async () => {
|
|
4351
|
+
if (this.lease !== lease || !this.stopping) return;
|
|
4352
|
+
this.leaderWorkStopped = true;
|
|
4353
|
+
this.releaseStoppedLease(lease);
|
|
4354
|
+
}).catch((error) => {
|
|
4355
|
+
console.error("[codebase-index] Failed to release background worker lease after automatic indexing stopped:", error);
|
|
4356
|
+
this.scheduleTeardownRetry();
|
|
4357
|
+
});
|
|
4358
|
+
},
|
|
4359
|
+
(error) => {
|
|
4360
|
+
console.error("[codebase-index] Failed while waiting for automatic indexing to stop:", error);
|
|
4361
|
+
this.scheduleTeardownRetry();
|
|
4362
|
+
}
|
|
4363
|
+
);
|
|
4364
|
+
}
|
|
4365
|
+
releaseStoppedLease(lease) {
|
|
4366
|
+
if (this.lease !== lease) {
|
|
4367
|
+
this.finishStoppedLease();
|
|
4368
|
+
return;
|
|
4369
|
+
}
|
|
4370
|
+
releaseLease(lease);
|
|
4371
|
+
this.lease = null;
|
|
4372
|
+
this.finishStoppedLease();
|
|
4373
|
+
}
|
|
4374
|
+
finishStoppedLease() {
|
|
4375
|
+
this.leaderWorkStopped = false;
|
|
4376
|
+
this.stopAutoIndexOnTeardown = true;
|
|
4377
|
+
this.stopping = false;
|
|
4378
|
+
this.clearTimers();
|
|
4379
|
+
this.restartAfterTeardown();
|
|
4380
|
+
if (!this.stopped || this.stopping) return;
|
|
4381
|
+
const projectKey = projectLookupKey(this.projectRoot, this.host);
|
|
4382
|
+
const key = controllerKey(this.identity, this.host);
|
|
4383
|
+
if (workers.get(key) === this) workers.delete(key);
|
|
4384
|
+
if (workerKeysByProject.get(projectKey) === key) workerKeysByProject.delete(projectKey);
|
|
4385
|
+
}
|
|
4386
|
+
startHeartbeat() {
|
|
4387
|
+
if (this.heartbeatTimer) return;
|
|
4388
|
+
const heartbeat = () => {
|
|
4389
|
+
void this.heartbeat();
|
|
4390
|
+
};
|
|
4391
|
+
this.heartbeatTimer = setInterval(heartbeat, HEARTBEAT_INTERVAL_MS);
|
|
4392
|
+
this.heartbeatTimer.unref?.();
|
|
4393
|
+
}
|
|
4394
|
+
async heartbeat() {
|
|
4395
|
+
const lease = this.lease;
|
|
4396
|
+
if (!lease || this.losingLeadership || this.stopped && !this.stopping) return;
|
|
4397
|
+
if (hasActiveReclaimMarker(lease.leasePath, lease.owner)) {
|
|
4398
|
+
await this.loseLeadership();
|
|
4399
|
+
return;
|
|
4400
|
+
}
|
|
4401
|
+
const currentOwner = readOwner(lease.leasePath);
|
|
4402
|
+
if (!currentOwner || !sameOwner2(currentOwner, lease.owner)) {
|
|
4403
|
+
await this.loseLeadership();
|
|
4404
|
+
return;
|
|
4405
|
+
}
|
|
4406
|
+
try {
|
|
4407
|
+
const nextOwner = { ...lease.owner, heartbeatAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
4408
|
+
if (!writeHeartbeat(lease.leasePath, nextOwner)) {
|
|
4409
|
+
await this.loseLeadership();
|
|
4410
|
+
return;
|
|
4411
|
+
}
|
|
4412
|
+
lease.owner = nextOwner;
|
|
4413
|
+
const refreshRequest = !this.stopping ? consumeRefreshRequest(lease.leasePath) : null;
|
|
4414
|
+
if (refreshRequest) {
|
|
4415
|
+
this.hooks.startAutoIndex("retrieval", refreshRequest.allowDisabledAutoIndex);
|
|
4416
|
+
}
|
|
4417
|
+
} catch (error) {
|
|
4418
|
+
const ownerAfterError = readOwner(lease.leasePath);
|
|
4419
|
+
if (hasActiveReclaimMarker(lease.leasePath, lease.owner) || !ownerAfterError || !sameOwner2(ownerAfterError, lease.owner)) {
|
|
4420
|
+
await this.loseLeadership();
|
|
4421
|
+
return;
|
|
4422
|
+
}
|
|
4423
|
+
console.error("[codebase-index] Failed to renew background worker lease:", error);
|
|
4424
|
+
}
|
|
4425
|
+
}
|
|
4426
|
+
async loseLeadership() {
|
|
4427
|
+
if (this.losingLeadership) return;
|
|
4428
|
+
this.losingLeadership = true;
|
|
4429
|
+
this.clearHeartbeat();
|
|
4430
|
+
await this.enqueue(async () => this.stopAfterLeadershipLoss());
|
|
3634
4431
|
}
|
|
3635
|
-
|
|
3636
|
-
|
|
3637
|
-
|
|
3638
|
-
|
|
3639
|
-
|
|
3640
|
-
|
|
4432
|
+
async stopAfterLeadershipLoss() {
|
|
4433
|
+
const lease = this.lease;
|
|
4434
|
+
if (!lease) {
|
|
4435
|
+
this.losingLeadership = false;
|
|
4436
|
+
return;
|
|
4437
|
+
}
|
|
4438
|
+
try {
|
|
4439
|
+
const stopped = await this.stopLeaderWork(true);
|
|
4440
|
+
this.lease = null;
|
|
4441
|
+
this.losingLeadership = false;
|
|
4442
|
+
if (stopped.completed) {
|
|
4443
|
+
this.scheduleRetry();
|
|
4444
|
+
} else {
|
|
4445
|
+
void stopped.completion.then(() => this.scheduleRetry());
|
|
4446
|
+
}
|
|
4447
|
+
} catch (error) {
|
|
4448
|
+
console.error("[codebase-index] Failed to stop background work after losing its lease:", error);
|
|
4449
|
+
this.scheduleLostLeadershipTeardownRetry();
|
|
4450
|
+
}
|
|
4451
|
+
}
|
|
4452
|
+
scheduleRetry() {
|
|
4453
|
+
if (this.stopped || !this.canRun() || this.retryTimer) return;
|
|
4454
|
+
this.retryTimer = setTimeout(() => {
|
|
4455
|
+
this.retryTimer = null;
|
|
4456
|
+
this.start();
|
|
4457
|
+
}, RETRY_DELAY_MS);
|
|
4458
|
+
this.retryTimer.unref?.();
|
|
4459
|
+
}
|
|
4460
|
+
scheduleTeardownRetry() {
|
|
4461
|
+
if (!this.stopping || this.teardownRetryTimer) return;
|
|
4462
|
+
this.teardownRetryTimer = setTimeout(() => {
|
|
4463
|
+
this.teardownRetryTimer = null;
|
|
4464
|
+
void this.stop(this.stopAutoIndexOnTeardown).catch((error) => {
|
|
4465
|
+
console.error("[codebase-index] Failed to retry background worker teardown:", error);
|
|
4466
|
+
});
|
|
4467
|
+
}, RETRY_DELAY_MS);
|
|
4468
|
+
this.teardownRetryTimer.unref?.();
|
|
4469
|
+
}
|
|
4470
|
+
restartAfterTeardown() {
|
|
4471
|
+
if (!this.restartAfterStop || !this.canRun() || this.losingLeadership) return;
|
|
4472
|
+
this.restartAfterStop = false;
|
|
4473
|
+
this.stopped = false;
|
|
4474
|
+
this.start();
|
|
4475
|
+
}
|
|
4476
|
+
scheduleLostLeadershipTeardownRetry() {
|
|
4477
|
+
if (this.stopped || !this.losingLeadership || this.retryTimer) return;
|
|
4478
|
+
this.retryTimer = setTimeout(() => {
|
|
4479
|
+
this.retryTimer = null;
|
|
4480
|
+
void this.enqueue(async () => this.stopAfterLeadershipLoss());
|
|
4481
|
+
}, RETRY_DELAY_MS);
|
|
4482
|
+
this.retryTimer.unref?.();
|
|
4483
|
+
}
|
|
4484
|
+
clearHeartbeat() {
|
|
4485
|
+
if (!this.heartbeatTimer) return;
|
|
4486
|
+
clearInterval(this.heartbeatTimer);
|
|
4487
|
+
this.heartbeatTimer = null;
|
|
4488
|
+
}
|
|
4489
|
+
clearTimers() {
|
|
4490
|
+
this.clearHeartbeat();
|
|
4491
|
+
this.clearRetryTimer();
|
|
4492
|
+
if (this.teardownRetryTimer) {
|
|
4493
|
+
clearTimeout(this.teardownRetryTimer);
|
|
4494
|
+
this.teardownRetryTimer = null;
|
|
4495
|
+
}
|
|
4496
|
+
}
|
|
4497
|
+
clearRetryTimer() {
|
|
4498
|
+
if (!this.retryTimer) return;
|
|
4499
|
+
clearTimeout(this.retryTimer);
|
|
4500
|
+
this.retryTimer = null;
|
|
4501
|
+
}
|
|
4502
|
+
reportAcquireError(error) {
|
|
4503
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
4504
|
+
if (this.reportedError === message) return;
|
|
4505
|
+
this.reportedError = message;
|
|
4506
|
+
console.error("[codebase-index] Failed to acquire background worker lease:", error);
|
|
3641
4507
|
}
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
4508
|
+
};
|
|
4509
|
+
function configureBackgroundWorker(projectRoot, host, config, hooks, options = {}) {
|
|
4510
|
+
const projectKey = projectLookupKey(projectRoot, host);
|
|
4511
|
+
const identity = resolveIdentity(projectRoot, config, host);
|
|
4512
|
+
const key = controllerKey(identity, host);
|
|
4513
|
+
const previousKey = workerKeysByProject.get(projectKey);
|
|
4514
|
+
if (previousKey && previousKey !== key) {
|
|
4515
|
+
const previous = workers.get(previousKey);
|
|
4516
|
+
const previousBarrier = workerReplacementBarriers.get(projectKey) ?? Promise.resolve();
|
|
4517
|
+
const stopPrevious = previous?.stop(options.stopPreviousAutoIndex ?? true) ?? Promise.resolve();
|
|
4518
|
+
const activation = Promise.all([previousBarrier, stopPrevious]).then(() => void 0);
|
|
4519
|
+
workerReplacementBarriers.set(projectKey, activation);
|
|
4520
|
+
workers.delete(previousKey);
|
|
4521
|
+
const worker2 = new BackgroundWorkerController(projectRoot, host, config, hooks, identity);
|
|
4522
|
+
worker2.startAfter(activation);
|
|
4523
|
+
workers.set(key, worker2);
|
|
4524
|
+
workerKeysByProject.set(projectKey, key);
|
|
4525
|
+
return;
|
|
3647
4526
|
}
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
(0, import_fs5.writeFileSync)(temporaryPath, JSON.stringify(nextOwner), {
|
|
3655
|
-
encoding: "utf-8",
|
|
3656
|
-
flag: "wx",
|
|
3657
|
-
mode: 384
|
|
3658
|
-
});
|
|
3659
|
-
retryTransientFilesystemOperation(() => (0, import_fs5.renameSync)(temporaryPath, ownerPath));
|
|
3660
|
-
} finally {
|
|
3661
|
-
if ((0, import_fs5.existsSync)(temporaryPath)) (0, import_fs5.rmSync)(temporaryPath, { force: true });
|
|
4527
|
+
let worker = workers.get(key);
|
|
4528
|
+
if (!worker) {
|
|
4529
|
+
worker = new BackgroundWorkerController(projectRoot, host, config, hooks, identity);
|
|
4530
|
+
workers.set(key, worker);
|
|
4531
|
+
} else {
|
|
4532
|
+
worker.update(config, hooks, options);
|
|
3662
4533
|
}
|
|
4534
|
+
workerKeysByProject.set(projectKey, key);
|
|
4535
|
+
worker.start();
|
|
3663
4536
|
}
|
|
3664
|
-
function
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
|
|
4537
|
+
function updateBackgroundWorkerConfig(projectRoot, host, config) {
|
|
4538
|
+
const projectKey = projectLookupKey(projectRoot, host);
|
|
4539
|
+
const key = workerKeysByProject.get(projectKey);
|
|
4540
|
+
const worker = key ? workers.get(key) : void 0;
|
|
4541
|
+
if (!worker) return;
|
|
4542
|
+
configureBackgroundWorker(projectRoot, host, config, worker.getHooksForConfig(config), {
|
|
4543
|
+
stopPreviousAutoIndex: false,
|
|
4544
|
+
restartAutoIndex: true
|
|
4545
|
+
});
|
|
3668
4546
|
}
|
|
3669
|
-
function
|
|
3670
|
-
|
|
4547
|
+
function waitForBackgroundWorkerStart(projectRoot, host) {
|
|
4548
|
+
const key = workerKeysByProject.get(projectLookupKey(projectRoot, host));
|
|
4549
|
+
return workers.get(key ?? "")?.waitForStart() ?? Promise.resolve();
|
|
3671
4550
|
}
|
|
3672
|
-
function
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
if (!(0, import_fs5.existsSync)(backupPath)) continue;
|
|
3676
|
-
if ((0, import_fs5.existsSync)(targetPath)) (0, import_fs5.rmSync)(targetPath, { recursive: true, force: true });
|
|
3677
|
-
(0, import_fs5.renameSync)(backupPath, targetPath);
|
|
3678
|
-
}
|
|
3679
|
-
const temporaryOwnerMarker = `.tmp.${owner.pid}.${owner.token}.`;
|
|
3680
|
-
for (const entry of (0, import_fs5.readdirSync)(indexPath)) {
|
|
3681
|
-
if (!entry.includes(temporaryOwnerMarker)) continue;
|
|
3682
|
-
(0, import_fs5.rmSync)(path9.join(indexPath, entry), { recursive: true, force: true });
|
|
3683
|
-
}
|
|
4551
|
+
function requestBackgroundWorkerRefresh(projectRoot, host, allowDisabledAutoIndex = false) {
|
|
4552
|
+
const key = workerKeysByProject.get(projectLookupKey(projectRoot, host));
|
|
4553
|
+
workers.get(key ?? "")?.requestRefresh(allowDisabledAutoIndex);
|
|
3684
4554
|
}
|
|
3685
|
-
function
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
|
|
3694
|
-
|
|
4555
|
+
function isBackgroundWorkerManaged(projectRoot, host) {
|
|
4556
|
+
const key = workerKeysByProject.get(projectLookupKey(projectRoot, host));
|
|
4557
|
+
return key !== void 0 && workers.has(key);
|
|
4558
|
+
}
|
|
4559
|
+
function isBackgroundWorkerLeader(projectRoot, host) {
|
|
4560
|
+
const key = workerKeysByProject.get(projectLookupKey(projectRoot, host));
|
|
4561
|
+
return key !== void 0 && workers.get(key)?.isLeader() === true;
|
|
4562
|
+
}
|
|
4563
|
+
async function stopBackgroundWorker(projectRoot, host) {
|
|
4564
|
+
const projectKey = projectLookupKey(projectRoot, host);
|
|
4565
|
+
const key = workerKeysByProject.get(projectKey);
|
|
4566
|
+
const worker = key ? workers.get(key) : void 0;
|
|
4567
|
+
if (!worker) return;
|
|
4568
|
+
await worker.stop();
|
|
3695
4569
|
}
|
|
3696
4570
|
|
|
3697
4571
|
// src/utils/files.ts
|
|
3698
4572
|
var import_ignore = __toESM(require_ignore(), 1);
|
|
3699
4573
|
var import_fs6 = require("fs");
|
|
3700
|
-
var
|
|
4574
|
+
var path11 = __toESM(require("path"), 1);
|
|
3701
4575
|
var PROJECT_MARKERS = [
|
|
3702
4576
|
".git",
|
|
3703
4577
|
"package.json",
|
|
@@ -3715,7 +4589,7 @@ var PROJECT_MARKERS = [
|
|
|
3715
4589
|
];
|
|
3716
4590
|
function hasProjectMarker(projectRoot) {
|
|
3717
4591
|
for (const marker of PROJECT_MARKERS) {
|
|
3718
|
-
if ((0, import_fs6.existsSync)(
|
|
4592
|
+
if ((0, import_fs6.existsSync)(path11.join(projectRoot, marker))) {
|
|
3719
4593
|
return true;
|
|
3720
4594
|
}
|
|
3721
4595
|
}
|
|
@@ -3742,33 +4616,53 @@ function createIgnoreFilter(projectRoot) {
|
|
|
3742
4616
|
"**/*build*/**"
|
|
3743
4617
|
];
|
|
3744
4618
|
ig.add(defaultIgnores);
|
|
3745
|
-
const gitignorePath =
|
|
4619
|
+
const gitignorePath = path11.join(projectRoot, ".gitignore");
|
|
3746
4620
|
if ((0, import_fs6.existsSync)(gitignorePath)) {
|
|
3747
4621
|
const gitignoreContent = (0, import_fs6.readFileSync)(gitignorePath, "utf-8");
|
|
3748
4622
|
ig.add(gitignoreContent);
|
|
3749
4623
|
}
|
|
3750
4624
|
return ig;
|
|
3751
4625
|
}
|
|
3752
|
-
function
|
|
3753
|
-
|
|
3754
|
-
|
|
3755
|
-
|
|
3756
|
-
|
|
3757
|
-
|
|
3758
|
-
|
|
4626
|
+
function toPosixRelativePath(relativePath) {
|
|
4627
|
+
return relativePath.split(path11.sep).join("/");
|
|
4628
|
+
}
|
|
4629
|
+
function matchesAnyGlob(filePath, patterns) {
|
|
4630
|
+
const normalized = toPosixRelativePath(filePath);
|
|
4631
|
+
return patterns.some((pattern) => matchGlob(normalized, pattern));
|
|
4632
|
+
}
|
|
4633
|
+
function isExcludedByPatterns(relativePath, excludePatterns) {
|
|
4634
|
+
return matchesAnyGlob(relativePath, excludePatterns);
|
|
4635
|
+
}
|
|
4636
|
+
function isExcludedDirectory(relativePath, excludePatterns) {
|
|
4637
|
+
const normalized = toPosixRelativePath(relativePath);
|
|
4638
|
+
if (matchesAnyGlob(normalized, excludePatterns)) {
|
|
4639
|
+
return true;
|
|
3759
4640
|
}
|
|
3760
4641
|
for (const pattern of excludePatterns) {
|
|
3761
|
-
|
|
3762
|
-
|
|
4642
|
+
const posixPattern = toPosixRelativePath(pattern).replace(/\/+$/, "");
|
|
4643
|
+
if (!posixPattern.endsWith("/**")) {
|
|
4644
|
+
continue;
|
|
3763
4645
|
}
|
|
3764
|
-
|
|
3765
|
-
|
|
3766
|
-
if (matchGlob(relativePath, pattern)) {
|
|
4646
|
+
const directoryPattern = posixPattern.slice(0, -3);
|
|
4647
|
+
if (directoryPattern && matchesAnyGlob(normalized, [directoryPattern])) {
|
|
3767
4648
|
return true;
|
|
3768
4649
|
}
|
|
3769
4650
|
}
|
|
3770
4651
|
return false;
|
|
3771
4652
|
}
|
|
4653
|
+
function shouldIncludeFile(filePath, projectRoot, includePatterns, excludePatterns, ignoreFilter) {
|
|
4654
|
+
const relativePath = toPosixRelativePath(path11.relative(projectRoot, filePath));
|
|
4655
|
+
if (hasFilteredPathSegment(relativePath, "/")) {
|
|
4656
|
+
return false;
|
|
4657
|
+
}
|
|
4658
|
+
if (ignoreFilter.ignores(relativePath)) {
|
|
4659
|
+
return false;
|
|
4660
|
+
}
|
|
4661
|
+
if (isExcludedByPatterns(relativePath, excludePatterns)) {
|
|
4662
|
+
return false;
|
|
4663
|
+
}
|
|
4664
|
+
return matchesAnyGlob(relativePath, includePatterns);
|
|
4665
|
+
}
|
|
3772
4666
|
function matchGlob(filePath, pattern) {
|
|
3773
4667
|
if (pattern.startsWith("**/")) {
|
|
3774
4668
|
const withoutPrefix = pattern.slice(3);
|
|
@@ -3789,8 +4683,8 @@ async function* walkDirectory(dir, projectRoot, includePatterns, excludePatterns
|
|
|
3789
4683
|
const filesInDir = [];
|
|
3790
4684
|
const subdirs = [];
|
|
3791
4685
|
for (const entry of entries) {
|
|
3792
|
-
const fullPath =
|
|
3793
|
-
const relativePath =
|
|
4686
|
+
const fullPath = path11.join(dir, entry.name);
|
|
4687
|
+
const relativePath = toPosixRelativePath(path11.relative(projectRoot, fullPath));
|
|
3794
4688
|
if (isHiddenPathSegment(entry.name)) {
|
|
3795
4689
|
if (entry.isDirectory()) {
|
|
3796
4690
|
skipped.push({ path: relativePath, reason: "excluded" });
|
|
@@ -3808,6 +4702,10 @@ async function* walkDirectory(dir, projectRoot, includePatterns, excludePatterns
|
|
|
3808
4702
|
continue;
|
|
3809
4703
|
}
|
|
3810
4704
|
if (entry.isDirectory()) {
|
|
4705
|
+
if (isExcludedDirectory(relativePath, excludePatterns)) {
|
|
4706
|
+
skipped.push({ path: relativePath, reason: "excluded" });
|
|
4707
|
+
continue;
|
|
4708
|
+
}
|
|
3811
4709
|
subdirs.push({ fullPath, relativePath });
|
|
3812
4710
|
} else if (entry.isFile()) {
|
|
3813
4711
|
const stat5 = await import_fs6.promises.stat(fullPath);
|
|
@@ -3815,20 +4713,11 @@ async function* walkDirectory(dir, projectRoot, includePatterns, excludePatterns
|
|
|
3815
4713
|
skipped.push({ path: relativePath, reason: "too_large" });
|
|
3816
4714
|
continue;
|
|
3817
4715
|
}
|
|
3818
|
-
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
continue;
|
|
3822
|
-
}
|
|
3823
|
-
}
|
|
3824
|
-
let matched = false;
|
|
3825
|
-
for (const pattern of includePatterns) {
|
|
3826
|
-
if (matchGlob(relativePath, pattern)) {
|
|
3827
|
-
matched = true;
|
|
3828
|
-
break;
|
|
3829
|
-
}
|
|
4716
|
+
if (isExcludedByPatterns(relativePath, excludePatterns)) {
|
|
4717
|
+
skipped.push({ path: relativePath, reason: "excluded" });
|
|
4718
|
+
continue;
|
|
3830
4719
|
}
|
|
3831
|
-
if (
|
|
4720
|
+
if (matchesAnyGlob(relativePath, includePatterns)) {
|
|
3832
4721
|
filesInDir.push({ path: fullPath, size: stat5.size });
|
|
3833
4722
|
}
|
|
3834
4723
|
}
|
|
@@ -3839,7 +4728,7 @@ async function* walkDirectory(dir, projectRoot, includePatterns, excludePatterns
|
|
|
3839
4728
|
yield f;
|
|
3840
4729
|
}
|
|
3841
4730
|
for (let i = options.maxFilesPerDirectory; i < filesInDir.length; i++) {
|
|
3842
|
-
skipped.push({ path:
|
|
4731
|
+
skipped.push({ path: toPosixRelativePath(path11.relative(projectRoot, filesInDir[i].path)), reason: "excluded" });
|
|
3843
4732
|
}
|
|
3844
4733
|
const canRecurse = options.maxDepth === -1 || currentDepth < options.maxDepth;
|
|
3845
4734
|
if (canRecurse) {
|
|
@@ -3879,8 +4768,8 @@ async function collectFiles(projectRoot, includePatterns, excludePatterns, maxFi
|
|
|
3879
4768
|
if (additionalRoots && additionalRoots.length > 0) {
|
|
3880
4769
|
const normalizedRoots = /* @__PURE__ */ new Set();
|
|
3881
4770
|
for (const kbRoot of additionalRoots) {
|
|
3882
|
-
const resolved =
|
|
3883
|
-
|
|
4771
|
+
const resolved = path11.normalize(
|
|
4772
|
+
path11.isAbsolute(kbRoot) ? kbRoot : path11.resolve(projectRoot, kbRoot)
|
|
3884
4773
|
);
|
|
3885
4774
|
normalizedRoots.add(resolved);
|
|
3886
4775
|
}
|
|
@@ -3921,7 +4810,7 @@ function getErrorMessage(error) {
|
|
|
3921
4810
|
return error instanceof Error ? error.message : String(error);
|
|
3922
4811
|
}
|
|
3923
4812
|
function runCommand(file, args, options) {
|
|
3924
|
-
return new Promise((
|
|
4813
|
+
return new Promise((resolve18, reject) => {
|
|
3925
4814
|
childProcess.execFile(
|
|
3926
4815
|
file,
|
|
3927
4816
|
args,
|
|
@@ -3931,7 +4820,7 @@ function runCommand(file, args, options) {
|
|
|
3931
4820
|
reject(error);
|
|
3932
4821
|
return;
|
|
3933
4822
|
}
|
|
3934
|
-
|
|
4823
|
+
resolve18(stdout);
|
|
3935
4824
|
}
|
|
3936
4825
|
);
|
|
3937
4826
|
});
|
|
@@ -4023,8 +4912,8 @@ var AutoIndexCancelledError = class extends Error {
|
|
|
4023
4912
|
function now() {
|
|
4024
4913
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
4025
4914
|
}
|
|
4026
|
-
function
|
|
4027
|
-
const resolved =
|
|
4915
|
+
function canonicalizePath2(targetPath) {
|
|
4916
|
+
const resolved = path12.resolve(targetPath);
|
|
4028
4917
|
if ((0, import_fs7.existsSync)(resolved)) {
|
|
4029
4918
|
try {
|
|
4030
4919
|
return import_fs7.realpathSync.native(resolved);
|
|
@@ -4032,20 +4921,20 @@ function canonicalizePath(targetPath) {
|
|
|
4032
4921
|
return resolved;
|
|
4033
4922
|
}
|
|
4034
4923
|
}
|
|
4035
|
-
const parent =
|
|
4924
|
+
const parent = path12.dirname(resolved);
|
|
4036
4925
|
if (parent === resolved) return resolved;
|
|
4037
|
-
return
|
|
4926
|
+
return path12.join(canonicalizePath2(parent), path12.basename(resolved));
|
|
4038
4927
|
}
|
|
4039
4928
|
function isHomeDirectory(projectRoot) {
|
|
4040
|
-
return
|
|
4929
|
+
return canonicalizePath2(projectRoot) === canonicalizePath2(os4.homedir());
|
|
4041
4930
|
}
|
|
4042
|
-
function
|
|
4043
|
-
return `${host}::${
|
|
4931
|
+
function projectLookupKey2(projectRoot, host) {
|
|
4932
|
+
return `${host}::${canonicalizePath2(projectRoot)}`;
|
|
4044
4933
|
}
|
|
4045
4934
|
function coordinatorKey(projectRoot, config, host) {
|
|
4046
|
-
const canonicalProjectRoot =
|
|
4935
|
+
const canonicalProjectRoot = canonicalizePath2(projectRoot);
|
|
4047
4936
|
const indexPath = resolveProjectIndexPath(projectRoot, config.scope, host);
|
|
4048
|
-
return `${
|
|
4937
|
+
return `${canonicalizePath2(indexPath)}::${canonicalProjectRoot}`;
|
|
4049
4938
|
}
|
|
4050
4939
|
function getProjectSafety(projectRoot, config) {
|
|
4051
4940
|
if (isHomeDirectory(projectRoot)) {
|
|
@@ -4076,10 +4965,10 @@ function safeFailureMessage(error) {
|
|
|
4076
4965
|
}
|
|
4077
4966
|
function cancellableDelay(delayMs, signal) {
|
|
4078
4967
|
if (signal.aborted) return Promise.reject(new AutoIndexCancelledError());
|
|
4079
|
-
return new Promise((
|
|
4968
|
+
return new Promise((resolve18, reject) => {
|
|
4080
4969
|
const timer = setTimeout(() => {
|
|
4081
4970
|
signal.removeEventListener("abort", onAbort);
|
|
4082
|
-
|
|
4971
|
+
resolve18();
|
|
4083
4972
|
}, delayMs);
|
|
4084
4973
|
timer.unref?.();
|
|
4085
4974
|
const onAbort = () => {
|
|
@@ -4091,18 +4980,44 @@ function cancellableDelay(delayMs, signal) {
|
|
|
4091
4980
|
}
|
|
4092
4981
|
function withTimeout(promise, timeoutMs) {
|
|
4093
4982
|
if (timeoutMs <= 0) return Promise.resolve(void 0);
|
|
4094
|
-
return new Promise((
|
|
4095
|
-
const timer = setTimeout(() =>
|
|
4983
|
+
return new Promise((resolve18) => {
|
|
4984
|
+
const timer = setTimeout(() => resolve18(void 0), timeoutMs);
|
|
4096
4985
|
timer.unref?.();
|
|
4097
4986
|
void promise.then((value) => {
|
|
4098
4987
|
clearTimeout(timer);
|
|
4099
|
-
|
|
4988
|
+
resolve18(value);
|
|
4100
4989
|
}, () => {
|
|
4101
4990
|
clearTimeout(timer);
|
|
4102
|
-
|
|
4991
|
+
resolve18(void 0);
|
|
4103
4992
|
});
|
|
4104
4993
|
});
|
|
4105
4994
|
}
|
|
4995
|
+
function settlesWithin(promise, timeoutMs) {
|
|
4996
|
+
if (timeoutMs <= 0) return Promise.resolve(false);
|
|
4997
|
+
return new Promise((resolve18) => {
|
|
4998
|
+
let settled = false;
|
|
4999
|
+
const timer = setTimeout(() => {
|
|
5000
|
+
if (settled) return;
|
|
5001
|
+
settled = true;
|
|
5002
|
+
resolve18(false);
|
|
5003
|
+
}, timeoutMs);
|
|
5004
|
+
timer.unref?.();
|
|
5005
|
+
void promise.then(
|
|
5006
|
+
() => {
|
|
5007
|
+
if (settled) return;
|
|
5008
|
+
settled = true;
|
|
5009
|
+
clearTimeout(timer);
|
|
5010
|
+
resolve18(true);
|
|
5011
|
+
},
|
|
5012
|
+
() => {
|
|
5013
|
+
if (settled) return;
|
|
5014
|
+
settled = true;
|
|
5015
|
+
clearTimeout(timer);
|
|
5016
|
+
resolve18(true);
|
|
5017
|
+
}
|
|
5018
|
+
);
|
|
5019
|
+
});
|
|
5020
|
+
}
|
|
4106
5021
|
function requestPriority(request) {
|
|
4107
5022
|
if (request.force) return 4;
|
|
4108
5023
|
if (request.source === "manual") return 3;
|
|
@@ -4113,6 +5028,7 @@ function mergeRequests(current, next) {
|
|
|
4113
5028
|
if (!current) return next;
|
|
4114
5029
|
const preferred = requestPriority(next) > requestPriority(current) ? next : current;
|
|
4115
5030
|
return {
|
|
5031
|
+
allowDisabledAutoIndex: current.allowDisabledAutoIndex || next.allowDisabledAutoIndex,
|
|
4116
5032
|
checkFreshness: current.checkFreshness && next.checkFreshness,
|
|
4117
5033
|
force: current.force || next.force,
|
|
4118
5034
|
onProgress: next.onProgress ?? current.onProgress,
|
|
@@ -4174,11 +5090,11 @@ var AutoIndexCoordinator = class {
|
|
|
4174
5090
|
progress: this.status.progress ? { ...this.status.progress } : void 0
|
|
4175
5091
|
};
|
|
4176
5092
|
}
|
|
4177
|
-
start(source) {
|
|
5093
|
+
start(source, allowDisabledAutoIndex = false) {
|
|
4178
5094
|
this.refreshSafety();
|
|
4179
|
-
if (!this.registration.config.indexing.autoIndex || !this.registration.safeToRun) return null;
|
|
5095
|
+
if (!this.registration.config.indexing.autoIndex && !allowDisabledAutoIndex || !this.registration.safeToRun) return null;
|
|
4180
5096
|
if (this.status.state === "failed") return this.inFlight;
|
|
4181
|
-
return this.request({ checkFreshness: true, force: false, source });
|
|
5097
|
+
return this.request({ allowDisabledAutoIndex, checkFreshness: true, force: false, source });
|
|
4182
5098
|
}
|
|
4183
5099
|
request(request) {
|
|
4184
5100
|
if (this.stopped) {
|
|
@@ -4253,13 +5169,15 @@ var AutoIndexCoordinator = class {
|
|
|
4253
5169
|
retryAttempt: void 0
|
|
4254
5170
|
});
|
|
4255
5171
|
const inFlight = this.inFlight;
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
4260
|
-
|
|
4261
|
-
|
|
5172
|
+
const completion = inFlight ? inFlight.then(() => void 0, () => void 0) : Promise.resolve();
|
|
5173
|
+
if (!inFlight) {
|
|
5174
|
+
return { completed: true, completion };
|
|
5175
|
+
}
|
|
5176
|
+
if (waitForCompletion) {
|
|
5177
|
+
await completion;
|
|
5178
|
+
return { completed: true, completion };
|
|
4262
5179
|
}
|
|
5180
|
+
return { completed: await settlesWithin(completion, SHUTDOWN_WAIT_MS), completion };
|
|
4263
5181
|
}
|
|
4264
5182
|
startRequest(request) {
|
|
4265
5183
|
if (this.stopped || !this.canRun(request)) {
|
|
@@ -4448,7 +5366,7 @@ var AutoIndexCoordinator = class {
|
|
|
4448
5366
|
if (request.source === "manual" || request.source === "watcher") {
|
|
4449
5367
|
return true;
|
|
4450
5368
|
}
|
|
4451
|
-
return this.registration.safeToRun && this.registration.config.indexing.autoIndex;
|
|
5369
|
+
return this.registration.safeToRun && (this.registration.config.indexing.autoIndex || request.allowDisabledAutoIndex === true);
|
|
4452
5370
|
}
|
|
4453
5371
|
shouldDeferForBattery(request) {
|
|
4454
5372
|
return this.registration.backgroundIndexingPolicy !== null && (request.source === "startup" || request.source === "watcher");
|
|
@@ -4481,17 +5399,17 @@ var AutoIndexCoordinator = class {
|
|
|
4481
5399
|
}
|
|
4482
5400
|
}
|
|
4483
5401
|
waitForBatteryRetry(delayMs) {
|
|
4484
|
-
return new Promise((
|
|
5402
|
+
return new Promise((resolve18) => {
|
|
4485
5403
|
const timer = setTimeout(() => {
|
|
4486
5404
|
if (this.batteryRetryTimer === timer) {
|
|
4487
5405
|
this.batteryRetryTimer = null;
|
|
4488
5406
|
this.resolveBatteryRetry = null;
|
|
4489
5407
|
}
|
|
4490
|
-
|
|
5408
|
+
resolve18();
|
|
4491
5409
|
}, delayMs);
|
|
4492
5410
|
timer.unref?.();
|
|
4493
5411
|
this.batteryRetryTimer = timer;
|
|
4494
|
-
this.resolveBatteryRetry =
|
|
5412
|
+
this.resolveBatteryRetry = resolve18;
|
|
4495
5413
|
});
|
|
4496
5414
|
}
|
|
4497
5415
|
cancelBatteryRetry() {
|
|
@@ -4499,9 +5417,9 @@ var AutoIndexCoordinator = class {
|
|
|
4499
5417
|
clearTimeout(this.batteryRetryTimer);
|
|
4500
5418
|
this.batteryRetryTimer = null;
|
|
4501
5419
|
}
|
|
4502
|
-
const
|
|
5420
|
+
const resolve18 = this.resolveBatteryRetry;
|
|
4503
5421
|
this.resolveBatteryRetry = null;
|
|
4504
|
-
|
|
5422
|
+
resolve18?.();
|
|
4505
5423
|
}
|
|
4506
5424
|
finishBatteryCheck(batteryCheck) {
|
|
4507
5425
|
if (this.batteryCheck !== batteryCheck) return;
|
|
@@ -4514,12 +5432,25 @@ var AutoIndexCoordinator = class {
|
|
|
4514
5432
|
}
|
|
4515
5433
|
};
|
|
4516
5434
|
function getCoordinator(projectRoot, host) {
|
|
4517
|
-
const key = coordinatorKeysByProject.get(
|
|
5435
|
+
const key = coordinatorKeysByProject.get(projectLookupKey2(projectRoot, host));
|
|
4518
5436
|
return key ? coordinators.get(key) ?? null : null;
|
|
4519
5437
|
}
|
|
4520
|
-
function
|
|
4521
|
-
|
|
5438
|
+
function synchronizeBackgroundWorker(projectRoot, host, config, safeToRun) {
|
|
5439
|
+
if (safeToRun) {
|
|
5440
|
+
updateBackgroundWorkerConfig(projectRoot, host, config);
|
|
5441
|
+
return;
|
|
5442
|
+
}
|
|
5443
|
+
void stopBackgroundWorker(projectRoot, host).catch((error) => {
|
|
5444
|
+
console.error("[codebase-index] Failed to stop background worker after project safety changed:", error);
|
|
5445
|
+
});
|
|
5446
|
+
}
|
|
5447
|
+
function configureAutoIndex(projectRoot, host, config, getIndexer, options = {}) {
|
|
5448
|
+
const projectKey = projectLookupKey2(projectRoot, host);
|
|
4522
5449
|
const safety = getProjectSafety(projectRoot, config);
|
|
5450
|
+
const synchronizeWorker = options.synchronizeBackgroundWorker ?? true;
|
|
5451
|
+
if (options.preserveManagedWorker === true && isBackgroundWorkerManaged(projectRoot, host)) {
|
|
5452
|
+
return;
|
|
5453
|
+
}
|
|
4523
5454
|
const registration = {
|
|
4524
5455
|
backgroundIndexingPolicy: createBackgroundIndexingPolicy(
|
|
4525
5456
|
config.indexing.pauseBackgroundIndexingOnBattery
|
|
@@ -4537,6 +5468,9 @@ function configureAutoIndex(projectRoot, host, config, getIndexer) {
|
|
|
4537
5468
|
const stopPrevious = previousCoordinator?.stop(true) ?? Promise.resolve();
|
|
4538
5469
|
const activation = Promise.all([previousBarrier, stopPrevious]).then(() => void 0);
|
|
4539
5470
|
coordinatorReplacementBarriers.set(projectKey, activation);
|
|
5471
|
+
if (synchronizeWorker) {
|
|
5472
|
+
synchronizeBackgroundWorker(projectRoot, host, config, safety.safeToRun);
|
|
5473
|
+
}
|
|
4540
5474
|
coordinators.delete(previousKey);
|
|
4541
5475
|
const coordinator2 = new AutoIndexCoordinator(registration);
|
|
4542
5476
|
coordinator2.activateAfter(activation);
|
|
@@ -4552,11 +5486,17 @@ function configureAutoIndex(projectRoot, host, config, getIndexer) {
|
|
|
4552
5486
|
coordinator.update(registration);
|
|
4553
5487
|
}
|
|
4554
5488
|
coordinatorKeysByProject.set(projectKey, key);
|
|
5489
|
+
if (synchronizeWorker) {
|
|
5490
|
+
synchronizeBackgroundWorker(projectRoot, host, config, safety.safeToRun);
|
|
5491
|
+
}
|
|
4555
5492
|
}
|
|
4556
|
-
function
|
|
4557
|
-
return getCoordinator(projectRoot, host)?.start(source) ?? null;
|
|
5493
|
+
function startAutoIndexForBackgroundWorker(projectRoot, host, source = "startup", allowDisabledAutoIndex = false) {
|
|
5494
|
+
return getCoordinator(projectRoot, host)?.start(source, allowDisabledAutoIndex) ?? null;
|
|
4558
5495
|
}
|
|
4559
5496
|
function requestBackgroundIndex(projectRoot, host) {
|
|
5497
|
+
if (isBackgroundWorkerManaged(projectRoot, host) && !isBackgroundWorkerLeader(projectRoot, host)) {
|
|
5498
|
+
return null;
|
|
5499
|
+
}
|
|
4560
5500
|
return getCoordinator(projectRoot, host)?.request({
|
|
4561
5501
|
checkFreshness: false,
|
|
4562
5502
|
force: false,
|
|
@@ -4596,15 +5536,23 @@ async function waitForAutoIndexForRetrieval(projectRoot, host) {
|
|
|
4596
5536
|
};
|
|
4597
5537
|
}
|
|
4598
5538
|
try {
|
|
4599
|
-
|
|
5539
|
+
const readiness = await getSearchReadiness(coordinator);
|
|
5540
|
+
if (readiness.searchable) {
|
|
5541
|
+
return { ready: true };
|
|
5542
|
+
}
|
|
5543
|
+
if (readiness.blocked) return unavailableSnapshotResult(readiness.reason);
|
|
4600
5544
|
} catch {
|
|
4601
5545
|
}
|
|
4602
|
-
const job =
|
|
5546
|
+
const job = startRetrievalRefresh(projectRoot, host, coordinator);
|
|
4603
5547
|
if (job) {
|
|
4604
5548
|
await withTimeout(job, coordinator.getWaitMs());
|
|
5549
|
+
} else if (isBackgroundWorkerManaged(projectRoot, host)) {
|
|
5550
|
+
await waitForPublishedSnapshot(coordinator, coordinator.getWaitMs());
|
|
4605
5551
|
}
|
|
4606
5552
|
try {
|
|
4607
|
-
|
|
5553
|
+
const readiness = await getSearchReadiness(coordinator);
|
|
5554
|
+
if (readiness.searchable) return { ready: true };
|
|
5555
|
+
if (readiness.blocked) return unavailableSnapshotResult(readiness.reason);
|
|
4608
5556
|
} catch {
|
|
4609
5557
|
}
|
|
4610
5558
|
const status = coordinator.snapshot();
|
|
@@ -4625,18 +5573,52 @@ async function waitForAutoIndexForRetrieval(projectRoot, host) {
|
|
|
4625
5573
|
text: `Automatic indexing is ${status.state}. Retry shortly or call index_status for progress. You can also run index_codebase explicitly.`
|
|
4626
5574
|
};
|
|
4627
5575
|
}
|
|
4628
|
-
async function
|
|
5576
|
+
async function stopAutoIndexForBackgroundWorker(projectRoot, host, waitForCompletion = false) {
|
|
5577
|
+
const coordinator = getCoordinator(projectRoot, host);
|
|
5578
|
+
if (!coordinator) {
|
|
5579
|
+
return { completed: true, completion: Promise.resolve() };
|
|
5580
|
+
}
|
|
5581
|
+
return coordinator.stop(waitForCompletion);
|
|
5582
|
+
}
|
|
5583
|
+
async function getSearchReadiness(coordinator) {
|
|
4629
5584
|
const indexer = coordinator.getIndexer();
|
|
4630
5585
|
if (indexer.getIndexFreshness) {
|
|
4631
5586
|
const freshness = await indexer.getIndexFreshness();
|
|
4632
|
-
|
|
5587
|
+
const searchable = freshness.readable && freshness.current && freshness.reason === "current";
|
|
5588
|
+
return {
|
|
5589
|
+
blocked: freshness.reason === "unreadable" || freshness.reason === "incompatible" || freshness.reason === "failed-batches" || freshness.reason === "migration-required",
|
|
5590
|
+
reason: freshness.reason,
|
|
5591
|
+
searchable
|
|
5592
|
+
};
|
|
5593
|
+
}
|
|
5594
|
+
const indexed = (await indexer.getStatus()).indexed;
|
|
5595
|
+
return { blocked: false, searchable: indexed };
|
|
5596
|
+
}
|
|
5597
|
+
function unavailableSnapshotResult(reason) {
|
|
5598
|
+
const detail = reason === "incompatible" ? "The existing index is incompatible with the configured embedding provider." : reason === "migration-required" ? "The existing index requires a storage migration." : reason === "failed-batches" ? "The existing index has failed embedding batches." : "The existing index is unreadable.";
|
|
5599
|
+
return {
|
|
5600
|
+
ready: false,
|
|
5601
|
+
text: `${detail} Run index_codebase before retrying retrieval.`
|
|
5602
|
+
};
|
|
5603
|
+
}
|
|
5604
|
+
function startRetrievalRefresh(projectRoot, host, coordinator) {
|
|
5605
|
+
if (isBackgroundWorkerManaged(projectRoot, host)) {
|
|
5606
|
+
requestBackgroundWorkerRefresh(projectRoot, host, true);
|
|
5607
|
+
return isBackgroundWorkerLeader(projectRoot, host) ? coordinator.currentJob() : null;
|
|
5608
|
+
}
|
|
5609
|
+
return coordinator.start("retrieval") ?? coordinator.currentJob();
|
|
5610
|
+
}
|
|
5611
|
+
async function waitForPublishedSnapshot(coordinator, waitMs) {
|
|
5612
|
+
const deadline = Date.now() + waitMs;
|
|
5613
|
+
while (Date.now() < deadline) {
|
|
5614
|
+
if ((await getSearchReadiness(coordinator)).searchable) return;
|
|
5615
|
+
await new Promise((resolve18) => setTimeout(resolve18, Math.min(250, deadline - Date.now())));
|
|
4633
5616
|
}
|
|
4634
|
-
return (await indexer.getStatus()).indexed;
|
|
4635
5617
|
}
|
|
4636
5618
|
|
|
4637
5619
|
// src/tools/config-state.ts
|
|
4638
5620
|
var import_fs8 = require("fs");
|
|
4639
|
-
var
|
|
5621
|
+
var path13 = __toESM(require("path"), 1);
|
|
4640
5622
|
function normalizeKnowledgeBasePaths(config, projectRoot) {
|
|
4641
5623
|
const normalized = { ...config };
|
|
4642
5624
|
if (Array.isArray(normalized.knowledgeBases)) {
|
|
@@ -4663,8 +5645,8 @@ function loadEditableConfig(projectRoot, host) {
|
|
|
4663
5645
|
}
|
|
4664
5646
|
function saveConfig(projectRoot, config, host) {
|
|
4665
5647
|
const configPath = getConfigPath(projectRoot, host);
|
|
4666
|
-
const configDir =
|
|
4667
|
-
const configBaseDir =
|
|
5648
|
+
const configDir = path13.dirname(configPath);
|
|
5649
|
+
const configBaseDir = path13.dirname(configDir);
|
|
4668
5650
|
if (!(0, import_fs8.existsSync)(configDir)) {
|
|
4669
5651
|
(0, import_fs8.mkdirSync)(configDir, { recursive: true });
|
|
4670
5652
|
}
|
|
@@ -4679,7 +5661,7 @@ function saveConfig(projectRoot, config, host) {
|
|
|
4679
5661
|
|
|
4680
5662
|
// src/indexer/index.ts
|
|
4681
5663
|
var import_fs12 = require("fs");
|
|
4682
|
-
var
|
|
5664
|
+
var path20 = __toESM(require("path"), 1);
|
|
4683
5665
|
var import_perf_hooks = require("perf_hooks");
|
|
4684
5666
|
var import_child_process4 = require("child_process");
|
|
4685
5667
|
var import_util4 = require("util");
|
|
@@ -4706,7 +5688,7 @@ function pTimeout(promise, options) {
|
|
|
4706
5688
|
} = options;
|
|
4707
5689
|
let timer;
|
|
4708
5690
|
let abortHandler;
|
|
4709
|
-
const wrappedPromise = new Promise((
|
|
5691
|
+
const wrappedPromise = new Promise((resolve18, reject) => {
|
|
4710
5692
|
if (typeof milliseconds !== "number" || Math.sign(milliseconds) !== 1) {
|
|
4711
5693
|
throw new TypeError(`Expected \`milliseconds\` to be a positive number, got \`${milliseconds}\``);
|
|
4712
5694
|
}
|
|
@@ -4720,7 +5702,7 @@ function pTimeout(promise, options) {
|
|
|
4720
5702
|
};
|
|
4721
5703
|
signal.addEventListener("abort", abortHandler, { once: true });
|
|
4722
5704
|
}
|
|
4723
|
-
promise.then(
|
|
5705
|
+
promise.then(resolve18, reject);
|
|
4724
5706
|
if (milliseconds === Number.POSITIVE_INFINITY) {
|
|
4725
5707
|
return;
|
|
4726
5708
|
}
|
|
@@ -4728,7 +5710,7 @@ function pTimeout(promise, options) {
|
|
|
4728
5710
|
timer = customTimers.setTimeout.call(void 0, () => {
|
|
4729
5711
|
if (fallback) {
|
|
4730
5712
|
try {
|
|
4731
|
-
|
|
5713
|
+
resolve18(fallback());
|
|
4732
5714
|
} catch (error) {
|
|
4733
5715
|
reject(error);
|
|
4734
5716
|
}
|
|
@@ -4738,7 +5720,7 @@ function pTimeout(promise, options) {
|
|
|
4738
5720
|
promise.cancel();
|
|
4739
5721
|
}
|
|
4740
5722
|
if (message === false) {
|
|
4741
|
-
|
|
5723
|
+
resolve18();
|
|
4742
5724
|
} else if (message instanceof Error) {
|
|
4743
5725
|
reject(message);
|
|
4744
5726
|
} else {
|
|
@@ -5140,7 +6122,7 @@ var PQueue = class extends import_index.default {
|
|
|
5140
6122
|
// Assign unique ID if not provided
|
|
5141
6123
|
id: options.id ?? (this.#idAssigner++).toString()
|
|
5142
6124
|
};
|
|
5143
|
-
return new Promise((
|
|
6125
|
+
return new Promise((resolve18, reject) => {
|
|
5144
6126
|
const taskSymbol = /* @__PURE__ */ Symbol(`task-${options.id}`);
|
|
5145
6127
|
let cleanupQueueAbortHandler = () => void 0;
|
|
5146
6128
|
const run = async () => {
|
|
@@ -5180,7 +6162,7 @@ var PQueue = class extends import_index.default {
|
|
|
5180
6162
|
})]);
|
|
5181
6163
|
}
|
|
5182
6164
|
const result = await operation;
|
|
5183
|
-
|
|
6165
|
+
resolve18(result);
|
|
5184
6166
|
this.emit("completed", result);
|
|
5185
6167
|
} catch (error) {
|
|
5186
6168
|
reject(error);
|
|
@@ -5368,13 +6350,13 @@ var PQueue = class extends import_index.default {
|
|
|
5368
6350
|
});
|
|
5369
6351
|
}
|
|
5370
6352
|
async #onEvent(event, filter) {
|
|
5371
|
-
return new Promise((
|
|
6353
|
+
return new Promise((resolve18) => {
|
|
5372
6354
|
const listener = () => {
|
|
5373
6355
|
if (filter && !filter()) {
|
|
5374
6356
|
return;
|
|
5375
6357
|
}
|
|
5376
6358
|
this.off(event, listener);
|
|
5377
|
-
|
|
6359
|
+
resolve18();
|
|
5378
6360
|
};
|
|
5379
6361
|
this.on(event, listener);
|
|
5380
6362
|
});
|
|
@@ -5660,7 +6642,7 @@ async function onAttemptFailure({ error, attemptNumber, retriesConsumed, startTi
|
|
|
5660
6642
|
const finalDelay = Math.min(delayTime, remainingTime);
|
|
5661
6643
|
options.signal?.throwIfAborted();
|
|
5662
6644
|
if (finalDelay > 0) {
|
|
5663
|
-
await new Promise((
|
|
6645
|
+
await new Promise((resolve18, reject) => {
|
|
5664
6646
|
const onAbort = () => {
|
|
5665
6647
|
clearTimeout(timeoutToken);
|
|
5666
6648
|
options.signal?.removeEventListener("abort", onAbort);
|
|
@@ -5668,7 +6650,7 @@ async function onAttemptFailure({ error, attemptNumber, retriesConsumed, startTi
|
|
|
5668
6650
|
};
|
|
5669
6651
|
const timeoutToken = setTimeout(() => {
|
|
5670
6652
|
options.signal?.removeEventListener("abort", onAbort);
|
|
5671
|
-
|
|
6653
|
+
resolve18();
|
|
5672
6654
|
}, finalDelay);
|
|
5673
6655
|
if (options.unref) {
|
|
5674
6656
|
timeoutToken.unref?.();
|
|
@@ -5730,10 +6712,10 @@ async function pRetry(input, options = {}) {
|
|
|
5730
6712
|
|
|
5731
6713
|
// src/embeddings/detector.ts
|
|
5732
6714
|
var import_fs9 = require("fs");
|
|
5733
|
-
var
|
|
5734
|
-
var
|
|
6715
|
+
var path14 = __toESM(require("path"), 1);
|
|
6716
|
+
var os5 = __toESM(require("os"), 1);
|
|
5735
6717
|
function getOpenCodeAuthPath() {
|
|
5736
|
-
return
|
|
6718
|
+
return path14.join(os5.homedir(), ".local", "share", "opencode", "auth.json");
|
|
5737
6719
|
}
|
|
5738
6720
|
function loadOpenCodeAuth() {
|
|
5739
6721
|
const authPath = getOpenCodeAuthPath();
|
|
@@ -6030,17 +7012,17 @@ function validateExternalUrl(urlString) {
|
|
|
6030
7012
|
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
6031
7013
|
return { valid: false, reason: `Blocked protocol: ${parsed.protocol}` };
|
|
6032
7014
|
}
|
|
6033
|
-
const
|
|
6034
|
-
if (BLOCKED_HOSTNAMES.has(
|
|
6035
|
-
return { valid: false, reason: `Blocked: cloud metadata service (${
|
|
7015
|
+
const hostname3 = parsed.hostname.toLowerCase();
|
|
7016
|
+
if (BLOCKED_HOSTNAMES.has(hostname3)) {
|
|
7017
|
+
return { valid: false, reason: `Blocked: cloud metadata service (${hostname3})` };
|
|
6036
7018
|
}
|
|
6037
7019
|
for (const pattern of BLOCKED_METADATA_IPS) {
|
|
6038
|
-
if (pattern.test(
|
|
6039
|
-
return { valid: false, reason: `Blocked: cloud metadata IP (${
|
|
7020
|
+
if (pattern.test(hostname3)) {
|
|
7021
|
+
return { valid: false, reason: `Blocked: cloud metadata IP (${hostname3})` };
|
|
6040
7022
|
}
|
|
6041
7023
|
}
|
|
6042
|
-
if (/^169\.254\./.test(
|
|
6043
|
-
return { valid: false, reason: `Blocked: link-local address (${
|
|
7024
|
+
if (/^169\.254\./.test(hostname3)) {
|
|
7025
|
+
return { valid: false, reason: `Blocked: link-local address (${hostname3})` };
|
|
6044
7026
|
}
|
|
6045
7027
|
return { valid: true };
|
|
6046
7028
|
}
|
|
@@ -6578,6 +7560,26 @@ function formatCostEstimate(estimate) {
|
|
|
6578
7560
|
\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518
|
|
6579
7561
|
`;
|
|
6580
7562
|
}
|
|
7563
|
+
function formatDryRunEstimate(estimate) {
|
|
7564
|
+
return `Dry run: parsed the file set to measure the embedding workload. No embedding requests were made and the index was not changed.
|
|
7565
|
+
|
|
7566
|
+
Files to embed: ${estimate.filesCount.toLocaleString()}
|
|
7567
|
+
Chunks to embed: ${estimate.chunksCount.toLocaleString()}
|
|
7568
|
+
Tokens to embed: ${estimate.tokensToEmbed.toLocaleString()}
|
|
7569
|
+
|
|
7570
|
+
The "Tokens to embed" value uses the local estimateTokens(text) = ceil(len/4). It
|
|
7571
|
+
matches the live "Tokens used" counter only for providers that report usage on the
|
|
7572
|
+
same basis (ollama); for providers that report a server tokenizer count (OpenAI,
|
|
7573
|
+
Gemini, custom) it is only an estimate.
|
|
7574
|
+
|
|
7575
|
+
For a matching provider and a project-scoped force index, the force pass clears its
|
|
7576
|
+
own cached embeddings, so the live counter climbs to this number. A force index on a
|
|
7577
|
+
shared global index can reuse cached embeddings from other projects, and an
|
|
7578
|
+
incremental index counts cached chunks that are not re-embedded; in both cases this
|
|
7579
|
+
number is an upper bound on the live counter, so a progress percent against this
|
|
7580
|
+
total tops out below 100%.
|
|
7581
|
+
`;
|
|
7582
|
+
}
|
|
6581
7583
|
function formatBytes(bytes) {
|
|
6582
7584
|
if (bytes === 0) return "0 B";
|
|
6583
7585
|
const k = 1024;
|
|
@@ -7112,8 +8114,8 @@ function extractParamNames(params) {
|
|
|
7112
8114
|
}
|
|
7113
8115
|
|
|
7114
8116
|
// src/native/binding.ts
|
|
7115
|
-
var
|
|
7116
|
-
var
|
|
8117
|
+
var os6 = __toESM(require("os"), 1);
|
|
8118
|
+
var path15 = __toESM(require("path"), 1);
|
|
7117
8119
|
var module2 = __toESM(require("module"), 1);
|
|
7118
8120
|
var import_node_url = require("url");
|
|
7119
8121
|
|
|
@@ -7150,7 +8152,7 @@ var STABLE_NATIVE_BINARY_NAME = IDENTITY_CATALOG.native.binaryName;
|
|
|
7150
8152
|
|
|
7151
8153
|
// src/native/binding.ts
|
|
7152
8154
|
var import_meta = {};
|
|
7153
|
-
function getNativeBindingFilename(platform2 =
|
|
8155
|
+
function getNativeBindingFilename(platform2 = os6.platform(), arch2 = os6.arch()) {
|
|
7154
8156
|
if (platform2 === "darwin" && arch2 === "arm64") {
|
|
7155
8157
|
return `${STABLE_NATIVE_BINARY_NAME}.darwin-arm64.node`;
|
|
7156
8158
|
}
|
|
@@ -7168,25 +8170,25 @@ function getNativeBindingFilename(platform2 = os5.platform(), arch2 = os5.arch()
|
|
|
7168
8170
|
}
|
|
7169
8171
|
throw new Error(`Unsupported platform: ${platform2}-${arch2}`);
|
|
7170
8172
|
}
|
|
7171
|
-
function resolveNativeBindingPath(packageRoot, platform2 =
|
|
7172
|
-
return
|
|
8173
|
+
function resolveNativeBindingPath(packageRoot, platform2 = os6.platform(), arch2 = os6.arch()) {
|
|
8174
|
+
return path15.join(packageRoot, "native", getNativeBindingFilename(platform2, arch2));
|
|
7173
8175
|
}
|
|
7174
8176
|
function getNativeBinding() {
|
|
7175
8177
|
let currentDir;
|
|
7176
8178
|
let requireTarget;
|
|
7177
8179
|
if (typeof import_meta !== "undefined" && import_meta.url) {
|
|
7178
|
-
currentDir =
|
|
8180
|
+
currentDir = path15.dirname((0, import_node_url.fileURLToPath)(import_meta.url));
|
|
7179
8181
|
requireTarget = import_meta.url;
|
|
7180
8182
|
} else if (typeof __dirname !== "undefined") {
|
|
7181
8183
|
currentDir = __dirname;
|
|
7182
8184
|
requireTarget = __filename;
|
|
7183
8185
|
} else {
|
|
7184
8186
|
currentDir = process.cwd();
|
|
7185
|
-
requireTarget =
|
|
8187
|
+
requireTarget = path15.join(currentDir, "index.js");
|
|
7186
8188
|
}
|
|
7187
8189
|
const normalizedDir = currentDir.replace(/\\/g, "/");
|
|
7188
|
-
const isDevMode = normalizedDir.includes("/src/native") || currentDir.includes(
|
|
7189
|
-
const packageRoot = isDevMode ?
|
|
8190
|
+
const isDevMode = normalizedDir.includes("/src/native") || currentDir.includes(path15.join("src", "native"));
|
|
8191
|
+
const packageRoot = isDevMode ? path15.resolve(currentDir, "../..") : path15.resolve(currentDir, "..");
|
|
7190
8192
|
const nativePath = resolveNativeBindingPath(packageRoot);
|
|
7191
8193
|
const require2 = module2.createRequire(requireTarget);
|
|
7192
8194
|
return require2(nativePath);
|
|
@@ -7770,8 +8772,8 @@ var Database = class _Database {
|
|
|
7770
8772
|
|
|
7771
8773
|
// src/git/branch-materialization.ts
|
|
7772
8774
|
var import_fs10 = require("fs");
|
|
7773
|
-
var
|
|
7774
|
-
var
|
|
8775
|
+
var os7 = __toESM(require("os"), 1);
|
|
8776
|
+
var path16 = __toESM(require("path"), 1);
|
|
7775
8777
|
|
|
7776
8778
|
// src/git/branch-resolution.ts
|
|
7777
8779
|
var import_child_process = require("child_process");
|
|
@@ -8090,13 +9092,13 @@ async function isWorktreeRegistered(projectRoot, worktreePath) {
|
|
|
8090
9092
|
return false;
|
|
8091
9093
|
}
|
|
8092
9094
|
function isPathWithinRoot(filePath, rootPath) {
|
|
8093
|
-
const relative14 =
|
|
8094
|
-
return relative14 === "" || !relative14.startsWith(`..${
|
|
9095
|
+
const relative14 = path16.relative(path16.resolve(rootPath), path16.resolve(filePath));
|
|
9096
|
+
return relative14 === "" || !relative14.startsWith(`..${path16.sep}`) && relative14 !== ".." && !path16.isAbsolute(relative14);
|
|
8095
9097
|
}
|
|
8096
9098
|
async function pruneExactMissingWorktreeRegistration(projectRoot, worktreePath) {
|
|
8097
9099
|
if (await pathExists(worktreePath)) return false;
|
|
8098
9100
|
const commonDir = await runGit(projectRoot, ["rev-parse", "--path-format=absolute", "--git-common-dir"]);
|
|
8099
|
-
const registrationsRoot =
|
|
9101
|
+
const registrationsRoot = path16.join(commonDir, "worktrees");
|
|
8100
9102
|
let entries;
|
|
8101
9103
|
try {
|
|
8102
9104
|
entries = await import_fs10.promises.readdir(registrationsRoot, { withFileTypes: true });
|
|
@@ -8107,16 +9109,16 @@ async function pruneExactMissingWorktreeRegistration(projectRoot, worktreePath)
|
|
|
8107
9109
|
const target = canonicalizePathForComparison(worktreePath);
|
|
8108
9110
|
for (const entry of entries) {
|
|
8109
9111
|
if (!entry.isDirectory()) continue;
|
|
8110
|
-
const registrationPath =
|
|
9112
|
+
const registrationPath = path16.join(registrationsRoot, entry.name);
|
|
8111
9113
|
if (!isPathWithinRoot(registrationPath, registrationsRoot)) continue;
|
|
8112
9114
|
let gitdirPath;
|
|
8113
9115
|
try {
|
|
8114
|
-
gitdirPath = (await import_fs10.promises.readFile(
|
|
9116
|
+
gitdirPath = (await import_fs10.promises.readFile(path16.join(registrationPath, "gitdir"), "utf8")).trim();
|
|
8115
9117
|
} catch {
|
|
8116
9118
|
continue;
|
|
8117
9119
|
}
|
|
8118
|
-
const resolvedGitdirPath =
|
|
8119
|
-
if (canonicalizePathForComparison(
|
|
9120
|
+
const resolvedGitdirPath = path16.isAbsolute(gitdirPath) ? gitdirPath : path16.resolve(registrationPath, gitdirPath);
|
|
9121
|
+
if (canonicalizePathForComparison(path16.dirname(resolvedGitdirPath)) !== target) continue;
|
|
8120
9122
|
await import_fs10.promises.rm(registrationPath, { recursive: true, force: true });
|
|
8121
9123
|
return true;
|
|
8122
9124
|
}
|
|
@@ -8134,7 +9136,7 @@ async function removeWorktree(projectRoot, worktreePath) {
|
|
|
8134
9136
|
registered = await isWorktreeRegistered(projectRoot, worktreePath);
|
|
8135
9137
|
} catch (error) {
|
|
8136
9138
|
errors.push(asError(error));
|
|
8137
|
-
throw new AggregateError(errors, `Could not verify temporary worktree deregistration; preserved ${
|
|
9139
|
+
throw new AggregateError(errors, `Could not verify temporary worktree deregistration; preserved ${path16.dirname(worktreePath)}`);
|
|
8138
9140
|
}
|
|
8139
9141
|
if (registered) {
|
|
8140
9142
|
try {
|
|
@@ -8150,7 +9152,7 @@ async function removeWorktree(projectRoot, worktreePath) {
|
|
|
8150
9152
|
registered = await isWorktreeRegistered(projectRoot, worktreePath);
|
|
8151
9153
|
} catch (error) {
|
|
8152
9154
|
errors.push(asError(error));
|
|
8153
|
-
throw new AggregateError(errors, `Could not verify temporary worktree deregistration; preserved ${
|
|
9155
|
+
throw new AggregateError(errors, `Could not verify temporary worktree deregistration; preserved ${path16.dirname(worktreePath)}`);
|
|
8154
9156
|
}
|
|
8155
9157
|
}
|
|
8156
9158
|
if (registered && !await pathExists(worktreePath)) {
|
|
@@ -8163,13 +9165,13 @@ async function removeWorktree(projectRoot, worktreePath) {
|
|
|
8163
9165
|
}
|
|
8164
9166
|
if (registered) {
|
|
8165
9167
|
errors.push(new Error(`Temporary worktree remains registered: ${worktreePath}`));
|
|
8166
|
-
throw new AggregateError(errors, `Failed to deregister temporary worktree; preserved ${
|
|
9168
|
+
throw new AggregateError(errors, `Failed to deregister temporary worktree; preserved ${path16.dirname(worktreePath)}`);
|
|
8167
9169
|
}
|
|
8168
9170
|
try {
|
|
8169
|
-
await import_fs10.promises.rm(
|
|
9171
|
+
await import_fs10.promises.rm(path16.dirname(worktreePath), { recursive: true, force: true });
|
|
8170
9172
|
} catch (error) {
|
|
8171
9173
|
errors.push(asError(error));
|
|
8172
|
-
throw new AggregateError(errors, `Deregistered the temporary worktree but could not remove ${
|
|
9174
|
+
throw new AggregateError(errors, `Deregistered the temporary worktree but could not remove ${path16.dirname(worktreePath)}`);
|
|
8173
9175
|
}
|
|
8174
9176
|
}
|
|
8175
9177
|
async function cleanupTemporaryWorktree(projectRoot, worktreePath, temporaryRoot) {
|
|
@@ -8205,9 +9207,9 @@ async function withMaterializedBranch(request, callback) {
|
|
|
8205
9207
|
`Git ref ${JSON.stringify(request.ref ?? request.branch)} is not available locally. For an unfetched branch, pass a remote-qualified name such as origin/feature.`
|
|
8206
9208
|
);
|
|
8207
9209
|
}
|
|
8208
|
-
const temporaryRoot = await import_fs10.promises.mkdtemp(
|
|
8209
|
-
const worktreePath =
|
|
8210
|
-
const hooksPath =
|
|
9210
|
+
const temporaryRoot = await import_fs10.promises.mkdtemp(path16.join(os7.tmpdir(), "codebase-index-branch-"));
|
|
9211
|
+
const worktreePath = path16.join(temporaryRoot, "worktree");
|
|
9212
|
+
const hooksPath = path16.join(temporaryRoot, "hooks");
|
|
8211
9213
|
await import_fs10.promises.mkdir(hooksPath);
|
|
8212
9214
|
const info = {
|
|
8213
9215
|
branch: request.branch,
|
|
@@ -8259,7 +9261,7 @@ async function withMaterializedBranch(request, callback) {
|
|
|
8259
9261
|
// src/tools/changed-files.ts
|
|
8260
9262
|
var import_child_process2 = require("child_process");
|
|
8261
9263
|
var import_fs11 = require("fs");
|
|
8262
|
-
var
|
|
9264
|
+
var path17 = __toESM(require("path"), 1);
|
|
8263
9265
|
var import_util2 = require("util");
|
|
8264
9266
|
var execFileAsync2 = (0, import_util2.promisify)(import_child_process2.execFile);
|
|
8265
9267
|
var GH_PR_VIEW_FIELDS = [
|
|
@@ -8401,7 +9403,7 @@ function getHeadRepositoryIdentity(data, host) {
|
|
|
8401
9403
|
return `${host}/${owner.toLowerCase()}/${repository.replace(/\.git$/i, "").toLowerCase()}`;
|
|
8402
9404
|
}
|
|
8403
9405
|
function getLocalRepositoryIdentity(projectRoot) {
|
|
8404
|
-
let canonicalRoot =
|
|
9406
|
+
let canonicalRoot = path17.resolve(projectRoot);
|
|
8405
9407
|
try {
|
|
8406
9408
|
canonicalRoot = import_fs11.realpathSync.native(canonicalRoot);
|
|
8407
9409
|
} catch {
|
|
@@ -8462,17 +9464,17 @@ async function getMergeBase(projectRoot, baseCommit, headCommit) {
|
|
|
8462
9464
|
return commit;
|
|
8463
9465
|
}
|
|
8464
9466
|
function normalizeFiles(rawFiles, projectRoot) {
|
|
8465
|
-
const root =
|
|
9467
|
+
const root = path17.resolve(projectRoot);
|
|
8466
9468
|
const seen = /* @__PURE__ */ new Set();
|
|
8467
9469
|
const result = [];
|
|
8468
9470
|
for (const raw of rawFiles) {
|
|
8469
9471
|
if (raw.length === 0) continue;
|
|
8470
|
-
const absolute =
|
|
8471
|
-
const relative14 =
|
|
8472
|
-
if (
|
|
9472
|
+
const absolute = path17.resolve(root, raw);
|
|
9473
|
+
const relative14 = path17.relative(root, absolute);
|
|
9474
|
+
if (path17.isAbsolute(raw) || relative14 === ".." || relative14.startsWith(`..${path17.sep}`) || path17.isAbsolute(relative14)) {
|
|
8473
9475
|
throw new Error(`Changed file escapes the project root: ${JSON.stringify(raw)}`);
|
|
8474
9476
|
}
|
|
8475
|
-
const cleaned = relative14.startsWith(`.${
|
|
9477
|
+
const cleaned = relative14.startsWith(`.${path17.sep}`) ? relative14.slice(2) : relative14;
|
|
8476
9478
|
if (!seen.has(cleaned)) {
|
|
8477
9479
|
seen.add(cleaned);
|
|
8478
9480
|
result.push(cleaned);
|
|
@@ -8483,7 +9485,7 @@ function normalizeFiles(rawFiles, projectRoot) {
|
|
|
8483
9485
|
|
|
8484
9486
|
// src/indexer/git-blame.ts
|
|
8485
9487
|
var import_child_process3 = require("child_process");
|
|
8486
|
-
var
|
|
9488
|
+
var path18 = __toESM(require("path"), 1);
|
|
8487
9489
|
var import_util3 = require("util");
|
|
8488
9490
|
var execFileAsync3 = (0, import_util3.promisify)(import_child_process3.execFile);
|
|
8489
9491
|
function parseGitBlamePorcelain(output) {
|
|
@@ -8521,7 +9523,7 @@ function parseGitBlamePorcelain(output) {
|
|
|
8521
9523
|
return Array.from(commits.values()).filter((commit) => commit.lines > 0).sort((a, b) => b.lines - a.lines || b.committedAt - a.committedAt)[0];
|
|
8522
9524
|
}
|
|
8523
9525
|
async function getChunkGitBlame(projectRoot, filePath, startLine, endLine) {
|
|
8524
|
-
const relativePath =
|
|
9526
|
+
const relativePath = path18.relative(projectRoot, filePath);
|
|
8525
9527
|
try {
|
|
8526
9528
|
const { stdout } = await execFileAsync3(
|
|
8527
9529
|
"git",
|
|
@@ -8853,6 +9855,9 @@ var CALL_GRAPH_SYMBOL_CHUNK_TYPES = /* @__PURE__ */ new Set([
|
|
|
8853
9855
|
"enum_declaration",
|
|
8854
9856
|
"function_definition",
|
|
8855
9857
|
"class_definition",
|
|
9858
|
+
// Ruby module/class symbols that are declaration-bearing and navigable.
|
|
9859
|
+
"class",
|
|
9860
|
+
"module",
|
|
8856
9861
|
"class_specifier",
|
|
8857
9862
|
"struct_specifier",
|
|
8858
9863
|
"namespace_definition",
|
|
@@ -9097,8 +10102,8 @@ function pathSegmentsForAffinityMatch(filePath) {
|
|
|
9097
10102
|
if (segments.length === 0) {
|
|
9098
10103
|
return [];
|
|
9099
10104
|
}
|
|
9100
|
-
const
|
|
9101
|
-
const basenameWithoutExt =
|
|
10105
|
+
const basename10 = segments[segments.length - 1] ?? "";
|
|
10106
|
+
const basenameWithoutExt = basename10.replace(/\.[^/.]+$/u, "");
|
|
9102
10107
|
const normalizedSegments = segments.map((segment) => segment.toLowerCase());
|
|
9103
10108
|
return Array.from(/* @__PURE__ */ new Set([
|
|
9104
10109
|
...normalizedSegments,
|
|
@@ -9407,8 +10412,8 @@ function hasAllEmbeddingParts(parts, expectedPartCount) {
|
|
|
9407
10412
|
|
|
9408
10413
|
// src/indexer/failed-state-persistence.ts
|
|
9409
10414
|
var fs2 = __toESM(require("fs"), 1);
|
|
9410
|
-
var
|
|
9411
|
-
var
|
|
10415
|
+
var import_node_crypto2 = require("crypto");
|
|
10416
|
+
var path19 = __toESM(require("path"), 1);
|
|
9412
10417
|
var import_node_string_decoder = require("string_decoder");
|
|
9413
10418
|
var CURRENT_FAILED_BATCH_VERSION = 1;
|
|
9414
10419
|
var DEFAULT_MALFORMED_LINE_ACTION = "skip";
|
|
@@ -9426,7 +10431,7 @@ function* readFailedBatchRecords(filePath, options = {}) {
|
|
|
9426
10431
|
function createFailedBatchWriter(targetPath) {
|
|
9427
10432
|
const temporaryPath = createTemporaryPath(targetPath);
|
|
9428
10433
|
let finalized = false;
|
|
9429
|
-
fs2.mkdirSync(
|
|
10434
|
+
fs2.mkdirSync(path19.dirname(targetPath), { recursive: true });
|
|
9430
10435
|
fs2.closeSync(fs2.openSync(temporaryPath, "w"));
|
|
9431
10436
|
const write = (record) => {
|
|
9432
10437
|
if (finalized) {
|
|
@@ -9445,7 +10450,7 @@ function createFailedBatchWriter(targetPath) {
|
|
|
9445
10450
|
if (lines.length === 0) {
|
|
9446
10451
|
return;
|
|
9447
10452
|
}
|
|
9448
|
-
fs2.mkdirSync(
|
|
10453
|
+
fs2.mkdirSync(path19.dirname(targetPath), { recursive: true });
|
|
9449
10454
|
fs2.appendFileSync(temporaryPath, `${lines.join("\n")}
|
|
9450
10455
|
`, "utf-8");
|
|
9451
10456
|
};
|
|
@@ -9453,7 +10458,7 @@ function createFailedBatchWriter(targetPath) {
|
|
|
9453
10458
|
if (finalized) {
|
|
9454
10459
|
return;
|
|
9455
10460
|
}
|
|
9456
|
-
fs2.mkdirSync(
|
|
10461
|
+
fs2.mkdirSync(path19.dirname(targetPath), { recursive: true });
|
|
9457
10462
|
fs2.renameSync(temporaryPath, targetPath);
|
|
9458
10463
|
finalized = true;
|
|
9459
10464
|
};
|
|
@@ -9599,10 +10604,10 @@ function stripLeadingBomAndWhitespace(value) {
|
|
|
9599
10604
|
return result;
|
|
9600
10605
|
}
|
|
9601
10606
|
function createTemporaryPath(targetPath) {
|
|
9602
|
-
const randomId = (0,
|
|
9603
|
-
const targetDir =
|
|
9604
|
-
const baseName =
|
|
9605
|
-
return
|
|
10607
|
+
const randomId = (0, import_node_crypto2.createHash)("sha1").update(`${Date.now()}:${(0, import_node_crypto2.randomBytes)(8).toString("hex")}`).digest("hex");
|
|
10608
|
+
const targetDir = path19.dirname(targetPath);
|
|
10609
|
+
const baseName = path19.basename(targetPath);
|
|
10610
|
+
return path19.join(targetDir, `.${baseName}.${randomId}.tmp`);
|
|
9606
10611
|
}
|
|
9607
10612
|
function handleMalformedLine(filePath, lineNumber, line, error, options) {
|
|
9608
10613
|
const action = options.malformedLineAction ?? DEFAULT_MALFORMED_LINE_ACTION;
|
|
@@ -9848,9 +10853,9 @@ var SWIFT_PARSER_VERSION = "1";
|
|
|
9848
10853
|
var METAL_PARSER_VERSION = "1";
|
|
9849
10854
|
var SYMBOL_EXTRACTOR_VERSION = "1";
|
|
9850
10855
|
function isPathWithinRoot2(filePath, rootPath) {
|
|
9851
|
-
const normalizedFilePath =
|
|
9852
|
-
const normalizedRoot =
|
|
9853
|
-
return normalizedFilePath === normalizedRoot || normalizedFilePath.startsWith(`${normalizedRoot}${
|
|
10856
|
+
const normalizedFilePath = path20.resolve(filePath);
|
|
10857
|
+
const normalizedRoot = path20.resolve(rootPath);
|
|
10858
|
+
return normalizedFilePath === normalizedRoot || normalizedFilePath.startsWith(`${normalizedRoot}${path20.sep}`);
|
|
9854
10859
|
}
|
|
9855
10860
|
function promoteIdentifierMatches(query, combined, semanticCandidates, keywordCandidates, database, branchChunkIds, prioritizeSourcePaths = classifyQueryIntentRaw(query) === "source") {
|
|
9856
10861
|
if (combined.length === 0) {
|
|
@@ -10181,10 +11186,10 @@ function matchesHardSearchFilters(candidate, options, projectRoot) {
|
|
|
10181
11186
|
}
|
|
10182
11187
|
if (options?.directory) {
|
|
10183
11188
|
const candidatePath = canonicalizePathForComparison(
|
|
10184
|
-
|
|
11189
|
+
path20.resolve(projectRoot, candidate.metadata.filePath.replace(/\\/g, path20.sep))
|
|
10185
11190
|
);
|
|
10186
11191
|
const directoryPath = canonicalizePathForComparison(
|
|
10187
|
-
|
|
11192
|
+
path20.resolve(projectRoot, options.directory.trim().replace(/\\/g, path20.sep))
|
|
10188
11193
|
);
|
|
10189
11194
|
if (!isPathWithinRoot2(candidatePath, directoryPath)) return false;
|
|
10190
11195
|
}
|
|
@@ -10297,26 +11302,37 @@ var Indexer = class _Indexer {
|
|
|
10297
11302
|
return this.indexPathOverride ?? resolveProjectIndexPath(this.projectRoot, this.config.scope, this.host);
|
|
10298
11303
|
}
|
|
10299
11304
|
toCanonicalFilePath(filePath) {
|
|
10300
|
-
if (!
|
|
11305
|
+
if (!path20.isAbsolute(filePath)) {
|
|
10301
11306
|
return this.resolveStoredFilePath(filePath, this.projectRoot);
|
|
10302
11307
|
}
|
|
10303
|
-
if (
|
|
11308
|
+
if (path20.resolve(this.materializedProjectRoot) === path20.resolve(this.projectRoot) || !isPathWithinRoot2(filePath, this.materializedProjectRoot)) {
|
|
10304
11309
|
return filePath;
|
|
10305
11310
|
}
|
|
10306
|
-
return
|
|
11311
|
+
return path20.resolve(this.projectRoot, path20.relative(this.materializedProjectRoot, filePath));
|
|
10307
11312
|
}
|
|
10308
11313
|
toStoredFilePath(filePath) {
|
|
10309
11314
|
const canonicalFilePath = this.toCanonicalFilePath(filePath);
|
|
10310
11315
|
if (this.config.scope !== "project" || !isPathWithinRoot2(canonicalFilePath, this.projectRoot)) {
|
|
10311
11316
|
return canonicalFilePath;
|
|
10312
11317
|
}
|
|
10313
|
-
return
|
|
11318
|
+
return path20.relative(this.projectRoot, canonicalFilePath).split(path20.sep).join("/");
|
|
11319
|
+
}
|
|
11320
|
+
isStoredPathExcluded(storedPath) {
|
|
11321
|
+
let matchPath = storedPath.split(path20.sep).join("/");
|
|
11322
|
+
if (path20.isAbsolute(storedPath)) {
|
|
11323
|
+
const relativePath = path20.relative(this.projectRoot, storedPath).split(path20.sep).join("/");
|
|
11324
|
+
if (relativePath.startsWith("..") || path20.isAbsolute(relativePath)) {
|
|
11325
|
+
return false;
|
|
11326
|
+
}
|
|
11327
|
+
matchPath = relativePath;
|
|
11328
|
+
}
|
|
11329
|
+
return isExcludedByPatterns(matchPath, this.config.exclude);
|
|
10314
11330
|
}
|
|
10315
11331
|
resolveStoredFilePath(filePath, rootPath = this.projectRoot) {
|
|
10316
|
-
if (
|
|
11332
|
+
if (path20.isAbsolute(filePath)) {
|
|
10317
11333
|
return filePath;
|
|
10318
11334
|
}
|
|
10319
|
-
const resolvedPath =
|
|
11335
|
+
const resolvedPath = path20.resolve(rootPath, ...filePath.split("/"));
|
|
10320
11336
|
if (!isPathWithinRoot2(resolvedPath, rootPath)) {
|
|
10321
11337
|
throw new Error(`Stored project path escapes project root: ${JSON.stringify(filePath)}`);
|
|
10322
11338
|
}
|
|
@@ -10340,7 +11356,7 @@ var Indexer = class _Indexer {
|
|
|
10340
11356
|
}
|
|
10341
11357
|
toMaterializedFilePath(filePath) {
|
|
10342
11358
|
const storedFilePath = this.toStoredFilePath(filePath);
|
|
10343
|
-
if (
|
|
11359
|
+
if (path20.isAbsolute(storedFilePath)) {
|
|
10344
11360
|
return storedFilePath;
|
|
10345
11361
|
}
|
|
10346
11362
|
return this.resolveStoredFilePath(storedFilePath, this.materializedProjectRoot);
|
|
@@ -10357,10 +11373,10 @@ var Indexer = class _Indexer {
|
|
|
10357
11373
|
}
|
|
10358
11374
|
getRuntimeArtifactPath(fileName) {
|
|
10359
11375
|
const namespace = this.getRuntimeArtifactNamespace();
|
|
10360
|
-
if (!namespace) return
|
|
10361
|
-
const extension =
|
|
11376
|
+
if (!namespace) return path20.join(this.indexPath, fileName);
|
|
11377
|
+
const extension = path20.extname(fileName);
|
|
10362
11378
|
const baseName = fileName.slice(0, fileName.length - extension.length);
|
|
10363
|
-
return
|
|
11379
|
+
return path20.join(this.indexPath, `${baseName}.${namespace}${extension}`);
|
|
10364
11380
|
}
|
|
10365
11381
|
refreshRuntimeArtifactPaths() {
|
|
10366
11382
|
this.fileHashCachePath = this.getRuntimeArtifactPath("file-hashes.json");
|
|
@@ -10373,14 +11389,14 @@ var Indexer = class _Indexer {
|
|
|
10373
11389
|
getMaterializedKnowledgeBases() {
|
|
10374
11390
|
const canonicalProjectRoot = this.getCanonicalPath(this.projectRoot);
|
|
10375
11391
|
return this.config.knowledgeBases.map((knowledgeBase) => {
|
|
10376
|
-
const configuredPath =
|
|
11392
|
+
const configuredPath = path20.isAbsolute(knowledgeBase) ? knowledgeBase : path20.resolve(this.projectRoot, knowledgeBase);
|
|
10377
11393
|
const canonicalPath = this.getCanonicalPath(configuredPath);
|
|
10378
11394
|
if (!isPathWithinRoot2(canonicalPath, canonicalProjectRoot)) {
|
|
10379
11395
|
return canonicalPath;
|
|
10380
11396
|
}
|
|
10381
|
-
return
|
|
11397
|
+
return path20.resolve(
|
|
10382
11398
|
this.materializedProjectRoot,
|
|
10383
|
-
|
|
11399
|
+
path20.relative(canonicalProjectRoot, canonicalPath)
|
|
10384
11400
|
);
|
|
10385
11401
|
});
|
|
10386
11402
|
}
|
|
@@ -10388,7 +11404,7 @@ var Indexer = class _Indexer {
|
|
|
10388
11404
|
try {
|
|
10389
11405
|
return canonicalizePathForComparison(targetPath);
|
|
10390
11406
|
} catch {
|
|
10391
|
-
return
|
|
11407
|
+
return path20.resolve(targetPath);
|
|
10392
11408
|
}
|
|
10393
11409
|
}
|
|
10394
11410
|
getProjectIdentityHash(projectRoot) {
|
|
@@ -10514,7 +11530,7 @@ var Indexer = class _Indexer {
|
|
|
10514
11530
|
atomicWriteSync(targetPath, data) {
|
|
10515
11531
|
const lease = this.requireActiveLease();
|
|
10516
11532
|
const tempPath = createLeaseTemporaryPath(targetPath, lease.owner, "tmp");
|
|
10517
|
-
(0, import_fs12.mkdirSync)(
|
|
11533
|
+
(0, import_fs12.mkdirSync)(path20.dirname(targetPath), { recursive: true });
|
|
10518
11534
|
try {
|
|
10519
11535
|
(0, import_fs12.writeFileSync)(tempPath, data);
|
|
10520
11536
|
(0, import_fs12.renameSync)(tempPath, targetPath);
|
|
@@ -10524,14 +11540,14 @@ var Indexer = class _Indexer {
|
|
|
10524
11540
|
}
|
|
10525
11541
|
saveInvertedIndex(invertedIndex) {
|
|
10526
11542
|
this.atomicWriteSync(
|
|
10527
|
-
|
|
11543
|
+
path20.join(this.indexPath, "inverted-index.json"),
|
|
10528
11544
|
invertedIndex.serialize()
|
|
10529
11545
|
);
|
|
10530
11546
|
}
|
|
10531
11547
|
getScopedRoots(projectRoot = this.projectRoot) {
|
|
10532
11548
|
const roots = /* @__PURE__ */ new Set([this.getCanonicalPath(projectRoot)]);
|
|
10533
11549
|
for (const kbRoot of this.config.knowledgeBases) {
|
|
10534
|
-
roots.add(this.getCanonicalPath(
|
|
11550
|
+
roots.add(this.getCanonicalPath(path20.resolve(projectRoot, kbRoot)));
|
|
10535
11551
|
}
|
|
10536
11552
|
return Array.from(roots);
|
|
10537
11553
|
}
|
|
@@ -10948,7 +11964,7 @@ var Indexer = class _Indexer {
|
|
|
10948
11964
|
return configuredProviderInfo !== null && recovery.embeddingProvider === configuredProviderInfo.provider && recovery.embeddingModel === configuredProviderInfo.modelInfo.model && recovery.embeddingDimensions === configuredProviderInfo.modelInfo.dimensions && recovery.embeddingStrategyVersion === EMBEDDING_STRATEGY_VERSION;
|
|
10949
11965
|
}
|
|
10950
11966
|
hasUnknownLegacyForceIndexClear(owner) {
|
|
10951
|
-
return owner.operation === "force-index" && owner.clearRecovery === void 0 && owner.recoveryProtocolVersion !== 1 && (0, import_fs12.existsSync)(
|
|
11967
|
+
return owner.operation === "force-index" && owner.clearRecovery === void 0 && owner.recoveryProtocolVersion !== 1 && (0, import_fs12.existsSync)(path20.join(this.indexPath, "force-index-phase"));
|
|
10952
11968
|
}
|
|
10953
11969
|
async recoverFromInterruptedIndexingUnlocked(owners) {
|
|
10954
11970
|
for (const owner of owners) {
|
|
@@ -11336,7 +12352,7 @@ var Indexer = class _Indexer {
|
|
|
11336
12352
|
await options.queue.onSizeLessThan(Math.max(1, options.providerRateLimits.concurrency));
|
|
11337
12353
|
const task = options.queue.add(async () => {
|
|
11338
12354
|
if (options.rateLimitState.backoffMs > 0) {
|
|
11339
|
-
await new Promise((
|
|
12355
|
+
await new Promise((resolve18) => setTimeout(resolve18, options.rateLimitState.backoffMs));
|
|
11340
12356
|
}
|
|
11341
12357
|
try {
|
|
11342
12358
|
const embeddingResult = await pRetry(
|
|
@@ -11755,12 +12771,12 @@ var Indexer = class _Indexer {
|
|
|
11755
12771
|
}
|
|
11756
12772
|
}
|
|
11757
12773
|
captureReaderArtifactFingerprint() {
|
|
11758
|
-
const storePath =
|
|
12774
|
+
const storePath = path20.join(this.indexPath, "vectors");
|
|
11759
12775
|
return {
|
|
11760
12776
|
vectors: `${this.getReaderFileFingerprint(storePath)}|${this.getReaderFileFingerprint(`${storePath}.meta.json`)}`,
|
|
11761
|
-
keyword: this.getReaderFileFingerprint(
|
|
11762
|
-
database: this.getReaderFileFingerprint(
|
|
11763
|
-
databaseIdentity: this.getReaderFileFingerprint(
|
|
12777
|
+
keyword: this.getReaderFileFingerprint(path20.join(this.indexPath, "inverted-index.json")),
|
|
12778
|
+
database: this.getReaderFileFingerprint(path20.join(this.indexPath, "codebase.db")),
|
|
12779
|
+
databaseIdentity: this.getReaderFileFingerprint(path20.join(this.indexPath, "codebase.db"), true)
|
|
11764
12780
|
};
|
|
11765
12781
|
}
|
|
11766
12782
|
refreshReaderArtifacts() {
|
|
@@ -11785,10 +12801,10 @@ var Indexer = class _Indexer {
|
|
|
11785
12801
|
issues.set(component, this.createReadIssue(component, message));
|
|
11786
12802
|
this.readerArtifactRetryAfter.set(component, Date.now() + READER_ARTIFACT_RETRY_INTERVAL_MS);
|
|
11787
12803
|
};
|
|
11788
|
-
const storePath =
|
|
12804
|
+
const storePath = path20.join(this.indexPath, "vectors");
|
|
11789
12805
|
const vectorMetadataPath = `${storePath}.meta.json`;
|
|
11790
|
-
const invertedIndexPath =
|
|
11791
|
-
const dbPath =
|
|
12806
|
+
const invertedIndexPath = path20.join(this.indexPath, "inverted-index.json");
|
|
12807
|
+
const dbPath = path20.join(this.indexPath, "codebase.db");
|
|
11792
12808
|
if (vectorsChanged || retryDue("vectors")) {
|
|
11793
12809
|
const vectorStoreExists = (0, import_fs12.existsSync)(storePath);
|
|
11794
12810
|
const vectorMetadataExists = (0, import_fs12.existsSync)(vectorMetadataPath);
|
|
@@ -11904,10 +12920,10 @@ var Indexer = class _Indexer {
|
|
|
11904
12920
|
});
|
|
11905
12921
|
this.provider = createEmbeddingProvider(this.configuredProviderInfo);
|
|
11906
12922
|
const dimensions = this.configuredProviderInfo.modelInfo.dimensions;
|
|
11907
|
-
const storePath =
|
|
12923
|
+
const storePath = path20.join(this.indexPath, "vectors");
|
|
11908
12924
|
const vectorMetadataPath = `${storePath}.meta.json`;
|
|
11909
|
-
const invertedIndexPath =
|
|
11910
|
-
const dbPath =
|
|
12925
|
+
const invertedIndexPath = path20.join(this.indexPath, "inverted-index.json");
|
|
12926
|
+
const dbPath = path20.join(this.indexPath, "codebase.db");
|
|
11911
12927
|
let dbIsNew = !(0, import_fs12.existsSync)(dbPath);
|
|
11912
12928
|
const readerArtifactFingerprint = mode === "reader" ? this.captureReaderArtifactFingerprint() : null;
|
|
11913
12929
|
if (mode === "writer") {
|
|
@@ -12085,7 +13101,7 @@ var Indexer = class _Indexer {
|
|
|
12085
13101
|
if (await this.tryResetCorruptedIndex("running automatic orphan garbage collection", error)) {
|
|
12086
13102
|
return {
|
|
12087
13103
|
resetCorruptedIndex: true,
|
|
12088
|
-
warning: this.getCorruptedIndexWarning(
|
|
13104
|
+
warning: this.getCorruptedIndexWarning(path20.join(this.indexPath, "codebase.db"))
|
|
12089
13105
|
};
|
|
12090
13106
|
}
|
|
12091
13107
|
throw error;
|
|
@@ -12100,7 +13116,7 @@ var Indexer = class _Indexer {
|
|
|
12100
13116
|
return;
|
|
12101
13117
|
}
|
|
12102
13118
|
const retainedEntries = store.getAllMetadata().filter(({ key }) => !excludedSet.has(key));
|
|
12103
|
-
const storeBasePath =
|
|
13119
|
+
const storeBasePath = path20.join(this.indexPath, "vectors");
|
|
12104
13120
|
const storeIndexPath = storeBasePath;
|
|
12105
13121
|
const storeMetadataPath = `${storeBasePath}.meta.json`;
|
|
12106
13122
|
const lease = this.requireActiveLease();
|
|
@@ -12187,7 +13203,7 @@ var Indexer = class _Indexer {
|
|
|
12187
13203
|
const names = await import_fs12.promises.readdir(this.indexPath);
|
|
12188
13204
|
const runtimeStatePattern = /^(?:file-hashes|failed-batches)(?:\.[a-f0-9]{16})?\.json$/;
|
|
12189
13205
|
await Promise.all(
|
|
12190
|
-
names.filter((name) => runtimeStatePattern.test(name)).map((name) => import_fs12.promises.rm(
|
|
13206
|
+
names.filter((name) => runtimeStatePattern.test(name)).map((name) => import_fs12.promises.rm(path20.join(this.indexPath, name), { force: true }))
|
|
12191
13207
|
);
|
|
12192
13208
|
}
|
|
12193
13209
|
async resetLocalIndexArtifacts() {
|
|
@@ -12203,13 +13219,13 @@ var Indexer = class _Indexer {
|
|
|
12203
13219
|
this.readerArtifactRetryAfter.clear();
|
|
12204
13220
|
this.fileHashCache.clear();
|
|
12205
13221
|
const resetPaths = [
|
|
12206
|
-
|
|
12207
|
-
|
|
12208
|
-
|
|
12209
|
-
|
|
12210
|
-
|
|
12211
|
-
|
|
12212
|
-
|
|
13222
|
+
path20.join(this.indexPath, "codebase.db"),
|
|
13223
|
+
path20.join(this.indexPath, "codebase.db-shm"),
|
|
13224
|
+
path20.join(this.indexPath, "codebase.db-wal"),
|
|
13225
|
+
path20.join(this.indexPath, "vectors"),
|
|
13226
|
+
path20.join(this.indexPath, "vectors.usearch"),
|
|
13227
|
+
path20.join(this.indexPath, "vectors.meta.json"),
|
|
13228
|
+
path20.join(this.indexPath, "inverted-index.json")
|
|
12213
13229
|
];
|
|
12214
13230
|
await Promise.all(resetPaths.map((targetPath) => import_fs12.promises.rm(targetPath, { recursive: true, force: true })));
|
|
12215
13231
|
await this.removeProjectRuntimeStateArtifacts();
|
|
@@ -12219,7 +13235,7 @@ var Indexer = class _Indexer {
|
|
|
12219
13235
|
if (!isSqliteCorruptionError(error)) {
|
|
12220
13236
|
return false;
|
|
12221
13237
|
}
|
|
12222
|
-
const dbPath =
|
|
13238
|
+
const dbPath = path20.join(this.indexPath, "codebase.db");
|
|
12223
13239
|
const warning = this.getCorruptedIndexWarning(dbPath);
|
|
12224
13240
|
const errorMessage = getErrorMessage4(error);
|
|
12225
13241
|
if (this.config.scope === "global") {
|
|
@@ -12453,6 +13469,70 @@ var Indexer = class _Indexer {
|
|
|
12453
13469
|
);
|
|
12454
13470
|
return createCostEstimate(files, configuredProviderInfo);
|
|
12455
13471
|
}
|
|
13472
|
+
// Dry-run counterpart to index()/forceIndex(): parse the real file set and sum
|
|
13473
|
+
// estimateTokens over the embedding text of every indexable chunk, without
|
|
13474
|
+
// calling the embedding provider or writing to the index. Read-only and
|
|
13475
|
+
// lock-free (mirrors estimateCost). The token sum is the exact value "Tokens
|
|
13476
|
+
// used" climbs to for a force index (cache bypassed); for an incremental it is
|
|
13477
|
+
// an upper bound because cached chunks are counted here but not re-embedded.
|
|
13478
|
+
// Used by index_codebase(dryRun:true) to give a stable, monotonic progress
|
|
13479
|
+
// denominator that matches the live "Tokens used" basis.
|
|
13480
|
+
async dryRunCost() {
|
|
13481
|
+
const { configuredProviderInfo } = await this.ensureInitialized();
|
|
13482
|
+
const maxChunkTokens = getSafeEmbeddingChunkTokenLimit(configuredProviderInfo);
|
|
13483
|
+
const includePatterns = [...this.config.include, ...this.config.additionalInclude];
|
|
13484
|
+
const { files } = await collectFiles(
|
|
13485
|
+
this.materializedProjectRoot,
|
|
13486
|
+
includePatterns,
|
|
13487
|
+
this.config.exclude,
|
|
13488
|
+
this.config.indexing.maxFileSize,
|
|
13489
|
+
this.getMaterializedKnowledgeBases(),
|
|
13490
|
+
{ maxDepth: this.config.indexing.maxDepth, maxFilesPerDirectory: this.config.indexing.maxFilesPerDirectory }
|
|
13491
|
+
);
|
|
13492
|
+
let filesCount = 0;
|
|
13493
|
+
let chunksCount = 0;
|
|
13494
|
+
let tokensToEmbed = 0;
|
|
13495
|
+
for (const batch of iterateOrderedFileBatches(files, (f) => f.size, this.fileBatchLimits)) {
|
|
13496
|
+
const loadedFiles = await Promise.all(batch.map(async (f) => {
|
|
13497
|
+
try {
|
|
13498
|
+
return {
|
|
13499
|
+
path: this.toStoredFilePath(f.path),
|
|
13500
|
+
content: await import_fs12.promises.readFile(f.path, "utf-8")
|
|
13501
|
+
};
|
|
13502
|
+
} catch {
|
|
13503
|
+
return null;
|
|
13504
|
+
}
|
|
13505
|
+
}));
|
|
13506
|
+
const readable = loadedFiles.filter(
|
|
13507
|
+
(f) => f !== null
|
|
13508
|
+
);
|
|
13509
|
+
filesCount += readable.length;
|
|
13510
|
+
const contentByPath = new Map(readable.map((f) => [f.path, f.content]));
|
|
13511
|
+
const parsedFiles = parseFiles(readable, this.config.indexing.linesPerChunk);
|
|
13512
|
+
for (const parsed of parsedFiles) {
|
|
13513
|
+
let chunksToProcess = parsed.chunks;
|
|
13514
|
+
if (this.config.indexing.fallbackToTextOnMaxChunks && chunksToProcess.length > this.config.indexing.maxChunksPerFile) {
|
|
13515
|
+
const content = contentByPath.get(parsed.path);
|
|
13516
|
+
if (content !== void 0) {
|
|
13517
|
+
chunksToProcess = parseFileAsText(parsed.path, content, this.config.indexing.linesPerChunk);
|
|
13518
|
+
}
|
|
13519
|
+
}
|
|
13520
|
+
chunksToProcess = selectIndexableChunks(
|
|
13521
|
+
chunksToProcess,
|
|
13522
|
+
this.config.indexing.maxChunksPerFile,
|
|
13523
|
+
this.config.indexing.semanticOnly
|
|
13524
|
+
);
|
|
13525
|
+
for (const chunk of chunksToProcess) {
|
|
13526
|
+
const texts = createEmbeddingTexts(chunk, parsed.path, maxChunkTokens);
|
|
13527
|
+
chunksCount += 1;
|
|
13528
|
+
for (const text of texts) {
|
|
13529
|
+
tokensToEmbed += estimateTokens(text);
|
|
13530
|
+
}
|
|
13531
|
+
}
|
|
13532
|
+
}
|
|
13533
|
+
}
|
|
13534
|
+
return { filesCount, chunksCount, tokensToEmbed };
|
|
13535
|
+
}
|
|
12456
13536
|
async index(onProgress) {
|
|
12457
13537
|
return this.withIndexMutationLease("index", async (recoveredOwners) => {
|
|
12458
13538
|
return this.indexUnlocked(onProgress, recoveredOwners);
|
|
@@ -12542,10 +13622,10 @@ var Indexer = class _Indexer {
|
|
|
12542
13622
|
const reparseCachedMetalFiles = database.getMetadata(metalParserMetadataKey) !== METAL_PARSER_VERSION;
|
|
12543
13623
|
const symbolExtractorMetadataKey = this.getSymbolExtractorVersionMetadataKey();
|
|
12544
13624
|
const refreshCachedSymbols = database.getMetadata(symbolExtractorMetadataKey) !== SYMBOL_EXTRACTOR_VERSION;
|
|
12545
|
-
if (reparseCachedSwiftFiles && Array.from(this.fileHashCache.keys()).some((filePath) =>
|
|
13625
|
+
if (reparseCachedSwiftFiles && Array.from(this.fileHashCache.keys()).some((filePath) => path20.extname(filePath).toLowerCase() === ".swift")) {
|
|
12546
13626
|
this.logger.info("Reindexing cached Swift files for parser support");
|
|
12547
13627
|
}
|
|
12548
|
-
if (reparseCachedMetalFiles && Array.from(this.fileHashCache.keys()).some((filePath) =>
|
|
13628
|
+
if (reparseCachedMetalFiles && Array.from(this.fileHashCache.keys()).some((filePath) => path20.extname(filePath).toLowerCase() === ".metal")) {
|
|
12549
13629
|
this.logger.info("Reindexing cached Metal files for parser support");
|
|
12550
13630
|
}
|
|
12551
13631
|
const includePatterns = [...this.config.include, ...this.config.additionalInclude];
|
|
@@ -12589,8 +13669,8 @@ var Indexer = class _Indexer {
|
|
|
12589
13669
|
const needsCallGraphRefresh = cachedHashMatches && needsCallGraphResolutionMigration && database.getChunksByFile(storedPath).some(
|
|
12590
13670
|
(chunk) => chunk.language === "php" || chunk.language === "c" || chunk.language === "cpp"
|
|
12591
13671
|
);
|
|
12592
|
-
const requiresSwiftParserUpgrade = reparseCachedSwiftFiles &&
|
|
12593
|
-
const requiresMetalParserUpgrade = reparseCachedMetalFiles &&
|
|
13672
|
+
const requiresSwiftParserUpgrade = reparseCachedSwiftFiles && path20.extname(storedPath).toLowerCase() === ".swift";
|
|
13673
|
+
const requiresMetalParserUpgrade = reparseCachedMetalFiles && path20.extname(storedPath).toLowerCase() === ".metal";
|
|
12594
13674
|
const inMigrationScope = forceScopedReembed && scopedRoots !== null && this.isFileInCurrentScope(storedPath, scopedRoots);
|
|
12595
13675
|
if (cachedHashMatches && !inMigrationScope && !needsCallGraphRefresh && !requiresSwiftParserUpgrade && !requiresMetalParserUpgrade && !refreshCachedSymbols) {
|
|
12596
13676
|
unchangedFilePaths.add(storedPath);
|
|
@@ -12649,7 +13729,7 @@ var Indexer = class _Indexer {
|
|
|
12649
13729
|
}
|
|
12650
13730
|
}
|
|
12651
13731
|
}
|
|
12652
|
-
const shouldRetryFailedPath = (filePath) => filePath !== null && currentFileHashes.has(filePath) && unchangedFilePaths.has(filePath);
|
|
13732
|
+
const shouldRetryFailedPath = (filePath) => filePath !== null && !this.isStoredPathExcluded(filePath) && currentFileHashes.has(filePath) && unchangedFilePaths.has(filePath);
|
|
12653
13733
|
const failedProcessing = this.prepareFailedBatchProcessing(scopedRoots, shouldRetryFailedPath);
|
|
12654
13734
|
const maxChunkTokens = getSafeEmbeddingChunkTokenLimit(configuredProviderInfo);
|
|
12655
13735
|
const providerRateLimits = this.getProviderRateLimits(configuredProviderInfo.provider);
|
|
@@ -12753,7 +13833,7 @@ var Indexer = class _Indexer {
|
|
|
12753
13833
|
throw new Error(`Parsed file was not present in its source batch: ${parsed.path}`);
|
|
12754
13834
|
}
|
|
12755
13835
|
if (parsed.chunks.length === 0) {
|
|
12756
|
-
stats.parseFailures.push(
|
|
13836
|
+
stats.parseFailures.push(path20.isAbsolute(parsed.path) ? path20.relative(this.projectRoot, parsed.path) : parsed.path);
|
|
12757
13837
|
}
|
|
12758
13838
|
let chunksToProcess = parsed.chunks;
|
|
12759
13839
|
if (this.config.indexing.fallbackToTextOnMaxChunks && chunksToProcess.length > this.config.indexing.maxChunksPerFile) {
|
|
@@ -13088,7 +14168,7 @@ var Indexer = class _Indexer {
|
|
|
13088
14168
|
previousBranchSymbolIds,
|
|
13089
14169
|
Array.from(allSymbolIds)
|
|
13090
14170
|
);
|
|
13091
|
-
const vectorPath =
|
|
14171
|
+
const vectorPath = path20.join(this.indexPath, "vectors");
|
|
13092
14172
|
const shouldFingerprintLegacyPair = !store.hasFingerprint() && (0, import_fs12.existsSync)(vectorPath) && (0, import_fs12.existsSync)(`${vectorPath}.meta.json`);
|
|
13093
14173
|
if (backfilledBlameMetadata || shouldFingerprintLegacyPair || removedStoredChunks) {
|
|
13094
14174
|
store.save();
|
|
@@ -13947,7 +15027,7 @@ var Indexer = class _Indexer {
|
|
|
13947
15027
|
gcOrphanSymbols: 0,
|
|
13948
15028
|
gcOrphanCallEdges: 0,
|
|
13949
15029
|
resetCorruptedIndex: true,
|
|
13950
|
-
warning: this.getCorruptedIndexWarning(
|
|
15030
|
+
warning: this.getCorruptedIndexWarning(path20.join(this.indexPath, "codebase.db"))
|
|
13951
15031
|
};
|
|
13952
15032
|
}
|
|
13953
15033
|
this.logger.recordGc(removedCount, gcOrphanChunks, gcOrphanEmbeddings);
|
|
@@ -13977,7 +15057,8 @@ var Indexer = class _Indexer {
|
|
|
13977
15057
|
const maxChunkTokens = getSafeEmbeddingChunkTokenLimit(configuredProviderInfo);
|
|
13978
15058
|
const providerRateLimits = this.getProviderRateLimits(configuredProviderInfo.provider);
|
|
13979
15059
|
const roots = this.config.scope === "global" ? this.getScopedRoots() : null;
|
|
13980
|
-
const
|
|
15060
|
+
const shouldProcessFailedPath = (filePath) => filePath === null || !this.isStoredPathExcluded(filePath);
|
|
15061
|
+
const failedProcessing = this.prepareFailedBatchProcessing(roots, shouldProcessFailedPath);
|
|
13981
15062
|
if (failedProcessing.latestById.size === 0) {
|
|
13982
15063
|
this.finalizeFailedBatchWriteState(failedProcessing.state);
|
|
13983
15064
|
return { succeeded: 0, failed: 0, remaining: 0 };
|
|
@@ -13990,7 +15071,7 @@ var Indexer = class _Indexer {
|
|
|
13990
15071
|
const retryableChunks = this.iterateLatestFailedChunks(
|
|
13991
15072
|
failedProcessing.latestById,
|
|
13992
15073
|
roots,
|
|
13993
|
-
|
|
15074
|
+
shouldProcessFailedPath,
|
|
13994
15075
|
maxChunkTokens
|
|
13995
15076
|
);
|
|
13996
15077
|
for (const retryBatch of iterateOrderedFileBatches(
|
|
@@ -14260,9 +15341,9 @@ var Indexer = class _Indexer {
|
|
|
14260
15341
|
this.requireReadableComponents(readIssues, "database");
|
|
14261
15342
|
let shortest = [];
|
|
14262
15343
|
for (const branchKey of this.getBranchCatalogKeys()) {
|
|
14263
|
-
const
|
|
14264
|
-
if (
|
|
14265
|
-
shortest =
|
|
15344
|
+
const path31 = database.findShortestPath(fromName, toName, branchKey, maxDepth);
|
|
15345
|
+
if (path31.length > 0 && (shortest.length === 0 || path31.length < shortest.length)) {
|
|
15346
|
+
shortest = path31;
|
|
14266
15347
|
}
|
|
14267
15348
|
}
|
|
14268
15349
|
return shortest.map((hop) => this.resolveFilePathRecord(hop));
|
|
@@ -14310,13 +15391,13 @@ var Indexer = class _Indexer {
|
|
|
14310
15391
|
}
|
|
14311
15392
|
}
|
|
14312
15393
|
if (!found) continue;
|
|
14313
|
-
const
|
|
15394
|
+
const path31 = [];
|
|
14314
15395
|
let currentSymbolId = toSymbolId;
|
|
14315
15396
|
while (true) {
|
|
14316
15397
|
const symbol = symbolsById.get(currentSymbolId);
|
|
14317
15398
|
if (!symbol) break;
|
|
14318
15399
|
const parent = parentBySymbolId.get(currentSymbolId);
|
|
14319
|
-
|
|
15400
|
+
path31.push({
|
|
14320
15401
|
symbolId: symbol.id,
|
|
14321
15402
|
symbolName: symbol.name,
|
|
14322
15403
|
filePath: symbol.filePath,
|
|
@@ -14326,9 +15407,9 @@ var Indexer = class _Indexer {
|
|
|
14326
15407
|
if (!parent) break;
|
|
14327
15408
|
currentSymbolId = parent.parentId;
|
|
14328
15409
|
}
|
|
14329
|
-
|
|
14330
|
-
if (
|
|
14331
|
-
shortest =
|
|
15410
|
+
path31.reverse();
|
|
15411
|
+
if (path31.length > 0 && (shortest.length === 0 || path31.length < shortest.length)) {
|
|
15412
|
+
shortest = path31;
|
|
14332
15413
|
}
|
|
14333
15414
|
}
|
|
14334
15415
|
return shortest.map((hop) => this.resolveFilePathRecord(hop));
|
|
@@ -14479,7 +15560,7 @@ var Indexer = class _Indexer {
|
|
|
14479
15560
|
);
|
|
14480
15561
|
}
|
|
14481
15562
|
}
|
|
14482
|
-
const toStoredChangedFiles = (filePaths) => filePaths.map((filePath) => this.toStoredFilePath(
|
|
15563
|
+
const toStoredChangedFiles = (filePaths) => filePaths.map((filePath) => this.toStoredFilePath(path20.resolve(this.projectRoot, filePath)));
|
|
14483
15564
|
const storedChangedFiles = toStoredChangedFiles(changedFiles);
|
|
14484
15565
|
const directSymbols = database.getSymbolsForFiles(storedChangedFiles, branchKey);
|
|
14485
15566
|
const directIds = directSymbols.map((s) => s.id);
|
|
@@ -14628,12 +15709,12 @@ var Indexer = class _Indexer {
|
|
|
14628
15709
|
if (meta.filePath) filePaths.add(meta.filePath);
|
|
14629
15710
|
}
|
|
14630
15711
|
const directory = options?.directory?.replace(/\/$/, "");
|
|
14631
|
-
const absoluteDirectoryFilter = directory ?
|
|
15712
|
+
const absoluteDirectoryFilter = directory ? path20.resolve(this.projectRoot, directory) : void 0;
|
|
14632
15713
|
for (const filePath of filePaths) {
|
|
14633
15714
|
if (directory) {
|
|
14634
15715
|
const absoluteFilePath = this.resolveStoredFilePath(filePath);
|
|
14635
15716
|
const matchesRelative = filePath === directory || filePath.startsWith(directory + "/");
|
|
14636
|
-
const matchesProjectRelative = absoluteDirectoryFilter !== void 0 && (absoluteFilePath === absoluteDirectoryFilter || absoluteFilePath.startsWith(absoluteDirectoryFilter +
|
|
15717
|
+
const matchesProjectRelative = absoluteDirectoryFilter !== void 0 && (absoluteFilePath === absoluteDirectoryFilter || absoluteFilePath.startsWith(absoluteDirectoryFilter + path20.sep));
|
|
14637
15718
|
if (!matchesRelative && !matchesProjectRelative) {
|
|
14638
15719
|
continue;
|
|
14639
15720
|
}
|
|
@@ -14750,15 +15831,24 @@ function getOrCreateIndexer(projectRoot, host) {
|
|
|
14750
15831
|
}
|
|
14751
15832
|
const indexer = new Indexer(projectRoot, config, host);
|
|
14752
15833
|
indexerCache.set(key, indexer);
|
|
14753
|
-
configureAutoIndex(projectRoot, host, config, () => getOrCreateIndexer(projectRoot, host)
|
|
15834
|
+
configureAutoIndex(projectRoot, host, config, () => getOrCreateIndexer(projectRoot, host), {
|
|
15835
|
+
preserveManagedWorker: true,
|
|
15836
|
+
synchronizeBackgroundWorker: false
|
|
15837
|
+
});
|
|
14754
15838
|
return indexer;
|
|
14755
15839
|
}
|
|
14756
|
-
function initializeTools(projectRoot, config, host) {
|
|
15840
|
+
function initializeTools(projectRoot, config, host, options = {}) {
|
|
14757
15841
|
defaultProjectRoots.set(host, projectRoot);
|
|
14758
15842
|
const key = getIndexerCacheKey(projectRoot, host);
|
|
15843
|
+
if (options.preserveManagedWorker === true && isBackgroundWorkerManaged(projectRoot, host) && indexerCache.has(key)) {
|
|
15844
|
+
return;
|
|
15845
|
+
}
|
|
14759
15846
|
configCache.set(key, config);
|
|
14760
15847
|
indexerCache.set(key, new Indexer(projectRoot, config, host));
|
|
14761
|
-
configureAutoIndex(projectRoot, host, config, () => getOrCreateIndexer(projectRoot, host)
|
|
15848
|
+
configureAutoIndex(projectRoot, host, config, () => getOrCreateIndexer(projectRoot, host), {
|
|
15849
|
+
preserveManagedWorker: options.preserveManagedWorker,
|
|
15850
|
+
synchronizeBackgroundWorker: false
|
|
15851
|
+
});
|
|
14762
15852
|
}
|
|
14763
15853
|
function getIndexerForProject(projectRoot, host) {
|
|
14764
15854
|
const root = getProjectRoot(projectRoot, host);
|
|
@@ -14772,7 +15862,9 @@ function refreshIndexerForDirectory(projectRoot, host, config = parseConfig(load
|
|
|
14772
15862
|
const key = getIndexerCacheKey(projectRoot, host);
|
|
14773
15863
|
configCache.set(key, config);
|
|
14774
15864
|
indexerCache.set(key, new Indexer(projectRoot, config, host));
|
|
14775
|
-
configureAutoIndex(projectRoot, host, config, () => getOrCreateIndexer(projectRoot, host)
|
|
15865
|
+
configureAutoIndex(projectRoot, host, config, () => getOrCreateIndexer(projectRoot, host), {
|
|
15866
|
+
synchronizeBackgroundWorker: true
|
|
15867
|
+
});
|
|
14776
15868
|
return config;
|
|
14777
15869
|
}
|
|
14778
15870
|
var AutoIndexRetrievalUnavailableError = class extends Error {
|
|
@@ -14799,7 +15891,7 @@ function trimOrUndefined(value) {
|
|
|
14799
15891
|
return normalized || void 0;
|
|
14800
15892
|
}
|
|
14801
15893
|
function normalizeCallGraphPath(value) {
|
|
14802
|
-
let normalized =
|
|
15894
|
+
let normalized = path21.posix.normalize(value.trim().replaceAll("\\", "/"));
|
|
14803
15895
|
if (normalized.startsWith("./")) {
|
|
14804
15896
|
normalized = normalized.slice(2);
|
|
14805
15897
|
}
|
|
@@ -14992,12 +16084,12 @@ async function getCallGraphPath(projectRoot, host, from, to, maxDepth, fromFileP
|
|
|
14992
16084
|
if (fromResolution.status !== "resolved" || toResolution.status !== "resolved") {
|
|
14993
16085
|
return { from: fromResolution, to: toResolution, path: [] };
|
|
14994
16086
|
}
|
|
14995
|
-
const
|
|
16087
|
+
const path31 = await indexer.findCallPathBySymbolIds(
|
|
14996
16088
|
fromResolution.symbolId,
|
|
14997
16089
|
toResolution.symbolId,
|
|
14998
16090
|
maxDepth
|
|
14999
16091
|
);
|
|
15000
|
-
return { from: fromResolution, to: toResolution, path:
|
|
16092
|
+
return { from: fromResolution, to: toResolution, path: path31 };
|
|
15001
16093
|
}
|
|
15002
16094
|
async function runIndexCodebase(projectRoot, host, args, onProgress) {
|
|
15003
16095
|
const root = getProjectRoot(projectRoot, host);
|
|
@@ -15006,6 +16098,9 @@ async function runIndexCodebase(projectRoot, host, args, onProgress) {
|
|
|
15006
16098
|
if (args.estimateOnly) {
|
|
15007
16099
|
return { kind: "estimate", estimate: await indexer.estimateCost() };
|
|
15008
16100
|
}
|
|
16101
|
+
if (args.dryRun) {
|
|
16102
|
+
return { kind: "dryrun", dryrun: await indexer.dryRunCost() };
|
|
16103
|
+
}
|
|
15009
16104
|
const coordinated = runCoordinatedIndex(root, host, args.force ?? false, (progress) => {
|
|
15010
16105
|
if (onProgress) {
|
|
15011
16106
|
void onProgress(formatProgressTitle(progress), {
|
|
@@ -15180,8 +16275,8 @@ async function getIndexLogs(projectRoot, host, args) {
|
|
|
15180
16275
|
function addKnowledgeBase(projectRoot, host, knowledgeBasePath) {
|
|
15181
16276
|
const root = getProjectRoot(projectRoot, host);
|
|
15182
16277
|
const inputPath = knowledgeBasePath.trim();
|
|
15183
|
-
const normalizedPath2 =
|
|
15184
|
-
|
|
16278
|
+
const normalizedPath2 = path21.resolve(
|
|
16279
|
+
path21.isAbsolute(inputPath) ? inputPath : resolveKnowledgeBasePath(inputPath, root)
|
|
15185
16280
|
);
|
|
15186
16281
|
if (!(0, import_fs13.existsSync)(normalizedPath2)) {
|
|
15187
16282
|
return `Error: Directory does not exist: ${normalizedPath2}`;
|
|
@@ -15217,7 +16312,7 @@ function addKnowledgeBase(projectRoot, host, knowledgeBasePath) {
|
|
|
15217
16312
|
}
|
|
15218
16313
|
}
|
|
15219
16314
|
for (const dotDir of sensitiveDotDirs) {
|
|
15220
|
-
const sensitiveDir =
|
|
16315
|
+
const sensitiveDir = path21.join(homeDir, dotDir);
|
|
15221
16316
|
if (sensitiveDir && (realPath === sensitiveDir || realPath.startsWith(`${sensitiveDir}/`))) {
|
|
15222
16317
|
return `Error: Adding sensitive directory as knowledge base is not allowed: ${normalizedPath2}`;
|
|
15223
16318
|
}
|
|
@@ -15280,7 +16375,7 @@ function listKnowledgeBases(projectRoot, host) {
|
|
|
15280
16375
|
}
|
|
15281
16376
|
result += "\n";
|
|
15282
16377
|
}
|
|
15283
|
-
const hasHostConfig = (0, import_fs13.existsSync)(
|
|
16378
|
+
const hasHostConfig = (0, import_fs13.existsSync)(path21.join(root, getHostProjectConfigRelativePath(host)));
|
|
15284
16379
|
if (hasHostConfig) {
|
|
15285
16380
|
result += `
|
|
15286
16381
|
Config sources: 1 file(s).`;
|
|
@@ -15318,7 +16413,7 @@ var import_fs14 = require("fs");
|
|
|
15318
16413
|
|
|
15319
16414
|
// node_modules/chokidar/index.js
|
|
15320
16415
|
var import_node_events = require("events");
|
|
15321
|
-
var
|
|
16416
|
+
var import_node_fs3 = require("fs");
|
|
15322
16417
|
var import_promises3 = require("fs/promises");
|
|
15323
16418
|
var sp2 = __toESM(require("path"), 1);
|
|
15324
16419
|
|
|
@@ -15406,7 +16501,7 @@ var ReaddirpStream = class extends import_node_stream.Readable {
|
|
|
15406
16501
|
this._directoryFilter = normalizeFilter(opts.directoryFilter);
|
|
15407
16502
|
const statMethod = opts.lstat ? import_promises.lstat : import_promises.stat;
|
|
15408
16503
|
if (wantBigintFsStats) {
|
|
15409
|
-
this._stat = (
|
|
16504
|
+
this._stat = (path31) => statMethod(path31, { bigint: true });
|
|
15410
16505
|
} else {
|
|
15411
16506
|
this._stat = statMethod;
|
|
15412
16507
|
}
|
|
@@ -15431,8 +16526,8 @@ var ReaddirpStream = class extends import_node_stream.Readable {
|
|
|
15431
16526
|
const par = this.parent;
|
|
15432
16527
|
const fil = par && par.files;
|
|
15433
16528
|
if (fil && fil.length > 0) {
|
|
15434
|
-
const { path:
|
|
15435
|
-
const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent,
|
|
16529
|
+
const { path: path31, depth } = par;
|
|
16530
|
+
const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path31));
|
|
15436
16531
|
const awaited = await Promise.all(slice);
|
|
15437
16532
|
for (const entry of awaited) {
|
|
15438
16533
|
if (!entry)
|
|
@@ -15472,21 +16567,21 @@ var ReaddirpStream = class extends import_node_stream.Readable {
|
|
|
15472
16567
|
this.reading = false;
|
|
15473
16568
|
}
|
|
15474
16569
|
}
|
|
15475
|
-
async _exploreDir(
|
|
16570
|
+
async _exploreDir(path31, depth) {
|
|
15476
16571
|
let files;
|
|
15477
16572
|
try {
|
|
15478
|
-
files = await (0, import_promises.readdir)(
|
|
16573
|
+
files = await (0, import_promises.readdir)(path31, this._rdOptions);
|
|
15479
16574
|
} catch (error) {
|
|
15480
16575
|
this._onError(error);
|
|
15481
16576
|
}
|
|
15482
|
-
return { files, depth, path:
|
|
16577
|
+
return { files, depth, path: path31 };
|
|
15483
16578
|
}
|
|
15484
|
-
async _formatEntry(dirent,
|
|
16579
|
+
async _formatEntry(dirent, path31) {
|
|
15485
16580
|
let entry;
|
|
15486
|
-
const
|
|
16581
|
+
const basename10 = this._isDirent ? dirent.name : dirent;
|
|
15487
16582
|
try {
|
|
15488
|
-
const fullPath = (0, import_node_path.resolve)((0, import_node_path.join)(
|
|
15489
|
-
entry = { path: (0, import_node_path.relative)(this._root, fullPath), fullPath, basename:
|
|
16583
|
+
const fullPath = (0, import_node_path.resolve)((0, import_node_path.join)(path31, basename10));
|
|
16584
|
+
entry = { path: (0, import_node_path.relative)(this._root, fullPath), fullPath, basename: basename10 };
|
|
15490
16585
|
entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
|
|
15491
16586
|
} catch (err) {
|
|
15492
16587
|
this._onError(err);
|
|
@@ -15556,7 +16651,7 @@ function readdirp(root, options = {}) {
|
|
|
15556
16651
|
}
|
|
15557
16652
|
|
|
15558
16653
|
// node_modules/chokidar/handler.js
|
|
15559
|
-
var
|
|
16654
|
+
var import_node_fs2 = require("fs");
|
|
15560
16655
|
var import_promises2 = require("fs/promises");
|
|
15561
16656
|
var import_node_os = require("os");
|
|
15562
16657
|
var sp = __toESM(require("path"), 1);
|
|
@@ -15885,16 +16980,16 @@ var delFromSet = (main, prop, item) => {
|
|
|
15885
16980
|
};
|
|
15886
16981
|
var isEmptySet = (val) => val instanceof Set ? val.size === 0 : !val;
|
|
15887
16982
|
var FsWatchInstances = /* @__PURE__ */ new Map();
|
|
15888
|
-
function createFsWatchInstance(
|
|
16983
|
+
function createFsWatchInstance(path31, options, listener, errHandler, emitRaw) {
|
|
15889
16984
|
const handleEvent = (rawEvent, evPath) => {
|
|
15890
|
-
listener(
|
|
15891
|
-
emitRaw(rawEvent, evPath, { watchedPath:
|
|
15892
|
-
if (evPath &&
|
|
15893
|
-
fsWatchBroadcast(sp.resolve(
|
|
16985
|
+
listener(path31);
|
|
16986
|
+
emitRaw(rawEvent, evPath, { watchedPath: path31 });
|
|
16987
|
+
if (evPath && path31 !== evPath) {
|
|
16988
|
+
fsWatchBroadcast(sp.resolve(path31, evPath), KEY_LISTENERS, sp.join(path31, evPath));
|
|
15894
16989
|
}
|
|
15895
16990
|
};
|
|
15896
16991
|
try {
|
|
15897
|
-
return (0,
|
|
16992
|
+
return (0, import_node_fs2.watch)(path31, {
|
|
15898
16993
|
persistent: options.persistent
|
|
15899
16994
|
}, handleEvent);
|
|
15900
16995
|
} catch (error) {
|
|
@@ -15910,12 +17005,12 @@ var fsWatchBroadcast = (fullPath, listenerType, val1, val2, val3) => {
|
|
|
15910
17005
|
listener(val1, val2, val3);
|
|
15911
17006
|
});
|
|
15912
17007
|
};
|
|
15913
|
-
var setFsWatchListener = (
|
|
17008
|
+
var setFsWatchListener = (path31, fullPath, options, handlers) => {
|
|
15914
17009
|
const { listener, errHandler, rawEmitter } = handlers;
|
|
15915
17010
|
let cont = FsWatchInstances.get(fullPath);
|
|
15916
17011
|
let watcher;
|
|
15917
17012
|
if (!options.persistent) {
|
|
15918
|
-
watcher = createFsWatchInstance(
|
|
17013
|
+
watcher = createFsWatchInstance(path31, options, listener, errHandler, rawEmitter);
|
|
15919
17014
|
if (!watcher)
|
|
15920
17015
|
return;
|
|
15921
17016
|
return watcher.close.bind(watcher);
|
|
@@ -15926,7 +17021,7 @@ var setFsWatchListener = (path30, fullPath, options, handlers) => {
|
|
|
15926
17021
|
addAndConvert(cont, KEY_RAW, rawEmitter);
|
|
15927
17022
|
} else {
|
|
15928
17023
|
watcher = createFsWatchInstance(
|
|
15929
|
-
|
|
17024
|
+
path31,
|
|
15930
17025
|
options,
|
|
15931
17026
|
fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS),
|
|
15932
17027
|
errHandler,
|
|
@@ -15941,7 +17036,7 @@ var setFsWatchListener = (path30, fullPath, options, handlers) => {
|
|
|
15941
17036
|
cont.watcherUnusable = true;
|
|
15942
17037
|
if (isWindows && error.code === "EPERM") {
|
|
15943
17038
|
try {
|
|
15944
|
-
const fd = await (0, import_promises2.open)(
|
|
17039
|
+
const fd = await (0, import_promises2.open)(path31, "r");
|
|
15945
17040
|
await fd.close();
|
|
15946
17041
|
broadcastErr(error);
|
|
15947
17042
|
} catch (err) {
|
|
@@ -15972,12 +17067,12 @@ var setFsWatchListener = (path30, fullPath, options, handlers) => {
|
|
|
15972
17067
|
};
|
|
15973
17068
|
};
|
|
15974
17069
|
var FsWatchFileInstances = /* @__PURE__ */ new Map();
|
|
15975
|
-
var setFsWatchFileListener = (
|
|
17070
|
+
var setFsWatchFileListener = (path31, fullPath, options, handlers) => {
|
|
15976
17071
|
const { listener, rawEmitter } = handlers;
|
|
15977
17072
|
let cont = FsWatchFileInstances.get(fullPath);
|
|
15978
17073
|
const copts = cont && cont.options;
|
|
15979
17074
|
if (copts && (copts.persistent < options.persistent || copts.interval > options.interval)) {
|
|
15980
|
-
(0,
|
|
17075
|
+
(0, import_node_fs2.unwatchFile)(fullPath);
|
|
15981
17076
|
cont = void 0;
|
|
15982
17077
|
}
|
|
15983
17078
|
if (cont) {
|
|
@@ -15988,13 +17083,13 @@ var setFsWatchFileListener = (path30, fullPath, options, handlers) => {
|
|
|
15988
17083
|
listeners: listener,
|
|
15989
17084
|
rawEmitters: rawEmitter,
|
|
15990
17085
|
options,
|
|
15991
|
-
watcher: (0,
|
|
17086
|
+
watcher: (0, import_node_fs2.watchFile)(fullPath, options, (curr, prev) => {
|
|
15992
17087
|
foreach(cont.rawEmitters, (rawEmitter2) => {
|
|
15993
17088
|
rawEmitter2(EV.CHANGE, fullPath, { curr, prev });
|
|
15994
17089
|
});
|
|
15995
17090
|
const currmtime = curr.mtimeMs;
|
|
15996
17091
|
if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {
|
|
15997
|
-
foreach(cont.listeners, (listener2) => listener2(
|
|
17092
|
+
foreach(cont.listeners, (listener2) => listener2(path31, curr));
|
|
15998
17093
|
}
|
|
15999
17094
|
})
|
|
16000
17095
|
};
|
|
@@ -16005,7 +17100,7 @@ var setFsWatchFileListener = (path30, fullPath, options, handlers) => {
|
|
|
16005
17100
|
delFromSet(cont, KEY_RAW, rawEmitter);
|
|
16006
17101
|
if (isEmptySet(cont.listeners)) {
|
|
16007
17102
|
FsWatchFileInstances.delete(fullPath);
|
|
16008
|
-
(0,
|
|
17103
|
+
(0, import_node_fs2.unwatchFile)(fullPath);
|
|
16009
17104
|
cont.options = cont.watcher = void 0;
|
|
16010
17105
|
Object.freeze(cont);
|
|
16011
17106
|
}
|
|
@@ -16024,13 +17119,13 @@ var NodeFsHandler = class {
|
|
|
16024
17119
|
* @param listener on fs change
|
|
16025
17120
|
* @returns closer for the watcher instance
|
|
16026
17121
|
*/
|
|
16027
|
-
_watchWithNodeFs(
|
|
17122
|
+
_watchWithNodeFs(path31, listener) {
|
|
16028
17123
|
const opts = this.fsw.options;
|
|
16029
|
-
const directory = sp.dirname(
|
|
16030
|
-
const
|
|
17124
|
+
const directory = sp.dirname(path31);
|
|
17125
|
+
const basename10 = sp.basename(path31);
|
|
16031
17126
|
const parent = this.fsw._getWatchedDir(directory);
|
|
16032
|
-
parent.add(
|
|
16033
|
-
const absolutePath = sp.resolve(
|
|
17127
|
+
parent.add(basename10);
|
|
17128
|
+
const absolutePath = sp.resolve(path31);
|
|
16034
17129
|
const options = {
|
|
16035
17130
|
persistent: opts.persistent
|
|
16036
17131
|
};
|
|
@@ -16039,13 +17134,13 @@ var NodeFsHandler = class {
|
|
|
16039
17134
|
let closer;
|
|
16040
17135
|
if (opts.usePolling) {
|
|
16041
17136
|
const enableBin = opts.interval !== opts.binaryInterval;
|
|
16042
|
-
options.interval = enableBin && isBinaryPath(
|
|
16043
|
-
closer = setFsWatchFileListener(
|
|
17137
|
+
options.interval = enableBin && isBinaryPath(basename10) ? opts.binaryInterval : opts.interval;
|
|
17138
|
+
closer = setFsWatchFileListener(path31, absolutePath, options, {
|
|
16044
17139
|
listener,
|
|
16045
17140
|
rawEmitter: this.fsw._emitRaw
|
|
16046
17141
|
});
|
|
16047
17142
|
} else {
|
|
16048
|
-
closer = setFsWatchListener(
|
|
17143
|
+
closer = setFsWatchListener(path31, absolutePath, options, {
|
|
16049
17144
|
listener,
|
|
16050
17145
|
errHandler: this._boundHandleError,
|
|
16051
17146
|
rawEmitter: this.fsw._emitRaw
|
|
@@ -16061,13 +17156,13 @@ var NodeFsHandler = class {
|
|
|
16061
17156
|
if (this.fsw.closed) {
|
|
16062
17157
|
return;
|
|
16063
17158
|
}
|
|
16064
|
-
const
|
|
16065
|
-
const
|
|
16066
|
-
const parent = this.fsw._getWatchedDir(
|
|
17159
|
+
const dirname16 = sp.dirname(file);
|
|
17160
|
+
const basename10 = sp.basename(file);
|
|
17161
|
+
const parent = this.fsw._getWatchedDir(dirname16);
|
|
16067
17162
|
let prevStats = stats;
|
|
16068
|
-
if (parent.has(
|
|
17163
|
+
if (parent.has(basename10))
|
|
16069
17164
|
return;
|
|
16070
|
-
const listener = async (
|
|
17165
|
+
const listener = async (path31, newStats) => {
|
|
16071
17166
|
if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5))
|
|
16072
17167
|
return;
|
|
16073
17168
|
if (!newStats || newStats.mtimeMs === 0) {
|
|
@@ -16081,18 +17176,18 @@ var NodeFsHandler = class {
|
|
|
16081
17176
|
this.fsw._emit(EV.CHANGE, file, newStats2);
|
|
16082
17177
|
}
|
|
16083
17178
|
if ((isMacos || isLinux || isFreeBSD) && prevStats.ino !== newStats2.ino) {
|
|
16084
|
-
this.fsw._closeFile(
|
|
17179
|
+
this.fsw._closeFile(path31);
|
|
16085
17180
|
prevStats = newStats2;
|
|
16086
17181
|
const closer2 = this._watchWithNodeFs(file, listener);
|
|
16087
17182
|
if (closer2)
|
|
16088
|
-
this.fsw._addPathCloser(
|
|
17183
|
+
this.fsw._addPathCloser(path31, closer2);
|
|
16089
17184
|
} else {
|
|
16090
17185
|
prevStats = newStats2;
|
|
16091
17186
|
}
|
|
16092
17187
|
} catch (error) {
|
|
16093
|
-
this.fsw._remove(
|
|
17188
|
+
this.fsw._remove(dirname16, basename10);
|
|
16094
17189
|
}
|
|
16095
|
-
} else if (parent.has(
|
|
17190
|
+
} else if (parent.has(basename10)) {
|
|
16096
17191
|
const at = newStats.atimeMs;
|
|
16097
17192
|
const mt = newStats.mtimeMs;
|
|
16098
17193
|
if (!at || at <= mt || mt !== prevStats.mtimeMs) {
|
|
@@ -16117,7 +17212,7 @@ var NodeFsHandler = class {
|
|
|
16117
17212
|
* @param item basename of this item
|
|
16118
17213
|
* @returns true if no more processing is needed for this entry.
|
|
16119
17214
|
*/
|
|
16120
|
-
async _handleSymlink(entry, directory,
|
|
17215
|
+
async _handleSymlink(entry, directory, path31, item) {
|
|
16121
17216
|
if (this.fsw.closed) {
|
|
16122
17217
|
return;
|
|
16123
17218
|
}
|
|
@@ -16127,7 +17222,7 @@ var NodeFsHandler = class {
|
|
|
16127
17222
|
this.fsw._incrReadyCount();
|
|
16128
17223
|
let linkPath;
|
|
16129
17224
|
try {
|
|
16130
|
-
linkPath = await (0, import_promises2.realpath)(
|
|
17225
|
+
linkPath = await (0, import_promises2.realpath)(path31);
|
|
16131
17226
|
} catch (e) {
|
|
16132
17227
|
this.fsw._emitReady();
|
|
16133
17228
|
return true;
|
|
@@ -16137,12 +17232,12 @@ var NodeFsHandler = class {
|
|
|
16137
17232
|
if (dir.has(item)) {
|
|
16138
17233
|
if (this.fsw._symlinkPaths.get(full) !== linkPath) {
|
|
16139
17234
|
this.fsw._symlinkPaths.set(full, linkPath);
|
|
16140
|
-
this.fsw._emit(EV.CHANGE,
|
|
17235
|
+
this.fsw._emit(EV.CHANGE, path31, entry.stats);
|
|
16141
17236
|
}
|
|
16142
17237
|
} else {
|
|
16143
17238
|
dir.add(item);
|
|
16144
17239
|
this.fsw._symlinkPaths.set(full, linkPath);
|
|
16145
|
-
this.fsw._emit(EV.ADD,
|
|
17240
|
+
this.fsw._emit(EV.ADD, path31, entry.stats);
|
|
16146
17241
|
}
|
|
16147
17242
|
this.fsw._emitReady();
|
|
16148
17243
|
return true;
|
|
@@ -16172,9 +17267,9 @@ var NodeFsHandler = class {
|
|
|
16172
17267
|
return;
|
|
16173
17268
|
}
|
|
16174
17269
|
const item = entry.path;
|
|
16175
|
-
let
|
|
17270
|
+
let path31 = sp.join(directory, item);
|
|
16176
17271
|
current.add(item);
|
|
16177
|
-
if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory,
|
|
17272
|
+
if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path31, item)) {
|
|
16178
17273
|
return;
|
|
16179
17274
|
}
|
|
16180
17275
|
if (this.fsw.closed) {
|
|
@@ -16183,11 +17278,11 @@ var NodeFsHandler = class {
|
|
|
16183
17278
|
}
|
|
16184
17279
|
if (item === target || !target && !previous.has(item)) {
|
|
16185
17280
|
this.fsw._incrReadyCount();
|
|
16186
|
-
|
|
16187
|
-
this._addToNodeFs(
|
|
17281
|
+
path31 = sp.join(dir, sp.relative(dir, path31));
|
|
17282
|
+
this._addToNodeFs(path31, initialAdd, wh, depth + 1);
|
|
16188
17283
|
}
|
|
16189
17284
|
}).on(EV.ERROR, this._boundHandleError);
|
|
16190
|
-
return new Promise((
|
|
17285
|
+
return new Promise((resolve18, reject) => {
|
|
16191
17286
|
if (!stream)
|
|
16192
17287
|
return reject();
|
|
16193
17288
|
stream.once(STR_END, () => {
|
|
@@ -16196,7 +17291,7 @@ var NodeFsHandler = class {
|
|
|
16196
17291
|
return;
|
|
16197
17292
|
}
|
|
16198
17293
|
const wasThrottled = throttler ? throttler.clear() : false;
|
|
16199
|
-
|
|
17294
|
+
resolve18(void 0);
|
|
16200
17295
|
previous.getChildren().filter((item) => {
|
|
16201
17296
|
return item !== directory && !current.has(item);
|
|
16202
17297
|
}).forEach((item) => {
|
|
@@ -16253,13 +17348,13 @@ var NodeFsHandler = class {
|
|
|
16253
17348
|
* @param depth Child path actually targeted for watch
|
|
16254
17349
|
* @param target Child path actually targeted for watch
|
|
16255
17350
|
*/
|
|
16256
|
-
async _addToNodeFs(
|
|
17351
|
+
async _addToNodeFs(path31, initialAdd, priorWh, depth, target) {
|
|
16257
17352
|
const ready = this.fsw._emitReady;
|
|
16258
|
-
if (this.fsw._isIgnored(
|
|
17353
|
+
if (this.fsw._isIgnored(path31) || this.fsw.closed) {
|
|
16259
17354
|
ready();
|
|
16260
17355
|
return false;
|
|
16261
17356
|
}
|
|
16262
|
-
const wh = this.fsw._getWatchHelpers(
|
|
17357
|
+
const wh = this.fsw._getWatchHelpers(path31);
|
|
16263
17358
|
if (priorWh) {
|
|
16264
17359
|
wh.filterPath = (entry) => priorWh.filterPath(entry);
|
|
16265
17360
|
wh.filterDir = (entry) => priorWh.filterDir(entry);
|
|
@@ -16275,8 +17370,8 @@ var NodeFsHandler = class {
|
|
|
16275
17370
|
const follow = this.fsw.options.followSymlinks;
|
|
16276
17371
|
let closer;
|
|
16277
17372
|
if (stats.isDirectory()) {
|
|
16278
|
-
const absPath = sp.resolve(
|
|
16279
|
-
const targetPath = follow ? await (0, import_promises2.realpath)(
|
|
17373
|
+
const absPath = sp.resolve(path31);
|
|
17374
|
+
const targetPath = follow ? await (0, import_promises2.realpath)(path31) : path31;
|
|
16280
17375
|
if (this.fsw.closed)
|
|
16281
17376
|
return;
|
|
16282
17377
|
closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
|
|
@@ -16286,29 +17381,29 @@ var NodeFsHandler = class {
|
|
|
16286
17381
|
this.fsw._symlinkPaths.set(absPath, targetPath);
|
|
16287
17382
|
}
|
|
16288
17383
|
} else if (stats.isSymbolicLink()) {
|
|
16289
|
-
const targetPath = follow ? await (0, import_promises2.realpath)(
|
|
17384
|
+
const targetPath = follow ? await (0, import_promises2.realpath)(path31) : path31;
|
|
16290
17385
|
if (this.fsw.closed)
|
|
16291
17386
|
return;
|
|
16292
17387
|
const parent = sp.dirname(wh.watchPath);
|
|
16293
17388
|
this.fsw._getWatchedDir(parent).add(wh.watchPath);
|
|
16294
17389
|
this.fsw._emit(EV.ADD, wh.watchPath, stats);
|
|
16295
|
-
closer = await this._handleDir(parent, stats, initialAdd, depth,
|
|
17390
|
+
closer = await this._handleDir(parent, stats, initialAdd, depth, path31, wh, targetPath);
|
|
16296
17391
|
if (this.fsw.closed)
|
|
16297
17392
|
return;
|
|
16298
17393
|
if (targetPath !== void 0) {
|
|
16299
|
-
this.fsw._symlinkPaths.set(sp.resolve(
|
|
17394
|
+
this.fsw._symlinkPaths.set(sp.resolve(path31), targetPath);
|
|
16300
17395
|
}
|
|
16301
17396
|
} else {
|
|
16302
17397
|
closer = this._handleFile(wh.watchPath, stats, initialAdd);
|
|
16303
17398
|
}
|
|
16304
17399
|
ready();
|
|
16305
17400
|
if (closer)
|
|
16306
|
-
this.fsw._addPathCloser(
|
|
17401
|
+
this.fsw._addPathCloser(path31, closer);
|
|
16307
17402
|
return false;
|
|
16308
17403
|
} catch (error) {
|
|
16309
17404
|
if (this.fsw._handleError(error)) {
|
|
16310
17405
|
ready();
|
|
16311
|
-
return
|
|
17406
|
+
return path31;
|
|
16312
17407
|
}
|
|
16313
17408
|
}
|
|
16314
17409
|
}
|
|
@@ -16351,24 +17446,24 @@ function createPattern(matcher) {
|
|
|
16351
17446
|
}
|
|
16352
17447
|
return () => false;
|
|
16353
17448
|
}
|
|
16354
|
-
function normalizePath2(
|
|
16355
|
-
if (typeof
|
|
17449
|
+
function normalizePath2(path31) {
|
|
17450
|
+
if (typeof path31 !== "string")
|
|
16356
17451
|
throw new Error("string expected");
|
|
16357
|
-
|
|
16358
|
-
|
|
17452
|
+
path31 = sp2.normalize(path31);
|
|
17453
|
+
path31 = path31.replace(/\\/g, "/");
|
|
16359
17454
|
let prepend = false;
|
|
16360
|
-
if (
|
|
17455
|
+
if (path31.startsWith("//"))
|
|
16361
17456
|
prepend = true;
|
|
16362
|
-
|
|
17457
|
+
path31 = path31.replace(DOUBLE_SLASH_RE, "/");
|
|
16363
17458
|
if (prepend)
|
|
16364
|
-
|
|
16365
|
-
return
|
|
17459
|
+
path31 = "/" + path31;
|
|
17460
|
+
return path31;
|
|
16366
17461
|
}
|
|
16367
17462
|
function matchPatterns(patterns, testString, stats) {
|
|
16368
|
-
const
|
|
17463
|
+
const path31 = normalizePath2(testString);
|
|
16369
17464
|
for (let index = 0; index < patterns.length; index++) {
|
|
16370
17465
|
const pattern = patterns[index];
|
|
16371
|
-
if (pattern(
|
|
17466
|
+
if (pattern(path31, stats)) {
|
|
16372
17467
|
return true;
|
|
16373
17468
|
}
|
|
16374
17469
|
}
|
|
@@ -16406,19 +17501,19 @@ var toUnix = (string) => {
|
|
|
16406
17501
|
}
|
|
16407
17502
|
return str;
|
|
16408
17503
|
};
|
|
16409
|
-
var normalizePathToUnix = (
|
|
16410
|
-
var normalizeIgnored = (cwd = "") => (
|
|
16411
|
-
if (typeof
|
|
16412
|
-
return normalizePathToUnix(sp2.isAbsolute(
|
|
17504
|
+
var normalizePathToUnix = (path31) => toUnix(sp2.normalize(toUnix(path31)));
|
|
17505
|
+
var normalizeIgnored = (cwd = "") => (path31) => {
|
|
17506
|
+
if (typeof path31 === "string") {
|
|
17507
|
+
return normalizePathToUnix(sp2.isAbsolute(path31) ? path31 : sp2.join(cwd, path31));
|
|
16413
17508
|
} else {
|
|
16414
|
-
return
|
|
17509
|
+
return path31;
|
|
16415
17510
|
}
|
|
16416
17511
|
};
|
|
16417
|
-
var getAbsolutePath = (
|
|
16418
|
-
if (sp2.isAbsolute(
|
|
16419
|
-
return
|
|
17512
|
+
var getAbsolutePath = (path31, cwd) => {
|
|
17513
|
+
if (sp2.isAbsolute(path31)) {
|
|
17514
|
+
return path31;
|
|
16420
17515
|
}
|
|
16421
|
-
return sp2.join(cwd,
|
|
17516
|
+
return sp2.join(cwd, path31);
|
|
16422
17517
|
};
|
|
16423
17518
|
var EMPTY_SET = Object.freeze(/* @__PURE__ */ new Set());
|
|
16424
17519
|
var DirEntry = class {
|
|
@@ -16483,10 +17578,10 @@ var WatchHelper = class {
|
|
|
16483
17578
|
dirParts;
|
|
16484
17579
|
followSymlinks;
|
|
16485
17580
|
statMethod;
|
|
16486
|
-
constructor(
|
|
17581
|
+
constructor(path31, follow, fsw) {
|
|
16487
17582
|
this.fsw = fsw;
|
|
16488
|
-
const watchPath =
|
|
16489
|
-
this.path =
|
|
17583
|
+
const watchPath = path31;
|
|
17584
|
+
this.path = path31 = path31.replace(REPLACER_RE, "");
|
|
16490
17585
|
this.watchPath = watchPath;
|
|
16491
17586
|
this.fullWatchPath = sp2.resolve(watchPath);
|
|
16492
17587
|
this.dirParts = [];
|
|
@@ -16626,20 +17721,20 @@ var FSWatcher = class extends import_node_events.EventEmitter {
|
|
|
16626
17721
|
this._closePromise = void 0;
|
|
16627
17722
|
let paths = unifyPaths(paths_);
|
|
16628
17723
|
if (cwd) {
|
|
16629
|
-
paths = paths.map((
|
|
16630
|
-
const absPath = getAbsolutePath(
|
|
17724
|
+
paths = paths.map((path31) => {
|
|
17725
|
+
const absPath = getAbsolutePath(path31, cwd);
|
|
16631
17726
|
return absPath;
|
|
16632
17727
|
});
|
|
16633
17728
|
}
|
|
16634
|
-
paths.forEach((
|
|
16635
|
-
this._removeIgnoredPath(
|
|
17729
|
+
paths.forEach((path31) => {
|
|
17730
|
+
this._removeIgnoredPath(path31);
|
|
16636
17731
|
});
|
|
16637
17732
|
this._userIgnored = void 0;
|
|
16638
17733
|
if (!this._readyCount)
|
|
16639
17734
|
this._readyCount = 0;
|
|
16640
17735
|
this._readyCount += paths.length;
|
|
16641
|
-
Promise.all(paths.map(async (
|
|
16642
|
-
const res = await this._nodeFsHandler._addToNodeFs(
|
|
17736
|
+
Promise.all(paths.map(async (path31) => {
|
|
17737
|
+
const res = await this._nodeFsHandler._addToNodeFs(path31, !_internal, void 0, 0, _origAdd);
|
|
16643
17738
|
if (res)
|
|
16644
17739
|
this._emitReady();
|
|
16645
17740
|
return res;
|
|
@@ -16661,17 +17756,17 @@ var FSWatcher = class extends import_node_events.EventEmitter {
|
|
|
16661
17756
|
return this;
|
|
16662
17757
|
const paths = unifyPaths(paths_);
|
|
16663
17758
|
const { cwd } = this.options;
|
|
16664
|
-
paths.forEach((
|
|
16665
|
-
if (!sp2.isAbsolute(
|
|
17759
|
+
paths.forEach((path31) => {
|
|
17760
|
+
if (!sp2.isAbsolute(path31) && !this._closers.has(path31)) {
|
|
16666
17761
|
if (cwd)
|
|
16667
|
-
|
|
16668
|
-
|
|
17762
|
+
path31 = sp2.join(cwd, path31);
|
|
17763
|
+
path31 = sp2.resolve(path31);
|
|
16669
17764
|
}
|
|
16670
|
-
this._closePath(
|
|
16671
|
-
this._addIgnoredPath(
|
|
16672
|
-
if (this._watched.has(
|
|
17765
|
+
this._closePath(path31);
|
|
17766
|
+
this._addIgnoredPath(path31);
|
|
17767
|
+
if (this._watched.has(path31)) {
|
|
16673
17768
|
this._addIgnoredPath({
|
|
16674
|
-
path:
|
|
17769
|
+
path: path31,
|
|
16675
17770
|
recursive: true
|
|
16676
17771
|
});
|
|
16677
17772
|
}
|
|
@@ -16735,38 +17830,38 @@ var FSWatcher = class extends import_node_events.EventEmitter {
|
|
|
16735
17830
|
* @param stats arguments to be passed with event
|
|
16736
17831
|
* @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag
|
|
16737
17832
|
*/
|
|
16738
|
-
async _emit(event,
|
|
17833
|
+
async _emit(event, path31, stats) {
|
|
16739
17834
|
if (this.closed)
|
|
16740
17835
|
return;
|
|
16741
17836
|
const opts = this.options;
|
|
16742
17837
|
if (isWindows)
|
|
16743
|
-
|
|
17838
|
+
path31 = sp2.normalize(path31);
|
|
16744
17839
|
if (opts.cwd)
|
|
16745
|
-
|
|
16746
|
-
const args = [
|
|
17840
|
+
path31 = sp2.relative(opts.cwd, path31);
|
|
17841
|
+
const args = [path31];
|
|
16747
17842
|
if (stats != null)
|
|
16748
17843
|
args.push(stats);
|
|
16749
17844
|
const awf = opts.awaitWriteFinish;
|
|
16750
17845
|
let pw;
|
|
16751
|
-
if (awf && (pw = this._pendingWrites.get(
|
|
17846
|
+
if (awf && (pw = this._pendingWrites.get(path31))) {
|
|
16752
17847
|
pw.lastChange = /* @__PURE__ */ new Date();
|
|
16753
17848
|
return this;
|
|
16754
17849
|
}
|
|
16755
17850
|
if (opts.atomic) {
|
|
16756
17851
|
if (event === EVENTS.UNLINK) {
|
|
16757
|
-
this._pendingUnlinks.set(
|
|
17852
|
+
this._pendingUnlinks.set(path31, [event, ...args]);
|
|
16758
17853
|
setTimeout(() => {
|
|
16759
|
-
this._pendingUnlinks.forEach((entry,
|
|
17854
|
+
this._pendingUnlinks.forEach((entry, path32) => {
|
|
16760
17855
|
this.emit(...entry);
|
|
16761
17856
|
this.emit(EVENTS.ALL, ...entry);
|
|
16762
|
-
this._pendingUnlinks.delete(
|
|
17857
|
+
this._pendingUnlinks.delete(path32);
|
|
16763
17858
|
});
|
|
16764
17859
|
}, typeof opts.atomic === "number" ? opts.atomic : 100);
|
|
16765
17860
|
return this;
|
|
16766
17861
|
}
|
|
16767
|
-
if (event === EVENTS.ADD && this._pendingUnlinks.has(
|
|
17862
|
+
if (event === EVENTS.ADD && this._pendingUnlinks.has(path31)) {
|
|
16768
17863
|
event = EVENTS.CHANGE;
|
|
16769
|
-
this._pendingUnlinks.delete(
|
|
17864
|
+
this._pendingUnlinks.delete(path31);
|
|
16770
17865
|
}
|
|
16771
17866
|
}
|
|
16772
17867
|
if (awf && (event === EVENTS.ADD || event === EVENTS.CHANGE) && this._readyEmitted) {
|
|
@@ -16784,16 +17879,16 @@ var FSWatcher = class extends import_node_events.EventEmitter {
|
|
|
16784
17879
|
this.emitWithAll(event, args);
|
|
16785
17880
|
}
|
|
16786
17881
|
};
|
|
16787
|
-
this._awaitWriteFinish(
|
|
17882
|
+
this._awaitWriteFinish(path31, awf.stabilityThreshold, event, awfEmit);
|
|
16788
17883
|
return this;
|
|
16789
17884
|
}
|
|
16790
17885
|
if (event === EVENTS.CHANGE) {
|
|
16791
|
-
const isThrottled = !this._throttle(EVENTS.CHANGE,
|
|
17886
|
+
const isThrottled = !this._throttle(EVENTS.CHANGE, path31, 50);
|
|
16792
17887
|
if (isThrottled)
|
|
16793
17888
|
return this;
|
|
16794
17889
|
}
|
|
16795
17890
|
if (opts.alwaysStat && stats === void 0 && (event === EVENTS.ADD || event === EVENTS.ADD_DIR || event === EVENTS.CHANGE)) {
|
|
16796
|
-
const fullPath = opts.cwd ? sp2.join(opts.cwd,
|
|
17891
|
+
const fullPath = opts.cwd ? sp2.join(opts.cwd, path31) : path31;
|
|
16797
17892
|
let stats2;
|
|
16798
17893
|
try {
|
|
16799
17894
|
stats2 = await (0, import_promises3.stat)(fullPath);
|
|
@@ -16824,23 +17919,23 @@ var FSWatcher = class extends import_node_events.EventEmitter {
|
|
|
16824
17919
|
* @param timeout duration of time to suppress duplicate actions
|
|
16825
17920
|
* @returns tracking object or false if action should be suppressed
|
|
16826
17921
|
*/
|
|
16827
|
-
_throttle(actionType,
|
|
17922
|
+
_throttle(actionType, path31, timeout) {
|
|
16828
17923
|
if (!this._throttled.has(actionType)) {
|
|
16829
17924
|
this._throttled.set(actionType, /* @__PURE__ */ new Map());
|
|
16830
17925
|
}
|
|
16831
17926
|
const action = this._throttled.get(actionType);
|
|
16832
17927
|
if (!action)
|
|
16833
17928
|
throw new Error("invalid throttle");
|
|
16834
|
-
const actionPath = action.get(
|
|
17929
|
+
const actionPath = action.get(path31);
|
|
16835
17930
|
if (actionPath) {
|
|
16836
17931
|
actionPath.count++;
|
|
16837
17932
|
return false;
|
|
16838
17933
|
}
|
|
16839
17934
|
let timeoutObject;
|
|
16840
17935
|
const clear = () => {
|
|
16841
|
-
const item = action.get(
|
|
17936
|
+
const item = action.get(path31);
|
|
16842
17937
|
const count = item ? item.count : 0;
|
|
16843
|
-
action.delete(
|
|
17938
|
+
action.delete(path31);
|
|
16844
17939
|
clearTimeout(timeoutObject);
|
|
16845
17940
|
if (item)
|
|
16846
17941
|
clearTimeout(item.timeoutObject);
|
|
@@ -16848,7 +17943,7 @@ var FSWatcher = class extends import_node_events.EventEmitter {
|
|
|
16848
17943
|
};
|
|
16849
17944
|
timeoutObject = setTimeout(clear, timeout);
|
|
16850
17945
|
const thr = { timeoutObject, clear, count: 0 };
|
|
16851
|
-
action.set(
|
|
17946
|
+
action.set(path31, thr);
|
|
16852
17947
|
return thr;
|
|
16853
17948
|
}
|
|
16854
17949
|
_incrReadyCount() {
|
|
@@ -16862,44 +17957,44 @@ var FSWatcher = class extends import_node_events.EventEmitter {
|
|
|
16862
17957
|
* @param event
|
|
16863
17958
|
* @param awfEmit Callback to be called when ready for event to be emitted.
|
|
16864
17959
|
*/
|
|
16865
|
-
_awaitWriteFinish(
|
|
17960
|
+
_awaitWriteFinish(path31, threshold, event, awfEmit) {
|
|
16866
17961
|
const awf = this.options.awaitWriteFinish;
|
|
16867
17962
|
if (typeof awf !== "object")
|
|
16868
17963
|
return;
|
|
16869
17964
|
const pollInterval = awf.pollInterval;
|
|
16870
17965
|
let timeoutHandler;
|
|
16871
|
-
let fullPath =
|
|
16872
|
-
if (this.options.cwd && !sp2.isAbsolute(
|
|
16873
|
-
fullPath = sp2.join(this.options.cwd,
|
|
17966
|
+
let fullPath = path31;
|
|
17967
|
+
if (this.options.cwd && !sp2.isAbsolute(path31)) {
|
|
17968
|
+
fullPath = sp2.join(this.options.cwd, path31);
|
|
16874
17969
|
}
|
|
16875
17970
|
const now2 = /* @__PURE__ */ new Date();
|
|
16876
17971
|
const writes = this._pendingWrites;
|
|
16877
17972
|
function awaitWriteFinishFn(prevStat) {
|
|
16878
|
-
(0,
|
|
16879
|
-
if (err || !writes.has(
|
|
17973
|
+
(0, import_node_fs3.stat)(fullPath, (err, curStat) => {
|
|
17974
|
+
if (err || !writes.has(path31)) {
|
|
16880
17975
|
if (err && err.code !== "ENOENT")
|
|
16881
17976
|
awfEmit(err);
|
|
16882
17977
|
return;
|
|
16883
17978
|
}
|
|
16884
17979
|
const now3 = Number(/* @__PURE__ */ new Date());
|
|
16885
17980
|
if (prevStat && curStat.size !== prevStat.size) {
|
|
16886
|
-
writes.get(
|
|
17981
|
+
writes.get(path31).lastChange = now3;
|
|
16887
17982
|
}
|
|
16888
|
-
const pw = writes.get(
|
|
17983
|
+
const pw = writes.get(path31);
|
|
16889
17984
|
const df = now3 - pw.lastChange;
|
|
16890
17985
|
if (df >= threshold) {
|
|
16891
|
-
writes.delete(
|
|
17986
|
+
writes.delete(path31);
|
|
16892
17987
|
awfEmit(void 0, curStat);
|
|
16893
17988
|
} else {
|
|
16894
17989
|
timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat);
|
|
16895
17990
|
}
|
|
16896
17991
|
});
|
|
16897
17992
|
}
|
|
16898
|
-
if (!writes.has(
|
|
16899
|
-
writes.set(
|
|
17993
|
+
if (!writes.has(path31)) {
|
|
17994
|
+
writes.set(path31, {
|
|
16900
17995
|
lastChange: now2,
|
|
16901
17996
|
cancelWait: () => {
|
|
16902
|
-
writes.delete(
|
|
17997
|
+
writes.delete(path31);
|
|
16903
17998
|
clearTimeout(timeoutHandler);
|
|
16904
17999
|
return event;
|
|
16905
18000
|
}
|
|
@@ -16910,8 +18005,8 @@ var FSWatcher = class extends import_node_events.EventEmitter {
|
|
|
16910
18005
|
/**
|
|
16911
18006
|
* Determines whether user has asked to ignore this path.
|
|
16912
18007
|
*/
|
|
16913
|
-
_isIgnored(
|
|
16914
|
-
if (this.options.atomic && DOT_RE.test(
|
|
18008
|
+
_isIgnored(path31, stats) {
|
|
18009
|
+
if (this.options.atomic && DOT_RE.test(path31))
|
|
16915
18010
|
return true;
|
|
16916
18011
|
if (!this._userIgnored) {
|
|
16917
18012
|
const { cwd } = this.options;
|
|
@@ -16921,17 +18016,17 @@ var FSWatcher = class extends import_node_events.EventEmitter {
|
|
|
16921
18016
|
const list = [...ignoredPaths.map(normalizeIgnored(cwd)), ...ignored];
|
|
16922
18017
|
this._userIgnored = anymatch(list, void 0);
|
|
16923
18018
|
}
|
|
16924
|
-
return this._userIgnored(
|
|
18019
|
+
return this._userIgnored(path31, stats);
|
|
16925
18020
|
}
|
|
16926
|
-
_isntIgnored(
|
|
16927
|
-
return !this._isIgnored(
|
|
18021
|
+
_isntIgnored(path31, stat5) {
|
|
18022
|
+
return !this._isIgnored(path31, stat5);
|
|
16928
18023
|
}
|
|
16929
18024
|
/**
|
|
16930
18025
|
* Provides a set of common helpers and properties relating to symlink handling.
|
|
16931
18026
|
* @param path file or directory pattern being watched
|
|
16932
18027
|
*/
|
|
16933
|
-
_getWatchHelpers(
|
|
16934
|
-
return new WatchHelper(
|
|
18028
|
+
_getWatchHelpers(path31) {
|
|
18029
|
+
return new WatchHelper(path31, this.options.followSymlinks, this);
|
|
16935
18030
|
}
|
|
16936
18031
|
// Directory helpers
|
|
16937
18032
|
// -----------------
|
|
@@ -16963,63 +18058,63 @@ var FSWatcher = class extends import_node_events.EventEmitter {
|
|
|
16963
18058
|
* @param item base path of item/directory
|
|
16964
18059
|
*/
|
|
16965
18060
|
_remove(directory, item, isDirectory) {
|
|
16966
|
-
const
|
|
16967
|
-
const fullPath = sp2.resolve(
|
|
16968
|
-
isDirectory = isDirectory != null ? isDirectory : this._watched.has(
|
|
16969
|
-
if (!this._throttle("remove",
|
|
18061
|
+
const path31 = sp2.join(directory, item);
|
|
18062
|
+
const fullPath = sp2.resolve(path31);
|
|
18063
|
+
isDirectory = isDirectory != null ? isDirectory : this._watched.has(path31) || this._watched.has(fullPath);
|
|
18064
|
+
if (!this._throttle("remove", path31, 100))
|
|
16970
18065
|
return;
|
|
16971
18066
|
if (!isDirectory && this._watched.size === 1) {
|
|
16972
18067
|
this.add(directory, item, true);
|
|
16973
18068
|
}
|
|
16974
|
-
const wp = this._getWatchedDir(
|
|
18069
|
+
const wp = this._getWatchedDir(path31);
|
|
16975
18070
|
const nestedDirectoryChildren = wp.getChildren();
|
|
16976
|
-
nestedDirectoryChildren.forEach((nested) => this._remove(
|
|
18071
|
+
nestedDirectoryChildren.forEach((nested) => this._remove(path31, nested));
|
|
16977
18072
|
const parent = this._getWatchedDir(directory);
|
|
16978
18073
|
const wasTracked = parent.has(item);
|
|
16979
18074
|
parent.remove(item);
|
|
16980
18075
|
if (this._symlinkPaths.has(fullPath)) {
|
|
16981
18076
|
this._symlinkPaths.delete(fullPath);
|
|
16982
18077
|
}
|
|
16983
|
-
let relPath =
|
|
18078
|
+
let relPath = path31;
|
|
16984
18079
|
if (this.options.cwd)
|
|
16985
|
-
relPath = sp2.relative(this.options.cwd,
|
|
18080
|
+
relPath = sp2.relative(this.options.cwd, path31);
|
|
16986
18081
|
if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
|
|
16987
18082
|
const event = this._pendingWrites.get(relPath).cancelWait();
|
|
16988
18083
|
if (event === EVENTS.ADD)
|
|
16989
18084
|
return;
|
|
16990
18085
|
}
|
|
16991
|
-
this._watched.delete(
|
|
18086
|
+
this._watched.delete(path31);
|
|
16992
18087
|
this._watched.delete(fullPath);
|
|
16993
18088
|
const eventName = isDirectory ? EVENTS.UNLINK_DIR : EVENTS.UNLINK;
|
|
16994
|
-
if (wasTracked && !this._isIgnored(
|
|
16995
|
-
this._emit(eventName,
|
|
16996
|
-
this._closePath(
|
|
18089
|
+
if (wasTracked && !this._isIgnored(path31))
|
|
18090
|
+
this._emit(eventName, path31);
|
|
18091
|
+
this._closePath(path31);
|
|
16997
18092
|
}
|
|
16998
18093
|
/**
|
|
16999
18094
|
* Closes all watchers for a path
|
|
17000
18095
|
*/
|
|
17001
|
-
_closePath(
|
|
17002
|
-
this._closeFile(
|
|
17003
|
-
const dir = sp2.dirname(
|
|
17004
|
-
this._getWatchedDir(dir).remove(sp2.basename(
|
|
18096
|
+
_closePath(path31) {
|
|
18097
|
+
this._closeFile(path31);
|
|
18098
|
+
const dir = sp2.dirname(path31);
|
|
18099
|
+
this._getWatchedDir(dir).remove(sp2.basename(path31));
|
|
17005
18100
|
}
|
|
17006
18101
|
/**
|
|
17007
18102
|
* Closes only file-specific watchers
|
|
17008
18103
|
*/
|
|
17009
|
-
_closeFile(
|
|
17010
|
-
const closers = this._closers.get(
|
|
18104
|
+
_closeFile(path31) {
|
|
18105
|
+
const closers = this._closers.get(path31);
|
|
17011
18106
|
if (!closers)
|
|
17012
18107
|
return;
|
|
17013
18108
|
closers.forEach((closer) => closer());
|
|
17014
|
-
this._closers.delete(
|
|
18109
|
+
this._closers.delete(path31);
|
|
17015
18110
|
}
|
|
17016
|
-
_addPathCloser(
|
|
18111
|
+
_addPathCloser(path31, closer) {
|
|
17017
18112
|
if (!closer)
|
|
17018
18113
|
return;
|
|
17019
|
-
let list = this._closers.get(
|
|
18114
|
+
let list = this._closers.get(path31);
|
|
17020
18115
|
if (!list) {
|
|
17021
18116
|
list = [];
|
|
17022
|
-
this._closers.set(
|
|
18117
|
+
this._closers.set(path31, list);
|
|
17023
18118
|
}
|
|
17024
18119
|
list.push(closer);
|
|
17025
18120
|
}
|
|
@@ -17049,11 +18144,11 @@ function watch(paths, options = {}) {
|
|
|
17049
18144
|
var chokidar_default = { watch, FSWatcher };
|
|
17050
18145
|
|
|
17051
18146
|
// src/watcher/file-watcher.ts
|
|
17052
|
-
var
|
|
18147
|
+
var path24 = __toESM(require("path"), 1);
|
|
17053
18148
|
|
|
17054
18149
|
// src/watcher/native-recursive-watcher.ts
|
|
17055
|
-
var
|
|
17056
|
-
var
|
|
18150
|
+
var import_node_fs4 = require("fs");
|
|
18151
|
+
var path22 = __toESM(require("path"), 1);
|
|
17057
18152
|
var NativeRecursiveWatcher = class {
|
|
17058
18153
|
constructor(root, onChange, options = {}) {
|
|
17059
18154
|
this.root = root;
|
|
@@ -17101,26 +18196,26 @@ var NativeRecursiveWatcher = class {
|
|
|
17101
18196
|
toAbsolutePath(filename) {
|
|
17102
18197
|
if (filename == null) return null;
|
|
17103
18198
|
const normalizedFilename = typeof filename === "string" ? filename : filename.toString();
|
|
17104
|
-
const absolutePath =
|
|
17105
|
-
const relativePath =
|
|
17106
|
-
const outsideRoot = relativePath === ".." || relativePath.startsWith(`..${
|
|
18199
|
+
const absolutePath = path22.resolve(this.root, normalizedFilename);
|
|
18200
|
+
const relativePath = path22.relative(this.root, absolutePath);
|
|
18201
|
+
const outsideRoot = relativePath === ".." || relativePath.startsWith(`..${path22.sep}`) || path22.isAbsolute(relativePath);
|
|
17107
18202
|
return outsideRoot ? null : absolutePath;
|
|
17108
18203
|
}
|
|
17109
|
-
defaultWatchFactory = (root, listener, options) => (0,
|
|
18204
|
+
defaultWatchFactory = (root, listener, options) => (0, import_node_fs4.watch)(root, options, listener);
|
|
17110
18205
|
};
|
|
17111
18206
|
|
|
17112
18207
|
// src/watcher/snapshot.ts
|
|
17113
18208
|
var fsPromises4 = __toESM(require("fs/promises"), 1);
|
|
17114
|
-
var
|
|
18209
|
+
var path23 = __toESM(require("path"), 1);
|
|
17115
18210
|
async function buildFileSnapshotScan(projectRoot, config, configPaths = []) {
|
|
17116
|
-
const normalizedProjectRoot =
|
|
18211
|
+
const normalizedProjectRoot = path23.resolve(projectRoot);
|
|
17117
18212
|
const ignoreFilter = createIgnoreFilter(normalizedProjectRoot);
|
|
17118
18213
|
const includePatterns = [...config.include, ...config.additionalInclude ?? []];
|
|
17119
18214
|
const maxDepth = config.indexing?.maxDepth ?? -1;
|
|
17120
18215
|
const snapshot = /* @__PURE__ */ new Map();
|
|
17121
18216
|
const unreadablePrefixes = /* @__PURE__ */ new Set();
|
|
17122
18217
|
const includeFile = async (filePath) => {
|
|
17123
|
-
const normalizedPath2 =
|
|
18218
|
+
const normalizedPath2 = path23.resolve(filePath);
|
|
17124
18219
|
if (!shouldIncludeFile(normalizedPath2, normalizedProjectRoot, includePatterns, config.exclude, ignoreFilter)) return;
|
|
17125
18220
|
const stat5 = await readStatIfFile(normalizedPath2, unreadablePrefixes);
|
|
17126
18221
|
if (stat5) snapshot.set(normalizedPath2, { size: stat5.size, mtimeMs: stat5.mtimeMs });
|
|
@@ -17132,16 +18227,16 @@ async function buildFileSnapshotScan(projectRoot, config, configPaths = []) {
|
|
|
17132
18227
|
} catch (error) {
|
|
17133
18228
|
if (isMissingFsError(error)) return;
|
|
17134
18229
|
if (isPermissionFsError(error)) {
|
|
17135
|
-
unreadablePrefixes.add(
|
|
18230
|
+
unreadablePrefixes.add(path23.resolve(directoryPath));
|
|
17136
18231
|
return;
|
|
17137
18232
|
}
|
|
17138
18233
|
throw error;
|
|
17139
18234
|
}
|
|
17140
18235
|
for (const entry of entries) {
|
|
17141
|
-
const fullPath =
|
|
17142
|
-
const relativePath =
|
|
18236
|
+
const fullPath = path23.join(directoryPath, entry.name);
|
|
18237
|
+
const relativePath = path23.relative(normalizedProjectRoot, fullPath);
|
|
17143
18238
|
if (entry.isDirectory()) {
|
|
17144
|
-
if (hasFilteredPathSegment(relativePath,
|
|
18239
|
+
if (hasFilteredPathSegment(relativePath, path23.sep) || isRestrictedDirectory(relativePath, path23.sep)) continue;
|
|
17145
18240
|
if (ignoreFilter.ignores(relativePath)) continue;
|
|
17146
18241
|
if (maxDepth === -1 || depth < maxDepth) await walk(fullPath, depth + 1);
|
|
17147
18242
|
} else if (entry.isFile()) {
|
|
@@ -17154,19 +18249,19 @@ async function buildFileSnapshotScan(projectRoot, config, configPaths = []) {
|
|
|
17154
18249
|
return { entries: snapshot, unreadablePrefixes };
|
|
17155
18250
|
}
|
|
17156
18251
|
async function buildFileSnapshotForPathScan(projectRoot, config, configPaths, targetPath) {
|
|
17157
|
-
const normalizedProjectRoot =
|
|
17158
|
-
const normalizedTargetPath =
|
|
18252
|
+
const normalizedProjectRoot = path23.resolve(projectRoot);
|
|
18253
|
+
const normalizedTargetPath = path23.resolve(targetPath);
|
|
17159
18254
|
if (!isWithinPath(normalizedProjectRoot, normalizedTargetPath)) {
|
|
17160
18255
|
return { entries: /* @__PURE__ */ new Map(), unreadablePrefixes: /* @__PURE__ */ new Set() };
|
|
17161
18256
|
}
|
|
17162
18257
|
const ignoreFilter = createIgnoreFilter(normalizedProjectRoot);
|
|
17163
18258
|
const includePatterns = [...config.include, ...config.additionalInclude ?? []];
|
|
17164
18259
|
const maxDepth = config.indexing?.maxDepth ?? -1;
|
|
17165
|
-
const explicitConfigPaths = new Set(configPaths.map((configPath) =>
|
|
18260
|
+
const explicitConfigPaths = new Set(configPaths.map((configPath) => path23.resolve(configPath)));
|
|
17166
18261
|
const snapshot = /* @__PURE__ */ new Map();
|
|
17167
18262
|
const unreadablePrefixes = /* @__PURE__ */ new Set();
|
|
17168
18263
|
const includeFile = async (filePath) => {
|
|
17169
|
-
const normalizedPath2 =
|
|
18264
|
+
const normalizedPath2 = path23.resolve(filePath);
|
|
17170
18265
|
if (!explicitConfigPaths.has(normalizedPath2) && !shouldIncludeFile(
|
|
17171
18266
|
normalizedPath2,
|
|
17172
18267
|
normalizedProjectRoot,
|
|
@@ -17184,16 +18279,16 @@ async function buildFileSnapshotForPathScan(projectRoot, config, configPaths, ta
|
|
|
17184
18279
|
} catch (error) {
|
|
17185
18280
|
if (isMissingFsError(error)) return;
|
|
17186
18281
|
if (isPermissionFsError(error)) {
|
|
17187
|
-
unreadablePrefixes.add(
|
|
18282
|
+
unreadablePrefixes.add(path23.resolve(directoryPath));
|
|
17188
18283
|
return;
|
|
17189
18284
|
}
|
|
17190
18285
|
throw error;
|
|
17191
18286
|
}
|
|
17192
18287
|
for (const entry of entries) {
|
|
17193
|
-
const fullPath =
|
|
17194
|
-
const relativePath =
|
|
18288
|
+
const fullPath = path23.join(directoryPath, entry.name);
|
|
18289
|
+
const relativePath = path23.relative(normalizedProjectRoot, fullPath);
|
|
17195
18290
|
if (entry.isDirectory()) {
|
|
17196
|
-
if (hasFilteredPathSegment(relativePath,
|
|
18291
|
+
if (hasFilteredPathSegment(relativePath, path23.sep) || isRestrictedDirectory(relativePath, path23.sep)) continue;
|
|
17197
18292
|
if (ignoreFilter.ignores(relativePath)) continue;
|
|
17198
18293
|
if (maxDepth === -1 || depth < maxDepth) await walk(fullPath, depth + 1);
|
|
17199
18294
|
} else if (entry.isFile()) {
|
|
@@ -17217,7 +18312,7 @@ function completeFileSnapshot(previous, scan) {
|
|
|
17217
18312
|
return completed;
|
|
17218
18313
|
}
|
|
17219
18314
|
async function includeExplicitConfigPaths(snapshot, unreadablePrefixes, configPaths) {
|
|
17220
|
-
for (const configPath of [...new Set(configPaths.map((value) =>
|
|
18315
|
+
for (const configPath of [...new Set(configPaths.map((value) => path23.resolve(value)))]) {
|
|
17221
18316
|
if (snapshot.has(configPath)) continue;
|
|
17222
18317
|
const stat5 = await readStatIfFile(configPath, unreadablePrefixes);
|
|
17223
18318
|
if (stat5) snapshot.set(configPath, { size: stat5.size, mtimeMs: stat5.mtimeMs });
|
|
@@ -17227,12 +18322,12 @@ async function includeExplicitConfigPathsInPath(snapshot, unreadablePrefixes, co
|
|
|
17227
18322
|
await includeExplicitConfigPaths(
|
|
17228
18323
|
snapshot,
|
|
17229
18324
|
unreadablePrefixes,
|
|
17230
|
-
configPaths.filter((configPath) => isWithinPath(targetPath,
|
|
18325
|
+
configPaths.filter((configPath) => isWithinPath(targetPath, path23.resolve(configPath)))
|
|
17231
18326
|
);
|
|
17232
18327
|
}
|
|
17233
18328
|
function isWithinPath(parentPath, childPath) {
|
|
17234
|
-
const relativePath =
|
|
17235
|
-
return relativePath === "" || !relativePath.startsWith(`..${
|
|
18329
|
+
const relativePath = path23.relative(parentPath, childPath);
|
|
18330
|
+
return relativePath === "" || !relativePath.startsWith(`..${path23.sep}`) && relativePath !== ".." && !path23.isAbsolute(relativePath);
|
|
17236
18331
|
}
|
|
17237
18332
|
async function readStatIfFile(filePath, unreadablePrefixes) {
|
|
17238
18333
|
try {
|
|
@@ -17241,7 +18336,7 @@ async function readStatIfFile(filePath, unreadablePrefixes) {
|
|
|
17241
18336
|
} catch (error) {
|
|
17242
18337
|
if (isMissingFsError(error)) return null;
|
|
17243
18338
|
if (isPermissionFsError(error)) {
|
|
17244
|
-
unreadablePrefixes.add(
|
|
18339
|
+
unreadablePrefixes.add(path23.resolve(filePath));
|
|
17245
18340
|
return null;
|
|
17246
18341
|
}
|
|
17247
18342
|
throw error;
|
|
@@ -17378,8 +18473,8 @@ var FileWatcher = class {
|
|
|
17378
18473
|
this.createWatcher();
|
|
17379
18474
|
}
|
|
17380
18475
|
resetReady() {
|
|
17381
|
-
this.readyPromise = new Promise((
|
|
17382
|
-
this.resolveReady =
|
|
18476
|
+
this.readyPromise = new Promise((resolve18) => {
|
|
18477
|
+
this.resolveReady = resolve18;
|
|
17383
18478
|
});
|
|
17384
18479
|
this.startupReadySignals = 1;
|
|
17385
18480
|
}
|
|
@@ -17410,7 +18505,7 @@ var FileWatcher = class {
|
|
|
17410
18505
|
const resolvedWatchTargets = watchTargets ?? this.getFullChokidarWatchTargets();
|
|
17411
18506
|
const watcherOptions = {
|
|
17412
18507
|
ignored: (filePath) => {
|
|
17413
|
-
const relativePath =
|
|
18508
|
+
const relativePath = path24.relative(this.projectRoot, filePath);
|
|
17414
18509
|
if (!relativePath) return false;
|
|
17415
18510
|
if (this.isProjectConfigPathOrAncestor(relativePath)) {
|
|
17416
18511
|
return false;
|
|
@@ -17418,10 +18513,10 @@ var FileWatcher = class {
|
|
|
17418
18513
|
if (this.isOutsideProjectPath(relativePath)) {
|
|
17419
18514
|
return true;
|
|
17420
18515
|
}
|
|
17421
|
-
if (hasFilteredPathSegment(relativePath,
|
|
18516
|
+
if (hasFilteredPathSegment(relativePath, path24.sep)) {
|
|
17422
18517
|
return true;
|
|
17423
18518
|
}
|
|
17424
|
-
if (isRestrictedDirectory(relativePath,
|
|
18519
|
+
if (isRestrictedDirectory(relativePath, path24.sep)) {
|
|
17425
18520
|
return true;
|
|
17426
18521
|
}
|
|
17427
18522
|
if (ignoreFilter.ignores(relativePath)) {
|
|
@@ -17512,13 +18607,13 @@ var FileWatcher = class {
|
|
|
17512
18607
|
getExternalConfigWatchTargets() {
|
|
17513
18608
|
return [...new Set(
|
|
17514
18609
|
this.projectConfigPaths.filter((projectConfigPath) => {
|
|
17515
|
-
const relativeConfigPath =
|
|
18610
|
+
const relativeConfigPath = path24.relative(this.projectRoot, projectConfigPath);
|
|
17516
18611
|
return this.isOutsideProjectPath(relativeConfigPath);
|
|
17517
18612
|
}).map((projectConfigPath) => {
|
|
17518
18613
|
if ((0, import_fs14.existsSync)(projectConfigPath)) {
|
|
17519
18614
|
return projectConfigPath;
|
|
17520
18615
|
}
|
|
17521
|
-
return this.getNearestExistingDirectory(
|
|
18616
|
+
return this.getNearestExistingDirectory(path24.dirname(projectConfigPath));
|
|
17522
18617
|
})
|
|
17523
18618
|
)];
|
|
17524
18619
|
}
|
|
@@ -17580,7 +18675,7 @@ var FileWatcher = class {
|
|
|
17580
18675
|
}
|
|
17581
18676
|
scheduleNativeReconciliation(generation, filePath) {
|
|
17582
18677
|
if (!this.isCurrentNativeSetup(generation)) return;
|
|
17583
|
-
const requiresFullReconciliation = filePath ===
|
|
18678
|
+
const requiresFullReconciliation = filePath === path24.join(this.projectRoot, ".gitignore");
|
|
17584
18679
|
const invalidatedPath = requiresFullReconciliation ? null : filePath;
|
|
17585
18680
|
this.nativeInvalidatedPaths.set(invalidatedPath, invalidatedPath !== null);
|
|
17586
18681
|
if (this.nativeReconcileTimer) {
|
|
@@ -17675,23 +18770,23 @@ var FileWatcher = class {
|
|
|
17675
18770
|
this.scheduleFlush();
|
|
17676
18771
|
}
|
|
17677
18772
|
isProjectConfigPath(filePath) {
|
|
17678
|
-
const relativePath =
|
|
17679
|
-
const normalizedRelativePath =
|
|
18773
|
+
const relativePath = path24.relative(this.projectRoot, filePath);
|
|
18774
|
+
const normalizedRelativePath = path24.normalize(relativePath);
|
|
17680
18775
|
return this.getProjectConfigRelativePaths().some((configPath) => configPath === normalizedRelativePath);
|
|
17681
18776
|
}
|
|
17682
18777
|
isProjectConfigPathOrAncestor(relativePath) {
|
|
17683
|
-
const normalizedRelativePath =
|
|
18778
|
+
const normalizedRelativePath = path24.normalize(relativePath);
|
|
17684
18779
|
return this.getProjectConfigRelativePaths().some(
|
|
17685
|
-
(configPath) => configPath === normalizedRelativePath || configPath.startsWith(`${normalizedRelativePath}${
|
|
18780
|
+
(configPath) => configPath === normalizedRelativePath || configPath.startsWith(`${normalizedRelativePath}${path24.sep}`)
|
|
17686
18781
|
);
|
|
17687
18782
|
}
|
|
17688
18783
|
isOutsideProjectPath(relativePath) {
|
|
17689
|
-
return relativePath === ".." || relativePath.startsWith(`..${
|
|
18784
|
+
return relativePath === ".." || relativePath.startsWith(`..${path24.sep}`) || path24.isAbsolute(relativePath);
|
|
17690
18785
|
}
|
|
17691
18786
|
getNearestExistingDirectory(directoryPath) {
|
|
17692
18787
|
let candidate = directoryPath;
|
|
17693
18788
|
while (!(0, import_fs14.existsSync)(candidate)) {
|
|
17694
|
-
const parent =
|
|
18789
|
+
const parent = path24.dirname(candidate);
|
|
17695
18790
|
if (parent === candidate) break;
|
|
17696
18791
|
candidate = parent;
|
|
17697
18792
|
}
|
|
@@ -17699,7 +18794,7 @@ var FileWatcher = class {
|
|
|
17699
18794
|
}
|
|
17700
18795
|
getProjectConfigRelativePaths() {
|
|
17701
18796
|
return this.projectConfigPaths.map(
|
|
17702
|
-
(configPath) =>
|
|
18797
|
+
(configPath) => path24.normalize(path24.relative(this.projectRoot, configPath))
|
|
17703
18798
|
);
|
|
17704
18799
|
}
|
|
17705
18800
|
getConfigPathStates() {
|
|
@@ -17757,7 +18852,7 @@ var FileWatcher = class {
|
|
|
17757
18852
|
return;
|
|
17758
18853
|
}
|
|
17759
18854
|
const changes = Array.from(this.pendingChanges.entries()).map(
|
|
17760
|
-
([
|
|
18855
|
+
([path31, type]) => ({ path: path31, type })
|
|
17761
18856
|
);
|
|
17762
18857
|
this.pendingChanges.clear();
|
|
17763
18858
|
try {
|
|
@@ -17803,7 +18898,7 @@ var FileWatcher = class {
|
|
|
17803
18898
|
};
|
|
17804
18899
|
|
|
17805
18900
|
// src/watcher/git-head-watcher.ts
|
|
17806
|
-
var
|
|
18901
|
+
var path25 = __toESM(require("path"), 1);
|
|
17807
18902
|
var GitHeadWatcher = class {
|
|
17808
18903
|
watcher = null;
|
|
17809
18904
|
projectRoot;
|
|
@@ -17825,13 +18920,13 @@ var GitHeadWatcher = class {
|
|
|
17825
18920
|
this.readyPromise = Promise.resolve();
|
|
17826
18921
|
return;
|
|
17827
18922
|
}
|
|
17828
|
-
this.readyPromise = new Promise((
|
|
17829
|
-
this.resolveReady =
|
|
18923
|
+
this.readyPromise = new Promise((resolve18) => {
|
|
18924
|
+
this.resolveReady = resolve18;
|
|
17830
18925
|
});
|
|
17831
18926
|
this.onBranchChange = handler;
|
|
17832
18927
|
this.currentBranch = getCurrentBranch(this.projectRoot);
|
|
17833
18928
|
const headPath = getHeadPath(this.projectRoot);
|
|
17834
|
-
const refsPath =
|
|
18929
|
+
const refsPath = path25.join(this.projectRoot, ".git", "refs", "heads");
|
|
17835
18930
|
this.watcher = chokidar_default.watch([headPath, refsPath], {
|
|
17836
18931
|
persistent: true,
|
|
17837
18932
|
ignoreInitial: true,
|
|
@@ -17899,7 +18994,9 @@ var GitHeadWatcher = class {
|
|
|
17899
18994
|
function createWatcherWithIndexer(getIndexer, projectRoot, config, host, options = {}) {
|
|
17900
18995
|
const fileWatcher = new FileWatcher(projectRoot, config, host, options);
|
|
17901
18996
|
const configPaths = getConfigPaths(projectRoot, host, options);
|
|
17902
|
-
configureAutoIndex(projectRoot, host, parseConfig(config), getIndexer
|
|
18997
|
+
configureAutoIndex(projectRoot, host, parseConfig(config), getIndexer, {
|
|
18998
|
+
synchronizeBackgroundWorker: false
|
|
18999
|
+
});
|
|
17903
19000
|
let stopped = false;
|
|
17904
19001
|
const requestReindex = () => {
|
|
17905
19002
|
if (stopped) return;
|
|
@@ -17919,7 +19016,9 @@ function createWatcherWithIndexer(getIndexer, projectRoot, config, host, options
|
|
|
17919
19016
|
const parsedConfig = options.configPath ? parseConfig(loadConfigFile(options.configPath)) : void 0;
|
|
17920
19017
|
const refreshedConfig = refreshIndexerForDirectory(projectRoot, host, parsedConfig);
|
|
17921
19018
|
if (refreshedConfig) {
|
|
17922
|
-
configureAutoIndex(projectRoot, host, refreshedConfig, getIndexer
|
|
19019
|
+
configureAutoIndex(projectRoot, host, refreshedConfig, getIndexer, {
|
|
19020
|
+
synchronizeBackgroundWorker: false
|
|
19021
|
+
});
|
|
17923
19022
|
}
|
|
17924
19023
|
}
|
|
17925
19024
|
requestReindex();
|
|
@@ -18695,7 +19794,7 @@ async function resolveCodebaseContextUnmeasured(projectRoot, host, input) {
|
|
|
18695
19794
|
const directory = input.directory ?? void 0;
|
|
18696
19795
|
const tokenBudget = input.tokenBudget ?? void 0;
|
|
18697
19796
|
if (from && to) {
|
|
18698
|
-
const
|
|
19797
|
+
const path31 = await getCallGraphPath(
|
|
18699
19798
|
projectRoot,
|
|
18700
19799
|
host,
|
|
18701
19800
|
from,
|
|
@@ -18704,25 +19803,25 @@ async function resolveCodebaseContextUnmeasured(projectRoot, host, input) {
|
|
|
18704
19803
|
fromFilePath,
|
|
18705
19804
|
toFilePath
|
|
18706
19805
|
);
|
|
18707
|
-
const pathText = formatCallGraphPathResult(
|
|
18708
|
-
if (
|
|
19806
|
+
const pathText = formatCallGraphPathResult(path31);
|
|
19807
|
+
if (path31.path.length > 0) {
|
|
18709
19808
|
const fitted2 = fitTextToContextBudget(
|
|
18710
19809
|
pathText,
|
|
18711
19810
|
tokenBudget
|
|
18712
19811
|
);
|
|
18713
19812
|
return {
|
|
18714
19813
|
text: fitted2.text,
|
|
18715
|
-
details: fittedDetails("path", fitted2,
|
|
19814
|
+
details: fittedDetails("path", fitted2, path31.path.length)
|
|
18716
19815
|
};
|
|
18717
19816
|
}
|
|
18718
|
-
if (
|
|
19817
|
+
if (path31.from.status !== "resolved" || path31.to.status !== "resolved") {
|
|
18719
19818
|
const fitted2 = fitTextToContextBudget(pathText, tokenBudget);
|
|
18720
19819
|
return {
|
|
18721
19820
|
text: fitted2.text,
|
|
18722
19821
|
details: fittedDetails("path", fitted2, 0)
|
|
18723
19822
|
};
|
|
18724
19823
|
}
|
|
18725
|
-
const resolvedFrom =
|
|
19824
|
+
const resolvedFrom = path31.from;
|
|
18726
19825
|
const { callers } = await getCallGraphData(projectRoot, host, {
|
|
18727
19826
|
name: to,
|
|
18728
19827
|
direction: "callers",
|
|
@@ -18846,6 +19945,7 @@ async function executeCodebaseEditContext(projectRoot, host, args) {
|
|
|
18846
19945
|
async function executeIndexCodebase(projectRoot, host, args, onProgress) {
|
|
18847
19946
|
const result = await runIndexCodebase(projectRoot, host, args, onProgress);
|
|
18848
19947
|
if (result.kind === "estimate") return { text: formatCostEstimate(result.estimate) };
|
|
19948
|
+
if (result.kind === "dryrun") return { text: formatDryRunEstimate(result.dryrun) };
|
|
18849
19949
|
if (result.kind === "busy") return { text: result.text, isError: true };
|
|
18850
19950
|
if (result.kind === "message") return { text: result.text };
|
|
18851
19951
|
return { text: formatIndexStats(result.stats, args.verbose ?? false) };
|
|
@@ -18882,7 +19982,7 @@ async function executeCallGraph(projectRoot, host, args) {
|
|
|
18882
19982
|
return { text: formatCallGraphResult(await getCallGraphData(projectRoot, host, args)) };
|
|
18883
19983
|
}
|
|
18884
19984
|
async function executeCallGraphPath(projectRoot, host, args) {
|
|
18885
|
-
const
|
|
19985
|
+
const path31 = await getCallGraphPath(
|
|
18886
19986
|
projectRoot,
|
|
18887
19987
|
host,
|
|
18888
19988
|
args.from,
|
|
@@ -18891,7 +19991,7 @@ async function executeCallGraphPath(projectRoot, host, args) {
|
|
|
18891
19991
|
args.fromFilePath,
|
|
18892
19992
|
args.toFilePath
|
|
18893
19993
|
);
|
|
18894
|
-
return { text: formatCallGraphPathResult(
|
|
19994
|
+
return { text: formatCallGraphPathResult(path31) };
|
|
18895
19995
|
}
|
|
18896
19996
|
async function executeCodeCommunities(projectRoot, host, args) {
|
|
18897
19997
|
const result = await getCodeCommunities(projectRoot, host, args);
|
|
@@ -18900,12 +20000,12 @@ async function executeCodeCommunities(projectRoot, host, args) {
|
|
|
18900
20000
|
|
|
18901
20001
|
// src/adapters/opencode/tools.ts
|
|
18902
20002
|
var import_fs15 = require("fs");
|
|
18903
|
-
var
|
|
18904
|
-
var
|
|
20003
|
+
var os8 = __toESM(require("os"), 1);
|
|
20004
|
+
var path28 = __toESM(require("path"), 1);
|
|
18905
20005
|
|
|
18906
20006
|
// src/tools/visualize/activity.ts
|
|
18907
20007
|
var import_child_process5 = require("child_process");
|
|
18908
|
-
var
|
|
20008
|
+
var path26 = __toESM(require("path"), 1);
|
|
18909
20009
|
function attachRecentActivity(data, projectRoot) {
|
|
18910
20010
|
const activity = readGitActivity(projectRoot);
|
|
18911
20011
|
const changes = activity.size > 0 ? buildGitChanges(data, activity, projectRoot) : buildGraphChanges(data);
|
|
@@ -19067,7 +20167,7 @@ function normalizePath3(filePath) {
|
|
|
19067
20167
|
return filePath.replace(/\\/g, "/");
|
|
19068
20168
|
}
|
|
19069
20169
|
function toGitRelativePath(projectRoot, filePath) {
|
|
19070
|
-
const relativePath =
|
|
20170
|
+
const relativePath = path26.isAbsolute(filePath) ? path26.relative(projectRoot, filePath) : filePath;
|
|
19071
20171
|
return normalizePath3(relativePath);
|
|
19072
20172
|
}
|
|
19073
20173
|
|
|
@@ -19325,7 +20425,7 @@ render();
|
|
|
19325
20425
|
}
|
|
19326
20426
|
|
|
19327
20427
|
// src/tools/visualize/transform.ts
|
|
19328
|
-
var
|
|
20428
|
+
var path27 = __toESM(require("path"), 1);
|
|
19329
20429
|
|
|
19330
20430
|
// src/tools/visualize/modules.ts
|
|
19331
20431
|
var MAX_MODULES = 18;
|
|
@@ -19585,7 +20685,7 @@ function transformForVisualization(symbols, edges, options = {}) {
|
|
|
19585
20685
|
filePath: s.filePath,
|
|
19586
20686
|
kind: s.kind,
|
|
19587
20687
|
line: s.startLine,
|
|
19588
|
-
directory:
|
|
20688
|
+
directory: path27.dirname(s.filePath),
|
|
19589
20689
|
moduleId: "",
|
|
19590
20690
|
moduleLabel: ""
|
|
19591
20691
|
}));
|
|
@@ -19710,6 +20810,7 @@ var index_codebase = tool({
|
|
|
19710
20810
|
args: {
|
|
19711
20811
|
force: z3.boolean().optional().default(false).describe("Force reindex even if already indexed"),
|
|
19712
20812
|
estimateOnly: z3.boolean().optional().default(false).describe("Only show cost estimate without indexing"),
|
|
20813
|
+
dryRun: z3.boolean().optional().default(false).describe("Parse the file set and report the exact embedding token total without indexing. Read-only; the index is not changed. The total is the value 'Tokens used' climbs to for a force index (and an upper bound for an incremental)."),
|
|
19713
20814
|
verbose: z3.boolean().optional().default(false).describe("Show detailed info about skipped files and parsing failures")
|
|
19714
20815
|
},
|
|
19715
20816
|
async execute(args, context) {
|
|
@@ -19913,7 +21014,7 @@ var index_visualize = tool({
|
|
|
19913
21014
|
return "No connected symbols found for visualization. Try including orphans with includeOrphans=true, or check that the call graph has resolved edges.";
|
|
19914
21015
|
}
|
|
19915
21016
|
const html = generateVisualizationHtml(vizData);
|
|
19916
|
-
const outputPath =
|
|
21017
|
+
const outputPath = path28.join(os8.tmpdir(), `call-graph-${Date.now()}.html`);
|
|
19917
21018
|
(0, import_fs15.writeFileSync)(outputPath, html, "utf-8");
|
|
19918
21019
|
let result = `Temporal call graph visualization generated: ${outputPath}
|
|
19919
21020
|
|
|
@@ -20026,7 +21127,7 @@ var MCP_TOOL_NAMES = [
|
|
|
20026
21127
|
|
|
20027
21128
|
// src/commands/loader.ts
|
|
20028
21129
|
var import_fs16 = require("fs");
|
|
20029
|
-
var
|
|
21130
|
+
var path29 = __toESM(require("path"), 1);
|
|
20030
21131
|
function parseFrontmatter(content) {
|
|
20031
21132
|
const frontmatterRegex = /^---\s*\n([\s\S]*?)\n---\s*\n([\s\S]*)$/;
|
|
20032
21133
|
const match = content.match(frontmatterRegex);
|
|
@@ -20052,7 +21153,7 @@ function loadCommandsFromDirectory(commandsDir) {
|
|
|
20052
21153
|
}
|
|
20053
21154
|
const files = (0, import_fs16.readdirSync)(commandsDir).filter((f) => f.endsWith(".md"));
|
|
20054
21155
|
for (const file of files) {
|
|
20055
|
-
const filePath =
|
|
21156
|
+
const filePath = path29.join(commandsDir, file);
|
|
20056
21157
|
let content;
|
|
20057
21158
|
try {
|
|
20058
21159
|
content = (0, import_fs16.readFileSync)(filePath, "utf-8");
|
|
@@ -20061,7 +21162,7 @@ function loadCommandsFromDirectory(commandsDir) {
|
|
|
20061
21162
|
throw new Error(`Failed to load command file ${filePath}: ${message}`);
|
|
20062
21163
|
}
|
|
20063
21164
|
const { frontmatter, body } = parseFrontmatter(content);
|
|
20064
|
-
const name =
|
|
21165
|
+
const name = path29.basename(file, ".md");
|
|
20065
21166
|
const description = frontmatter.description || `Run the ${name} command`;
|
|
20066
21167
|
commands.set(name, {
|
|
20067
21168
|
description,
|
|
@@ -20310,6 +21411,7 @@ function assessRoutingIntent(text) {
|
|
|
20310
21411
|
};
|
|
20311
21412
|
}
|
|
20312
21413
|
function buildRoutingHint(assessment, status, includeGraphHandoff = false) {
|
|
21414
|
+
const hasSymbolCue = hasIdentifierShape(assessment.text) || containsQuotedIdentifier(assessment.text);
|
|
20313
21415
|
if (assessment.intent === "definition_lookup") {
|
|
20314
21416
|
if (!status || !status.indexed || status.compatibility?.compatible === false) {
|
|
20315
21417
|
return "For this turn, if you need a symbol definition, check `index_status` first and run `index_codebase` if the index is missing or incompatible. Then use `implementation_lookup` for the definition site. Use `grep` for exhaustive literal matches.";
|
|
@@ -20319,12 +21421,13 @@ function buildRoutingHint(assessment, status, includeGraphHandoff = false) {
|
|
|
20319
21421
|
if (assessment.intent !== "local_conceptual" && assessment.intent !== "local_broad_task") {
|
|
20320
21422
|
return null;
|
|
20321
21423
|
}
|
|
21424
|
+
const preEditHint = assessment.intent === "local_broad_task" && hasSymbolCue ? " If a likely target symbol is already known or strongly suspected, consider optional `codebase_edit_context` as a compact pre-edit next step for bounded source plus direct callers and callees." : "";
|
|
20322
21425
|
if (!status || !status.indexed || status.compatibility?.compatible === false) {
|
|
20323
21426
|
const graphHandoff2 = includeGraphHandoff ? " Use graph tools after semantic discovery identifies relevant symbols." : "";
|
|
20324
|
-
return `For this turn, if local code discovery by behavior is needed, check \`index_status\` first and run \`index_codebase\` if the index is missing or incompatible.${graphHandoff2} Then use \`codebase_context\` as the first local repository lookup. Use \`grep\` for exact identifiers or exhaustive matches
|
|
21427
|
+
return `For this turn, if local code discovery by behavior is needed, check \`index_status\` first and run \`index_codebase\` if the index is missing or incompatible.${graphHandoff2} Then use \`codebase_context\` as the first local repository lookup. Use \`grep\` for exact identifiers or exhaustive matches.${preEditHint}`;
|
|
20325
21428
|
}
|
|
20326
21429
|
const graphHandoff = includeGraphHandoff ? " before graph tools such as `call_graph`, `call_graph_path`, `pr_impact`, or OMO CodeGraph" : "";
|
|
20327
|
-
return `For this turn, prefer \`codebase_context\` for local code discovery, then use \`codebase_peek\` for metadata and \`codebase_search\` when you need implementation content${graphHandoff}. Use \`grep\` for exact identifiers or exhaustive matches
|
|
21430
|
+
return `For this turn, prefer \`codebase_context\` for local code discovery, then use \`codebase_peek\` for metadata and \`codebase_search\` when you need implementation content${graphHandoff}. Use \`grep\` for exact identifiers or exhaustive matches.${preEditHint}`;
|
|
20328
21431
|
}
|
|
20329
21432
|
var RoutingHintController = class {
|
|
20330
21433
|
constructor(getStatus, maxSessions = 200, includeGraphHandoff = false) {
|
|
@@ -20366,7 +21469,7 @@ var RoutingHintController = class {
|
|
|
20366
21469
|
if (!state || !state.pendingHint) {
|
|
20367
21470
|
return;
|
|
20368
21471
|
}
|
|
20369
|
-
if (toolName === "codebase_context" || toolName === "codebase_peek" || toolName === "codebase_search" || toolName === "implementation_lookup" || toolName === "index_status" || toolName === "index_codebase") {
|
|
21472
|
+
if (toolName === "codebase_context" || toolName === "codebase_edit_context" || toolName === "codebase_peek" || toolName === "codebase_search" || toolName === "implementation_lookup" || toolName === "index_status" || toolName === "index_codebase") {
|
|
20370
21473
|
state.pendingHint = false;
|
|
20371
21474
|
state.updatedAt = Date.now();
|
|
20372
21475
|
this.sessionState.set(sessionID, state);
|
|
@@ -20395,42 +21498,13 @@ var RoutingHintController = class {
|
|
|
20395
21498
|
|
|
20396
21499
|
// src/adapters/opencode.ts
|
|
20397
21500
|
var import_meta2 = {};
|
|
20398
|
-
var activeWatchers = /* @__PURE__ */ new Map();
|
|
20399
|
-
var watcherReplacementChains = /* @__PURE__ */ new Map();
|
|
20400
|
-
async function replaceActiveWatcher(projectRoot, createNextWatcher) {
|
|
20401
|
-
const chain = (watcherReplacementChains.get(projectRoot) ?? Promise.resolve()).catch(() => void 0).then(async () => {
|
|
20402
|
-
const existing = activeWatchers.get(projectRoot);
|
|
20403
|
-
if (existing) {
|
|
20404
|
-
try {
|
|
20405
|
-
await existing.stop();
|
|
20406
|
-
} catch (error) {
|
|
20407
|
-
console.error("[codebase-index] Failed to stop replaced watcher:", error);
|
|
20408
|
-
throw error;
|
|
20409
|
-
}
|
|
20410
|
-
if (activeWatchers.get(projectRoot) === existing) {
|
|
20411
|
-
activeWatchers.delete(projectRoot);
|
|
20412
|
-
}
|
|
20413
|
-
}
|
|
20414
|
-
if (createNextWatcher) {
|
|
20415
|
-
activeWatchers.set(projectRoot, createNextWatcher());
|
|
20416
|
-
}
|
|
20417
|
-
});
|
|
20418
|
-
watcherReplacementChains.set(projectRoot, chain);
|
|
20419
|
-
try {
|
|
20420
|
-
await chain;
|
|
20421
|
-
} finally {
|
|
20422
|
-
if (watcherReplacementChains.get(projectRoot) === chain) {
|
|
20423
|
-
watcherReplacementChains.delete(projectRoot);
|
|
20424
|
-
}
|
|
20425
|
-
}
|
|
20426
|
-
}
|
|
20427
21501
|
function getCommandsDir() {
|
|
20428
21502
|
let currentDir = process.cwd();
|
|
20429
21503
|
if (typeof import_meta2 !== "undefined" && import_meta2.url) {
|
|
20430
|
-
currentDir =
|
|
21504
|
+
currentDir = path30.dirname((0, import_url.fileURLToPath)(import_meta2.url));
|
|
20431
21505
|
}
|
|
20432
|
-
const packageRoot =
|
|
20433
|
-
return
|
|
21506
|
+
const packageRoot = path30.basename(currentDir) === "adapters" ? path30.join(currentDir, "..", "..") : path30.join(currentDir, "..");
|
|
21507
|
+
return path30.join(packageRoot, "commands");
|
|
20434
21508
|
}
|
|
20435
21509
|
function appendRoutingHints(output, hints, preferredRole) {
|
|
20436
21510
|
const preferredBucket = preferredRole === "developer" ? output.developer : output.system;
|
|
@@ -20456,8 +21530,9 @@ var plugin = async ({ directory, worktree }) => {
|
|
|
20456
21530
|
initializeTools2(projectRoot, config);
|
|
20457
21531
|
const getProjectIndexer = () => getIndexerForProject2(projectRoot);
|
|
20458
21532
|
const routingHints = config.search.routingHints ? new RoutingHintController(() => getProjectIndexer().getStatus(), 200, config.search.routingGraphHandoffHints) : null;
|
|
20459
|
-
const
|
|
20460
|
-
const
|
|
21533
|
+
const projectSafety = getProjectSafety(projectRoot, config);
|
|
21534
|
+
const isHomeDir = projectSafety.blockedReason === "home-directory";
|
|
21535
|
+
const isValidProject = projectSafety.safeToRun;
|
|
20461
21536
|
if (isHomeDir) {
|
|
20462
21537
|
console.warn(
|
|
20463
21538
|
`[codebase-index] Refusing to watch or index home directory "${projectRoot}". Open a specific project directory instead.`
|
|
@@ -20467,16 +21542,24 @@ var plugin = async ({ directory, worktree }) => {
|
|
|
20467
21542
|
`[codebase-index] Skipping file watching and auto-indexing: no project marker found in "${projectRoot}". Set "indexing.requireProjectMarker": false in config to override.`
|
|
20468
21543
|
);
|
|
20469
21544
|
}
|
|
20470
|
-
if (
|
|
20471
|
-
|
|
20472
|
-
|
|
20473
|
-
|
|
20474
|
-
await replaceActiveWatcher(
|
|
20475
|
-
projectRoot,
|
|
20476
|
-
() => createWatcherWithIndexer(getProjectIndexer, projectRoot, config, "opencode")
|
|
20477
|
-
);
|
|
21545
|
+
if (!isValidProject) {
|
|
21546
|
+
await stopBackgroundWorker(projectRoot, "opencode").catch((error) => {
|
|
21547
|
+
console.error("[codebase-index] Failed to stop unsafe OpenCode background worker:", error);
|
|
21548
|
+
});
|
|
20478
21549
|
} else {
|
|
20479
|
-
|
|
21550
|
+
const watcherFactoryForConfig = (refreshedConfig) => refreshedConfig.indexing.watchFiles ? () => createWatcherWithIndexer(getProjectIndexer, projectRoot, refreshedConfig, "opencode") : null;
|
|
21551
|
+
configureBackgroundWorker(projectRoot, "opencode", config, {
|
|
21552
|
+
startAutoIndex: (source, allowDisabledAutoIndex) => {
|
|
21553
|
+
startAutoIndexForBackgroundWorker(projectRoot, "opencode", source, allowDisabledAutoIndex);
|
|
21554
|
+
},
|
|
21555
|
+
stopAutoIndex: () => stopAutoIndexForBackgroundWorker(projectRoot, "opencode"),
|
|
21556
|
+
watcherFactory: watcherFactoryForConfig(config),
|
|
21557
|
+
watcherFactoryForConfig,
|
|
21558
|
+
replaceWatcher: true
|
|
21559
|
+
}, {
|
|
21560
|
+
restartAutoIndex: true
|
|
21561
|
+
});
|
|
21562
|
+
await waitForBackgroundWorkerStart(projectRoot, "opencode");
|
|
20480
21563
|
}
|
|
20481
21564
|
return {
|
|
20482
21565
|
tool: {
|