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.js
CHANGED
|
@@ -328,7 +328,7 @@ var require_ignore = __commonJS({
|
|
|
328
328
|
// path matching.
|
|
329
329
|
// - check `string` either `MODE_IGNORE` or `MODE_CHECK_IGNORE`
|
|
330
330
|
// @returns {TestResult} true if a file is ignored
|
|
331
|
-
test(
|
|
331
|
+
test(path31, checkUnignored, mode) {
|
|
332
332
|
let ignored = false;
|
|
333
333
|
let unignored = false;
|
|
334
334
|
let matchedRule;
|
|
@@ -337,7 +337,7 @@ var require_ignore = __commonJS({
|
|
|
337
337
|
if (unignored === negative && ignored !== unignored || negative && !ignored && !unignored && !checkUnignored) {
|
|
338
338
|
return;
|
|
339
339
|
}
|
|
340
|
-
const matched = rule[mode].test(
|
|
340
|
+
const matched = rule[mode].test(path31);
|
|
341
341
|
if (!matched) {
|
|
342
342
|
return;
|
|
343
343
|
}
|
|
@@ -358,17 +358,17 @@ var require_ignore = __commonJS({
|
|
|
358
358
|
var throwError = (message, Ctor) => {
|
|
359
359
|
throw new Ctor(message);
|
|
360
360
|
};
|
|
361
|
-
var checkPath = (
|
|
362
|
-
if (!isString(
|
|
361
|
+
var checkPath = (path31, originalPath, doThrow) => {
|
|
362
|
+
if (!isString(path31)) {
|
|
363
363
|
return doThrow(
|
|
364
364
|
`path must be a string, but got \`${originalPath}\``,
|
|
365
365
|
TypeError
|
|
366
366
|
);
|
|
367
367
|
}
|
|
368
|
-
if (!
|
|
368
|
+
if (!path31) {
|
|
369
369
|
return doThrow(`path must not be empty`, TypeError);
|
|
370
370
|
}
|
|
371
|
-
if (checkPath.isNotRelative(
|
|
371
|
+
if (checkPath.isNotRelative(path31)) {
|
|
372
372
|
const r = "`path.relative()`d";
|
|
373
373
|
return doThrow(
|
|
374
374
|
`path should be a ${r} string, but got "${originalPath}"`,
|
|
@@ -377,7 +377,7 @@ var require_ignore = __commonJS({
|
|
|
377
377
|
}
|
|
378
378
|
return true;
|
|
379
379
|
};
|
|
380
|
-
var isNotRelative = (
|
|
380
|
+
var isNotRelative = (path31) => REGEX_TEST_INVALID_PATH.test(path31);
|
|
381
381
|
checkPath.isNotRelative = isNotRelative;
|
|
382
382
|
checkPath.convert = (p) => p;
|
|
383
383
|
var Ignore2 = class {
|
|
@@ -407,19 +407,19 @@ var require_ignore = __commonJS({
|
|
|
407
407
|
}
|
|
408
408
|
// @returns {TestResult}
|
|
409
409
|
_test(originalPath, cache, checkUnignored, slices) {
|
|
410
|
-
const
|
|
410
|
+
const path31 = originalPath && checkPath.convert(originalPath);
|
|
411
411
|
checkPath(
|
|
412
|
-
|
|
412
|
+
path31,
|
|
413
413
|
originalPath,
|
|
414
414
|
this._strictPathCheck ? throwError : RETURN_FALSE
|
|
415
415
|
);
|
|
416
|
-
return this._t(
|
|
416
|
+
return this._t(path31, cache, checkUnignored, slices);
|
|
417
417
|
}
|
|
418
|
-
checkIgnore(
|
|
419
|
-
if (!REGEX_TEST_TRAILING_SLASH.test(
|
|
420
|
-
return this.test(
|
|
418
|
+
checkIgnore(path31) {
|
|
419
|
+
if (!REGEX_TEST_TRAILING_SLASH.test(path31)) {
|
|
420
|
+
return this.test(path31);
|
|
421
421
|
}
|
|
422
|
-
const slices =
|
|
422
|
+
const slices = path31.split(SLASH2).filter(Boolean);
|
|
423
423
|
slices.pop();
|
|
424
424
|
if (slices.length) {
|
|
425
425
|
const parent = this._t(
|
|
@@ -432,18 +432,18 @@ var require_ignore = __commonJS({
|
|
|
432
432
|
return parent;
|
|
433
433
|
}
|
|
434
434
|
}
|
|
435
|
-
return this._rules.test(
|
|
435
|
+
return this._rules.test(path31, false, MODE_CHECK_IGNORE);
|
|
436
436
|
}
|
|
437
|
-
_t(
|
|
438
|
-
if (
|
|
439
|
-
return cache[
|
|
437
|
+
_t(path31, cache, checkUnignored, slices) {
|
|
438
|
+
if (path31 in cache) {
|
|
439
|
+
return cache[path31];
|
|
440
440
|
}
|
|
441
441
|
if (!slices) {
|
|
442
|
-
slices =
|
|
442
|
+
slices = path31.split(SLASH2).filter(Boolean);
|
|
443
443
|
}
|
|
444
444
|
slices.pop();
|
|
445
445
|
if (!slices.length) {
|
|
446
|
-
return cache[
|
|
446
|
+
return cache[path31] = this._rules.test(path31, checkUnignored, MODE_IGNORE);
|
|
447
447
|
}
|
|
448
448
|
const parent = this._t(
|
|
449
449
|
slices.join(SLASH2) + SLASH2,
|
|
@@ -451,29 +451,29 @@ var require_ignore = __commonJS({
|
|
|
451
451
|
checkUnignored,
|
|
452
452
|
slices
|
|
453
453
|
);
|
|
454
|
-
return cache[
|
|
454
|
+
return cache[path31] = parent.ignored ? parent : this._rules.test(path31, checkUnignored, MODE_IGNORE);
|
|
455
455
|
}
|
|
456
|
-
ignores(
|
|
457
|
-
return this._test(
|
|
456
|
+
ignores(path31) {
|
|
457
|
+
return this._test(path31, this._ignoreCache, false).ignored;
|
|
458
458
|
}
|
|
459
459
|
createFilter() {
|
|
460
|
-
return (
|
|
460
|
+
return (path31) => !this.ignores(path31);
|
|
461
461
|
}
|
|
462
462
|
filter(paths) {
|
|
463
463
|
return makeArray(paths).filter(this.createFilter());
|
|
464
464
|
}
|
|
465
465
|
// @returns {TestResult}
|
|
466
|
-
test(
|
|
467
|
-
return this._test(
|
|
466
|
+
test(path31) {
|
|
467
|
+
return this._test(path31, this._testCache, true);
|
|
468
468
|
}
|
|
469
469
|
};
|
|
470
470
|
var factory = (options) => new Ignore2(options);
|
|
471
|
-
var isPathValid = (
|
|
471
|
+
var isPathValid = (path31) => checkPath(path31 && checkPath.convert(path31), path31, RETURN_FALSE);
|
|
472
472
|
var setupWindows = () => {
|
|
473
473
|
const makePosix = (str) => /^\\\\\?\\/.test(str) || /["<>|\u0000-\u001F]+/u.test(str) ? str : str.replace(/\\/g, "/");
|
|
474
474
|
checkPath.convert = makePosix;
|
|
475
475
|
const REGEX_TEST_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i;
|
|
476
|
-
checkPath.isNotRelative = (
|
|
476
|
+
checkPath.isNotRelative = (path31) => REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path31) || isNotRelative(path31);
|
|
477
477
|
};
|
|
478
478
|
if (
|
|
479
479
|
// Detect `process` so that it can run in browsers.
|
|
@@ -651,7 +651,7 @@ var require_eventemitter3 = __commonJS({
|
|
|
651
651
|
});
|
|
652
652
|
|
|
653
653
|
// src/adapters/opencode.ts
|
|
654
|
-
import * as
|
|
654
|
+
import * as path30 from "path";
|
|
655
655
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
656
656
|
|
|
657
657
|
// src/config/constants.ts
|
|
@@ -1749,8 +1749,8 @@ function loadMergedConfig(projectRoot, host) {
|
|
|
1749
1749
|
}
|
|
1750
1750
|
|
|
1751
1751
|
// src/tools/operations.ts
|
|
1752
|
-
import { existsSync as
|
|
1753
|
-
import * as
|
|
1752
|
+
import { existsSync as existsSync13, realpathSync as realpathSync6, statSync as statSync5 } from "fs";
|
|
1753
|
+
import * as path21 from "path";
|
|
1754
1754
|
|
|
1755
1755
|
// src/tools/knowledge-base-paths.ts
|
|
1756
1756
|
import * as path8 from "path";
|
|
@@ -2599,8 +2599,8 @@ function formatExactSearchHandoff(results) {
|
|
|
2599
2599
|
}
|
|
2600
2600
|
function formatContextEvidence(result, index) {
|
|
2601
2601
|
const symbol = result.name ? ` ${JSON.stringify(compactEvidenceValue(result.name, 80))}` : "";
|
|
2602
|
-
const
|
|
2603
|
-
return `[${index}] ${result.chunkType}${symbol} in ${
|
|
2602
|
+
const path31 = compactEvidenceValue(result.filePath, 120);
|
|
2603
|
+
return `[${index}] ${result.chunkType}${symbol} in ${path31}:${result.startLine}-${result.endLine} (score ${result.score.toFixed(2)})`;
|
|
2604
2604
|
}
|
|
2605
2605
|
function formatContextPack(heading, selected, candidateCount, duplicateCount, limitOmittedCount, budgetOmittedCount, includeExactSearchHandoff) {
|
|
2606
2606
|
const lines = selected.map((result, index) => formatContextEvidence(result, index + 1));
|
|
@@ -3242,9 +3242,9 @@ function formatEffectivenessMetrics(snapshot) {
|
|
|
3242
3242
|
}
|
|
3243
3243
|
|
|
3244
3244
|
// src/utils/auto-index.ts
|
|
3245
|
-
import { existsSync as
|
|
3246
|
-
import * as
|
|
3247
|
-
import * as
|
|
3245
|
+
import { existsSync as existsSync8, realpathSync as realpathSync4 } from "fs";
|
|
3246
|
+
import * as os4 from "os";
|
|
3247
|
+
import * as path12 from "path";
|
|
3248
3248
|
|
|
3249
3249
|
// src/indexer/index-lock.ts
|
|
3250
3250
|
import { randomUUID } from "crypto";
|
|
@@ -3501,7 +3501,7 @@ function removeDeadReclaimMarker(lockPath, expectedOwner) {
|
|
|
3501
3501
|
return true;
|
|
3502
3502
|
}
|
|
3503
3503
|
function reclaimDeadOwner(indexPath, lockPath, expectedOwner) {
|
|
3504
|
-
const
|
|
3504
|
+
const reclaimPath2 = path9.join(lockPath, RECLAIM_DIRECTORY_NAME);
|
|
3505
3505
|
const reclaimOwner = {
|
|
3506
3506
|
pid: process.pid,
|
|
3507
3507
|
hostname: os2.hostname(),
|
|
@@ -3510,19 +3510,19 @@ function reclaimDeadOwner(indexPath, lockPath, expectedOwner) {
|
|
|
3510
3510
|
expectedOwnerToken: expectedOwner.token
|
|
3511
3511
|
};
|
|
3512
3512
|
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
3513
|
-
if (publishJsonDirectory(
|
|
3513
|
+
if (publishJsonDirectory(reclaimPath2, reclaimOwner)) break;
|
|
3514
3514
|
if (attempt === 0 && removeDeadReclaimMarker(lockPath, expectedOwner)) continue;
|
|
3515
3515
|
return false;
|
|
3516
3516
|
}
|
|
3517
3517
|
try {
|
|
3518
|
-
const currentReclaimer = readReclaimOwner(
|
|
3518
|
+
const currentReclaimer = readReclaimOwner(reclaimPath2);
|
|
3519
3519
|
const currentOwner = readDirectoryOwner(lockPath);
|
|
3520
3520
|
if (!currentReclaimer || !sameReclaimOwner(currentReclaimer, reclaimOwner) || !currentOwner || !sameOwner(currentOwner, expectedOwner) || getOwnerLiveness(currentOwner) !== "dead") {
|
|
3521
3521
|
return false;
|
|
3522
3522
|
}
|
|
3523
3523
|
publishRecoveryMarker(indexPath, expectedOwner);
|
|
3524
3524
|
const ownerBeforeQuarantine = readDirectoryOwner(lockPath);
|
|
3525
|
-
const reclaimerBeforeQuarantine = readReclaimOwner(
|
|
3525
|
+
const reclaimerBeforeQuarantine = readReclaimOwner(reclaimPath2);
|
|
3526
3526
|
if (!ownerBeforeQuarantine || !sameOwner(ownerBeforeQuarantine, expectedOwner) || getOwnerLiveness(ownerBeforeQuarantine) !== "dead" || !reclaimerBeforeQuarantine || !sameReclaimOwner(reclaimerBeforeQuarantine, reclaimOwner)) {
|
|
3527
3527
|
return false;
|
|
3528
3528
|
}
|
|
@@ -3692,10 +3692,893 @@ function completeLeaseRecovery(lease) {
|
|
|
3692
3692
|
}
|
|
3693
3693
|
}
|
|
3694
3694
|
|
|
3695
|
+
// src/utils/background-worker.ts
|
|
3696
|
+
import { createHash, randomUUID as randomUUID2 } from "crypto";
|
|
3697
|
+
import {
|
|
3698
|
+
existsSync as existsSync6,
|
|
3699
|
+
lstatSync as lstatSync2,
|
|
3700
|
+
mkdirSync as mkdirSync2,
|
|
3701
|
+
readFileSync as readFileSync5,
|
|
3702
|
+
realpathSync as realpathSync3,
|
|
3703
|
+
renameSync as renameSync2,
|
|
3704
|
+
rmSync as rmSync2,
|
|
3705
|
+
writeFileSync as writeFileSync2
|
|
3706
|
+
} from "fs";
|
|
3707
|
+
import * as os3 from "os";
|
|
3708
|
+
import * as path10 from "path";
|
|
3709
|
+
var OWNER_FILE_NAME2 = "owner.json";
|
|
3710
|
+
var HEARTBEAT_FILE_PREFIX = "heartbeat.";
|
|
3711
|
+
var RECLAIM_DIRECTORY_NAME2 = "reclaim";
|
|
3712
|
+
var REFRESH_REQUEST_FILE_NAME = "refresh-request.json";
|
|
3713
|
+
var HEARTBEAT_INTERVAL_MS = 5e3;
|
|
3714
|
+
var STALE_LEASE_MS = 3e4;
|
|
3715
|
+
var RETRY_DELAY_MS = 5e3;
|
|
3716
|
+
var UUID_PATTERN2 = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
3717
|
+
var BackgroundWorkerStopError = class extends Error {
|
|
3718
|
+
constructor(watcherError, autoIndexError) {
|
|
3719
|
+
super("Failed to stop background worker");
|
|
3720
|
+
this.watcherError = watcherError;
|
|
3721
|
+
this.autoIndexError = autoIndexError;
|
|
3722
|
+
this.name = "BackgroundWorkerStopError";
|
|
3723
|
+
}
|
|
3724
|
+
watcherError;
|
|
3725
|
+
autoIndexError;
|
|
3726
|
+
};
|
|
3727
|
+
var workers = /* @__PURE__ */ new Map();
|
|
3728
|
+
var workerKeysByProject = /* @__PURE__ */ new Map();
|
|
3729
|
+
var workerReplacementBarriers = /* @__PURE__ */ new Map();
|
|
3730
|
+
function getErrorCode2(error) {
|
|
3731
|
+
return typeof error === "object" && error !== null && "code" in error ? String(error.code) : void 0;
|
|
3732
|
+
}
|
|
3733
|
+
function canonicalizePath(targetPath) {
|
|
3734
|
+
const resolved = path10.resolve(targetPath);
|
|
3735
|
+
if (existsSync6(resolved)) {
|
|
3736
|
+
try {
|
|
3737
|
+
return realpathSync3.native(resolved);
|
|
3738
|
+
} catch {
|
|
3739
|
+
return resolved;
|
|
3740
|
+
}
|
|
3741
|
+
}
|
|
3742
|
+
const parent = path10.dirname(resolved);
|
|
3743
|
+
if (parent === resolved) return resolved;
|
|
3744
|
+
return path10.join(canonicalizePath(parent), path10.basename(resolved));
|
|
3745
|
+
}
|
|
3746
|
+
function projectLookupKey(projectRoot, host) {
|
|
3747
|
+
return `${host}::${canonicalizePath(projectRoot)}`;
|
|
3748
|
+
}
|
|
3749
|
+
function resolveIdentity(projectRoot, config, host) {
|
|
3750
|
+
const canonicalProjectRoot = canonicalizePath(projectRoot);
|
|
3751
|
+
const canonicalIndexPath = canonicalizePath(resolveProjectIndexPath(projectRoot, config.scope, host));
|
|
3752
|
+
return {
|
|
3753
|
+
canonicalIndexPath,
|
|
3754
|
+
canonicalProjectRoot,
|
|
3755
|
+
key: `${canonicalIndexPath}::${canonicalProjectRoot}`
|
|
3756
|
+
};
|
|
3757
|
+
}
|
|
3758
|
+
function controllerKey(identity, host) {
|
|
3759
|
+
return `${identity.key}::${host}`;
|
|
3760
|
+
}
|
|
3761
|
+
function leaseDirectoryName(identity) {
|
|
3762
|
+
const hash = createHash("sha256").update(identity.key).digest("hex").slice(0, 32);
|
|
3763
|
+
return `background-worker.${hash}.lease`;
|
|
3764
|
+
}
|
|
3765
|
+
function leasePathFor(identity) {
|
|
3766
|
+
return path10.join(identity.canonicalIndexPath, leaseDirectoryName(identity));
|
|
3767
|
+
}
|
|
3768
|
+
function parseOwner2(value) {
|
|
3769
|
+
if (typeof value !== "object" || value === null) return null;
|
|
3770
|
+
const candidate = value;
|
|
3771
|
+
if (candidate.version !== 1) return null;
|
|
3772
|
+
if (!Number.isInteger(candidate.pid) || (candidate.pid ?? 0) <= 0) return null;
|
|
3773
|
+
if (typeof candidate.hostname !== "string" || candidate.hostname.length === 0) return null;
|
|
3774
|
+
if (typeof candidate.startedAt !== "string" || Number.isNaN(Date.parse(candidate.startedAt))) return null;
|
|
3775
|
+
if (typeof candidate.heartbeatAt !== "string" || Number.isNaN(Date.parse(candidate.heartbeatAt))) return null;
|
|
3776
|
+
if (typeof candidate.projectRoot !== "string" || candidate.projectRoot.length === 0) return null;
|
|
3777
|
+
if (typeof candidate.indexPath !== "string" || candidate.indexPath.length === 0) return null;
|
|
3778
|
+
if (typeof candidate.token !== "string" || !UUID_PATTERN2.test(candidate.token)) return null;
|
|
3779
|
+
return candidate;
|
|
3780
|
+
}
|
|
3781
|
+
function parseHeartbeat(value, expectedToken) {
|
|
3782
|
+
if (typeof value !== "object" || value === null) return null;
|
|
3783
|
+
const candidate = value;
|
|
3784
|
+
if (candidate.version !== 1 || candidate.token !== expectedToken) return null;
|
|
3785
|
+
if (typeof candidate.heartbeatAt !== "string" || Number.isNaN(Date.parse(candidate.heartbeatAt))) return null;
|
|
3786
|
+
return candidate;
|
|
3787
|
+
}
|
|
3788
|
+
function parseReclaimOwner2(value) {
|
|
3789
|
+
if (typeof value !== "object" || value === null) return null;
|
|
3790
|
+
const candidate = value;
|
|
3791
|
+
if (candidate.version !== 1) return null;
|
|
3792
|
+
if (!Number.isInteger(candidate.pid) || (candidate.pid ?? 0) <= 0) return null;
|
|
3793
|
+
if (typeof candidate.hostname !== "string" || candidate.hostname.length === 0) return null;
|
|
3794
|
+
if (typeof candidate.startedAt !== "string" || Number.isNaN(Date.parse(candidate.startedAt))) return null;
|
|
3795
|
+
if (typeof candidate.token !== "string" || !UUID_PATTERN2.test(candidate.token)) return null;
|
|
3796
|
+
if (candidate.expectedOwnerToken !== null && (typeof candidate.expectedOwnerToken !== "string" || !UUID_PATTERN2.test(candidate.expectedOwnerToken))) return null;
|
|
3797
|
+
return candidate;
|
|
3798
|
+
}
|
|
3799
|
+
function heartbeatPath(leasePath, token) {
|
|
3800
|
+
return path10.join(leasePath, `${HEARTBEAT_FILE_PREFIX}${token}.json`);
|
|
3801
|
+
}
|
|
3802
|
+
function reclaimPath(leasePath) {
|
|
3803
|
+
return path10.join(leasePath, RECLAIM_DIRECTORY_NAME2);
|
|
3804
|
+
}
|
|
3805
|
+
function refreshRequestPath(leasePath) {
|
|
3806
|
+
return path10.join(leasePath, REFRESH_REQUEST_FILE_NAME);
|
|
3807
|
+
}
|
|
3808
|
+
function readLeaseOwner(leasePath) {
|
|
3809
|
+
try {
|
|
3810
|
+
return parseOwner2(JSON.parse(readFileSync5(path10.join(leasePath, OWNER_FILE_NAME2), "utf-8")));
|
|
3811
|
+
} catch {
|
|
3812
|
+
return null;
|
|
3813
|
+
}
|
|
3814
|
+
}
|
|
3815
|
+
function readOwner(leasePath) {
|
|
3816
|
+
const owner = readLeaseOwner(leasePath);
|
|
3817
|
+
if (!owner) return null;
|
|
3818
|
+
try {
|
|
3819
|
+
const heartbeat = parseHeartbeat(
|
|
3820
|
+
JSON.parse(readFileSync5(heartbeatPath(leasePath, owner.token), "utf-8")),
|
|
3821
|
+
owner.token
|
|
3822
|
+
);
|
|
3823
|
+
return heartbeat ? { ...owner, heartbeatAt: heartbeat.heartbeatAt } : owner;
|
|
3824
|
+
} catch {
|
|
3825
|
+
return owner;
|
|
3826
|
+
}
|
|
3827
|
+
}
|
|
3828
|
+
function readReclaimOwner2(leasePath) {
|
|
3829
|
+
try {
|
|
3830
|
+
return parseReclaimOwner2(JSON.parse(readFileSync5(path10.join(reclaimPath(leasePath), OWNER_FILE_NAME2), "utf-8")));
|
|
3831
|
+
} catch {
|
|
3832
|
+
return null;
|
|
3833
|
+
}
|
|
3834
|
+
}
|
|
3835
|
+
function ownerLiveness(owner) {
|
|
3836
|
+
if (owner.hostname !== os3.hostname()) return "unknown";
|
|
3837
|
+
try {
|
|
3838
|
+
process.kill(owner.pid, 0);
|
|
3839
|
+
return "alive";
|
|
3840
|
+
} catch (error) {
|
|
3841
|
+
const code = getErrorCode2(error);
|
|
3842
|
+
if (code === "ESRCH") return "dead";
|
|
3843
|
+
if (code === "EPERM") return "alive";
|
|
3844
|
+
return "unknown";
|
|
3845
|
+
}
|
|
3846
|
+
}
|
|
3847
|
+
function isHeartbeatExpired(owner) {
|
|
3848
|
+
return Date.now() - Date.parse(owner.heartbeatAt) >= STALE_LEASE_MS;
|
|
3849
|
+
}
|
|
3850
|
+
function sameOwner2(left, right) {
|
|
3851
|
+
return left.pid === right.pid && left.hostname === right.hostname && left.token === right.token;
|
|
3852
|
+
}
|
|
3853
|
+
function writeHeartbeat(leasePath, owner) {
|
|
3854
|
+
const targetPath = heartbeatPath(leasePath, owner.token);
|
|
3855
|
+
const temporaryPath = `${targetPath}.tmp.${process.pid}.${owner.token}.${randomUUID2()}`;
|
|
3856
|
+
const heartbeat = {
|
|
3857
|
+
version: 1,
|
|
3858
|
+
token: owner.token,
|
|
3859
|
+
heartbeatAt: owner.heartbeatAt
|
|
3860
|
+
};
|
|
3861
|
+
try {
|
|
3862
|
+
writeFileSync2(temporaryPath, JSON.stringify(heartbeat), {
|
|
3863
|
+
encoding: "utf-8",
|
|
3864
|
+
flag: "wx",
|
|
3865
|
+
mode: 384
|
|
3866
|
+
});
|
|
3867
|
+
renameSync2(temporaryPath, targetPath);
|
|
3868
|
+
const currentOwner = readLeaseOwner(leasePath);
|
|
3869
|
+
return currentOwner !== null && sameOwner2(currentOwner, owner);
|
|
3870
|
+
} finally {
|
|
3871
|
+
if (existsSync6(temporaryPath)) rmSync2(temporaryPath, { force: true });
|
|
3872
|
+
}
|
|
3873
|
+
}
|
|
3874
|
+
function requestRefreshFromLeader(leasePath, allowDisabledAutoIndex) {
|
|
3875
|
+
const requestPath = refreshRequestPath(leasePath);
|
|
3876
|
+
const temporaryPath = `${requestPath}.tmp.${process.pid}.${randomUUID2()}`;
|
|
3877
|
+
try {
|
|
3878
|
+
const request = {
|
|
3879
|
+
allowDisabledAutoIndex,
|
|
3880
|
+
requestedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3881
|
+
version: 1
|
|
3882
|
+
};
|
|
3883
|
+
writeFileSync2(temporaryPath, JSON.stringify(request), {
|
|
3884
|
+
encoding: "utf-8",
|
|
3885
|
+
flag: "wx",
|
|
3886
|
+
mode: 384
|
|
3887
|
+
});
|
|
3888
|
+
renameSync2(temporaryPath, requestPath);
|
|
3889
|
+
} catch (error) {
|
|
3890
|
+
if (getErrorCode2(error) !== "ENOENT") {
|
|
3891
|
+
console.error("[codebase-index] Failed to request background index refresh from the project worker:", error);
|
|
3892
|
+
}
|
|
3893
|
+
} finally {
|
|
3894
|
+
if (existsSync6(temporaryPath)) rmSync2(temporaryPath, { force: true });
|
|
3895
|
+
}
|
|
3896
|
+
}
|
|
3897
|
+
function consumeRefreshRequest(leasePath) {
|
|
3898
|
+
const requestPath = refreshRequestPath(leasePath);
|
|
3899
|
+
const claimedPath = `${requestPath}.handling.${process.pid}.${randomUUID2()}`;
|
|
3900
|
+
try {
|
|
3901
|
+
renameSync2(requestPath, claimedPath);
|
|
3902
|
+
} catch (error) {
|
|
3903
|
+
if (getErrorCode2(error) === "ENOENT") return null;
|
|
3904
|
+
throw error;
|
|
3905
|
+
}
|
|
3906
|
+
try {
|
|
3907
|
+
const value = JSON.parse(readFileSync5(claimedPath, "utf-8"));
|
|
3908
|
+
return {
|
|
3909
|
+
allowDisabledAutoIndex: value.version === 1 && value.allowDisabledAutoIndex === true,
|
|
3910
|
+
requestedAt: typeof value.requestedAt === "string" ? value.requestedAt : (/* @__PURE__ */ new Date()).toISOString(),
|
|
3911
|
+
version: 1
|
|
3912
|
+
};
|
|
3913
|
+
} catch {
|
|
3914
|
+
return { allowDisabledAutoIndex: false, requestedAt: (/* @__PURE__ */ new Date()).toISOString(), version: 1 };
|
|
3915
|
+
} finally {
|
|
3916
|
+
rmSync2(claimedPath, { force: true });
|
|
3917
|
+
}
|
|
3918
|
+
}
|
|
3919
|
+
function publishLease(leasePath, owner) {
|
|
3920
|
+
const candidatePath = `${leasePath}.candidate.${process.pid}.${owner.token}`;
|
|
3921
|
+
try {
|
|
3922
|
+
mkdirSync2(candidatePath, { mode: 448 });
|
|
3923
|
+
} catch (error) {
|
|
3924
|
+
if (getErrorCode2(error) === "ENOENT") return false;
|
|
3925
|
+
throw error;
|
|
3926
|
+
}
|
|
3927
|
+
try {
|
|
3928
|
+
writeFileSync2(path10.join(candidatePath, OWNER_FILE_NAME2), JSON.stringify(owner), {
|
|
3929
|
+
encoding: "utf-8",
|
|
3930
|
+
flag: "wx",
|
|
3931
|
+
mode: 384
|
|
3932
|
+
});
|
|
3933
|
+
if (existsSync6(leasePath)) return false;
|
|
3934
|
+
try {
|
|
3935
|
+
renameSync2(candidatePath, leasePath);
|
|
3936
|
+
return true;
|
|
3937
|
+
} catch (error) {
|
|
3938
|
+
if (existsSync6(leasePath) || getErrorCode2(error) === "ENOENT") return false;
|
|
3939
|
+
throw error;
|
|
3940
|
+
}
|
|
3941
|
+
} finally {
|
|
3942
|
+
if (existsSync6(candidatePath)) rmSync2(candidatePath, { recursive: true, force: true });
|
|
3943
|
+
}
|
|
3944
|
+
}
|
|
3945
|
+
function sameReclaimOwner2(left, right) {
|
|
3946
|
+
return left.pid === right.pid && left.hostname === right.hostname && left.token === right.token && left.expectedOwnerToken === right.expectedOwnerToken;
|
|
3947
|
+
}
|
|
3948
|
+
function reclaimerLiveness(owner) {
|
|
3949
|
+
return ownerLiveness(owner);
|
|
3950
|
+
}
|
|
3951
|
+
function isReclaimMarkerExpired(leasePath, owner) {
|
|
3952
|
+
const startedAt = owner ? Date.parse(owner.startedAt) : (() => {
|
|
3953
|
+
try {
|
|
3954
|
+
return lstatSync2(reclaimPath(leasePath)).mtimeMs;
|
|
3955
|
+
} catch {
|
|
3956
|
+
return Date.now();
|
|
3957
|
+
}
|
|
3958
|
+
})();
|
|
3959
|
+
return Date.now() - startedAt >= STALE_LEASE_MS;
|
|
3960
|
+
}
|
|
3961
|
+
function hasActiveReclaimMarker(leasePath, owner) {
|
|
3962
|
+
const marker = readReclaimOwner2(leasePath);
|
|
3963
|
+
return marker !== null && marker.expectedOwnerToken === owner.token && (marker.hostname !== os3.hostname() || ownerLiveness(owner) !== "alive");
|
|
3964
|
+
}
|
|
3965
|
+
function publishReclaimMarker(leasePath, expectedOwner) {
|
|
3966
|
+
const markerPath = reclaimPath(leasePath);
|
|
3967
|
+
const owner = {
|
|
3968
|
+
version: 1,
|
|
3969
|
+
pid: process.pid,
|
|
3970
|
+
hostname: os3.hostname(),
|
|
3971
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3972
|
+
token: randomUUID2(),
|
|
3973
|
+
expectedOwnerToken: expectedOwner?.token ?? null
|
|
3974
|
+
};
|
|
3975
|
+
try {
|
|
3976
|
+
mkdirSync2(markerPath, { mode: 448 });
|
|
3977
|
+
} catch (error) {
|
|
3978
|
+
if (getErrorCode2(error) === "EEXIST" || getErrorCode2(error) === "ENOENT") return null;
|
|
3979
|
+
throw error;
|
|
3980
|
+
}
|
|
3981
|
+
try {
|
|
3982
|
+
writeFileSync2(path10.join(markerPath, OWNER_FILE_NAME2), JSON.stringify(owner), {
|
|
3983
|
+
encoding: "utf-8",
|
|
3984
|
+
flag: "wx",
|
|
3985
|
+
mode: 384
|
|
3986
|
+
});
|
|
3987
|
+
return owner;
|
|
3988
|
+
} catch (error) {
|
|
3989
|
+
rmSync2(markerPath, { recursive: true, force: true });
|
|
3990
|
+
throw error;
|
|
3991
|
+
}
|
|
3992
|
+
}
|
|
3993
|
+
function removeExpiredReclaimMarker(leasePath, expectedOwner) {
|
|
3994
|
+
const marker = readReclaimOwner2(leasePath);
|
|
3995
|
+
const markerPath = reclaimPath(leasePath);
|
|
3996
|
+
if (!existsSync6(markerPath)) return false;
|
|
3997
|
+
if (marker && marker.expectedOwnerToken !== (expectedOwner?.token ?? null)) return false;
|
|
3998
|
+
if (marker && (reclaimerLiveness(marker) === "alive" || !isReclaimMarkerExpired(leasePath, marker))) return false;
|
|
3999
|
+
if (!marker && !isReclaimMarkerExpired(leasePath, null)) return false;
|
|
4000
|
+
const staleMarkerPath = `${markerPath}.stale.${marker?.pid ?? process.pid}.${marker?.token ?? randomUUID2()}.${randomUUID2()}`;
|
|
4001
|
+
try {
|
|
4002
|
+
renameSync2(markerPath, staleMarkerPath);
|
|
4003
|
+
} catch (error) {
|
|
4004
|
+
if (getErrorCode2(error) === "ENOENT") return false;
|
|
4005
|
+
throw error;
|
|
4006
|
+
}
|
|
4007
|
+
try {
|
|
4008
|
+
let claimedMarker = null;
|
|
4009
|
+
try {
|
|
4010
|
+
claimedMarker = parseReclaimOwner2(
|
|
4011
|
+
JSON.parse(readFileSync5(path10.join(staleMarkerPath, OWNER_FILE_NAME2), "utf-8"))
|
|
4012
|
+
);
|
|
4013
|
+
} catch {
|
|
4014
|
+
claimedMarker = null;
|
|
4015
|
+
}
|
|
4016
|
+
const markerMatches = marker ? claimedMarker !== null && sameReclaimOwner2(claimedMarker, marker) : claimedMarker === null;
|
|
4017
|
+
if (!markerMatches || !canReclaimLease(leasePath, expectedOwner)) {
|
|
4018
|
+
if (!existsSync6(markerPath) && existsSync6(staleMarkerPath)) renameSync2(staleMarkerPath, markerPath);
|
|
4019
|
+
return false;
|
|
4020
|
+
}
|
|
4021
|
+
rmSync2(staleMarkerPath, { recursive: true, force: true });
|
|
4022
|
+
return true;
|
|
4023
|
+
} catch (error) {
|
|
4024
|
+
if (getErrorCode2(error) === "ENOENT") return false;
|
|
4025
|
+
throw error;
|
|
4026
|
+
}
|
|
4027
|
+
}
|
|
4028
|
+
function canReclaimLease(leasePath, expectedOwner) {
|
|
4029
|
+
if (!existsSync6(leasePath)) return false;
|
|
4030
|
+
if (!expectedOwner) return false;
|
|
4031
|
+
const currentOwner = readOwner(leasePath);
|
|
4032
|
+
if (!currentOwner || !sameOwner2(currentOwner, expectedOwner)) return false;
|
|
4033
|
+
if (currentOwner.hostname === os3.hostname()) {
|
|
4034
|
+
return ownerLiveness(currentOwner) === "dead";
|
|
4035
|
+
}
|
|
4036
|
+
return isHeartbeatExpired(currentOwner);
|
|
4037
|
+
}
|
|
4038
|
+
function reclaimLease(leasePath, expectedOwner) {
|
|
4039
|
+
let marker = null;
|
|
4040
|
+
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
4041
|
+
marker = publishReclaimMarker(leasePath, expectedOwner);
|
|
4042
|
+
if (marker) break;
|
|
4043
|
+
if (attempt === 0 && removeExpiredReclaimMarker(leasePath, expectedOwner)) continue;
|
|
4044
|
+
return false;
|
|
4045
|
+
}
|
|
4046
|
+
if (!marker) return false;
|
|
4047
|
+
const markerPath = reclaimPath(leasePath);
|
|
4048
|
+
try {
|
|
4049
|
+
const currentMarker = readReclaimOwner2(leasePath);
|
|
4050
|
+
if (!currentMarker || !sameReclaimOwner2(currentMarker, marker) || !canReclaimLease(leasePath, expectedOwner)) {
|
|
4051
|
+
return false;
|
|
4052
|
+
}
|
|
4053
|
+
const stalePath = `${leasePath}.stale.${process.pid}.${marker.token}`;
|
|
4054
|
+
renameSync2(leasePath, stalePath);
|
|
4055
|
+
const quarantinedOwner = readOwner(stalePath);
|
|
4056
|
+
const quarantinedMarker = readReclaimOwner2(stalePath);
|
|
4057
|
+
if (!quarantinedMarker || !sameReclaimOwner2(quarantinedMarker, marker) || expectedOwner !== null && (!quarantinedOwner || !sameOwner2(quarantinedOwner, expectedOwner))) {
|
|
4058
|
+
if (!existsSync6(leasePath) && existsSync6(stalePath)) renameSync2(stalePath, leasePath);
|
|
4059
|
+
return false;
|
|
4060
|
+
}
|
|
4061
|
+
rmSync2(stalePath, { recursive: true, force: true });
|
|
4062
|
+
return true;
|
|
4063
|
+
} catch (error) {
|
|
4064
|
+
if (getErrorCode2(error) === "ENOENT") return false;
|
|
4065
|
+
throw error;
|
|
4066
|
+
} finally {
|
|
4067
|
+
const currentMarker = readReclaimOwner2(leasePath);
|
|
4068
|
+
if (currentMarker && sameReclaimOwner2(currentMarker, marker)) {
|
|
4069
|
+
rmSync2(markerPath, { recursive: true, force: true });
|
|
4070
|
+
}
|
|
4071
|
+
}
|
|
4072
|
+
}
|
|
4073
|
+
function acquireLease(identity) {
|
|
4074
|
+
mkdirSync2(identity.canonicalIndexPath, { recursive: true, mode: 448 });
|
|
4075
|
+
const canonicalIndexPath = realpathSync3.native(identity.canonicalIndexPath);
|
|
4076
|
+
const leasePath = path10.join(canonicalIndexPath, leaseDirectoryName({ ...identity, canonicalIndexPath }));
|
|
4077
|
+
for (let attempt = 0; attempt < 4; attempt += 1) {
|
|
4078
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
4079
|
+
const owner = {
|
|
4080
|
+
version: 1,
|
|
4081
|
+
pid: process.pid,
|
|
4082
|
+
hostname: os3.hostname(),
|
|
4083
|
+
startedAt: timestamp,
|
|
4084
|
+
heartbeatAt: timestamp,
|
|
4085
|
+
projectRoot: identity.canonicalProjectRoot,
|
|
4086
|
+
indexPath: canonicalIndexPath,
|
|
4087
|
+
token: randomUUID2()
|
|
4088
|
+
};
|
|
4089
|
+
if (publishLease(leasePath, owner)) {
|
|
4090
|
+
return { leasePath, owner };
|
|
4091
|
+
}
|
|
4092
|
+
const existingOwner = readOwner(leasePath);
|
|
4093
|
+
if (existingOwner) {
|
|
4094
|
+
if (canReclaimLease(leasePath, existingOwner) && reclaimLease(leasePath, existingOwner)) continue;
|
|
4095
|
+
return null;
|
|
4096
|
+
}
|
|
4097
|
+
return null;
|
|
4098
|
+
}
|
|
4099
|
+
return null;
|
|
4100
|
+
}
|
|
4101
|
+
function releaseLease(lease) {
|
|
4102
|
+
const currentOwner = readOwner(lease.leasePath);
|
|
4103
|
+
if (!currentOwner || !sameOwner2(currentOwner, lease.owner)) return false;
|
|
4104
|
+
const releasePath = `${lease.leasePath}.release.${lease.owner.pid}.${lease.owner.token}`;
|
|
4105
|
+
try {
|
|
4106
|
+
renameSync2(lease.leasePath, releasePath);
|
|
4107
|
+
} catch (error) {
|
|
4108
|
+
if (getErrorCode2(error) === "ENOENT") return false;
|
|
4109
|
+
throw error;
|
|
4110
|
+
}
|
|
4111
|
+
const claimedOwner = readOwner(releasePath);
|
|
4112
|
+
if (!claimedOwner || !sameOwner2(claimedOwner, lease.owner)) {
|
|
4113
|
+
if (!existsSync6(lease.leasePath) && existsSync6(releasePath)) {
|
|
4114
|
+
renameSync2(releasePath, lease.leasePath);
|
|
4115
|
+
}
|
|
4116
|
+
return false;
|
|
4117
|
+
}
|
|
4118
|
+
rmSync2(releasePath, { recursive: true, force: true });
|
|
4119
|
+
return true;
|
|
4120
|
+
}
|
|
4121
|
+
var BackgroundWorkerController = class {
|
|
4122
|
+
constructor(projectRoot, host, config, hooks, identity) {
|
|
4123
|
+
this.projectRoot = projectRoot;
|
|
4124
|
+
this.host = host;
|
|
4125
|
+
this.config = config;
|
|
4126
|
+
this.hooks = hooks;
|
|
4127
|
+
this.identity = identity;
|
|
4128
|
+
}
|
|
4129
|
+
projectRoot;
|
|
4130
|
+
host;
|
|
4131
|
+
config;
|
|
4132
|
+
hooks;
|
|
4133
|
+
identity;
|
|
4134
|
+
lease = null;
|
|
4135
|
+
watcher = null;
|
|
4136
|
+
leaderReady = Promise.resolve();
|
|
4137
|
+
heartbeatTimer = null;
|
|
4138
|
+
retryTimer = null;
|
|
4139
|
+
teardownRetryTimer = null;
|
|
4140
|
+
transition = Promise.resolve();
|
|
4141
|
+
stopPromise = null;
|
|
4142
|
+
stopped = false;
|
|
4143
|
+
stopping = false;
|
|
4144
|
+
losingLeadership = false;
|
|
4145
|
+
restartAfterStop = false;
|
|
4146
|
+
leaderWorkStopped = false;
|
|
4147
|
+
startingLeaderWork = false;
|
|
4148
|
+
stopAutoIndexOnTeardown = true;
|
|
4149
|
+
autoIndexStarted = false;
|
|
4150
|
+
reportedError = null;
|
|
4151
|
+
update(config, hooks, options) {
|
|
4152
|
+
const autoIndexWasEnabled = this.config.indexing.autoIndex;
|
|
4153
|
+
const shouldReplaceWatcher = this.watcher !== null && hooks.watcherFactory !== void 0 && (hooks.watcherFactory === null || hooks.replaceWatcher === true);
|
|
4154
|
+
this.config = config;
|
|
4155
|
+
this.hooks = {
|
|
4156
|
+
...this.hooks,
|
|
4157
|
+
...hooks,
|
|
4158
|
+
watcherFactory: hooks.watcherFactory === void 0 ? this.hooks.watcherFactory : hooks.watcherFactory,
|
|
4159
|
+
watcherFactoryForConfig: hooks.watcherFactoryForConfig === void 0 ? this.hooks.watcherFactoryForConfig : hooks.watcherFactoryForConfig
|
|
4160
|
+
};
|
|
4161
|
+
if (autoIndexWasEnabled && !config.indexing.autoIndex || options.restartAutoIndex === true && config.indexing.autoIndex && !this.startingLeaderWork) {
|
|
4162
|
+
this.autoIndexStarted = false;
|
|
4163
|
+
}
|
|
4164
|
+
if (!this.canRun()) {
|
|
4165
|
+
void this.stop().catch((error) => {
|
|
4166
|
+
console.error("[codebase-index] Failed to stop background worker after disabling automatic work:", error);
|
|
4167
|
+
});
|
|
4168
|
+
return;
|
|
4169
|
+
}
|
|
4170
|
+
if (shouldReplaceWatcher) {
|
|
4171
|
+
void this.enqueue(async () => {
|
|
4172
|
+
const watcher = this.watcher;
|
|
4173
|
+
if (watcher) {
|
|
4174
|
+
await watcher.stop();
|
|
4175
|
+
if (this.watcher === watcher) this.watcher = null;
|
|
4176
|
+
}
|
|
4177
|
+
if (this.lease && !this.stopped) this.startLeaderWork();
|
|
4178
|
+
}).catch((error) => {
|
|
4179
|
+
console.error("[codebase-index] Failed to replace background file watcher:", error);
|
|
4180
|
+
});
|
|
4181
|
+
}
|
|
4182
|
+
this.start();
|
|
4183
|
+
}
|
|
4184
|
+
startAfter(activation) {
|
|
4185
|
+
this.transition = activation.catch(() => void 0);
|
|
4186
|
+
this.start();
|
|
4187
|
+
}
|
|
4188
|
+
start() {
|
|
4189
|
+
if (!this.canRun() || this.losingLeadership) return;
|
|
4190
|
+
if (this.stopping) {
|
|
4191
|
+
this.restartAfterStop = true;
|
|
4192
|
+
return;
|
|
4193
|
+
}
|
|
4194
|
+
this.stopped = false;
|
|
4195
|
+
void this.enqueue(async () => {
|
|
4196
|
+
if (this.stopped || this.stopping || this.losingLeadership || !this.canRun()) return;
|
|
4197
|
+
if (!this.lease) {
|
|
4198
|
+
try {
|
|
4199
|
+
this.lease = acquireLease(this.identity);
|
|
4200
|
+
this.reportedError = null;
|
|
4201
|
+
} catch (error) {
|
|
4202
|
+
this.reportAcquireError(error);
|
|
4203
|
+
this.scheduleRetry();
|
|
4204
|
+
return;
|
|
4205
|
+
}
|
|
4206
|
+
}
|
|
4207
|
+
if (!this.lease) {
|
|
4208
|
+
this.scheduleRetry();
|
|
4209
|
+
return;
|
|
4210
|
+
}
|
|
4211
|
+
this.startHeartbeat();
|
|
4212
|
+
this.startLeaderWork();
|
|
4213
|
+
});
|
|
4214
|
+
}
|
|
4215
|
+
waitForStart() {
|
|
4216
|
+
return this.transition.catch(() => void 0).then(() => this.leaderReady);
|
|
4217
|
+
}
|
|
4218
|
+
requestRefresh(allowDisabledAutoIndex = false) {
|
|
4219
|
+
this.start();
|
|
4220
|
+
if (!this.isLeader()) {
|
|
4221
|
+
requestRefreshFromLeader(leasePathFor(this.identity), allowDisabledAutoIndex);
|
|
4222
|
+
return;
|
|
4223
|
+
}
|
|
4224
|
+
void this.enqueue(async () => {
|
|
4225
|
+
if (this.stopped || !this.lease) return;
|
|
4226
|
+
this.hooks.startAutoIndex("retrieval", allowDisabledAutoIndex);
|
|
4227
|
+
});
|
|
4228
|
+
}
|
|
4229
|
+
isLeader() {
|
|
4230
|
+
return this.lease !== null && !this.stopping && !this.losingLeadership;
|
|
4231
|
+
}
|
|
4232
|
+
isStopping() {
|
|
4233
|
+
return this.stopping;
|
|
4234
|
+
}
|
|
4235
|
+
getHooksForConfig(config) {
|
|
4236
|
+
const watcherFactoryForConfig = this.hooks.watcherFactoryForConfig;
|
|
4237
|
+
if (!watcherFactoryForConfig) return this.hooks;
|
|
4238
|
+
return {
|
|
4239
|
+
...this.hooks,
|
|
4240
|
+
watcherFactory: watcherFactoryForConfig(config),
|
|
4241
|
+
replaceWatcher: true
|
|
4242
|
+
};
|
|
4243
|
+
}
|
|
4244
|
+
attachWatcher(watcherFactory, watcherFactoryForConfig) {
|
|
4245
|
+
if (this.hooks.watcherFactory !== void 0) return;
|
|
4246
|
+
this.hooks = {
|
|
4247
|
+
...this.hooks,
|
|
4248
|
+
watcherFactory,
|
|
4249
|
+
watcherFactoryForConfig: watcherFactoryForConfig ?? this.hooks.watcherFactoryForConfig
|
|
4250
|
+
};
|
|
4251
|
+
this.start();
|
|
4252
|
+
}
|
|
4253
|
+
async stop(stopAutoIndex = true) {
|
|
4254
|
+
if (this.stopPromise) return this.stopPromise;
|
|
4255
|
+
this.stopped = true;
|
|
4256
|
+
this.stopping = true;
|
|
4257
|
+
this.stopAutoIndexOnTeardown &&= stopAutoIndex;
|
|
4258
|
+
this.clearRetryTimer();
|
|
4259
|
+
const attempt = this.enqueue(async () => {
|
|
4260
|
+
try {
|
|
4261
|
+
const lease = this.lease;
|
|
4262
|
+
if (this.leaderWorkStopped) {
|
|
4263
|
+
if (lease) {
|
|
4264
|
+
this.releaseStoppedLease(lease);
|
|
4265
|
+
} else {
|
|
4266
|
+
this.finishStoppedLease();
|
|
4267
|
+
}
|
|
4268
|
+
return;
|
|
4269
|
+
}
|
|
4270
|
+
const hadLeaderWork = lease !== null || this.watcher !== null || this.autoIndexStarted;
|
|
4271
|
+
const stopped = await this.stopLeaderWork(hadLeaderWork && this.stopAutoIndexOnTeardown);
|
|
4272
|
+
if (!lease) {
|
|
4273
|
+
this.finishStoppedLease();
|
|
4274
|
+
return;
|
|
4275
|
+
}
|
|
4276
|
+
if (!stopped.completed) {
|
|
4277
|
+
this.releaseLeaseWhenAutoIndexStops(lease, stopped.completion);
|
|
4278
|
+
return;
|
|
4279
|
+
}
|
|
4280
|
+
this.leaderWorkStopped = true;
|
|
4281
|
+
this.releaseStoppedLease(lease);
|
|
4282
|
+
} catch (error) {
|
|
4283
|
+
this.scheduleTeardownRetry();
|
|
4284
|
+
throw error;
|
|
4285
|
+
}
|
|
4286
|
+
});
|
|
4287
|
+
const completion = attempt.finally(() => {
|
|
4288
|
+
if (this.stopPromise === completion) this.stopPromise = null;
|
|
4289
|
+
});
|
|
4290
|
+
this.stopPromise = completion;
|
|
4291
|
+
return completion;
|
|
4292
|
+
}
|
|
4293
|
+
canRun() {
|
|
4294
|
+
return this.config.indexing.autoIndex || this.hooks.watcherFactory != null;
|
|
4295
|
+
}
|
|
4296
|
+
enqueue(operation) {
|
|
4297
|
+
const next = this.transition.catch(() => void 0).then(operation);
|
|
4298
|
+
this.transition = next;
|
|
4299
|
+
return next;
|
|
4300
|
+
}
|
|
4301
|
+
startLeaderWork() {
|
|
4302
|
+
if (this.stopped || this.stopping || this.losingLeadership) return;
|
|
4303
|
+
this.startingLeaderWork = true;
|
|
4304
|
+
try {
|
|
4305
|
+
if (this.config.indexing.autoIndex && !this.autoIndexStarted) {
|
|
4306
|
+
this.autoIndexStarted = true;
|
|
4307
|
+
this.hooks.startAutoIndex("startup");
|
|
4308
|
+
}
|
|
4309
|
+
if (!this.watcher && this.hooks.watcherFactory) {
|
|
4310
|
+
try {
|
|
4311
|
+
const watcher = this.hooks.watcherFactory();
|
|
4312
|
+
this.watcher = watcher;
|
|
4313
|
+
this.leaderReady = watcher.whenReady?.().catch((error) => {
|
|
4314
|
+
console.error("[codebase-index] Failed while waiting for background file watcher startup:", error);
|
|
4315
|
+
}) ?? Promise.resolve();
|
|
4316
|
+
} catch (error) {
|
|
4317
|
+
console.error("[codebase-index] Failed to start background file watcher:", error);
|
|
4318
|
+
this.leaderReady = Promise.resolve();
|
|
4319
|
+
}
|
|
4320
|
+
}
|
|
4321
|
+
} finally {
|
|
4322
|
+
this.startingLeaderWork = false;
|
|
4323
|
+
}
|
|
4324
|
+
}
|
|
4325
|
+
async stopLeaderWork(stopAutoIndex) {
|
|
4326
|
+
const watcher = this.watcher;
|
|
4327
|
+
let watcherError;
|
|
4328
|
+
if (watcher) {
|
|
4329
|
+
try {
|
|
4330
|
+
await watcher.stop();
|
|
4331
|
+
if (this.watcher === watcher) this.watcher = null;
|
|
4332
|
+
} catch (error) {
|
|
4333
|
+
watcherError = error;
|
|
4334
|
+
}
|
|
4335
|
+
}
|
|
4336
|
+
let autoIndexError;
|
|
4337
|
+
let autoIndexStop = {
|
|
4338
|
+
completed: true,
|
|
4339
|
+
completion: Promise.resolve()
|
|
4340
|
+
};
|
|
4341
|
+
if (stopAutoIndex) {
|
|
4342
|
+
try {
|
|
4343
|
+
autoIndexStop = await this.hooks.stopAutoIndex();
|
|
4344
|
+
this.autoIndexStarted = false;
|
|
4345
|
+
} catch (error) {
|
|
4346
|
+
autoIndexError = error;
|
|
4347
|
+
}
|
|
4348
|
+
}
|
|
4349
|
+
if (watcherError !== void 0 || autoIndexError !== void 0) {
|
|
4350
|
+
throw new BackgroundWorkerStopError(watcherError, autoIndexError);
|
|
4351
|
+
}
|
|
4352
|
+
return autoIndexStop;
|
|
4353
|
+
}
|
|
4354
|
+
releaseLeaseWhenAutoIndexStops(lease, completion) {
|
|
4355
|
+
void completion.then(
|
|
4356
|
+
() => {
|
|
4357
|
+
void this.enqueue(async () => {
|
|
4358
|
+
if (this.lease !== lease || !this.stopping) return;
|
|
4359
|
+
this.leaderWorkStopped = true;
|
|
4360
|
+
this.releaseStoppedLease(lease);
|
|
4361
|
+
}).catch((error) => {
|
|
4362
|
+
console.error("[codebase-index] Failed to release background worker lease after automatic indexing stopped:", error);
|
|
4363
|
+
this.scheduleTeardownRetry();
|
|
4364
|
+
});
|
|
4365
|
+
},
|
|
4366
|
+
(error) => {
|
|
4367
|
+
console.error("[codebase-index] Failed while waiting for automatic indexing to stop:", error);
|
|
4368
|
+
this.scheduleTeardownRetry();
|
|
4369
|
+
}
|
|
4370
|
+
);
|
|
4371
|
+
}
|
|
4372
|
+
releaseStoppedLease(lease) {
|
|
4373
|
+
if (this.lease !== lease) {
|
|
4374
|
+
this.finishStoppedLease();
|
|
4375
|
+
return;
|
|
4376
|
+
}
|
|
4377
|
+
releaseLease(lease);
|
|
4378
|
+
this.lease = null;
|
|
4379
|
+
this.finishStoppedLease();
|
|
4380
|
+
}
|
|
4381
|
+
finishStoppedLease() {
|
|
4382
|
+
this.leaderWorkStopped = false;
|
|
4383
|
+
this.stopAutoIndexOnTeardown = true;
|
|
4384
|
+
this.stopping = false;
|
|
4385
|
+
this.clearTimers();
|
|
4386
|
+
this.restartAfterTeardown();
|
|
4387
|
+
if (!this.stopped || this.stopping) return;
|
|
4388
|
+
const projectKey = projectLookupKey(this.projectRoot, this.host);
|
|
4389
|
+
const key = controllerKey(this.identity, this.host);
|
|
4390
|
+
if (workers.get(key) === this) workers.delete(key);
|
|
4391
|
+
if (workerKeysByProject.get(projectKey) === key) workerKeysByProject.delete(projectKey);
|
|
4392
|
+
}
|
|
4393
|
+
startHeartbeat() {
|
|
4394
|
+
if (this.heartbeatTimer) return;
|
|
4395
|
+
const heartbeat = () => {
|
|
4396
|
+
void this.heartbeat();
|
|
4397
|
+
};
|
|
4398
|
+
this.heartbeatTimer = setInterval(heartbeat, HEARTBEAT_INTERVAL_MS);
|
|
4399
|
+
this.heartbeatTimer.unref?.();
|
|
4400
|
+
}
|
|
4401
|
+
async heartbeat() {
|
|
4402
|
+
const lease = this.lease;
|
|
4403
|
+
if (!lease || this.losingLeadership || this.stopped && !this.stopping) return;
|
|
4404
|
+
if (hasActiveReclaimMarker(lease.leasePath, lease.owner)) {
|
|
4405
|
+
await this.loseLeadership();
|
|
4406
|
+
return;
|
|
4407
|
+
}
|
|
4408
|
+
const currentOwner = readOwner(lease.leasePath);
|
|
4409
|
+
if (!currentOwner || !sameOwner2(currentOwner, lease.owner)) {
|
|
4410
|
+
await this.loseLeadership();
|
|
4411
|
+
return;
|
|
4412
|
+
}
|
|
4413
|
+
try {
|
|
4414
|
+
const nextOwner = { ...lease.owner, heartbeatAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
4415
|
+
if (!writeHeartbeat(lease.leasePath, nextOwner)) {
|
|
4416
|
+
await this.loseLeadership();
|
|
4417
|
+
return;
|
|
4418
|
+
}
|
|
4419
|
+
lease.owner = nextOwner;
|
|
4420
|
+
const refreshRequest = !this.stopping ? consumeRefreshRequest(lease.leasePath) : null;
|
|
4421
|
+
if (refreshRequest) {
|
|
4422
|
+
this.hooks.startAutoIndex("retrieval", refreshRequest.allowDisabledAutoIndex);
|
|
4423
|
+
}
|
|
4424
|
+
} catch (error) {
|
|
4425
|
+
const ownerAfterError = readOwner(lease.leasePath);
|
|
4426
|
+
if (hasActiveReclaimMarker(lease.leasePath, lease.owner) || !ownerAfterError || !sameOwner2(ownerAfterError, lease.owner)) {
|
|
4427
|
+
await this.loseLeadership();
|
|
4428
|
+
return;
|
|
4429
|
+
}
|
|
4430
|
+
console.error("[codebase-index] Failed to renew background worker lease:", error);
|
|
4431
|
+
}
|
|
4432
|
+
}
|
|
4433
|
+
async loseLeadership() {
|
|
4434
|
+
if (this.losingLeadership) return;
|
|
4435
|
+
this.losingLeadership = true;
|
|
4436
|
+
this.clearHeartbeat();
|
|
4437
|
+
await this.enqueue(async () => this.stopAfterLeadershipLoss());
|
|
4438
|
+
}
|
|
4439
|
+
async stopAfterLeadershipLoss() {
|
|
4440
|
+
const lease = this.lease;
|
|
4441
|
+
if (!lease) {
|
|
4442
|
+
this.losingLeadership = false;
|
|
4443
|
+
return;
|
|
4444
|
+
}
|
|
4445
|
+
try {
|
|
4446
|
+
const stopped = await this.stopLeaderWork(true);
|
|
4447
|
+
this.lease = null;
|
|
4448
|
+
this.losingLeadership = false;
|
|
4449
|
+
if (stopped.completed) {
|
|
4450
|
+
this.scheduleRetry();
|
|
4451
|
+
} else {
|
|
4452
|
+
void stopped.completion.then(() => this.scheduleRetry());
|
|
4453
|
+
}
|
|
4454
|
+
} catch (error) {
|
|
4455
|
+
console.error("[codebase-index] Failed to stop background work after losing its lease:", error);
|
|
4456
|
+
this.scheduleLostLeadershipTeardownRetry();
|
|
4457
|
+
}
|
|
4458
|
+
}
|
|
4459
|
+
scheduleRetry() {
|
|
4460
|
+
if (this.stopped || !this.canRun() || this.retryTimer) return;
|
|
4461
|
+
this.retryTimer = setTimeout(() => {
|
|
4462
|
+
this.retryTimer = null;
|
|
4463
|
+
this.start();
|
|
4464
|
+
}, RETRY_DELAY_MS);
|
|
4465
|
+
this.retryTimer.unref?.();
|
|
4466
|
+
}
|
|
4467
|
+
scheduleTeardownRetry() {
|
|
4468
|
+
if (!this.stopping || this.teardownRetryTimer) return;
|
|
4469
|
+
this.teardownRetryTimer = setTimeout(() => {
|
|
4470
|
+
this.teardownRetryTimer = null;
|
|
4471
|
+
void this.stop(this.stopAutoIndexOnTeardown).catch((error) => {
|
|
4472
|
+
console.error("[codebase-index] Failed to retry background worker teardown:", error);
|
|
4473
|
+
});
|
|
4474
|
+
}, RETRY_DELAY_MS);
|
|
4475
|
+
this.teardownRetryTimer.unref?.();
|
|
4476
|
+
}
|
|
4477
|
+
restartAfterTeardown() {
|
|
4478
|
+
if (!this.restartAfterStop || !this.canRun() || this.losingLeadership) return;
|
|
4479
|
+
this.restartAfterStop = false;
|
|
4480
|
+
this.stopped = false;
|
|
4481
|
+
this.start();
|
|
4482
|
+
}
|
|
4483
|
+
scheduleLostLeadershipTeardownRetry() {
|
|
4484
|
+
if (this.stopped || !this.losingLeadership || this.retryTimer) return;
|
|
4485
|
+
this.retryTimer = setTimeout(() => {
|
|
4486
|
+
this.retryTimer = null;
|
|
4487
|
+
void this.enqueue(async () => this.stopAfterLeadershipLoss());
|
|
4488
|
+
}, RETRY_DELAY_MS);
|
|
4489
|
+
this.retryTimer.unref?.();
|
|
4490
|
+
}
|
|
4491
|
+
clearHeartbeat() {
|
|
4492
|
+
if (!this.heartbeatTimer) return;
|
|
4493
|
+
clearInterval(this.heartbeatTimer);
|
|
4494
|
+
this.heartbeatTimer = null;
|
|
4495
|
+
}
|
|
4496
|
+
clearTimers() {
|
|
4497
|
+
this.clearHeartbeat();
|
|
4498
|
+
this.clearRetryTimer();
|
|
4499
|
+
if (this.teardownRetryTimer) {
|
|
4500
|
+
clearTimeout(this.teardownRetryTimer);
|
|
4501
|
+
this.teardownRetryTimer = null;
|
|
4502
|
+
}
|
|
4503
|
+
}
|
|
4504
|
+
clearRetryTimer() {
|
|
4505
|
+
if (!this.retryTimer) return;
|
|
4506
|
+
clearTimeout(this.retryTimer);
|
|
4507
|
+
this.retryTimer = null;
|
|
4508
|
+
}
|
|
4509
|
+
reportAcquireError(error) {
|
|
4510
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
4511
|
+
if (this.reportedError === message) return;
|
|
4512
|
+
this.reportedError = message;
|
|
4513
|
+
console.error("[codebase-index] Failed to acquire background worker lease:", error);
|
|
4514
|
+
}
|
|
4515
|
+
};
|
|
4516
|
+
function configureBackgroundWorker(projectRoot, host, config, hooks, options = {}) {
|
|
4517
|
+
const projectKey = projectLookupKey(projectRoot, host);
|
|
4518
|
+
const identity = resolveIdentity(projectRoot, config, host);
|
|
4519
|
+
const key = controllerKey(identity, host);
|
|
4520
|
+
const previousKey = workerKeysByProject.get(projectKey);
|
|
4521
|
+
if (previousKey && previousKey !== key) {
|
|
4522
|
+
const previous = workers.get(previousKey);
|
|
4523
|
+
const previousBarrier = workerReplacementBarriers.get(projectKey) ?? Promise.resolve();
|
|
4524
|
+
const stopPrevious = previous?.stop(options.stopPreviousAutoIndex ?? true) ?? Promise.resolve();
|
|
4525
|
+
const activation = Promise.all([previousBarrier, stopPrevious]).then(() => void 0);
|
|
4526
|
+
workerReplacementBarriers.set(projectKey, activation);
|
|
4527
|
+
workers.delete(previousKey);
|
|
4528
|
+
const worker2 = new BackgroundWorkerController(projectRoot, host, config, hooks, identity);
|
|
4529
|
+
worker2.startAfter(activation);
|
|
4530
|
+
workers.set(key, worker2);
|
|
4531
|
+
workerKeysByProject.set(projectKey, key);
|
|
4532
|
+
return;
|
|
4533
|
+
}
|
|
4534
|
+
let worker = workers.get(key);
|
|
4535
|
+
if (!worker) {
|
|
4536
|
+
worker = new BackgroundWorkerController(projectRoot, host, config, hooks, identity);
|
|
4537
|
+
workers.set(key, worker);
|
|
4538
|
+
} else {
|
|
4539
|
+
worker.update(config, hooks, options);
|
|
4540
|
+
}
|
|
4541
|
+
workerKeysByProject.set(projectKey, key);
|
|
4542
|
+
worker.start();
|
|
4543
|
+
}
|
|
4544
|
+
function updateBackgroundWorkerConfig(projectRoot, host, config) {
|
|
4545
|
+
const projectKey = projectLookupKey(projectRoot, host);
|
|
4546
|
+
const key = workerKeysByProject.get(projectKey);
|
|
4547
|
+
const worker = key ? workers.get(key) : void 0;
|
|
4548
|
+
if (!worker) return;
|
|
4549
|
+
configureBackgroundWorker(projectRoot, host, config, worker.getHooksForConfig(config), {
|
|
4550
|
+
stopPreviousAutoIndex: false,
|
|
4551
|
+
restartAutoIndex: true
|
|
4552
|
+
});
|
|
4553
|
+
}
|
|
4554
|
+
function waitForBackgroundWorkerStart(projectRoot, host) {
|
|
4555
|
+
const key = workerKeysByProject.get(projectLookupKey(projectRoot, host));
|
|
4556
|
+
return workers.get(key ?? "")?.waitForStart() ?? Promise.resolve();
|
|
4557
|
+
}
|
|
4558
|
+
function requestBackgroundWorkerRefresh(projectRoot, host, allowDisabledAutoIndex = false) {
|
|
4559
|
+
const key = workerKeysByProject.get(projectLookupKey(projectRoot, host));
|
|
4560
|
+
workers.get(key ?? "")?.requestRefresh(allowDisabledAutoIndex);
|
|
4561
|
+
}
|
|
4562
|
+
function isBackgroundWorkerManaged(projectRoot, host) {
|
|
4563
|
+
const key = workerKeysByProject.get(projectLookupKey(projectRoot, host));
|
|
4564
|
+
return key !== void 0 && workers.has(key);
|
|
4565
|
+
}
|
|
4566
|
+
function isBackgroundWorkerLeader(projectRoot, host) {
|
|
4567
|
+
const key = workerKeysByProject.get(projectLookupKey(projectRoot, host));
|
|
4568
|
+
return key !== void 0 && workers.get(key)?.isLeader() === true;
|
|
4569
|
+
}
|
|
4570
|
+
async function stopBackgroundWorker(projectRoot, host) {
|
|
4571
|
+
const projectKey = projectLookupKey(projectRoot, host);
|
|
4572
|
+
const key = workerKeysByProject.get(projectKey);
|
|
4573
|
+
const worker = key ? workers.get(key) : void 0;
|
|
4574
|
+
if (!worker) return;
|
|
4575
|
+
await worker.stop();
|
|
4576
|
+
}
|
|
4577
|
+
|
|
3695
4578
|
// src/utils/files.ts
|
|
3696
4579
|
var import_ignore = __toESM(require_ignore(), 1);
|
|
3697
|
-
import { existsSync as
|
|
3698
|
-
import * as
|
|
4580
|
+
import { existsSync as existsSync7, readFileSync as readFileSync6, promises as fsPromises } from "fs";
|
|
4581
|
+
import * as path11 from "path";
|
|
3699
4582
|
var PROJECT_MARKERS = [
|
|
3700
4583
|
".git",
|
|
3701
4584
|
"package.json",
|
|
@@ -3713,7 +4596,7 @@ var PROJECT_MARKERS = [
|
|
|
3713
4596
|
];
|
|
3714
4597
|
function hasProjectMarker(projectRoot) {
|
|
3715
4598
|
for (const marker of PROJECT_MARKERS) {
|
|
3716
|
-
if (
|
|
4599
|
+
if (existsSync7(path11.join(projectRoot, marker))) {
|
|
3717
4600
|
return true;
|
|
3718
4601
|
}
|
|
3719
4602
|
}
|
|
@@ -3740,33 +4623,53 @@ function createIgnoreFilter(projectRoot) {
|
|
|
3740
4623
|
"**/*build*/**"
|
|
3741
4624
|
];
|
|
3742
4625
|
ig.add(defaultIgnores);
|
|
3743
|
-
const gitignorePath =
|
|
3744
|
-
if (
|
|
3745
|
-
const gitignoreContent =
|
|
4626
|
+
const gitignorePath = path11.join(projectRoot, ".gitignore");
|
|
4627
|
+
if (existsSync7(gitignorePath)) {
|
|
4628
|
+
const gitignoreContent = readFileSync6(gitignorePath, "utf-8");
|
|
3746
4629
|
ig.add(gitignoreContent);
|
|
3747
4630
|
}
|
|
3748
4631
|
return ig;
|
|
3749
4632
|
}
|
|
3750
|
-
function
|
|
3751
|
-
|
|
3752
|
-
|
|
3753
|
-
|
|
3754
|
-
|
|
3755
|
-
|
|
3756
|
-
|
|
4633
|
+
function toPosixRelativePath(relativePath) {
|
|
4634
|
+
return relativePath.split(path11.sep).join("/");
|
|
4635
|
+
}
|
|
4636
|
+
function matchesAnyGlob(filePath, patterns) {
|
|
4637
|
+
const normalized = toPosixRelativePath(filePath);
|
|
4638
|
+
return patterns.some((pattern) => matchGlob(normalized, pattern));
|
|
4639
|
+
}
|
|
4640
|
+
function isExcludedByPatterns(relativePath, excludePatterns) {
|
|
4641
|
+
return matchesAnyGlob(relativePath, excludePatterns);
|
|
4642
|
+
}
|
|
4643
|
+
function isExcludedDirectory(relativePath, excludePatterns) {
|
|
4644
|
+
const normalized = toPosixRelativePath(relativePath);
|
|
4645
|
+
if (matchesAnyGlob(normalized, excludePatterns)) {
|
|
4646
|
+
return true;
|
|
3757
4647
|
}
|
|
3758
4648
|
for (const pattern of excludePatterns) {
|
|
3759
|
-
|
|
3760
|
-
|
|
4649
|
+
const posixPattern = toPosixRelativePath(pattern).replace(/\/+$/, "");
|
|
4650
|
+
if (!posixPattern.endsWith("/**")) {
|
|
4651
|
+
continue;
|
|
3761
4652
|
}
|
|
3762
|
-
|
|
3763
|
-
|
|
3764
|
-
if (matchGlob(relativePath, pattern)) {
|
|
4653
|
+
const directoryPattern = posixPattern.slice(0, -3);
|
|
4654
|
+
if (directoryPattern && matchesAnyGlob(normalized, [directoryPattern])) {
|
|
3765
4655
|
return true;
|
|
3766
4656
|
}
|
|
3767
4657
|
}
|
|
3768
4658
|
return false;
|
|
3769
4659
|
}
|
|
4660
|
+
function shouldIncludeFile(filePath, projectRoot, includePatterns, excludePatterns, ignoreFilter) {
|
|
4661
|
+
const relativePath = toPosixRelativePath(path11.relative(projectRoot, filePath));
|
|
4662
|
+
if (hasFilteredPathSegment(relativePath, "/")) {
|
|
4663
|
+
return false;
|
|
4664
|
+
}
|
|
4665
|
+
if (ignoreFilter.ignores(relativePath)) {
|
|
4666
|
+
return false;
|
|
4667
|
+
}
|
|
4668
|
+
if (isExcludedByPatterns(relativePath, excludePatterns)) {
|
|
4669
|
+
return false;
|
|
4670
|
+
}
|
|
4671
|
+
return matchesAnyGlob(relativePath, includePatterns);
|
|
4672
|
+
}
|
|
3770
4673
|
function matchGlob(filePath, pattern) {
|
|
3771
4674
|
if (pattern.startsWith("**/")) {
|
|
3772
4675
|
const withoutPrefix = pattern.slice(3);
|
|
@@ -3787,8 +4690,8 @@ async function* walkDirectory(dir, projectRoot, includePatterns, excludePatterns
|
|
|
3787
4690
|
const filesInDir = [];
|
|
3788
4691
|
const subdirs = [];
|
|
3789
4692
|
for (const entry of entries) {
|
|
3790
|
-
const fullPath =
|
|
3791
|
-
const relativePath =
|
|
4693
|
+
const fullPath = path11.join(dir, entry.name);
|
|
4694
|
+
const relativePath = toPosixRelativePath(path11.relative(projectRoot, fullPath));
|
|
3792
4695
|
if (isHiddenPathSegment(entry.name)) {
|
|
3793
4696
|
if (entry.isDirectory()) {
|
|
3794
4697
|
skipped.push({ path: relativePath, reason: "excluded" });
|
|
@@ -3806,6 +4709,10 @@ async function* walkDirectory(dir, projectRoot, includePatterns, excludePatterns
|
|
|
3806
4709
|
continue;
|
|
3807
4710
|
}
|
|
3808
4711
|
if (entry.isDirectory()) {
|
|
4712
|
+
if (isExcludedDirectory(relativePath, excludePatterns)) {
|
|
4713
|
+
skipped.push({ path: relativePath, reason: "excluded" });
|
|
4714
|
+
continue;
|
|
4715
|
+
}
|
|
3809
4716
|
subdirs.push({ fullPath, relativePath });
|
|
3810
4717
|
} else if (entry.isFile()) {
|
|
3811
4718
|
const stat5 = await fsPromises.stat(fullPath);
|
|
@@ -3813,20 +4720,11 @@ async function* walkDirectory(dir, projectRoot, includePatterns, excludePatterns
|
|
|
3813
4720
|
skipped.push({ path: relativePath, reason: "too_large" });
|
|
3814
4721
|
continue;
|
|
3815
4722
|
}
|
|
3816
|
-
|
|
3817
|
-
|
|
3818
|
-
|
|
3819
|
-
continue;
|
|
3820
|
-
}
|
|
3821
|
-
}
|
|
3822
|
-
let matched = false;
|
|
3823
|
-
for (const pattern of includePatterns) {
|
|
3824
|
-
if (matchGlob(relativePath, pattern)) {
|
|
3825
|
-
matched = true;
|
|
3826
|
-
break;
|
|
3827
|
-
}
|
|
4723
|
+
if (isExcludedByPatterns(relativePath, excludePatterns)) {
|
|
4724
|
+
skipped.push({ path: relativePath, reason: "excluded" });
|
|
4725
|
+
continue;
|
|
3828
4726
|
}
|
|
3829
|
-
if (
|
|
4727
|
+
if (matchesAnyGlob(relativePath, includePatterns)) {
|
|
3830
4728
|
filesInDir.push({ path: fullPath, size: stat5.size });
|
|
3831
4729
|
}
|
|
3832
4730
|
}
|
|
@@ -3837,7 +4735,7 @@ async function* walkDirectory(dir, projectRoot, includePatterns, excludePatterns
|
|
|
3837
4735
|
yield f;
|
|
3838
4736
|
}
|
|
3839
4737
|
for (let i = options.maxFilesPerDirectory; i < filesInDir.length; i++) {
|
|
3840
|
-
skipped.push({ path:
|
|
4738
|
+
skipped.push({ path: toPosixRelativePath(path11.relative(projectRoot, filesInDir[i].path)), reason: "excluded" });
|
|
3841
4739
|
}
|
|
3842
4740
|
const canRecurse = options.maxDepth === -1 || currentDepth < options.maxDepth;
|
|
3843
4741
|
if (canRecurse) {
|
|
@@ -3877,8 +4775,8 @@ async function collectFiles(projectRoot, includePatterns, excludePatterns, maxFi
|
|
|
3877
4775
|
if (additionalRoots && additionalRoots.length > 0) {
|
|
3878
4776
|
const normalizedRoots = /* @__PURE__ */ new Set();
|
|
3879
4777
|
for (const kbRoot of additionalRoots) {
|
|
3880
|
-
const resolved =
|
|
3881
|
-
|
|
4778
|
+
const resolved = path11.normalize(
|
|
4779
|
+
path11.isAbsolute(kbRoot) ? kbRoot : path11.resolve(projectRoot, kbRoot)
|
|
3882
4780
|
);
|
|
3883
4781
|
normalizedRoots.add(resolved);
|
|
3884
4782
|
}
|
|
@@ -3919,7 +4817,7 @@ function getErrorMessage(error) {
|
|
|
3919
4817
|
return error instanceof Error ? error.message : String(error);
|
|
3920
4818
|
}
|
|
3921
4819
|
function runCommand(file, args, options) {
|
|
3922
|
-
return new Promise((
|
|
4820
|
+
return new Promise((resolve18, reject) => {
|
|
3923
4821
|
childProcess.execFile(
|
|
3924
4822
|
file,
|
|
3925
4823
|
args,
|
|
@@ -3929,7 +4827,7 @@ function runCommand(file, args, options) {
|
|
|
3929
4827
|
reject(error);
|
|
3930
4828
|
return;
|
|
3931
4829
|
}
|
|
3932
|
-
|
|
4830
|
+
resolve18(stdout);
|
|
3933
4831
|
}
|
|
3934
4832
|
);
|
|
3935
4833
|
});
|
|
@@ -4021,29 +4919,29 @@ var AutoIndexCancelledError = class extends Error {
|
|
|
4021
4919
|
function now() {
|
|
4022
4920
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
4023
4921
|
}
|
|
4024
|
-
function
|
|
4025
|
-
const resolved =
|
|
4026
|
-
if (
|
|
4922
|
+
function canonicalizePath2(targetPath) {
|
|
4923
|
+
const resolved = path12.resolve(targetPath);
|
|
4924
|
+
if (existsSync8(resolved)) {
|
|
4027
4925
|
try {
|
|
4028
|
-
return
|
|
4926
|
+
return realpathSync4.native(resolved);
|
|
4029
4927
|
} catch {
|
|
4030
4928
|
return resolved;
|
|
4031
4929
|
}
|
|
4032
4930
|
}
|
|
4033
|
-
const parent =
|
|
4931
|
+
const parent = path12.dirname(resolved);
|
|
4034
4932
|
if (parent === resolved) return resolved;
|
|
4035
|
-
return
|
|
4933
|
+
return path12.join(canonicalizePath2(parent), path12.basename(resolved));
|
|
4036
4934
|
}
|
|
4037
4935
|
function isHomeDirectory(projectRoot) {
|
|
4038
|
-
return
|
|
4936
|
+
return canonicalizePath2(projectRoot) === canonicalizePath2(os4.homedir());
|
|
4039
4937
|
}
|
|
4040
|
-
function
|
|
4041
|
-
return `${host}::${
|
|
4938
|
+
function projectLookupKey2(projectRoot, host) {
|
|
4939
|
+
return `${host}::${canonicalizePath2(projectRoot)}`;
|
|
4042
4940
|
}
|
|
4043
4941
|
function coordinatorKey(projectRoot, config, host) {
|
|
4044
|
-
const canonicalProjectRoot =
|
|
4942
|
+
const canonicalProjectRoot = canonicalizePath2(projectRoot);
|
|
4045
4943
|
const indexPath = resolveProjectIndexPath(projectRoot, config.scope, host);
|
|
4046
|
-
return `${
|
|
4944
|
+
return `${canonicalizePath2(indexPath)}::${canonicalProjectRoot}`;
|
|
4047
4945
|
}
|
|
4048
4946
|
function getProjectSafety(projectRoot, config) {
|
|
4049
4947
|
if (isHomeDirectory(projectRoot)) {
|
|
@@ -4074,10 +4972,10 @@ function safeFailureMessage(error) {
|
|
|
4074
4972
|
}
|
|
4075
4973
|
function cancellableDelay(delayMs, signal) {
|
|
4076
4974
|
if (signal.aborted) return Promise.reject(new AutoIndexCancelledError());
|
|
4077
|
-
return new Promise((
|
|
4975
|
+
return new Promise((resolve18, reject) => {
|
|
4078
4976
|
const timer = setTimeout(() => {
|
|
4079
4977
|
signal.removeEventListener("abort", onAbort);
|
|
4080
|
-
|
|
4978
|
+
resolve18();
|
|
4081
4979
|
}, delayMs);
|
|
4082
4980
|
timer.unref?.();
|
|
4083
4981
|
const onAbort = () => {
|
|
@@ -4089,18 +4987,44 @@ function cancellableDelay(delayMs, signal) {
|
|
|
4089
4987
|
}
|
|
4090
4988
|
function withTimeout(promise, timeoutMs) {
|
|
4091
4989
|
if (timeoutMs <= 0) return Promise.resolve(void 0);
|
|
4092
|
-
return new Promise((
|
|
4093
|
-
const timer = setTimeout(() =>
|
|
4990
|
+
return new Promise((resolve18) => {
|
|
4991
|
+
const timer = setTimeout(() => resolve18(void 0), timeoutMs);
|
|
4094
4992
|
timer.unref?.();
|
|
4095
4993
|
void promise.then((value) => {
|
|
4096
4994
|
clearTimeout(timer);
|
|
4097
|
-
|
|
4995
|
+
resolve18(value);
|
|
4098
4996
|
}, () => {
|
|
4099
4997
|
clearTimeout(timer);
|
|
4100
|
-
|
|
4998
|
+
resolve18(void 0);
|
|
4101
4999
|
});
|
|
4102
5000
|
});
|
|
4103
5001
|
}
|
|
5002
|
+
function settlesWithin(promise, timeoutMs) {
|
|
5003
|
+
if (timeoutMs <= 0) return Promise.resolve(false);
|
|
5004
|
+
return new Promise((resolve18) => {
|
|
5005
|
+
let settled = false;
|
|
5006
|
+
const timer = setTimeout(() => {
|
|
5007
|
+
if (settled) return;
|
|
5008
|
+
settled = true;
|
|
5009
|
+
resolve18(false);
|
|
5010
|
+
}, timeoutMs);
|
|
5011
|
+
timer.unref?.();
|
|
5012
|
+
void promise.then(
|
|
5013
|
+
() => {
|
|
5014
|
+
if (settled) return;
|
|
5015
|
+
settled = true;
|
|
5016
|
+
clearTimeout(timer);
|
|
5017
|
+
resolve18(true);
|
|
5018
|
+
},
|
|
5019
|
+
() => {
|
|
5020
|
+
if (settled) return;
|
|
5021
|
+
settled = true;
|
|
5022
|
+
clearTimeout(timer);
|
|
5023
|
+
resolve18(true);
|
|
5024
|
+
}
|
|
5025
|
+
);
|
|
5026
|
+
});
|
|
5027
|
+
}
|
|
4104
5028
|
function requestPriority(request) {
|
|
4105
5029
|
if (request.force) return 4;
|
|
4106
5030
|
if (request.source === "manual") return 3;
|
|
@@ -4111,6 +5035,7 @@ function mergeRequests(current, next) {
|
|
|
4111
5035
|
if (!current) return next;
|
|
4112
5036
|
const preferred = requestPriority(next) > requestPriority(current) ? next : current;
|
|
4113
5037
|
return {
|
|
5038
|
+
allowDisabledAutoIndex: current.allowDisabledAutoIndex || next.allowDisabledAutoIndex,
|
|
4114
5039
|
checkFreshness: current.checkFreshness && next.checkFreshness,
|
|
4115
5040
|
force: current.force || next.force,
|
|
4116
5041
|
onProgress: next.onProgress ?? current.onProgress,
|
|
@@ -4172,11 +5097,11 @@ var AutoIndexCoordinator = class {
|
|
|
4172
5097
|
progress: this.status.progress ? { ...this.status.progress } : void 0
|
|
4173
5098
|
};
|
|
4174
5099
|
}
|
|
4175
|
-
start(source) {
|
|
5100
|
+
start(source, allowDisabledAutoIndex = false) {
|
|
4176
5101
|
this.refreshSafety();
|
|
4177
|
-
if (!this.registration.config.indexing.autoIndex || !this.registration.safeToRun) return null;
|
|
5102
|
+
if (!this.registration.config.indexing.autoIndex && !allowDisabledAutoIndex || !this.registration.safeToRun) return null;
|
|
4178
5103
|
if (this.status.state === "failed") return this.inFlight;
|
|
4179
|
-
return this.request({ checkFreshness: true, force: false, source });
|
|
5104
|
+
return this.request({ allowDisabledAutoIndex, checkFreshness: true, force: false, source });
|
|
4180
5105
|
}
|
|
4181
5106
|
request(request) {
|
|
4182
5107
|
if (this.stopped) {
|
|
@@ -4251,13 +5176,15 @@ var AutoIndexCoordinator = class {
|
|
|
4251
5176
|
retryAttempt: void 0
|
|
4252
5177
|
});
|
|
4253
5178
|
const inFlight = this.inFlight;
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
5179
|
+
const completion = inFlight ? inFlight.then(() => void 0, () => void 0) : Promise.resolve();
|
|
5180
|
+
if (!inFlight) {
|
|
5181
|
+
return { completed: true, completion };
|
|
5182
|
+
}
|
|
5183
|
+
if (waitForCompletion) {
|
|
5184
|
+
await completion;
|
|
5185
|
+
return { completed: true, completion };
|
|
4260
5186
|
}
|
|
5187
|
+
return { completed: await settlesWithin(completion, SHUTDOWN_WAIT_MS), completion };
|
|
4261
5188
|
}
|
|
4262
5189
|
startRequest(request) {
|
|
4263
5190
|
if (this.stopped || !this.canRun(request)) {
|
|
@@ -4446,7 +5373,7 @@ var AutoIndexCoordinator = class {
|
|
|
4446
5373
|
if (request.source === "manual" || request.source === "watcher") {
|
|
4447
5374
|
return true;
|
|
4448
5375
|
}
|
|
4449
|
-
return this.registration.safeToRun && this.registration.config.indexing.autoIndex;
|
|
5376
|
+
return this.registration.safeToRun && (this.registration.config.indexing.autoIndex || request.allowDisabledAutoIndex === true);
|
|
4450
5377
|
}
|
|
4451
5378
|
shouldDeferForBattery(request) {
|
|
4452
5379
|
return this.registration.backgroundIndexingPolicy !== null && (request.source === "startup" || request.source === "watcher");
|
|
@@ -4479,17 +5406,17 @@ var AutoIndexCoordinator = class {
|
|
|
4479
5406
|
}
|
|
4480
5407
|
}
|
|
4481
5408
|
waitForBatteryRetry(delayMs) {
|
|
4482
|
-
return new Promise((
|
|
5409
|
+
return new Promise((resolve18) => {
|
|
4483
5410
|
const timer = setTimeout(() => {
|
|
4484
5411
|
if (this.batteryRetryTimer === timer) {
|
|
4485
5412
|
this.batteryRetryTimer = null;
|
|
4486
5413
|
this.resolveBatteryRetry = null;
|
|
4487
5414
|
}
|
|
4488
|
-
|
|
5415
|
+
resolve18();
|
|
4489
5416
|
}, delayMs);
|
|
4490
5417
|
timer.unref?.();
|
|
4491
5418
|
this.batteryRetryTimer = timer;
|
|
4492
|
-
this.resolveBatteryRetry =
|
|
5419
|
+
this.resolveBatteryRetry = resolve18;
|
|
4493
5420
|
});
|
|
4494
5421
|
}
|
|
4495
5422
|
cancelBatteryRetry() {
|
|
@@ -4497,9 +5424,9 @@ var AutoIndexCoordinator = class {
|
|
|
4497
5424
|
clearTimeout(this.batteryRetryTimer);
|
|
4498
5425
|
this.batteryRetryTimer = null;
|
|
4499
5426
|
}
|
|
4500
|
-
const
|
|
5427
|
+
const resolve18 = this.resolveBatteryRetry;
|
|
4501
5428
|
this.resolveBatteryRetry = null;
|
|
4502
|
-
|
|
5429
|
+
resolve18?.();
|
|
4503
5430
|
}
|
|
4504
5431
|
finishBatteryCheck(batteryCheck) {
|
|
4505
5432
|
if (this.batteryCheck !== batteryCheck) return;
|
|
@@ -4512,12 +5439,25 @@ var AutoIndexCoordinator = class {
|
|
|
4512
5439
|
}
|
|
4513
5440
|
};
|
|
4514
5441
|
function getCoordinator(projectRoot, host) {
|
|
4515
|
-
const key = coordinatorKeysByProject.get(
|
|
5442
|
+
const key = coordinatorKeysByProject.get(projectLookupKey2(projectRoot, host));
|
|
4516
5443
|
return key ? coordinators.get(key) ?? null : null;
|
|
4517
5444
|
}
|
|
4518
|
-
function
|
|
4519
|
-
|
|
5445
|
+
function synchronizeBackgroundWorker(projectRoot, host, config, safeToRun) {
|
|
5446
|
+
if (safeToRun) {
|
|
5447
|
+
updateBackgroundWorkerConfig(projectRoot, host, config);
|
|
5448
|
+
return;
|
|
5449
|
+
}
|
|
5450
|
+
void stopBackgroundWorker(projectRoot, host).catch((error) => {
|
|
5451
|
+
console.error("[codebase-index] Failed to stop background worker after project safety changed:", error);
|
|
5452
|
+
});
|
|
5453
|
+
}
|
|
5454
|
+
function configureAutoIndex(projectRoot, host, config, getIndexer, options = {}) {
|
|
5455
|
+
const projectKey = projectLookupKey2(projectRoot, host);
|
|
4520
5456
|
const safety = getProjectSafety(projectRoot, config);
|
|
5457
|
+
const synchronizeWorker = options.synchronizeBackgroundWorker ?? true;
|
|
5458
|
+
if (options.preserveManagedWorker === true && isBackgroundWorkerManaged(projectRoot, host)) {
|
|
5459
|
+
return;
|
|
5460
|
+
}
|
|
4521
5461
|
const registration = {
|
|
4522
5462
|
backgroundIndexingPolicy: createBackgroundIndexingPolicy(
|
|
4523
5463
|
config.indexing.pauseBackgroundIndexingOnBattery
|
|
@@ -4535,6 +5475,9 @@ function configureAutoIndex(projectRoot, host, config, getIndexer) {
|
|
|
4535
5475
|
const stopPrevious = previousCoordinator?.stop(true) ?? Promise.resolve();
|
|
4536
5476
|
const activation = Promise.all([previousBarrier, stopPrevious]).then(() => void 0);
|
|
4537
5477
|
coordinatorReplacementBarriers.set(projectKey, activation);
|
|
5478
|
+
if (synchronizeWorker) {
|
|
5479
|
+
synchronizeBackgroundWorker(projectRoot, host, config, safety.safeToRun);
|
|
5480
|
+
}
|
|
4538
5481
|
coordinators.delete(previousKey);
|
|
4539
5482
|
const coordinator2 = new AutoIndexCoordinator(registration);
|
|
4540
5483
|
coordinator2.activateAfter(activation);
|
|
@@ -4550,11 +5493,17 @@ function configureAutoIndex(projectRoot, host, config, getIndexer) {
|
|
|
4550
5493
|
coordinator.update(registration);
|
|
4551
5494
|
}
|
|
4552
5495
|
coordinatorKeysByProject.set(projectKey, key);
|
|
5496
|
+
if (synchronizeWorker) {
|
|
5497
|
+
synchronizeBackgroundWorker(projectRoot, host, config, safety.safeToRun);
|
|
5498
|
+
}
|
|
4553
5499
|
}
|
|
4554
|
-
function
|
|
4555
|
-
return getCoordinator(projectRoot, host)?.start(source) ?? null;
|
|
5500
|
+
function startAutoIndexForBackgroundWorker(projectRoot, host, source = "startup", allowDisabledAutoIndex = false) {
|
|
5501
|
+
return getCoordinator(projectRoot, host)?.start(source, allowDisabledAutoIndex) ?? null;
|
|
4556
5502
|
}
|
|
4557
5503
|
function requestBackgroundIndex(projectRoot, host) {
|
|
5504
|
+
if (isBackgroundWorkerManaged(projectRoot, host) && !isBackgroundWorkerLeader(projectRoot, host)) {
|
|
5505
|
+
return null;
|
|
5506
|
+
}
|
|
4558
5507
|
return getCoordinator(projectRoot, host)?.request({
|
|
4559
5508
|
checkFreshness: false,
|
|
4560
5509
|
force: false,
|
|
@@ -4594,15 +5543,23 @@ async function waitForAutoIndexForRetrieval(projectRoot, host) {
|
|
|
4594
5543
|
};
|
|
4595
5544
|
}
|
|
4596
5545
|
try {
|
|
4597
|
-
|
|
5546
|
+
const readiness = await getSearchReadiness(coordinator);
|
|
5547
|
+
if (readiness.searchable) {
|
|
5548
|
+
return { ready: true };
|
|
5549
|
+
}
|
|
5550
|
+
if (readiness.blocked) return unavailableSnapshotResult(readiness.reason);
|
|
4598
5551
|
} catch {
|
|
4599
5552
|
}
|
|
4600
|
-
const job =
|
|
5553
|
+
const job = startRetrievalRefresh(projectRoot, host, coordinator);
|
|
4601
5554
|
if (job) {
|
|
4602
5555
|
await withTimeout(job, coordinator.getWaitMs());
|
|
5556
|
+
} else if (isBackgroundWorkerManaged(projectRoot, host)) {
|
|
5557
|
+
await waitForPublishedSnapshot(coordinator, coordinator.getWaitMs());
|
|
4603
5558
|
}
|
|
4604
5559
|
try {
|
|
4605
|
-
|
|
5560
|
+
const readiness = await getSearchReadiness(coordinator);
|
|
5561
|
+
if (readiness.searchable) return { ready: true };
|
|
5562
|
+
if (readiness.blocked) return unavailableSnapshotResult(readiness.reason);
|
|
4606
5563
|
} catch {
|
|
4607
5564
|
}
|
|
4608
5565
|
const status = coordinator.snapshot();
|
|
@@ -4623,18 +5580,52 @@ async function waitForAutoIndexForRetrieval(projectRoot, host) {
|
|
|
4623
5580
|
text: `Automatic indexing is ${status.state}. Retry shortly or call index_status for progress. You can also run index_codebase explicitly.`
|
|
4624
5581
|
};
|
|
4625
5582
|
}
|
|
4626
|
-
async function
|
|
5583
|
+
async function stopAutoIndexForBackgroundWorker(projectRoot, host, waitForCompletion = false) {
|
|
5584
|
+
const coordinator = getCoordinator(projectRoot, host);
|
|
5585
|
+
if (!coordinator) {
|
|
5586
|
+
return { completed: true, completion: Promise.resolve() };
|
|
5587
|
+
}
|
|
5588
|
+
return coordinator.stop(waitForCompletion);
|
|
5589
|
+
}
|
|
5590
|
+
async function getSearchReadiness(coordinator) {
|
|
4627
5591
|
const indexer = coordinator.getIndexer();
|
|
4628
5592
|
if (indexer.getIndexFreshness) {
|
|
4629
5593
|
const freshness = await indexer.getIndexFreshness();
|
|
4630
|
-
|
|
5594
|
+
const searchable = freshness.readable && freshness.current && freshness.reason === "current";
|
|
5595
|
+
return {
|
|
5596
|
+
blocked: freshness.reason === "unreadable" || freshness.reason === "incompatible" || freshness.reason === "failed-batches" || freshness.reason === "migration-required",
|
|
5597
|
+
reason: freshness.reason,
|
|
5598
|
+
searchable
|
|
5599
|
+
};
|
|
5600
|
+
}
|
|
5601
|
+
const indexed = (await indexer.getStatus()).indexed;
|
|
5602
|
+
return { blocked: false, searchable: indexed };
|
|
5603
|
+
}
|
|
5604
|
+
function unavailableSnapshotResult(reason) {
|
|
5605
|
+
const detail = reason === "incompatible" ? "The existing index is incompatible with the configured embedding provider." : reason === "migration-required" ? "The existing index requires a storage migration." : reason === "failed-batches" ? "The existing index has failed embedding batches." : "The existing index is unreadable.";
|
|
5606
|
+
return {
|
|
5607
|
+
ready: false,
|
|
5608
|
+
text: `${detail} Run index_codebase before retrying retrieval.`
|
|
5609
|
+
};
|
|
5610
|
+
}
|
|
5611
|
+
function startRetrievalRefresh(projectRoot, host, coordinator) {
|
|
5612
|
+
if (isBackgroundWorkerManaged(projectRoot, host)) {
|
|
5613
|
+
requestBackgroundWorkerRefresh(projectRoot, host, true);
|
|
5614
|
+
return isBackgroundWorkerLeader(projectRoot, host) ? coordinator.currentJob() : null;
|
|
5615
|
+
}
|
|
5616
|
+
return coordinator.start("retrieval") ?? coordinator.currentJob();
|
|
5617
|
+
}
|
|
5618
|
+
async function waitForPublishedSnapshot(coordinator, waitMs) {
|
|
5619
|
+
const deadline = Date.now() + waitMs;
|
|
5620
|
+
while (Date.now() < deadline) {
|
|
5621
|
+
if ((await getSearchReadiness(coordinator)).searchable) return;
|
|
5622
|
+
await new Promise((resolve18) => setTimeout(resolve18, Math.min(250, deadline - Date.now())));
|
|
4631
5623
|
}
|
|
4632
|
-
return (await indexer.getStatus()).indexed;
|
|
4633
5624
|
}
|
|
4634
5625
|
|
|
4635
5626
|
// src/tools/config-state.ts
|
|
4636
|
-
import { existsSync as
|
|
4637
|
-
import * as
|
|
5627
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
5628
|
+
import * as path13 from "path";
|
|
4638
5629
|
function normalizeKnowledgeBasePaths(config, projectRoot) {
|
|
4639
5630
|
const normalized = { ...config };
|
|
4640
5631
|
if (Array.isArray(normalized.knowledgeBases)) {
|
|
@@ -4661,10 +5652,10 @@ function loadEditableConfig(projectRoot, host) {
|
|
|
4661
5652
|
}
|
|
4662
5653
|
function saveConfig(projectRoot, config, host) {
|
|
4663
5654
|
const configPath = getConfigPath(projectRoot, host);
|
|
4664
|
-
const configDir =
|
|
4665
|
-
const configBaseDir =
|
|
4666
|
-
if (!
|
|
4667
|
-
|
|
5655
|
+
const configDir = path13.dirname(configPath);
|
|
5656
|
+
const configBaseDir = path13.dirname(configDir);
|
|
5657
|
+
if (!existsSync9(configDir)) {
|
|
5658
|
+
mkdirSync3(configDir, { recursive: true });
|
|
4668
5659
|
}
|
|
4669
5660
|
const serializableConfig = { ...config };
|
|
4670
5661
|
if (Array.isArray(serializableConfig.knowledgeBases)) {
|
|
@@ -4672,12 +5663,12 @@ function saveConfig(projectRoot, config, host) {
|
|
|
4672
5663
|
(kb) => serializeConfigPathValue(kb, configBaseDir)
|
|
4673
5664
|
);
|
|
4674
5665
|
}
|
|
4675
|
-
|
|
5666
|
+
writeFileSync3(configPath, JSON.stringify(serializableConfig, null, 2) + "\n", "utf-8");
|
|
4676
5667
|
}
|
|
4677
5668
|
|
|
4678
5669
|
// src/indexer/index.ts
|
|
4679
|
-
import { existsSync as
|
|
4680
|
-
import * as
|
|
5670
|
+
import { existsSync as existsSync12, readFileSync as readFileSync9, statSync as statSync4, writeFileSync as writeFileSync4, renameSync as renameSync4, unlinkSync as unlinkSync2, mkdirSync as mkdirSync5, promises as fsPromises3 } from "fs";
|
|
5671
|
+
import * as path20 from "path";
|
|
4681
5672
|
import { performance as performance2 } from "perf_hooks";
|
|
4682
5673
|
import { execFile as execFile5 } from "child_process";
|
|
4683
5674
|
import { promisify as promisify4 } from "util";
|
|
@@ -4704,7 +5695,7 @@ function pTimeout(promise, options) {
|
|
|
4704
5695
|
} = options;
|
|
4705
5696
|
let timer;
|
|
4706
5697
|
let abortHandler;
|
|
4707
|
-
const wrappedPromise = new Promise((
|
|
5698
|
+
const wrappedPromise = new Promise((resolve18, reject) => {
|
|
4708
5699
|
if (typeof milliseconds !== "number" || Math.sign(milliseconds) !== 1) {
|
|
4709
5700
|
throw new TypeError(`Expected \`milliseconds\` to be a positive number, got \`${milliseconds}\``);
|
|
4710
5701
|
}
|
|
@@ -4718,7 +5709,7 @@ function pTimeout(promise, options) {
|
|
|
4718
5709
|
};
|
|
4719
5710
|
signal.addEventListener("abort", abortHandler, { once: true });
|
|
4720
5711
|
}
|
|
4721
|
-
promise.then(
|
|
5712
|
+
promise.then(resolve18, reject);
|
|
4722
5713
|
if (milliseconds === Number.POSITIVE_INFINITY) {
|
|
4723
5714
|
return;
|
|
4724
5715
|
}
|
|
@@ -4726,7 +5717,7 @@ function pTimeout(promise, options) {
|
|
|
4726
5717
|
timer = customTimers.setTimeout.call(void 0, () => {
|
|
4727
5718
|
if (fallback) {
|
|
4728
5719
|
try {
|
|
4729
|
-
|
|
5720
|
+
resolve18(fallback());
|
|
4730
5721
|
} catch (error) {
|
|
4731
5722
|
reject(error);
|
|
4732
5723
|
}
|
|
@@ -4736,7 +5727,7 @@ function pTimeout(promise, options) {
|
|
|
4736
5727
|
promise.cancel();
|
|
4737
5728
|
}
|
|
4738
5729
|
if (message === false) {
|
|
4739
|
-
|
|
5730
|
+
resolve18();
|
|
4740
5731
|
} else if (message instanceof Error) {
|
|
4741
5732
|
reject(message);
|
|
4742
5733
|
} else {
|
|
@@ -5138,7 +6129,7 @@ var PQueue = class extends import_index.default {
|
|
|
5138
6129
|
// Assign unique ID if not provided
|
|
5139
6130
|
id: options.id ?? (this.#idAssigner++).toString()
|
|
5140
6131
|
};
|
|
5141
|
-
return new Promise((
|
|
6132
|
+
return new Promise((resolve18, reject) => {
|
|
5142
6133
|
const taskSymbol = /* @__PURE__ */ Symbol(`task-${options.id}`);
|
|
5143
6134
|
let cleanupQueueAbortHandler = () => void 0;
|
|
5144
6135
|
const run = async () => {
|
|
@@ -5178,7 +6169,7 @@ var PQueue = class extends import_index.default {
|
|
|
5178
6169
|
})]);
|
|
5179
6170
|
}
|
|
5180
6171
|
const result = await operation;
|
|
5181
|
-
|
|
6172
|
+
resolve18(result);
|
|
5182
6173
|
this.emit("completed", result);
|
|
5183
6174
|
} catch (error) {
|
|
5184
6175
|
reject(error);
|
|
@@ -5366,13 +6357,13 @@ var PQueue = class extends import_index.default {
|
|
|
5366
6357
|
});
|
|
5367
6358
|
}
|
|
5368
6359
|
async #onEvent(event, filter) {
|
|
5369
|
-
return new Promise((
|
|
6360
|
+
return new Promise((resolve18) => {
|
|
5370
6361
|
const listener = () => {
|
|
5371
6362
|
if (filter && !filter()) {
|
|
5372
6363
|
return;
|
|
5373
6364
|
}
|
|
5374
6365
|
this.off(event, listener);
|
|
5375
|
-
|
|
6366
|
+
resolve18();
|
|
5376
6367
|
};
|
|
5377
6368
|
this.on(event, listener);
|
|
5378
6369
|
});
|
|
@@ -5658,7 +6649,7 @@ async function onAttemptFailure({ error, attemptNumber, retriesConsumed, startTi
|
|
|
5658
6649
|
const finalDelay = Math.min(delayTime, remainingTime);
|
|
5659
6650
|
options.signal?.throwIfAborted();
|
|
5660
6651
|
if (finalDelay > 0) {
|
|
5661
|
-
await new Promise((
|
|
6652
|
+
await new Promise((resolve18, reject) => {
|
|
5662
6653
|
const onAbort = () => {
|
|
5663
6654
|
clearTimeout(timeoutToken);
|
|
5664
6655
|
options.signal?.removeEventListener("abort", onAbort);
|
|
@@ -5666,7 +6657,7 @@ async function onAttemptFailure({ error, attemptNumber, retriesConsumed, startTi
|
|
|
5666
6657
|
};
|
|
5667
6658
|
const timeoutToken = setTimeout(() => {
|
|
5668
6659
|
options.signal?.removeEventListener("abort", onAbort);
|
|
5669
|
-
|
|
6660
|
+
resolve18();
|
|
5670
6661
|
}, finalDelay);
|
|
5671
6662
|
if (options.unref) {
|
|
5672
6663
|
timeoutToken.unref?.();
|
|
@@ -5727,17 +6718,17 @@ async function pRetry(input, options = {}) {
|
|
|
5727
6718
|
}
|
|
5728
6719
|
|
|
5729
6720
|
// src/embeddings/detector.ts
|
|
5730
|
-
import { existsSync as
|
|
5731
|
-
import * as
|
|
5732
|
-
import * as
|
|
6721
|
+
import { existsSync as existsSync10, readFileSync as readFileSync7 } from "fs";
|
|
6722
|
+
import * as path14 from "path";
|
|
6723
|
+
import * as os5 from "os";
|
|
5733
6724
|
function getOpenCodeAuthPath() {
|
|
5734
|
-
return
|
|
6725
|
+
return path14.join(os5.homedir(), ".local", "share", "opencode", "auth.json");
|
|
5735
6726
|
}
|
|
5736
6727
|
function loadOpenCodeAuth() {
|
|
5737
6728
|
const authPath = getOpenCodeAuthPath();
|
|
5738
6729
|
try {
|
|
5739
|
-
if (
|
|
5740
|
-
return JSON.parse(
|
|
6730
|
+
if (existsSync10(authPath)) {
|
|
6731
|
+
return JSON.parse(readFileSync7(authPath, "utf-8"));
|
|
5741
6732
|
}
|
|
5742
6733
|
} catch {
|
|
5743
6734
|
}
|
|
@@ -6028,17 +7019,17 @@ function validateExternalUrl(urlString) {
|
|
|
6028
7019
|
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
6029
7020
|
return { valid: false, reason: `Blocked protocol: ${parsed.protocol}` };
|
|
6030
7021
|
}
|
|
6031
|
-
const
|
|
6032
|
-
if (BLOCKED_HOSTNAMES.has(
|
|
6033
|
-
return { valid: false, reason: `Blocked: cloud metadata service (${
|
|
7022
|
+
const hostname3 = parsed.hostname.toLowerCase();
|
|
7023
|
+
if (BLOCKED_HOSTNAMES.has(hostname3)) {
|
|
7024
|
+
return { valid: false, reason: `Blocked: cloud metadata service (${hostname3})` };
|
|
6034
7025
|
}
|
|
6035
7026
|
for (const pattern of BLOCKED_METADATA_IPS) {
|
|
6036
|
-
if (pattern.test(
|
|
6037
|
-
return { valid: false, reason: `Blocked: cloud metadata IP (${
|
|
7027
|
+
if (pattern.test(hostname3)) {
|
|
7028
|
+
return { valid: false, reason: `Blocked: cloud metadata IP (${hostname3})` };
|
|
6038
7029
|
}
|
|
6039
7030
|
}
|
|
6040
|
-
if (/^169\.254\./.test(
|
|
6041
|
-
return { valid: false, reason: `Blocked: link-local address (${
|
|
7031
|
+
if (/^169\.254\./.test(hostname3)) {
|
|
7032
|
+
return { valid: false, reason: `Blocked: link-local address (${hostname3})` };
|
|
6042
7033
|
}
|
|
6043
7034
|
return { valid: true };
|
|
6044
7035
|
}
|
|
@@ -6576,6 +7567,26 @@ function formatCostEstimate(estimate) {
|
|
|
6576
7567
|
\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
|
|
6577
7568
|
`;
|
|
6578
7569
|
}
|
|
7570
|
+
function formatDryRunEstimate(estimate) {
|
|
7571
|
+
return `Dry run: parsed the file set to measure the embedding workload. No embedding requests were made and the index was not changed.
|
|
7572
|
+
|
|
7573
|
+
Files to embed: ${estimate.filesCount.toLocaleString()}
|
|
7574
|
+
Chunks to embed: ${estimate.chunksCount.toLocaleString()}
|
|
7575
|
+
Tokens to embed: ${estimate.tokensToEmbed.toLocaleString()}
|
|
7576
|
+
|
|
7577
|
+
The "Tokens to embed" value uses the local estimateTokens(text) = ceil(len/4). It
|
|
7578
|
+
matches the live "Tokens used" counter only for providers that report usage on the
|
|
7579
|
+
same basis (ollama); for providers that report a server tokenizer count (OpenAI,
|
|
7580
|
+
Gemini, custom) it is only an estimate.
|
|
7581
|
+
|
|
7582
|
+
For a matching provider and a project-scoped force index, the force pass clears its
|
|
7583
|
+
own cached embeddings, so the live counter climbs to this number. A force index on a
|
|
7584
|
+
shared global index can reuse cached embeddings from other projects, and an
|
|
7585
|
+
incremental index counts cached chunks that are not re-embedded; in both cases this
|
|
7586
|
+
number is an upper bound on the live counter, so a progress percent against this
|
|
7587
|
+
total tops out below 100%.
|
|
7588
|
+
`;
|
|
7589
|
+
}
|
|
6579
7590
|
function formatBytes(bytes) {
|
|
6580
7591
|
if (bytes === 0) return "0 B";
|
|
6581
7592
|
const k = 1024;
|
|
@@ -7110,8 +8121,8 @@ function extractParamNames(params) {
|
|
|
7110
8121
|
}
|
|
7111
8122
|
|
|
7112
8123
|
// src/native/binding.ts
|
|
7113
|
-
import * as
|
|
7114
|
-
import * as
|
|
8124
|
+
import * as os6 from "os";
|
|
8125
|
+
import * as path15 from "path";
|
|
7115
8126
|
import * as module from "module";
|
|
7116
8127
|
import { fileURLToPath } from "url";
|
|
7117
8128
|
|
|
@@ -7147,7 +8158,7 @@ var MCP_BINARY_CURRENT_NAME = CURRENT_PRODUCT.mcpBinary;
|
|
|
7147
8158
|
var STABLE_NATIVE_BINARY_NAME = IDENTITY_CATALOG.native.binaryName;
|
|
7148
8159
|
|
|
7149
8160
|
// src/native/binding.ts
|
|
7150
|
-
function getNativeBindingFilename(platform2 =
|
|
8161
|
+
function getNativeBindingFilename(platform2 = os6.platform(), arch2 = os6.arch()) {
|
|
7151
8162
|
if (platform2 === "darwin" && arch2 === "arm64") {
|
|
7152
8163
|
return `${STABLE_NATIVE_BINARY_NAME}.darwin-arm64.node`;
|
|
7153
8164
|
}
|
|
@@ -7165,25 +8176,25 @@ function getNativeBindingFilename(platform2 = os5.platform(), arch2 = os5.arch()
|
|
|
7165
8176
|
}
|
|
7166
8177
|
throw new Error(`Unsupported platform: ${platform2}-${arch2}`);
|
|
7167
8178
|
}
|
|
7168
|
-
function resolveNativeBindingPath(packageRoot, platform2 =
|
|
7169
|
-
return
|
|
8179
|
+
function resolveNativeBindingPath(packageRoot, platform2 = os6.platform(), arch2 = os6.arch()) {
|
|
8180
|
+
return path15.join(packageRoot, "native", getNativeBindingFilename(platform2, arch2));
|
|
7170
8181
|
}
|
|
7171
8182
|
function getNativeBinding() {
|
|
7172
8183
|
let currentDir;
|
|
7173
8184
|
let requireTarget;
|
|
7174
8185
|
if (typeof import.meta !== "undefined" && import.meta.url) {
|
|
7175
|
-
currentDir =
|
|
8186
|
+
currentDir = path15.dirname(fileURLToPath(import.meta.url));
|
|
7176
8187
|
requireTarget = import.meta.url;
|
|
7177
8188
|
} else if (typeof __dirname !== "undefined") {
|
|
7178
8189
|
currentDir = __dirname;
|
|
7179
8190
|
requireTarget = __filename;
|
|
7180
8191
|
} else {
|
|
7181
8192
|
currentDir = process.cwd();
|
|
7182
|
-
requireTarget =
|
|
8193
|
+
requireTarget = path15.join(currentDir, "index.js");
|
|
7183
8194
|
}
|
|
7184
8195
|
const normalizedDir = currentDir.replace(/\\/g, "/");
|
|
7185
|
-
const isDevMode = normalizedDir.includes("/src/native") || currentDir.includes(
|
|
7186
|
-
const packageRoot = isDevMode ?
|
|
8196
|
+
const isDevMode = normalizedDir.includes("/src/native") || currentDir.includes(path15.join("src", "native"));
|
|
8197
|
+
const packageRoot = isDevMode ? path15.resolve(currentDir, "../..") : path15.resolve(currentDir, "..");
|
|
7187
8198
|
const nativePath = resolveNativeBindingPath(packageRoot);
|
|
7188
8199
|
const require2 = module.createRequire(requireTarget);
|
|
7189
8200
|
return require2(nativePath);
|
|
@@ -7767,8 +8778,8 @@ var Database = class _Database {
|
|
|
7767
8778
|
|
|
7768
8779
|
// src/git/branch-materialization.ts
|
|
7769
8780
|
import { promises as fsPromises2 } from "fs";
|
|
7770
|
-
import * as
|
|
7771
|
-
import * as
|
|
8781
|
+
import * as os7 from "os";
|
|
8782
|
+
import * as path16 from "path";
|
|
7772
8783
|
|
|
7773
8784
|
// src/git/branch-resolution.ts
|
|
7774
8785
|
import { execFile as execFile2 } from "child_process";
|
|
@@ -8087,13 +9098,13 @@ async function isWorktreeRegistered(projectRoot, worktreePath) {
|
|
|
8087
9098
|
return false;
|
|
8088
9099
|
}
|
|
8089
9100
|
function isPathWithinRoot(filePath, rootPath) {
|
|
8090
|
-
const relative14 =
|
|
8091
|
-
return relative14 === "" || !relative14.startsWith(`..${
|
|
9101
|
+
const relative14 = path16.relative(path16.resolve(rootPath), path16.resolve(filePath));
|
|
9102
|
+
return relative14 === "" || !relative14.startsWith(`..${path16.sep}`) && relative14 !== ".." && !path16.isAbsolute(relative14);
|
|
8092
9103
|
}
|
|
8093
9104
|
async function pruneExactMissingWorktreeRegistration(projectRoot, worktreePath) {
|
|
8094
9105
|
if (await pathExists(worktreePath)) return false;
|
|
8095
9106
|
const commonDir = await runGit(projectRoot, ["rev-parse", "--path-format=absolute", "--git-common-dir"]);
|
|
8096
|
-
const registrationsRoot =
|
|
9107
|
+
const registrationsRoot = path16.join(commonDir, "worktrees");
|
|
8097
9108
|
let entries;
|
|
8098
9109
|
try {
|
|
8099
9110
|
entries = await fsPromises2.readdir(registrationsRoot, { withFileTypes: true });
|
|
@@ -8104,16 +9115,16 @@ async function pruneExactMissingWorktreeRegistration(projectRoot, worktreePath)
|
|
|
8104
9115
|
const target = canonicalizePathForComparison(worktreePath);
|
|
8105
9116
|
for (const entry of entries) {
|
|
8106
9117
|
if (!entry.isDirectory()) continue;
|
|
8107
|
-
const registrationPath =
|
|
9118
|
+
const registrationPath = path16.join(registrationsRoot, entry.name);
|
|
8108
9119
|
if (!isPathWithinRoot(registrationPath, registrationsRoot)) continue;
|
|
8109
9120
|
let gitdirPath;
|
|
8110
9121
|
try {
|
|
8111
|
-
gitdirPath = (await fsPromises2.readFile(
|
|
9122
|
+
gitdirPath = (await fsPromises2.readFile(path16.join(registrationPath, "gitdir"), "utf8")).trim();
|
|
8112
9123
|
} catch {
|
|
8113
9124
|
continue;
|
|
8114
9125
|
}
|
|
8115
|
-
const resolvedGitdirPath =
|
|
8116
|
-
if (canonicalizePathForComparison(
|
|
9126
|
+
const resolvedGitdirPath = path16.isAbsolute(gitdirPath) ? gitdirPath : path16.resolve(registrationPath, gitdirPath);
|
|
9127
|
+
if (canonicalizePathForComparison(path16.dirname(resolvedGitdirPath)) !== target) continue;
|
|
8117
9128
|
await fsPromises2.rm(registrationPath, { recursive: true, force: true });
|
|
8118
9129
|
return true;
|
|
8119
9130
|
}
|
|
@@ -8131,7 +9142,7 @@ async function removeWorktree(projectRoot, worktreePath) {
|
|
|
8131
9142
|
registered = await isWorktreeRegistered(projectRoot, worktreePath);
|
|
8132
9143
|
} catch (error) {
|
|
8133
9144
|
errors.push(asError(error));
|
|
8134
|
-
throw new AggregateError(errors, `Could not verify temporary worktree deregistration; preserved ${
|
|
9145
|
+
throw new AggregateError(errors, `Could not verify temporary worktree deregistration; preserved ${path16.dirname(worktreePath)}`);
|
|
8135
9146
|
}
|
|
8136
9147
|
if (registered) {
|
|
8137
9148
|
try {
|
|
@@ -8147,7 +9158,7 @@ async function removeWorktree(projectRoot, worktreePath) {
|
|
|
8147
9158
|
registered = await isWorktreeRegistered(projectRoot, worktreePath);
|
|
8148
9159
|
} catch (error) {
|
|
8149
9160
|
errors.push(asError(error));
|
|
8150
|
-
throw new AggregateError(errors, `Could not verify temporary worktree deregistration; preserved ${
|
|
9161
|
+
throw new AggregateError(errors, `Could not verify temporary worktree deregistration; preserved ${path16.dirname(worktreePath)}`);
|
|
8151
9162
|
}
|
|
8152
9163
|
}
|
|
8153
9164
|
if (registered && !await pathExists(worktreePath)) {
|
|
@@ -8160,13 +9171,13 @@ async function removeWorktree(projectRoot, worktreePath) {
|
|
|
8160
9171
|
}
|
|
8161
9172
|
if (registered) {
|
|
8162
9173
|
errors.push(new Error(`Temporary worktree remains registered: ${worktreePath}`));
|
|
8163
|
-
throw new AggregateError(errors, `Failed to deregister temporary worktree; preserved ${
|
|
9174
|
+
throw new AggregateError(errors, `Failed to deregister temporary worktree; preserved ${path16.dirname(worktreePath)}`);
|
|
8164
9175
|
}
|
|
8165
9176
|
try {
|
|
8166
|
-
await fsPromises2.rm(
|
|
9177
|
+
await fsPromises2.rm(path16.dirname(worktreePath), { recursive: true, force: true });
|
|
8167
9178
|
} catch (error) {
|
|
8168
9179
|
errors.push(asError(error));
|
|
8169
|
-
throw new AggregateError(errors, `Deregistered the temporary worktree but could not remove ${
|
|
9180
|
+
throw new AggregateError(errors, `Deregistered the temporary worktree but could not remove ${path16.dirname(worktreePath)}`);
|
|
8170
9181
|
}
|
|
8171
9182
|
}
|
|
8172
9183
|
async function cleanupTemporaryWorktree(projectRoot, worktreePath, temporaryRoot) {
|
|
@@ -8202,9 +9213,9 @@ async function withMaterializedBranch(request, callback) {
|
|
|
8202
9213
|
`Git ref ${JSON.stringify(request.ref ?? request.branch)} is not available locally. For an unfetched branch, pass a remote-qualified name such as origin/feature.`
|
|
8203
9214
|
);
|
|
8204
9215
|
}
|
|
8205
|
-
const temporaryRoot = await fsPromises2.mkdtemp(
|
|
8206
|
-
const worktreePath =
|
|
8207
|
-
const hooksPath =
|
|
9216
|
+
const temporaryRoot = await fsPromises2.mkdtemp(path16.join(os7.tmpdir(), "codebase-index-branch-"));
|
|
9217
|
+
const worktreePath = path16.join(temporaryRoot, "worktree");
|
|
9218
|
+
const hooksPath = path16.join(temporaryRoot, "hooks");
|
|
8208
9219
|
await fsPromises2.mkdir(hooksPath);
|
|
8209
9220
|
const info = {
|
|
8210
9221
|
branch: request.branch,
|
|
@@ -8255,8 +9266,8 @@ async function withMaterializedBranch(request, callback) {
|
|
|
8255
9266
|
|
|
8256
9267
|
// src/tools/changed-files.ts
|
|
8257
9268
|
import { execFile as execFile3 } from "child_process";
|
|
8258
|
-
import { realpathSync as
|
|
8259
|
-
import * as
|
|
9269
|
+
import { realpathSync as realpathSync5 } from "fs";
|
|
9270
|
+
import * as path17 from "path";
|
|
8260
9271
|
import { promisify as promisify2 } from "util";
|
|
8261
9272
|
var execFileAsync2 = promisify2(execFile3);
|
|
8262
9273
|
var GH_PR_VIEW_FIELDS = [
|
|
@@ -8398,9 +9409,9 @@ function getHeadRepositoryIdentity(data, host) {
|
|
|
8398
9409
|
return `${host}/${owner.toLowerCase()}/${repository.replace(/\.git$/i, "").toLowerCase()}`;
|
|
8399
9410
|
}
|
|
8400
9411
|
function getLocalRepositoryIdentity(projectRoot) {
|
|
8401
|
-
let canonicalRoot =
|
|
9412
|
+
let canonicalRoot = path17.resolve(projectRoot);
|
|
8402
9413
|
try {
|
|
8403
|
-
canonicalRoot =
|
|
9414
|
+
canonicalRoot = realpathSync5.native(canonicalRoot);
|
|
8404
9415
|
} catch {
|
|
8405
9416
|
}
|
|
8406
9417
|
return `local:${canonicalRoot}`;
|
|
@@ -8459,17 +9470,17 @@ async function getMergeBase(projectRoot, baseCommit, headCommit) {
|
|
|
8459
9470
|
return commit;
|
|
8460
9471
|
}
|
|
8461
9472
|
function normalizeFiles(rawFiles, projectRoot) {
|
|
8462
|
-
const root =
|
|
9473
|
+
const root = path17.resolve(projectRoot);
|
|
8463
9474
|
const seen = /* @__PURE__ */ new Set();
|
|
8464
9475
|
const result = [];
|
|
8465
9476
|
for (const raw of rawFiles) {
|
|
8466
9477
|
if (raw.length === 0) continue;
|
|
8467
|
-
const absolute =
|
|
8468
|
-
const relative14 =
|
|
8469
|
-
if (
|
|
9478
|
+
const absolute = path17.resolve(root, raw);
|
|
9479
|
+
const relative14 = path17.relative(root, absolute);
|
|
9480
|
+
if (path17.isAbsolute(raw) || relative14 === ".." || relative14.startsWith(`..${path17.sep}`) || path17.isAbsolute(relative14)) {
|
|
8470
9481
|
throw new Error(`Changed file escapes the project root: ${JSON.stringify(raw)}`);
|
|
8471
9482
|
}
|
|
8472
|
-
const cleaned = relative14.startsWith(`.${
|
|
9483
|
+
const cleaned = relative14.startsWith(`.${path17.sep}`) ? relative14.slice(2) : relative14;
|
|
8473
9484
|
if (!seen.has(cleaned)) {
|
|
8474
9485
|
seen.add(cleaned);
|
|
8475
9486
|
result.push(cleaned);
|
|
@@ -8480,7 +9491,7 @@ function normalizeFiles(rawFiles, projectRoot) {
|
|
|
8480
9491
|
|
|
8481
9492
|
// src/indexer/git-blame.ts
|
|
8482
9493
|
import { execFile as execFile4 } from "child_process";
|
|
8483
|
-
import * as
|
|
9494
|
+
import * as path18 from "path";
|
|
8484
9495
|
import { promisify as promisify3 } from "util";
|
|
8485
9496
|
var execFileAsync3 = promisify3(execFile4);
|
|
8486
9497
|
function parseGitBlamePorcelain(output) {
|
|
@@ -8518,7 +9529,7 @@ function parseGitBlamePorcelain(output) {
|
|
|
8518
9529
|
return Array.from(commits.values()).filter((commit) => commit.lines > 0).sort((a, b) => b.lines - a.lines || b.committedAt - a.committedAt)[0];
|
|
8519
9530
|
}
|
|
8520
9531
|
async function getChunkGitBlame(projectRoot, filePath, startLine, endLine) {
|
|
8521
|
-
const relativePath =
|
|
9532
|
+
const relativePath = path18.relative(projectRoot, filePath);
|
|
8522
9533
|
try {
|
|
8523
9534
|
const { stdout } = await execFileAsync3(
|
|
8524
9535
|
"git",
|
|
@@ -8850,6 +9861,9 @@ var CALL_GRAPH_SYMBOL_CHUNK_TYPES = /* @__PURE__ */ new Set([
|
|
|
8850
9861
|
"enum_declaration",
|
|
8851
9862
|
"function_definition",
|
|
8852
9863
|
"class_definition",
|
|
9864
|
+
// Ruby module/class symbols that are declaration-bearing and navigable.
|
|
9865
|
+
"class",
|
|
9866
|
+
"module",
|
|
8853
9867
|
"class_specifier",
|
|
8854
9868
|
"struct_specifier",
|
|
8855
9869
|
"namespace_definition",
|
|
@@ -9094,8 +10108,8 @@ function pathSegmentsForAffinityMatch(filePath) {
|
|
|
9094
10108
|
if (segments.length === 0) {
|
|
9095
10109
|
return [];
|
|
9096
10110
|
}
|
|
9097
|
-
const
|
|
9098
|
-
const basenameWithoutExt =
|
|
10111
|
+
const basename10 = segments[segments.length - 1] ?? "";
|
|
10112
|
+
const basenameWithoutExt = basename10.replace(/\.[^/.]+$/u, "");
|
|
9099
10113
|
const normalizedSegments = segments.map((segment) => segment.toLowerCase());
|
|
9100
10114
|
return Array.from(/* @__PURE__ */ new Set([
|
|
9101
10115
|
...normalizedSegments,
|
|
@@ -9404,8 +10418,8 @@ function hasAllEmbeddingParts(parts, expectedPartCount) {
|
|
|
9404
10418
|
|
|
9405
10419
|
// src/indexer/failed-state-persistence.ts
|
|
9406
10420
|
import * as fs2 from "fs";
|
|
9407
|
-
import { createHash, randomBytes as randomBytes3 } from "crypto";
|
|
9408
|
-
import * as
|
|
10421
|
+
import { createHash as createHash2, randomBytes as randomBytes3 } from "crypto";
|
|
10422
|
+
import * as path19 from "path";
|
|
9409
10423
|
import { StringDecoder } from "string_decoder";
|
|
9410
10424
|
var CURRENT_FAILED_BATCH_VERSION = 1;
|
|
9411
10425
|
var DEFAULT_MALFORMED_LINE_ACTION = "skip";
|
|
@@ -9423,7 +10437,7 @@ function* readFailedBatchRecords(filePath, options = {}) {
|
|
|
9423
10437
|
function createFailedBatchWriter(targetPath) {
|
|
9424
10438
|
const temporaryPath = createTemporaryPath(targetPath);
|
|
9425
10439
|
let finalized = false;
|
|
9426
|
-
fs2.mkdirSync(
|
|
10440
|
+
fs2.mkdirSync(path19.dirname(targetPath), { recursive: true });
|
|
9427
10441
|
fs2.closeSync(fs2.openSync(temporaryPath, "w"));
|
|
9428
10442
|
const write = (record) => {
|
|
9429
10443
|
if (finalized) {
|
|
@@ -9442,7 +10456,7 @@ function createFailedBatchWriter(targetPath) {
|
|
|
9442
10456
|
if (lines.length === 0) {
|
|
9443
10457
|
return;
|
|
9444
10458
|
}
|
|
9445
|
-
fs2.mkdirSync(
|
|
10459
|
+
fs2.mkdirSync(path19.dirname(targetPath), { recursive: true });
|
|
9446
10460
|
fs2.appendFileSync(temporaryPath, `${lines.join("\n")}
|
|
9447
10461
|
`, "utf-8");
|
|
9448
10462
|
};
|
|
@@ -9450,7 +10464,7 @@ function createFailedBatchWriter(targetPath) {
|
|
|
9450
10464
|
if (finalized) {
|
|
9451
10465
|
return;
|
|
9452
10466
|
}
|
|
9453
|
-
fs2.mkdirSync(
|
|
10467
|
+
fs2.mkdirSync(path19.dirname(targetPath), { recursive: true });
|
|
9454
10468
|
fs2.renameSync(temporaryPath, targetPath);
|
|
9455
10469
|
finalized = true;
|
|
9456
10470
|
};
|
|
@@ -9596,10 +10610,10 @@ function stripLeadingBomAndWhitespace(value) {
|
|
|
9596
10610
|
return result;
|
|
9597
10611
|
}
|
|
9598
10612
|
function createTemporaryPath(targetPath) {
|
|
9599
|
-
const randomId =
|
|
9600
|
-
const targetDir =
|
|
9601
|
-
const baseName =
|
|
9602
|
-
return
|
|
10613
|
+
const randomId = createHash2("sha1").update(`${Date.now()}:${randomBytes3(8).toString("hex")}`).digest("hex");
|
|
10614
|
+
const targetDir = path19.dirname(targetPath);
|
|
10615
|
+
const baseName = path19.basename(targetPath);
|
|
10616
|
+
return path19.join(targetDir, `.${baseName}.${randomId}.tmp`);
|
|
9603
10617
|
}
|
|
9604
10618
|
function handleMalformedLine(filePath, lineNumber, line, error, options) {
|
|
9605
10619
|
const action = options.malformedLineAction ?? DEFAULT_MALFORMED_LINE_ACTION;
|
|
@@ -9845,9 +10859,9 @@ var SWIFT_PARSER_VERSION = "1";
|
|
|
9845
10859
|
var METAL_PARSER_VERSION = "1";
|
|
9846
10860
|
var SYMBOL_EXTRACTOR_VERSION = "1";
|
|
9847
10861
|
function isPathWithinRoot2(filePath, rootPath) {
|
|
9848
|
-
const normalizedFilePath =
|
|
9849
|
-
const normalizedRoot =
|
|
9850
|
-
return normalizedFilePath === normalizedRoot || normalizedFilePath.startsWith(`${normalizedRoot}${
|
|
10862
|
+
const normalizedFilePath = path20.resolve(filePath);
|
|
10863
|
+
const normalizedRoot = path20.resolve(rootPath);
|
|
10864
|
+
return normalizedFilePath === normalizedRoot || normalizedFilePath.startsWith(`${normalizedRoot}${path20.sep}`);
|
|
9851
10865
|
}
|
|
9852
10866
|
function promoteIdentifierMatches(query, combined, semanticCandidates, keywordCandidates, database, branchChunkIds, prioritizeSourcePaths = classifyQueryIntentRaw(query) === "source") {
|
|
9853
10867
|
if (combined.length === 0) {
|
|
@@ -10178,10 +11192,10 @@ function matchesHardSearchFilters(candidate, options, projectRoot) {
|
|
|
10178
11192
|
}
|
|
10179
11193
|
if (options?.directory) {
|
|
10180
11194
|
const candidatePath = canonicalizePathForComparison(
|
|
10181
|
-
|
|
11195
|
+
path20.resolve(projectRoot, candidate.metadata.filePath.replace(/\\/g, path20.sep))
|
|
10182
11196
|
);
|
|
10183
11197
|
const directoryPath = canonicalizePathForComparison(
|
|
10184
|
-
|
|
11198
|
+
path20.resolve(projectRoot, options.directory.trim().replace(/\\/g, path20.sep))
|
|
10185
11199
|
);
|
|
10186
11200
|
if (!isPathWithinRoot2(candidatePath, directoryPath)) return false;
|
|
10187
11201
|
}
|
|
@@ -10294,26 +11308,37 @@ var Indexer = class _Indexer {
|
|
|
10294
11308
|
return this.indexPathOverride ?? resolveProjectIndexPath(this.projectRoot, this.config.scope, this.host);
|
|
10295
11309
|
}
|
|
10296
11310
|
toCanonicalFilePath(filePath) {
|
|
10297
|
-
if (!
|
|
11311
|
+
if (!path20.isAbsolute(filePath)) {
|
|
10298
11312
|
return this.resolveStoredFilePath(filePath, this.projectRoot);
|
|
10299
11313
|
}
|
|
10300
|
-
if (
|
|
11314
|
+
if (path20.resolve(this.materializedProjectRoot) === path20.resolve(this.projectRoot) || !isPathWithinRoot2(filePath, this.materializedProjectRoot)) {
|
|
10301
11315
|
return filePath;
|
|
10302
11316
|
}
|
|
10303
|
-
return
|
|
11317
|
+
return path20.resolve(this.projectRoot, path20.relative(this.materializedProjectRoot, filePath));
|
|
10304
11318
|
}
|
|
10305
11319
|
toStoredFilePath(filePath) {
|
|
10306
11320
|
const canonicalFilePath = this.toCanonicalFilePath(filePath);
|
|
10307
11321
|
if (this.config.scope !== "project" || !isPathWithinRoot2(canonicalFilePath, this.projectRoot)) {
|
|
10308
11322
|
return canonicalFilePath;
|
|
10309
11323
|
}
|
|
10310
|
-
return
|
|
11324
|
+
return path20.relative(this.projectRoot, canonicalFilePath).split(path20.sep).join("/");
|
|
11325
|
+
}
|
|
11326
|
+
isStoredPathExcluded(storedPath) {
|
|
11327
|
+
let matchPath = storedPath.split(path20.sep).join("/");
|
|
11328
|
+
if (path20.isAbsolute(storedPath)) {
|
|
11329
|
+
const relativePath = path20.relative(this.projectRoot, storedPath).split(path20.sep).join("/");
|
|
11330
|
+
if (relativePath.startsWith("..") || path20.isAbsolute(relativePath)) {
|
|
11331
|
+
return false;
|
|
11332
|
+
}
|
|
11333
|
+
matchPath = relativePath;
|
|
11334
|
+
}
|
|
11335
|
+
return isExcludedByPatterns(matchPath, this.config.exclude);
|
|
10311
11336
|
}
|
|
10312
11337
|
resolveStoredFilePath(filePath, rootPath = this.projectRoot) {
|
|
10313
|
-
if (
|
|
11338
|
+
if (path20.isAbsolute(filePath)) {
|
|
10314
11339
|
return filePath;
|
|
10315
11340
|
}
|
|
10316
|
-
const resolvedPath =
|
|
11341
|
+
const resolvedPath = path20.resolve(rootPath, ...filePath.split("/"));
|
|
10317
11342
|
if (!isPathWithinRoot2(resolvedPath, rootPath)) {
|
|
10318
11343
|
throw new Error(`Stored project path escapes project root: ${JSON.stringify(filePath)}`);
|
|
10319
11344
|
}
|
|
@@ -10337,7 +11362,7 @@ var Indexer = class _Indexer {
|
|
|
10337
11362
|
}
|
|
10338
11363
|
toMaterializedFilePath(filePath) {
|
|
10339
11364
|
const storedFilePath = this.toStoredFilePath(filePath);
|
|
10340
|
-
if (
|
|
11365
|
+
if (path20.isAbsolute(storedFilePath)) {
|
|
10341
11366
|
return storedFilePath;
|
|
10342
11367
|
}
|
|
10343
11368
|
return this.resolveStoredFilePath(storedFilePath, this.materializedProjectRoot);
|
|
@@ -10354,10 +11379,10 @@ var Indexer = class _Indexer {
|
|
|
10354
11379
|
}
|
|
10355
11380
|
getRuntimeArtifactPath(fileName) {
|
|
10356
11381
|
const namespace = this.getRuntimeArtifactNamespace();
|
|
10357
|
-
if (!namespace) return
|
|
10358
|
-
const extension =
|
|
11382
|
+
if (!namespace) return path20.join(this.indexPath, fileName);
|
|
11383
|
+
const extension = path20.extname(fileName);
|
|
10359
11384
|
const baseName = fileName.slice(0, fileName.length - extension.length);
|
|
10360
|
-
return
|
|
11385
|
+
return path20.join(this.indexPath, `${baseName}.${namespace}${extension}`);
|
|
10361
11386
|
}
|
|
10362
11387
|
refreshRuntimeArtifactPaths() {
|
|
10363
11388
|
this.fileHashCachePath = this.getRuntimeArtifactPath("file-hashes.json");
|
|
@@ -10370,14 +11395,14 @@ var Indexer = class _Indexer {
|
|
|
10370
11395
|
getMaterializedKnowledgeBases() {
|
|
10371
11396
|
const canonicalProjectRoot = this.getCanonicalPath(this.projectRoot);
|
|
10372
11397
|
return this.config.knowledgeBases.map((knowledgeBase) => {
|
|
10373
|
-
const configuredPath =
|
|
11398
|
+
const configuredPath = path20.isAbsolute(knowledgeBase) ? knowledgeBase : path20.resolve(this.projectRoot, knowledgeBase);
|
|
10374
11399
|
const canonicalPath = this.getCanonicalPath(configuredPath);
|
|
10375
11400
|
if (!isPathWithinRoot2(canonicalPath, canonicalProjectRoot)) {
|
|
10376
11401
|
return canonicalPath;
|
|
10377
11402
|
}
|
|
10378
|
-
return
|
|
11403
|
+
return path20.resolve(
|
|
10379
11404
|
this.materializedProjectRoot,
|
|
10380
|
-
|
|
11405
|
+
path20.relative(canonicalProjectRoot, canonicalPath)
|
|
10381
11406
|
);
|
|
10382
11407
|
});
|
|
10383
11408
|
}
|
|
@@ -10385,7 +11410,7 @@ var Indexer = class _Indexer {
|
|
|
10385
11410
|
try {
|
|
10386
11411
|
return canonicalizePathForComparison(targetPath);
|
|
10387
11412
|
} catch {
|
|
10388
|
-
return
|
|
11413
|
+
return path20.resolve(targetPath);
|
|
10389
11414
|
}
|
|
10390
11415
|
}
|
|
10391
11416
|
getProjectIdentityHash(projectRoot) {
|
|
@@ -10466,7 +11491,7 @@ var Indexer = class _Indexer {
|
|
|
10466
11491
|
} catch (error) {
|
|
10467
11492
|
releaseError = error;
|
|
10468
11493
|
this.writerArtifactFingerprint = null;
|
|
10469
|
-
if (!
|
|
11494
|
+
if (!existsSync12(lease.lockPath) && this.activeIndexLease?.owner.token === lease.owner.token) {
|
|
10470
11495
|
this.activeIndexLease = null;
|
|
10471
11496
|
}
|
|
10472
11497
|
}
|
|
@@ -10484,12 +11509,12 @@ var Indexer = class _Indexer {
|
|
|
10484
11509
|
return this.activeIndexLease;
|
|
10485
11510
|
}
|
|
10486
11511
|
loadFileHashCache() {
|
|
10487
|
-
if (!
|
|
11512
|
+
if (!existsSync12(this.fileHashCachePath)) {
|
|
10488
11513
|
this.fileHashCache = /* @__PURE__ */ new Map();
|
|
10489
11514
|
return;
|
|
10490
11515
|
}
|
|
10491
11516
|
try {
|
|
10492
|
-
const data =
|
|
11517
|
+
const data = readFileSync9(this.fileHashCachePath, "utf-8");
|
|
10493
11518
|
const parsed = JSON.parse(data);
|
|
10494
11519
|
this.fileHashCache = new Map(Object.entries(parsed));
|
|
10495
11520
|
} catch (error) {
|
|
@@ -10511,24 +11536,24 @@ var Indexer = class _Indexer {
|
|
|
10511
11536
|
atomicWriteSync(targetPath, data) {
|
|
10512
11537
|
const lease = this.requireActiveLease();
|
|
10513
11538
|
const tempPath = createLeaseTemporaryPath(targetPath, lease.owner, "tmp");
|
|
10514
|
-
|
|
11539
|
+
mkdirSync5(path20.dirname(targetPath), { recursive: true });
|
|
10515
11540
|
try {
|
|
10516
|
-
|
|
10517
|
-
|
|
11541
|
+
writeFileSync4(tempPath, data);
|
|
11542
|
+
renameSync4(tempPath, targetPath);
|
|
10518
11543
|
} finally {
|
|
10519
11544
|
removeLeaseTemporaryPath(tempPath);
|
|
10520
11545
|
}
|
|
10521
11546
|
}
|
|
10522
11547
|
saveInvertedIndex(invertedIndex) {
|
|
10523
11548
|
this.atomicWriteSync(
|
|
10524
|
-
|
|
11549
|
+
path20.join(this.indexPath, "inverted-index.json"),
|
|
10525
11550
|
invertedIndex.serialize()
|
|
10526
11551
|
);
|
|
10527
11552
|
}
|
|
10528
11553
|
getScopedRoots(projectRoot = this.projectRoot) {
|
|
10529
11554
|
const roots = /* @__PURE__ */ new Set([this.getCanonicalPath(projectRoot)]);
|
|
10530
11555
|
for (const kbRoot of this.config.knowledgeBases) {
|
|
10531
|
-
roots.add(this.getCanonicalPath(
|
|
11556
|
+
roots.add(this.getCanonicalPath(path20.resolve(projectRoot, kbRoot)));
|
|
10532
11557
|
}
|
|
10533
11558
|
return Array.from(roots);
|
|
10534
11559
|
}
|
|
@@ -10945,7 +11970,7 @@ var Indexer = class _Indexer {
|
|
|
10945
11970
|
return configuredProviderInfo !== null && recovery.embeddingProvider === configuredProviderInfo.provider && recovery.embeddingModel === configuredProviderInfo.modelInfo.model && recovery.embeddingDimensions === configuredProviderInfo.modelInfo.dimensions && recovery.embeddingStrategyVersion === EMBEDDING_STRATEGY_VERSION;
|
|
10946
11971
|
}
|
|
10947
11972
|
hasUnknownLegacyForceIndexClear(owner) {
|
|
10948
|
-
return owner.operation === "force-index" && owner.clearRecovery === void 0 && owner.recoveryProtocolVersion !== 1 &&
|
|
11973
|
+
return owner.operation === "force-index" && owner.clearRecovery === void 0 && owner.recoveryProtocolVersion !== 1 && existsSync12(path20.join(this.indexPath, "force-index-phase"));
|
|
10949
11974
|
}
|
|
10950
11975
|
async recoverFromInterruptedIndexingUnlocked(owners) {
|
|
10951
11976
|
for (const owner of owners) {
|
|
@@ -11131,7 +12156,7 @@ var Indexer = class _Indexer {
|
|
|
11131
12156
|
}
|
|
11132
12157
|
}
|
|
11133
12158
|
clearFailedBatchState() {
|
|
11134
|
-
if (
|
|
12159
|
+
if (existsSync12(this.failedBatchesPath)) {
|
|
11135
12160
|
try {
|
|
11136
12161
|
unlinkSync2(this.failedBatchesPath);
|
|
11137
12162
|
} catch {
|
|
@@ -11333,7 +12358,7 @@ var Indexer = class _Indexer {
|
|
|
11333
12358
|
await options.queue.onSizeLessThan(Math.max(1, options.providerRateLimits.concurrency));
|
|
11334
12359
|
const task = options.queue.add(async () => {
|
|
11335
12360
|
if (options.rateLimitState.backoffMs > 0) {
|
|
11336
|
-
await new Promise((
|
|
12361
|
+
await new Promise((resolve18) => setTimeout(resolve18, options.rateLimitState.backoffMs));
|
|
11337
12362
|
}
|
|
11338
12363
|
try {
|
|
11339
12364
|
const embeddingResult = await pRetry(
|
|
@@ -11752,12 +12777,12 @@ var Indexer = class _Indexer {
|
|
|
11752
12777
|
}
|
|
11753
12778
|
}
|
|
11754
12779
|
captureReaderArtifactFingerprint() {
|
|
11755
|
-
const storePath =
|
|
12780
|
+
const storePath = path20.join(this.indexPath, "vectors");
|
|
11756
12781
|
return {
|
|
11757
12782
|
vectors: `${this.getReaderFileFingerprint(storePath)}|${this.getReaderFileFingerprint(`${storePath}.meta.json`)}`,
|
|
11758
|
-
keyword: this.getReaderFileFingerprint(
|
|
11759
|
-
database: this.getReaderFileFingerprint(
|
|
11760
|
-
databaseIdentity: this.getReaderFileFingerprint(
|
|
12783
|
+
keyword: this.getReaderFileFingerprint(path20.join(this.indexPath, "inverted-index.json")),
|
|
12784
|
+
database: this.getReaderFileFingerprint(path20.join(this.indexPath, "codebase.db")),
|
|
12785
|
+
databaseIdentity: this.getReaderFileFingerprint(path20.join(this.indexPath, "codebase.db"), true)
|
|
11761
12786
|
};
|
|
11762
12787
|
}
|
|
11763
12788
|
refreshReaderArtifacts() {
|
|
@@ -11782,13 +12807,13 @@ var Indexer = class _Indexer {
|
|
|
11782
12807
|
issues.set(component, this.createReadIssue(component, message));
|
|
11783
12808
|
this.readerArtifactRetryAfter.set(component, Date.now() + READER_ARTIFACT_RETRY_INTERVAL_MS);
|
|
11784
12809
|
};
|
|
11785
|
-
const storePath =
|
|
12810
|
+
const storePath = path20.join(this.indexPath, "vectors");
|
|
11786
12811
|
const vectorMetadataPath = `${storePath}.meta.json`;
|
|
11787
|
-
const invertedIndexPath =
|
|
11788
|
-
const dbPath =
|
|
12812
|
+
const invertedIndexPath = path20.join(this.indexPath, "inverted-index.json");
|
|
12813
|
+
const dbPath = path20.join(this.indexPath, "codebase.db");
|
|
11789
12814
|
if (vectorsChanged || retryDue("vectors")) {
|
|
11790
|
-
const vectorStoreExists =
|
|
11791
|
-
const vectorMetadataExists =
|
|
12815
|
+
const vectorStoreExists = existsSync12(storePath);
|
|
12816
|
+
const vectorMetadataExists = existsSync12(vectorMetadataPath);
|
|
11792
12817
|
if (vectorStoreExists && vectorMetadataExists) {
|
|
11793
12818
|
try {
|
|
11794
12819
|
const store = new VectorStore(storePath, this.configuredProviderInfo.modelInfo.dimensions);
|
|
@@ -11803,8 +12828,8 @@ var Indexer = class _Indexer {
|
|
|
11803
12828
|
setIssue("vectors", this.getVectorReadIssueMessage());
|
|
11804
12829
|
}
|
|
11805
12830
|
}
|
|
11806
|
-
if (keywordChanged || retryDue("keyword") || !
|
|
11807
|
-
if (
|
|
12831
|
+
if (keywordChanged || retryDue("keyword") || !existsSync12(invertedIndexPath) && (this.store?.count() ?? 0) > 0) {
|
|
12832
|
+
if (existsSync12(invertedIndexPath)) {
|
|
11808
12833
|
try {
|
|
11809
12834
|
const invertedIndex = new InvertedIndex(invertedIndexPath);
|
|
11810
12835
|
invertedIndex.load();
|
|
@@ -11819,7 +12844,7 @@ var Indexer = class _Indexer {
|
|
|
11819
12844
|
}
|
|
11820
12845
|
}
|
|
11821
12846
|
if (databaseReplaced || databaseChanged && issues.has("database") || retryDue("database")) {
|
|
11822
|
-
if (
|
|
12847
|
+
if (existsSync12(dbPath)) {
|
|
11823
12848
|
try {
|
|
11824
12849
|
const database = Database.openReadOnly(dbPath);
|
|
11825
12850
|
if (this.database) {
|
|
@@ -11901,11 +12926,11 @@ var Indexer = class _Indexer {
|
|
|
11901
12926
|
});
|
|
11902
12927
|
this.provider = createEmbeddingProvider(this.configuredProviderInfo);
|
|
11903
12928
|
const dimensions = this.configuredProviderInfo.modelInfo.dimensions;
|
|
11904
|
-
const storePath =
|
|
12929
|
+
const storePath = path20.join(this.indexPath, "vectors");
|
|
11905
12930
|
const vectorMetadataPath = `${storePath}.meta.json`;
|
|
11906
|
-
const invertedIndexPath =
|
|
11907
|
-
const dbPath =
|
|
11908
|
-
let dbIsNew = !
|
|
12931
|
+
const invertedIndexPath = path20.join(this.indexPath, "inverted-index.json");
|
|
12932
|
+
const dbPath = path20.join(this.indexPath, "codebase.db");
|
|
12933
|
+
let dbIsNew = !existsSync12(dbPath);
|
|
11909
12934
|
const readerArtifactFingerprint = mode === "reader" ? this.captureReaderArtifactFingerprint() : null;
|
|
11910
12935
|
if (mode === "writer") {
|
|
11911
12936
|
await fsPromises3.mkdir(this.indexPath, { recursive: true });
|
|
@@ -11937,14 +12962,14 @@ var Indexer = class _Indexer {
|
|
|
11937
12962
|
}
|
|
11938
12963
|
}
|
|
11939
12964
|
this.store = new VectorStore(storePath, dimensions);
|
|
11940
|
-
if (
|
|
12965
|
+
if (existsSync12(storePath) || existsSync12(vectorMetadataPath)) {
|
|
11941
12966
|
this.store.load();
|
|
11942
12967
|
}
|
|
11943
12968
|
this.invertedIndex = new InvertedIndex(invertedIndexPath);
|
|
11944
12969
|
try {
|
|
11945
12970
|
this.invertedIndex.load();
|
|
11946
12971
|
} catch {
|
|
11947
|
-
if (
|
|
12972
|
+
if (existsSync12(invertedIndexPath)) {
|
|
11948
12973
|
await fsPromises3.unlink(invertedIndexPath);
|
|
11949
12974
|
}
|
|
11950
12975
|
this.invertedIndex = new InvertedIndex(invertedIndexPath);
|
|
@@ -11962,8 +12987,8 @@ var Indexer = class _Indexer {
|
|
|
11962
12987
|
}
|
|
11963
12988
|
} else {
|
|
11964
12989
|
this.store = new VectorStore(storePath, dimensions);
|
|
11965
|
-
const vectorStoreExists =
|
|
11966
|
-
const vectorMetadataExists =
|
|
12990
|
+
const vectorStoreExists = existsSync12(storePath);
|
|
12991
|
+
const vectorMetadataExists = existsSync12(vectorMetadataPath);
|
|
11967
12992
|
const vectorReadFailureMessage = this.getVectorReadIssueMessage();
|
|
11968
12993
|
if (vectorStoreExists !== vectorMetadataExists) {
|
|
11969
12994
|
this.recordReadIssue("vectors", vectorReadFailureMessage);
|
|
@@ -11976,7 +13001,7 @@ var Indexer = class _Indexer {
|
|
|
11976
13001
|
}
|
|
11977
13002
|
}
|
|
11978
13003
|
this.invertedIndex = new InvertedIndex(invertedIndexPath);
|
|
11979
|
-
if (
|
|
13004
|
+
if (existsSync12(invertedIndexPath)) {
|
|
11980
13005
|
try {
|
|
11981
13006
|
this.invertedIndex.load();
|
|
11982
13007
|
} catch (error) {
|
|
@@ -11990,7 +13015,7 @@ var Indexer = class _Indexer {
|
|
|
11990
13015
|
} else if (this.store.count() > 0) {
|
|
11991
13016
|
this.recordReadIssue("keyword", this.getKeywordReadIssueMessage());
|
|
11992
13017
|
}
|
|
11993
|
-
if (
|
|
13018
|
+
if (existsSync12(dbPath)) {
|
|
11994
13019
|
try {
|
|
11995
13020
|
this.database = Database.openReadOnly(dbPath);
|
|
11996
13021
|
} catch (error) {
|
|
@@ -12082,7 +13107,7 @@ var Indexer = class _Indexer {
|
|
|
12082
13107
|
if (await this.tryResetCorruptedIndex("running automatic orphan garbage collection", error)) {
|
|
12083
13108
|
return {
|
|
12084
13109
|
resetCorruptedIndex: true,
|
|
12085
|
-
warning: this.getCorruptedIndexWarning(
|
|
13110
|
+
warning: this.getCorruptedIndexWarning(path20.join(this.indexPath, "codebase.db"))
|
|
12086
13111
|
};
|
|
12087
13112
|
}
|
|
12088
13113
|
throw error;
|
|
@@ -12097,7 +13122,7 @@ var Indexer = class _Indexer {
|
|
|
12097
13122
|
return;
|
|
12098
13123
|
}
|
|
12099
13124
|
const retainedEntries = store.getAllMetadata().filter(({ key }) => !excludedSet.has(key));
|
|
12100
|
-
const storeBasePath =
|
|
13125
|
+
const storeBasePath = path20.join(this.indexPath, "vectors");
|
|
12101
13126
|
const storeIndexPath = storeBasePath;
|
|
12102
13127
|
const storeMetadataPath = `${storeBasePath}.meta.json`;
|
|
12103
13128
|
const lease = this.requireActiveLease();
|
|
@@ -12107,19 +13132,19 @@ var Indexer = class _Indexer {
|
|
|
12107
13132
|
let backedUpMetadata = false;
|
|
12108
13133
|
let rebuiltCount = 0;
|
|
12109
13134
|
let skippedCount = 0;
|
|
12110
|
-
if (
|
|
13135
|
+
if (existsSync12(backupIndexPath)) {
|
|
12111
13136
|
unlinkSync2(backupIndexPath);
|
|
12112
13137
|
}
|
|
12113
|
-
if (
|
|
13138
|
+
if (existsSync12(backupMetadataPath)) {
|
|
12114
13139
|
unlinkSync2(backupMetadataPath);
|
|
12115
13140
|
}
|
|
12116
13141
|
try {
|
|
12117
|
-
if (
|
|
12118
|
-
|
|
13142
|
+
if (existsSync12(storeIndexPath)) {
|
|
13143
|
+
renameSync4(storeIndexPath, backupIndexPath);
|
|
12119
13144
|
backedUpIndex = true;
|
|
12120
13145
|
}
|
|
12121
|
-
if (
|
|
12122
|
-
|
|
13146
|
+
if (existsSync12(storeMetadataPath)) {
|
|
13147
|
+
renameSync4(storeMetadataPath, backupMetadataPath);
|
|
12123
13148
|
backedUpMetadata = true;
|
|
12124
13149
|
}
|
|
12125
13150
|
store.clear();
|
|
@@ -12139,10 +13164,10 @@ var Indexer = class _Indexer {
|
|
|
12139
13164
|
rebuiltCount += 1;
|
|
12140
13165
|
}
|
|
12141
13166
|
store.save();
|
|
12142
|
-
if (backedUpIndex &&
|
|
13167
|
+
if (backedUpIndex && existsSync12(backupIndexPath)) {
|
|
12143
13168
|
unlinkSync2(backupIndexPath);
|
|
12144
13169
|
}
|
|
12145
|
-
if (backedUpMetadata &&
|
|
13170
|
+
if (backedUpMetadata && existsSync12(backupMetadataPath)) {
|
|
12146
13171
|
unlinkSync2(backupMetadataPath);
|
|
12147
13172
|
}
|
|
12148
13173
|
this.logger.gc("info", "Rebuilt vector store to avoid native remove", {
|
|
@@ -12155,17 +13180,17 @@ var Indexer = class _Indexer {
|
|
|
12155
13180
|
store.clear();
|
|
12156
13181
|
} catch {
|
|
12157
13182
|
}
|
|
12158
|
-
if (
|
|
13183
|
+
if (existsSync12(storeIndexPath)) {
|
|
12159
13184
|
unlinkSync2(storeIndexPath);
|
|
12160
13185
|
}
|
|
12161
|
-
if (
|
|
13186
|
+
if (existsSync12(storeMetadataPath)) {
|
|
12162
13187
|
unlinkSync2(storeMetadataPath);
|
|
12163
13188
|
}
|
|
12164
|
-
if (backedUpIndex &&
|
|
12165
|
-
|
|
13189
|
+
if (backedUpIndex && existsSync12(backupIndexPath)) {
|
|
13190
|
+
renameSync4(backupIndexPath, storeIndexPath);
|
|
12166
13191
|
}
|
|
12167
|
-
if (backedUpMetadata &&
|
|
12168
|
-
|
|
13192
|
+
if (backedUpMetadata && existsSync12(backupMetadataPath)) {
|
|
13193
|
+
renameSync4(backupMetadataPath, storeMetadataPath);
|
|
12169
13194
|
}
|
|
12170
13195
|
if (backedUpIndex || backedUpMetadata) {
|
|
12171
13196
|
store.load();
|
|
@@ -12180,11 +13205,11 @@ var Indexer = class _Indexer {
|
|
|
12180
13205
|
return `Detected a corrupted local SQLite index at ${dbPath} and reset the local index. Run index_codebase to rebuild search data.`;
|
|
12181
13206
|
}
|
|
12182
13207
|
async removeProjectRuntimeStateArtifacts() {
|
|
12183
|
-
if (!
|
|
13208
|
+
if (!existsSync12(this.indexPath)) return;
|
|
12184
13209
|
const names = await fsPromises3.readdir(this.indexPath);
|
|
12185
13210
|
const runtimeStatePattern = /^(?:file-hashes|failed-batches)(?:\.[a-f0-9]{16})?\.json$/;
|
|
12186
13211
|
await Promise.all(
|
|
12187
|
-
names.filter((name) => runtimeStatePattern.test(name)).map((name) => fsPromises3.rm(
|
|
13212
|
+
names.filter((name) => runtimeStatePattern.test(name)).map((name) => fsPromises3.rm(path20.join(this.indexPath, name), { force: true }))
|
|
12188
13213
|
);
|
|
12189
13214
|
}
|
|
12190
13215
|
async resetLocalIndexArtifacts() {
|
|
@@ -12200,13 +13225,13 @@ var Indexer = class _Indexer {
|
|
|
12200
13225
|
this.readerArtifactRetryAfter.clear();
|
|
12201
13226
|
this.fileHashCache.clear();
|
|
12202
13227
|
const resetPaths = [
|
|
12203
|
-
|
|
12204
|
-
|
|
12205
|
-
|
|
12206
|
-
|
|
12207
|
-
|
|
12208
|
-
|
|
12209
|
-
|
|
13228
|
+
path20.join(this.indexPath, "codebase.db"),
|
|
13229
|
+
path20.join(this.indexPath, "codebase.db-shm"),
|
|
13230
|
+
path20.join(this.indexPath, "codebase.db-wal"),
|
|
13231
|
+
path20.join(this.indexPath, "vectors"),
|
|
13232
|
+
path20.join(this.indexPath, "vectors.usearch"),
|
|
13233
|
+
path20.join(this.indexPath, "vectors.meta.json"),
|
|
13234
|
+
path20.join(this.indexPath, "inverted-index.json")
|
|
12210
13235
|
];
|
|
12211
13236
|
await Promise.all(resetPaths.map((targetPath) => fsPromises3.rm(targetPath, { recursive: true, force: true })));
|
|
12212
13237
|
await this.removeProjectRuntimeStateArtifacts();
|
|
@@ -12216,7 +13241,7 @@ var Indexer = class _Indexer {
|
|
|
12216
13241
|
if (!isSqliteCorruptionError(error)) {
|
|
12217
13242
|
return false;
|
|
12218
13243
|
}
|
|
12219
|
-
const dbPath =
|
|
13244
|
+
const dbPath = path20.join(this.indexPath, "codebase.db");
|
|
12220
13245
|
const warning = this.getCorruptedIndexWarning(dbPath);
|
|
12221
13246
|
const errorMessage = getErrorMessage4(error);
|
|
12222
13247
|
if (this.config.scope === "global") {
|
|
@@ -12450,6 +13475,70 @@ var Indexer = class _Indexer {
|
|
|
12450
13475
|
);
|
|
12451
13476
|
return createCostEstimate(files, configuredProviderInfo);
|
|
12452
13477
|
}
|
|
13478
|
+
// Dry-run counterpart to index()/forceIndex(): parse the real file set and sum
|
|
13479
|
+
// estimateTokens over the embedding text of every indexable chunk, without
|
|
13480
|
+
// calling the embedding provider or writing to the index. Read-only and
|
|
13481
|
+
// lock-free (mirrors estimateCost). The token sum is the exact value "Tokens
|
|
13482
|
+
// used" climbs to for a force index (cache bypassed); for an incremental it is
|
|
13483
|
+
// an upper bound because cached chunks are counted here but not re-embedded.
|
|
13484
|
+
// Used by index_codebase(dryRun:true) to give a stable, monotonic progress
|
|
13485
|
+
// denominator that matches the live "Tokens used" basis.
|
|
13486
|
+
async dryRunCost() {
|
|
13487
|
+
const { configuredProviderInfo } = await this.ensureInitialized();
|
|
13488
|
+
const maxChunkTokens = getSafeEmbeddingChunkTokenLimit(configuredProviderInfo);
|
|
13489
|
+
const includePatterns = [...this.config.include, ...this.config.additionalInclude];
|
|
13490
|
+
const { files } = await collectFiles(
|
|
13491
|
+
this.materializedProjectRoot,
|
|
13492
|
+
includePatterns,
|
|
13493
|
+
this.config.exclude,
|
|
13494
|
+
this.config.indexing.maxFileSize,
|
|
13495
|
+
this.getMaterializedKnowledgeBases(),
|
|
13496
|
+
{ maxDepth: this.config.indexing.maxDepth, maxFilesPerDirectory: this.config.indexing.maxFilesPerDirectory }
|
|
13497
|
+
);
|
|
13498
|
+
let filesCount = 0;
|
|
13499
|
+
let chunksCount = 0;
|
|
13500
|
+
let tokensToEmbed = 0;
|
|
13501
|
+
for (const batch of iterateOrderedFileBatches(files, (f) => f.size, this.fileBatchLimits)) {
|
|
13502
|
+
const loadedFiles = await Promise.all(batch.map(async (f) => {
|
|
13503
|
+
try {
|
|
13504
|
+
return {
|
|
13505
|
+
path: this.toStoredFilePath(f.path),
|
|
13506
|
+
content: await fsPromises3.readFile(f.path, "utf-8")
|
|
13507
|
+
};
|
|
13508
|
+
} catch {
|
|
13509
|
+
return null;
|
|
13510
|
+
}
|
|
13511
|
+
}));
|
|
13512
|
+
const readable = loadedFiles.filter(
|
|
13513
|
+
(f) => f !== null
|
|
13514
|
+
);
|
|
13515
|
+
filesCount += readable.length;
|
|
13516
|
+
const contentByPath = new Map(readable.map((f) => [f.path, f.content]));
|
|
13517
|
+
const parsedFiles = parseFiles(readable, this.config.indexing.linesPerChunk);
|
|
13518
|
+
for (const parsed of parsedFiles) {
|
|
13519
|
+
let chunksToProcess = parsed.chunks;
|
|
13520
|
+
if (this.config.indexing.fallbackToTextOnMaxChunks && chunksToProcess.length > this.config.indexing.maxChunksPerFile) {
|
|
13521
|
+
const content = contentByPath.get(parsed.path);
|
|
13522
|
+
if (content !== void 0) {
|
|
13523
|
+
chunksToProcess = parseFileAsText(parsed.path, content, this.config.indexing.linesPerChunk);
|
|
13524
|
+
}
|
|
13525
|
+
}
|
|
13526
|
+
chunksToProcess = selectIndexableChunks(
|
|
13527
|
+
chunksToProcess,
|
|
13528
|
+
this.config.indexing.maxChunksPerFile,
|
|
13529
|
+
this.config.indexing.semanticOnly
|
|
13530
|
+
);
|
|
13531
|
+
for (const chunk of chunksToProcess) {
|
|
13532
|
+
const texts = createEmbeddingTexts(chunk, parsed.path, maxChunkTokens);
|
|
13533
|
+
chunksCount += 1;
|
|
13534
|
+
for (const text of texts) {
|
|
13535
|
+
tokensToEmbed += estimateTokens(text);
|
|
13536
|
+
}
|
|
13537
|
+
}
|
|
13538
|
+
}
|
|
13539
|
+
}
|
|
13540
|
+
return { filesCount, chunksCount, tokensToEmbed };
|
|
13541
|
+
}
|
|
12453
13542
|
async index(onProgress) {
|
|
12454
13543
|
return this.withIndexMutationLease("index", async (recoveredOwners) => {
|
|
12455
13544
|
return this.indexUnlocked(onProgress, recoveredOwners);
|
|
@@ -12539,10 +13628,10 @@ var Indexer = class _Indexer {
|
|
|
12539
13628
|
const reparseCachedMetalFiles = database.getMetadata(metalParserMetadataKey) !== METAL_PARSER_VERSION;
|
|
12540
13629
|
const symbolExtractorMetadataKey = this.getSymbolExtractorVersionMetadataKey();
|
|
12541
13630
|
const refreshCachedSymbols = database.getMetadata(symbolExtractorMetadataKey) !== SYMBOL_EXTRACTOR_VERSION;
|
|
12542
|
-
if (reparseCachedSwiftFiles && Array.from(this.fileHashCache.keys()).some((filePath) =>
|
|
13631
|
+
if (reparseCachedSwiftFiles && Array.from(this.fileHashCache.keys()).some((filePath) => path20.extname(filePath).toLowerCase() === ".swift")) {
|
|
12543
13632
|
this.logger.info("Reindexing cached Swift files for parser support");
|
|
12544
13633
|
}
|
|
12545
|
-
if (reparseCachedMetalFiles && Array.from(this.fileHashCache.keys()).some((filePath) =>
|
|
13634
|
+
if (reparseCachedMetalFiles && Array.from(this.fileHashCache.keys()).some((filePath) => path20.extname(filePath).toLowerCase() === ".metal")) {
|
|
12546
13635
|
this.logger.info("Reindexing cached Metal files for parser support");
|
|
12547
13636
|
}
|
|
12548
13637
|
const includePatterns = [...this.config.include, ...this.config.additionalInclude];
|
|
@@ -12586,8 +13675,8 @@ var Indexer = class _Indexer {
|
|
|
12586
13675
|
const needsCallGraphRefresh = cachedHashMatches && needsCallGraphResolutionMigration && database.getChunksByFile(storedPath).some(
|
|
12587
13676
|
(chunk) => chunk.language === "php" || chunk.language === "c" || chunk.language === "cpp"
|
|
12588
13677
|
);
|
|
12589
|
-
const requiresSwiftParserUpgrade = reparseCachedSwiftFiles &&
|
|
12590
|
-
const requiresMetalParserUpgrade = reparseCachedMetalFiles &&
|
|
13678
|
+
const requiresSwiftParserUpgrade = reparseCachedSwiftFiles && path20.extname(storedPath).toLowerCase() === ".swift";
|
|
13679
|
+
const requiresMetalParserUpgrade = reparseCachedMetalFiles && path20.extname(storedPath).toLowerCase() === ".metal";
|
|
12591
13680
|
const inMigrationScope = forceScopedReembed && scopedRoots !== null && this.isFileInCurrentScope(storedPath, scopedRoots);
|
|
12592
13681
|
if (cachedHashMatches && !inMigrationScope && !needsCallGraphRefresh && !requiresSwiftParserUpgrade && !requiresMetalParserUpgrade && !refreshCachedSymbols) {
|
|
12593
13682
|
unchangedFilePaths.add(storedPath);
|
|
@@ -12646,7 +13735,7 @@ var Indexer = class _Indexer {
|
|
|
12646
13735
|
}
|
|
12647
13736
|
}
|
|
12648
13737
|
}
|
|
12649
|
-
const shouldRetryFailedPath = (filePath) => filePath !== null && currentFileHashes.has(filePath) && unchangedFilePaths.has(filePath);
|
|
13738
|
+
const shouldRetryFailedPath = (filePath) => filePath !== null && !this.isStoredPathExcluded(filePath) && currentFileHashes.has(filePath) && unchangedFilePaths.has(filePath);
|
|
12650
13739
|
const failedProcessing = this.prepareFailedBatchProcessing(scopedRoots, shouldRetryFailedPath);
|
|
12651
13740
|
const maxChunkTokens = getSafeEmbeddingChunkTokenLimit(configuredProviderInfo);
|
|
12652
13741
|
const providerRateLimits = this.getProviderRateLimits(configuredProviderInfo.provider);
|
|
@@ -12750,7 +13839,7 @@ var Indexer = class _Indexer {
|
|
|
12750
13839
|
throw new Error(`Parsed file was not present in its source batch: ${parsed.path}`);
|
|
12751
13840
|
}
|
|
12752
13841
|
if (parsed.chunks.length === 0) {
|
|
12753
|
-
stats.parseFailures.push(
|
|
13842
|
+
stats.parseFailures.push(path20.isAbsolute(parsed.path) ? path20.relative(this.projectRoot, parsed.path) : parsed.path);
|
|
12754
13843
|
}
|
|
12755
13844
|
let chunksToProcess = parsed.chunks;
|
|
12756
13845
|
if (this.config.indexing.fallbackToTextOnMaxChunks && chunksToProcess.length > this.config.indexing.maxChunksPerFile) {
|
|
@@ -13085,8 +14174,8 @@ var Indexer = class _Indexer {
|
|
|
13085
14174
|
previousBranchSymbolIds,
|
|
13086
14175
|
Array.from(allSymbolIds)
|
|
13087
14176
|
);
|
|
13088
|
-
const vectorPath =
|
|
13089
|
-
const shouldFingerprintLegacyPair = !store.hasFingerprint() &&
|
|
14177
|
+
const vectorPath = path20.join(this.indexPath, "vectors");
|
|
14178
|
+
const shouldFingerprintLegacyPair = !store.hasFingerprint() && existsSync12(vectorPath) && existsSync12(`${vectorPath}.meta.json`);
|
|
13090
14179
|
if (backfilledBlameMetadata || shouldFingerprintLegacyPair || removedStoredChunks) {
|
|
13091
14180
|
store.save();
|
|
13092
14181
|
}
|
|
@@ -13881,7 +14970,7 @@ var Indexer = class _Indexer {
|
|
|
13881
14970
|
const missingChunkKeys = [];
|
|
13882
14971
|
const chunkKeysByRemovedFile = /* @__PURE__ */ new Map();
|
|
13883
14972
|
for (const [filePath, chunkKeys] of filePathsToChunkKeys) {
|
|
13884
|
-
if (!
|
|
14973
|
+
if (!existsSync12(this.toMaterializedFilePath(filePath))) {
|
|
13885
14974
|
chunkKeysByRemovedFile.set(filePath, chunkKeys);
|
|
13886
14975
|
for (const key of chunkKeys) {
|
|
13887
14976
|
missingChunkKeys.push(key);
|
|
@@ -13944,7 +15033,7 @@ var Indexer = class _Indexer {
|
|
|
13944
15033
|
gcOrphanSymbols: 0,
|
|
13945
15034
|
gcOrphanCallEdges: 0,
|
|
13946
15035
|
resetCorruptedIndex: true,
|
|
13947
|
-
warning: this.getCorruptedIndexWarning(
|
|
15036
|
+
warning: this.getCorruptedIndexWarning(path20.join(this.indexPath, "codebase.db"))
|
|
13948
15037
|
};
|
|
13949
15038
|
}
|
|
13950
15039
|
this.logger.recordGc(removedCount, gcOrphanChunks, gcOrphanEmbeddings);
|
|
@@ -13974,7 +15063,8 @@ var Indexer = class _Indexer {
|
|
|
13974
15063
|
const maxChunkTokens = getSafeEmbeddingChunkTokenLimit(configuredProviderInfo);
|
|
13975
15064
|
const providerRateLimits = this.getProviderRateLimits(configuredProviderInfo.provider);
|
|
13976
15065
|
const roots = this.config.scope === "global" ? this.getScopedRoots() : null;
|
|
13977
|
-
const
|
|
15066
|
+
const shouldProcessFailedPath = (filePath) => filePath === null || !this.isStoredPathExcluded(filePath);
|
|
15067
|
+
const failedProcessing = this.prepareFailedBatchProcessing(roots, shouldProcessFailedPath);
|
|
13978
15068
|
if (failedProcessing.latestById.size === 0) {
|
|
13979
15069
|
this.finalizeFailedBatchWriteState(failedProcessing.state);
|
|
13980
15070
|
return { succeeded: 0, failed: 0, remaining: 0 };
|
|
@@ -13987,7 +15077,7 @@ var Indexer = class _Indexer {
|
|
|
13987
15077
|
const retryableChunks = this.iterateLatestFailedChunks(
|
|
13988
15078
|
failedProcessing.latestById,
|
|
13989
15079
|
roots,
|
|
13990
|
-
|
|
15080
|
+
shouldProcessFailedPath,
|
|
13991
15081
|
maxChunkTokens
|
|
13992
15082
|
);
|
|
13993
15083
|
for (const retryBatch of iterateOrderedFileBatches(
|
|
@@ -14257,9 +15347,9 @@ var Indexer = class _Indexer {
|
|
|
14257
15347
|
this.requireReadableComponents(readIssues, "database");
|
|
14258
15348
|
let shortest = [];
|
|
14259
15349
|
for (const branchKey of this.getBranchCatalogKeys()) {
|
|
14260
|
-
const
|
|
14261
|
-
if (
|
|
14262
|
-
shortest =
|
|
15350
|
+
const path31 = database.findShortestPath(fromName, toName, branchKey, maxDepth);
|
|
15351
|
+
if (path31.length > 0 && (shortest.length === 0 || path31.length < shortest.length)) {
|
|
15352
|
+
shortest = path31;
|
|
14263
15353
|
}
|
|
14264
15354
|
}
|
|
14265
15355
|
return shortest.map((hop) => this.resolveFilePathRecord(hop));
|
|
@@ -14307,13 +15397,13 @@ var Indexer = class _Indexer {
|
|
|
14307
15397
|
}
|
|
14308
15398
|
}
|
|
14309
15399
|
if (!found) continue;
|
|
14310
|
-
const
|
|
15400
|
+
const path31 = [];
|
|
14311
15401
|
let currentSymbolId = toSymbolId;
|
|
14312
15402
|
while (true) {
|
|
14313
15403
|
const symbol = symbolsById.get(currentSymbolId);
|
|
14314
15404
|
if (!symbol) break;
|
|
14315
15405
|
const parent = parentBySymbolId.get(currentSymbolId);
|
|
14316
|
-
|
|
15406
|
+
path31.push({
|
|
14317
15407
|
symbolId: symbol.id,
|
|
14318
15408
|
symbolName: symbol.name,
|
|
14319
15409
|
filePath: symbol.filePath,
|
|
@@ -14323,9 +15413,9 @@ var Indexer = class _Indexer {
|
|
|
14323
15413
|
if (!parent) break;
|
|
14324
15414
|
currentSymbolId = parent.parentId;
|
|
14325
15415
|
}
|
|
14326
|
-
|
|
14327
|
-
if (
|
|
14328
|
-
shortest =
|
|
15416
|
+
path31.reverse();
|
|
15417
|
+
if (path31.length > 0 && (shortest.length === 0 || path31.length < shortest.length)) {
|
|
15418
|
+
shortest = path31;
|
|
14329
15419
|
}
|
|
14330
15420
|
}
|
|
14331
15421
|
return shortest.map((hop) => this.resolveFilePathRecord(hop));
|
|
@@ -14476,7 +15566,7 @@ var Indexer = class _Indexer {
|
|
|
14476
15566
|
);
|
|
14477
15567
|
}
|
|
14478
15568
|
}
|
|
14479
|
-
const toStoredChangedFiles = (filePaths) => filePaths.map((filePath) => this.toStoredFilePath(
|
|
15569
|
+
const toStoredChangedFiles = (filePaths) => filePaths.map((filePath) => this.toStoredFilePath(path20.resolve(this.projectRoot, filePath)));
|
|
14480
15570
|
const storedChangedFiles = toStoredChangedFiles(changedFiles);
|
|
14481
15571
|
const directSymbols = database.getSymbolsForFiles(storedChangedFiles, branchKey);
|
|
14482
15572
|
const directIds = directSymbols.map((s) => s.id);
|
|
@@ -14625,12 +15715,12 @@ var Indexer = class _Indexer {
|
|
|
14625
15715
|
if (meta.filePath) filePaths.add(meta.filePath);
|
|
14626
15716
|
}
|
|
14627
15717
|
const directory = options?.directory?.replace(/\/$/, "");
|
|
14628
|
-
const absoluteDirectoryFilter = directory ?
|
|
15718
|
+
const absoluteDirectoryFilter = directory ? path20.resolve(this.projectRoot, directory) : void 0;
|
|
14629
15719
|
for (const filePath of filePaths) {
|
|
14630
15720
|
if (directory) {
|
|
14631
15721
|
const absoluteFilePath = this.resolveStoredFilePath(filePath);
|
|
14632
15722
|
const matchesRelative = filePath === directory || filePath.startsWith(directory + "/");
|
|
14633
|
-
const matchesProjectRelative = absoluteDirectoryFilter !== void 0 && (absoluteFilePath === absoluteDirectoryFilter || absoluteFilePath.startsWith(absoluteDirectoryFilter +
|
|
15723
|
+
const matchesProjectRelative = absoluteDirectoryFilter !== void 0 && (absoluteFilePath === absoluteDirectoryFilter || absoluteFilePath.startsWith(absoluteDirectoryFilter + path20.sep));
|
|
14634
15724
|
if (!matchesRelative && !matchesProjectRelative) {
|
|
14635
15725
|
continue;
|
|
14636
15726
|
}
|
|
@@ -14747,15 +15837,24 @@ function getOrCreateIndexer(projectRoot, host) {
|
|
|
14747
15837
|
}
|
|
14748
15838
|
const indexer = new Indexer(projectRoot, config, host);
|
|
14749
15839
|
indexerCache.set(key, indexer);
|
|
14750
|
-
configureAutoIndex(projectRoot, host, config, () => getOrCreateIndexer(projectRoot, host)
|
|
15840
|
+
configureAutoIndex(projectRoot, host, config, () => getOrCreateIndexer(projectRoot, host), {
|
|
15841
|
+
preserveManagedWorker: true,
|
|
15842
|
+
synchronizeBackgroundWorker: false
|
|
15843
|
+
});
|
|
14751
15844
|
return indexer;
|
|
14752
15845
|
}
|
|
14753
|
-
function initializeTools(projectRoot, config, host) {
|
|
15846
|
+
function initializeTools(projectRoot, config, host, options = {}) {
|
|
14754
15847
|
defaultProjectRoots.set(host, projectRoot);
|
|
14755
15848
|
const key = getIndexerCacheKey(projectRoot, host);
|
|
15849
|
+
if (options.preserveManagedWorker === true && isBackgroundWorkerManaged(projectRoot, host) && indexerCache.has(key)) {
|
|
15850
|
+
return;
|
|
15851
|
+
}
|
|
14756
15852
|
configCache.set(key, config);
|
|
14757
15853
|
indexerCache.set(key, new Indexer(projectRoot, config, host));
|
|
14758
|
-
configureAutoIndex(projectRoot, host, config, () => getOrCreateIndexer(projectRoot, host)
|
|
15854
|
+
configureAutoIndex(projectRoot, host, config, () => getOrCreateIndexer(projectRoot, host), {
|
|
15855
|
+
preserveManagedWorker: options.preserveManagedWorker,
|
|
15856
|
+
synchronizeBackgroundWorker: false
|
|
15857
|
+
});
|
|
14759
15858
|
}
|
|
14760
15859
|
function getIndexerForProject(projectRoot, host) {
|
|
14761
15860
|
const root = getProjectRoot(projectRoot, host);
|
|
@@ -14769,7 +15868,9 @@ function refreshIndexerForDirectory(projectRoot, host, config = parseConfig(load
|
|
|
14769
15868
|
const key = getIndexerCacheKey(projectRoot, host);
|
|
14770
15869
|
configCache.set(key, config);
|
|
14771
15870
|
indexerCache.set(key, new Indexer(projectRoot, config, host));
|
|
14772
|
-
configureAutoIndex(projectRoot, host, config, () => getOrCreateIndexer(projectRoot, host)
|
|
15871
|
+
configureAutoIndex(projectRoot, host, config, () => getOrCreateIndexer(projectRoot, host), {
|
|
15872
|
+
synchronizeBackgroundWorker: true
|
|
15873
|
+
});
|
|
14773
15874
|
return config;
|
|
14774
15875
|
}
|
|
14775
15876
|
var AutoIndexRetrievalUnavailableError = class extends Error {
|
|
@@ -14796,7 +15897,7 @@ function trimOrUndefined(value) {
|
|
|
14796
15897
|
return normalized || void 0;
|
|
14797
15898
|
}
|
|
14798
15899
|
function normalizeCallGraphPath(value) {
|
|
14799
|
-
let normalized =
|
|
15900
|
+
let normalized = path21.posix.normalize(value.trim().replaceAll("\\", "/"));
|
|
14800
15901
|
if (normalized.startsWith("./")) {
|
|
14801
15902
|
normalized = normalized.slice(2);
|
|
14802
15903
|
}
|
|
@@ -14989,12 +16090,12 @@ async function getCallGraphPath(projectRoot, host, from, to, maxDepth, fromFileP
|
|
|
14989
16090
|
if (fromResolution.status !== "resolved" || toResolution.status !== "resolved") {
|
|
14990
16091
|
return { from: fromResolution, to: toResolution, path: [] };
|
|
14991
16092
|
}
|
|
14992
|
-
const
|
|
16093
|
+
const path31 = await indexer.findCallPathBySymbolIds(
|
|
14993
16094
|
fromResolution.symbolId,
|
|
14994
16095
|
toResolution.symbolId,
|
|
14995
16096
|
maxDepth
|
|
14996
16097
|
);
|
|
14997
|
-
return { from: fromResolution, to: toResolution, path:
|
|
16098
|
+
return { from: fromResolution, to: toResolution, path: path31 };
|
|
14998
16099
|
}
|
|
14999
16100
|
async function runIndexCodebase(projectRoot, host, args, onProgress) {
|
|
15000
16101
|
const root = getProjectRoot(projectRoot, host);
|
|
@@ -15003,6 +16104,9 @@ async function runIndexCodebase(projectRoot, host, args, onProgress) {
|
|
|
15003
16104
|
if (args.estimateOnly) {
|
|
15004
16105
|
return { kind: "estimate", estimate: await indexer.estimateCost() };
|
|
15005
16106
|
}
|
|
16107
|
+
if (args.dryRun) {
|
|
16108
|
+
return { kind: "dryrun", dryrun: await indexer.dryRunCost() };
|
|
16109
|
+
}
|
|
15006
16110
|
const coordinated = runCoordinatedIndex(root, host, args.force ?? false, (progress) => {
|
|
15007
16111
|
if (onProgress) {
|
|
15008
16112
|
void onProgress(formatProgressTitle(progress), {
|
|
@@ -15177,15 +16281,15 @@ async function getIndexLogs(projectRoot, host, args) {
|
|
|
15177
16281
|
function addKnowledgeBase(projectRoot, host, knowledgeBasePath) {
|
|
15178
16282
|
const root = getProjectRoot(projectRoot, host);
|
|
15179
16283
|
const inputPath = knowledgeBasePath.trim();
|
|
15180
|
-
const normalizedPath2 =
|
|
15181
|
-
|
|
16284
|
+
const normalizedPath2 = path21.resolve(
|
|
16285
|
+
path21.isAbsolute(inputPath) ? inputPath : resolveKnowledgeBasePath(inputPath, root)
|
|
15182
16286
|
);
|
|
15183
|
-
if (!
|
|
16287
|
+
if (!existsSync13(normalizedPath2)) {
|
|
15184
16288
|
return `Error: Directory does not exist: ${normalizedPath2}`;
|
|
15185
16289
|
}
|
|
15186
16290
|
let realPath;
|
|
15187
16291
|
try {
|
|
15188
|
-
realPath =
|
|
16292
|
+
realPath = realpathSync6(normalizedPath2);
|
|
15189
16293
|
} catch {
|
|
15190
16294
|
return `Error: Cannot resolve path: ${normalizedPath2}`;
|
|
15191
16295
|
}
|
|
@@ -15214,7 +16318,7 @@ function addKnowledgeBase(projectRoot, host, knowledgeBasePath) {
|
|
|
15214
16318
|
}
|
|
15215
16319
|
}
|
|
15216
16320
|
for (const dotDir of sensitiveDotDirs) {
|
|
15217
|
-
const sensitiveDir =
|
|
16321
|
+
const sensitiveDir = path21.join(homeDir, dotDir);
|
|
15218
16322
|
if (sensitiveDir && (realPath === sensitiveDir || realPath.startsWith(`${sensitiveDir}/`))) {
|
|
15219
16323
|
return `Error: Adding sensitive directory as knowledge base is not allowed: ${normalizedPath2}`;
|
|
15220
16324
|
}
|
|
@@ -15260,7 +16364,7 @@ function listKnowledgeBases(projectRoot, host) {
|
|
|
15260
16364
|
for (let i = 0; i < knowledgeBases.length; i++) {
|
|
15261
16365
|
const kb = knowledgeBases[i];
|
|
15262
16366
|
const resolvedPath = resolveKnowledgeBasePath(kb, root);
|
|
15263
|
-
const exists =
|
|
16367
|
+
const exists = existsSync13(resolvedPath);
|
|
15264
16368
|
result += `[${i + 1}] ${kb}
|
|
15265
16369
|
`;
|
|
15266
16370
|
result += ` Resolved: ${resolvedPath}
|
|
@@ -15277,7 +16381,7 @@ function listKnowledgeBases(projectRoot, host) {
|
|
|
15277
16381
|
}
|
|
15278
16382
|
result += "\n";
|
|
15279
16383
|
}
|
|
15280
|
-
const hasHostConfig =
|
|
16384
|
+
const hasHostConfig = existsSync13(path21.join(root, getHostProjectConfigRelativePath(host)));
|
|
15281
16385
|
if (hasHostConfig) {
|
|
15282
16386
|
result += `
|
|
15283
16387
|
Config sources: 1 file(s).`;
|
|
@@ -15311,7 +16415,7 @@ Run /index to rebuild the index without the removed knowledge base.`;
|
|
|
15311
16415
|
}
|
|
15312
16416
|
|
|
15313
16417
|
// src/watcher/file-watcher.ts
|
|
15314
|
-
import { existsSync as
|
|
16418
|
+
import { existsSync as existsSync14, statSync as statSync6 } from "fs";
|
|
15315
16419
|
|
|
15316
16420
|
// node_modules/chokidar/index.js
|
|
15317
16421
|
import { EventEmitter as EventEmitter2 } from "events";
|
|
@@ -15403,7 +16507,7 @@ var ReaddirpStream = class extends Readable {
|
|
|
15403
16507
|
this._directoryFilter = normalizeFilter(opts.directoryFilter);
|
|
15404
16508
|
const statMethod = opts.lstat ? lstat : stat;
|
|
15405
16509
|
if (wantBigintFsStats) {
|
|
15406
|
-
this._stat = (
|
|
16510
|
+
this._stat = (path31) => statMethod(path31, { bigint: true });
|
|
15407
16511
|
} else {
|
|
15408
16512
|
this._stat = statMethod;
|
|
15409
16513
|
}
|
|
@@ -15428,8 +16532,8 @@ var ReaddirpStream = class extends Readable {
|
|
|
15428
16532
|
const par = this.parent;
|
|
15429
16533
|
const fil = par && par.files;
|
|
15430
16534
|
if (fil && fil.length > 0) {
|
|
15431
|
-
const { path:
|
|
15432
|
-
const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent,
|
|
16535
|
+
const { path: path31, depth } = par;
|
|
16536
|
+
const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path31));
|
|
15433
16537
|
const awaited = await Promise.all(slice);
|
|
15434
16538
|
for (const entry of awaited) {
|
|
15435
16539
|
if (!entry)
|
|
@@ -15469,21 +16573,21 @@ var ReaddirpStream = class extends Readable {
|
|
|
15469
16573
|
this.reading = false;
|
|
15470
16574
|
}
|
|
15471
16575
|
}
|
|
15472
|
-
async _exploreDir(
|
|
16576
|
+
async _exploreDir(path31, depth) {
|
|
15473
16577
|
let files;
|
|
15474
16578
|
try {
|
|
15475
|
-
files = await readdir(
|
|
16579
|
+
files = await readdir(path31, this._rdOptions);
|
|
15476
16580
|
} catch (error) {
|
|
15477
16581
|
this._onError(error);
|
|
15478
16582
|
}
|
|
15479
|
-
return { files, depth, path:
|
|
16583
|
+
return { files, depth, path: path31 };
|
|
15480
16584
|
}
|
|
15481
|
-
async _formatEntry(dirent,
|
|
16585
|
+
async _formatEntry(dirent, path31) {
|
|
15482
16586
|
let entry;
|
|
15483
|
-
const
|
|
16587
|
+
const basename10 = this._isDirent ? dirent.name : dirent;
|
|
15484
16588
|
try {
|
|
15485
|
-
const fullPath = presolve(pjoin(
|
|
15486
|
-
entry = { path: prelative(this._root, fullPath), fullPath, basename:
|
|
16589
|
+
const fullPath = presolve(pjoin(path31, basename10));
|
|
16590
|
+
entry = { path: prelative(this._root, fullPath), fullPath, basename: basename10 };
|
|
15487
16591
|
entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
|
|
15488
16592
|
} catch (err) {
|
|
15489
16593
|
this._onError(err);
|
|
@@ -15882,16 +16986,16 @@ var delFromSet = (main, prop, item) => {
|
|
|
15882
16986
|
};
|
|
15883
16987
|
var isEmptySet = (val) => val instanceof Set ? val.size === 0 : !val;
|
|
15884
16988
|
var FsWatchInstances = /* @__PURE__ */ new Map();
|
|
15885
|
-
function createFsWatchInstance(
|
|
16989
|
+
function createFsWatchInstance(path31, options, listener, errHandler, emitRaw) {
|
|
15886
16990
|
const handleEvent = (rawEvent, evPath) => {
|
|
15887
|
-
listener(
|
|
15888
|
-
emitRaw(rawEvent, evPath, { watchedPath:
|
|
15889
|
-
if (evPath &&
|
|
15890
|
-
fsWatchBroadcast(sp.resolve(
|
|
16991
|
+
listener(path31);
|
|
16992
|
+
emitRaw(rawEvent, evPath, { watchedPath: path31 });
|
|
16993
|
+
if (evPath && path31 !== evPath) {
|
|
16994
|
+
fsWatchBroadcast(sp.resolve(path31, evPath), KEY_LISTENERS, sp.join(path31, evPath));
|
|
15891
16995
|
}
|
|
15892
16996
|
};
|
|
15893
16997
|
try {
|
|
15894
|
-
return fs_watch(
|
|
16998
|
+
return fs_watch(path31, {
|
|
15895
16999
|
persistent: options.persistent
|
|
15896
17000
|
}, handleEvent);
|
|
15897
17001
|
} catch (error) {
|
|
@@ -15907,12 +17011,12 @@ var fsWatchBroadcast = (fullPath, listenerType, val1, val2, val3) => {
|
|
|
15907
17011
|
listener(val1, val2, val3);
|
|
15908
17012
|
});
|
|
15909
17013
|
};
|
|
15910
|
-
var setFsWatchListener = (
|
|
17014
|
+
var setFsWatchListener = (path31, fullPath, options, handlers) => {
|
|
15911
17015
|
const { listener, errHandler, rawEmitter } = handlers;
|
|
15912
17016
|
let cont = FsWatchInstances.get(fullPath);
|
|
15913
17017
|
let watcher;
|
|
15914
17018
|
if (!options.persistent) {
|
|
15915
|
-
watcher = createFsWatchInstance(
|
|
17019
|
+
watcher = createFsWatchInstance(path31, options, listener, errHandler, rawEmitter);
|
|
15916
17020
|
if (!watcher)
|
|
15917
17021
|
return;
|
|
15918
17022
|
return watcher.close.bind(watcher);
|
|
@@ -15923,7 +17027,7 @@ var setFsWatchListener = (path30, fullPath, options, handlers) => {
|
|
|
15923
17027
|
addAndConvert(cont, KEY_RAW, rawEmitter);
|
|
15924
17028
|
} else {
|
|
15925
17029
|
watcher = createFsWatchInstance(
|
|
15926
|
-
|
|
17030
|
+
path31,
|
|
15927
17031
|
options,
|
|
15928
17032
|
fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS),
|
|
15929
17033
|
errHandler,
|
|
@@ -15938,7 +17042,7 @@ var setFsWatchListener = (path30, fullPath, options, handlers) => {
|
|
|
15938
17042
|
cont.watcherUnusable = true;
|
|
15939
17043
|
if (isWindows && error.code === "EPERM") {
|
|
15940
17044
|
try {
|
|
15941
|
-
const fd = await open(
|
|
17045
|
+
const fd = await open(path31, "r");
|
|
15942
17046
|
await fd.close();
|
|
15943
17047
|
broadcastErr(error);
|
|
15944
17048
|
} catch (err) {
|
|
@@ -15969,7 +17073,7 @@ var setFsWatchListener = (path30, fullPath, options, handlers) => {
|
|
|
15969
17073
|
};
|
|
15970
17074
|
};
|
|
15971
17075
|
var FsWatchFileInstances = /* @__PURE__ */ new Map();
|
|
15972
|
-
var setFsWatchFileListener = (
|
|
17076
|
+
var setFsWatchFileListener = (path31, fullPath, options, handlers) => {
|
|
15973
17077
|
const { listener, rawEmitter } = handlers;
|
|
15974
17078
|
let cont = FsWatchFileInstances.get(fullPath);
|
|
15975
17079
|
const copts = cont && cont.options;
|
|
@@ -15991,7 +17095,7 @@ var setFsWatchFileListener = (path30, fullPath, options, handlers) => {
|
|
|
15991
17095
|
});
|
|
15992
17096
|
const currmtime = curr.mtimeMs;
|
|
15993
17097
|
if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {
|
|
15994
|
-
foreach(cont.listeners, (listener2) => listener2(
|
|
17098
|
+
foreach(cont.listeners, (listener2) => listener2(path31, curr));
|
|
15995
17099
|
}
|
|
15996
17100
|
})
|
|
15997
17101
|
};
|
|
@@ -16021,13 +17125,13 @@ var NodeFsHandler = class {
|
|
|
16021
17125
|
* @param listener on fs change
|
|
16022
17126
|
* @returns closer for the watcher instance
|
|
16023
17127
|
*/
|
|
16024
|
-
_watchWithNodeFs(
|
|
17128
|
+
_watchWithNodeFs(path31, listener) {
|
|
16025
17129
|
const opts = this.fsw.options;
|
|
16026
|
-
const directory = sp.dirname(
|
|
16027
|
-
const
|
|
17130
|
+
const directory = sp.dirname(path31);
|
|
17131
|
+
const basename10 = sp.basename(path31);
|
|
16028
17132
|
const parent = this.fsw._getWatchedDir(directory);
|
|
16029
|
-
parent.add(
|
|
16030
|
-
const absolutePath = sp.resolve(
|
|
17133
|
+
parent.add(basename10);
|
|
17134
|
+
const absolutePath = sp.resolve(path31);
|
|
16031
17135
|
const options = {
|
|
16032
17136
|
persistent: opts.persistent
|
|
16033
17137
|
};
|
|
@@ -16036,13 +17140,13 @@ var NodeFsHandler = class {
|
|
|
16036
17140
|
let closer;
|
|
16037
17141
|
if (opts.usePolling) {
|
|
16038
17142
|
const enableBin = opts.interval !== opts.binaryInterval;
|
|
16039
|
-
options.interval = enableBin && isBinaryPath(
|
|
16040
|
-
closer = setFsWatchFileListener(
|
|
17143
|
+
options.interval = enableBin && isBinaryPath(basename10) ? opts.binaryInterval : opts.interval;
|
|
17144
|
+
closer = setFsWatchFileListener(path31, absolutePath, options, {
|
|
16041
17145
|
listener,
|
|
16042
17146
|
rawEmitter: this.fsw._emitRaw
|
|
16043
17147
|
});
|
|
16044
17148
|
} else {
|
|
16045
|
-
closer = setFsWatchListener(
|
|
17149
|
+
closer = setFsWatchListener(path31, absolutePath, options, {
|
|
16046
17150
|
listener,
|
|
16047
17151
|
errHandler: this._boundHandleError,
|
|
16048
17152
|
rawEmitter: this.fsw._emitRaw
|
|
@@ -16058,13 +17162,13 @@ var NodeFsHandler = class {
|
|
|
16058
17162
|
if (this.fsw.closed) {
|
|
16059
17163
|
return;
|
|
16060
17164
|
}
|
|
16061
|
-
const
|
|
16062
|
-
const
|
|
16063
|
-
const parent = this.fsw._getWatchedDir(
|
|
17165
|
+
const dirname16 = sp.dirname(file);
|
|
17166
|
+
const basename10 = sp.basename(file);
|
|
17167
|
+
const parent = this.fsw._getWatchedDir(dirname16);
|
|
16064
17168
|
let prevStats = stats;
|
|
16065
|
-
if (parent.has(
|
|
17169
|
+
if (parent.has(basename10))
|
|
16066
17170
|
return;
|
|
16067
|
-
const listener = async (
|
|
17171
|
+
const listener = async (path31, newStats) => {
|
|
16068
17172
|
if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5))
|
|
16069
17173
|
return;
|
|
16070
17174
|
if (!newStats || newStats.mtimeMs === 0) {
|
|
@@ -16078,18 +17182,18 @@ var NodeFsHandler = class {
|
|
|
16078
17182
|
this.fsw._emit(EV.CHANGE, file, newStats2);
|
|
16079
17183
|
}
|
|
16080
17184
|
if ((isMacos || isLinux || isFreeBSD) && prevStats.ino !== newStats2.ino) {
|
|
16081
|
-
this.fsw._closeFile(
|
|
17185
|
+
this.fsw._closeFile(path31);
|
|
16082
17186
|
prevStats = newStats2;
|
|
16083
17187
|
const closer2 = this._watchWithNodeFs(file, listener);
|
|
16084
17188
|
if (closer2)
|
|
16085
|
-
this.fsw._addPathCloser(
|
|
17189
|
+
this.fsw._addPathCloser(path31, closer2);
|
|
16086
17190
|
} else {
|
|
16087
17191
|
prevStats = newStats2;
|
|
16088
17192
|
}
|
|
16089
17193
|
} catch (error) {
|
|
16090
|
-
this.fsw._remove(
|
|
17194
|
+
this.fsw._remove(dirname16, basename10);
|
|
16091
17195
|
}
|
|
16092
|
-
} else if (parent.has(
|
|
17196
|
+
} else if (parent.has(basename10)) {
|
|
16093
17197
|
const at = newStats.atimeMs;
|
|
16094
17198
|
const mt = newStats.mtimeMs;
|
|
16095
17199
|
if (!at || at <= mt || mt !== prevStats.mtimeMs) {
|
|
@@ -16114,7 +17218,7 @@ var NodeFsHandler = class {
|
|
|
16114
17218
|
* @param item basename of this item
|
|
16115
17219
|
* @returns true if no more processing is needed for this entry.
|
|
16116
17220
|
*/
|
|
16117
|
-
async _handleSymlink(entry, directory,
|
|
17221
|
+
async _handleSymlink(entry, directory, path31, item) {
|
|
16118
17222
|
if (this.fsw.closed) {
|
|
16119
17223
|
return;
|
|
16120
17224
|
}
|
|
@@ -16124,7 +17228,7 @@ var NodeFsHandler = class {
|
|
|
16124
17228
|
this.fsw._incrReadyCount();
|
|
16125
17229
|
let linkPath;
|
|
16126
17230
|
try {
|
|
16127
|
-
linkPath = await fsrealpath(
|
|
17231
|
+
linkPath = await fsrealpath(path31);
|
|
16128
17232
|
} catch (e) {
|
|
16129
17233
|
this.fsw._emitReady();
|
|
16130
17234
|
return true;
|
|
@@ -16134,12 +17238,12 @@ var NodeFsHandler = class {
|
|
|
16134
17238
|
if (dir.has(item)) {
|
|
16135
17239
|
if (this.fsw._symlinkPaths.get(full) !== linkPath) {
|
|
16136
17240
|
this.fsw._symlinkPaths.set(full, linkPath);
|
|
16137
|
-
this.fsw._emit(EV.CHANGE,
|
|
17241
|
+
this.fsw._emit(EV.CHANGE, path31, entry.stats);
|
|
16138
17242
|
}
|
|
16139
17243
|
} else {
|
|
16140
17244
|
dir.add(item);
|
|
16141
17245
|
this.fsw._symlinkPaths.set(full, linkPath);
|
|
16142
|
-
this.fsw._emit(EV.ADD,
|
|
17246
|
+
this.fsw._emit(EV.ADD, path31, entry.stats);
|
|
16143
17247
|
}
|
|
16144
17248
|
this.fsw._emitReady();
|
|
16145
17249
|
return true;
|
|
@@ -16169,9 +17273,9 @@ var NodeFsHandler = class {
|
|
|
16169
17273
|
return;
|
|
16170
17274
|
}
|
|
16171
17275
|
const item = entry.path;
|
|
16172
|
-
let
|
|
17276
|
+
let path31 = sp.join(directory, item);
|
|
16173
17277
|
current.add(item);
|
|
16174
|
-
if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory,
|
|
17278
|
+
if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path31, item)) {
|
|
16175
17279
|
return;
|
|
16176
17280
|
}
|
|
16177
17281
|
if (this.fsw.closed) {
|
|
@@ -16180,11 +17284,11 @@ var NodeFsHandler = class {
|
|
|
16180
17284
|
}
|
|
16181
17285
|
if (item === target || !target && !previous.has(item)) {
|
|
16182
17286
|
this.fsw._incrReadyCount();
|
|
16183
|
-
|
|
16184
|
-
this._addToNodeFs(
|
|
17287
|
+
path31 = sp.join(dir, sp.relative(dir, path31));
|
|
17288
|
+
this._addToNodeFs(path31, initialAdd, wh, depth + 1);
|
|
16185
17289
|
}
|
|
16186
17290
|
}).on(EV.ERROR, this._boundHandleError);
|
|
16187
|
-
return new Promise((
|
|
17291
|
+
return new Promise((resolve18, reject) => {
|
|
16188
17292
|
if (!stream)
|
|
16189
17293
|
return reject();
|
|
16190
17294
|
stream.once(STR_END, () => {
|
|
@@ -16193,7 +17297,7 @@ var NodeFsHandler = class {
|
|
|
16193
17297
|
return;
|
|
16194
17298
|
}
|
|
16195
17299
|
const wasThrottled = throttler ? throttler.clear() : false;
|
|
16196
|
-
|
|
17300
|
+
resolve18(void 0);
|
|
16197
17301
|
previous.getChildren().filter((item) => {
|
|
16198
17302
|
return item !== directory && !current.has(item);
|
|
16199
17303
|
}).forEach((item) => {
|
|
@@ -16250,13 +17354,13 @@ var NodeFsHandler = class {
|
|
|
16250
17354
|
* @param depth Child path actually targeted for watch
|
|
16251
17355
|
* @param target Child path actually targeted for watch
|
|
16252
17356
|
*/
|
|
16253
|
-
async _addToNodeFs(
|
|
17357
|
+
async _addToNodeFs(path31, initialAdd, priorWh, depth, target) {
|
|
16254
17358
|
const ready = this.fsw._emitReady;
|
|
16255
|
-
if (this.fsw._isIgnored(
|
|
17359
|
+
if (this.fsw._isIgnored(path31) || this.fsw.closed) {
|
|
16256
17360
|
ready();
|
|
16257
17361
|
return false;
|
|
16258
17362
|
}
|
|
16259
|
-
const wh = this.fsw._getWatchHelpers(
|
|
17363
|
+
const wh = this.fsw._getWatchHelpers(path31);
|
|
16260
17364
|
if (priorWh) {
|
|
16261
17365
|
wh.filterPath = (entry) => priorWh.filterPath(entry);
|
|
16262
17366
|
wh.filterDir = (entry) => priorWh.filterDir(entry);
|
|
@@ -16272,8 +17376,8 @@ var NodeFsHandler = class {
|
|
|
16272
17376
|
const follow = this.fsw.options.followSymlinks;
|
|
16273
17377
|
let closer;
|
|
16274
17378
|
if (stats.isDirectory()) {
|
|
16275
|
-
const absPath = sp.resolve(
|
|
16276
|
-
const targetPath = follow ? await fsrealpath(
|
|
17379
|
+
const absPath = sp.resolve(path31);
|
|
17380
|
+
const targetPath = follow ? await fsrealpath(path31) : path31;
|
|
16277
17381
|
if (this.fsw.closed)
|
|
16278
17382
|
return;
|
|
16279
17383
|
closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
|
|
@@ -16283,29 +17387,29 @@ var NodeFsHandler = class {
|
|
|
16283
17387
|
this.fsw._symlinkPaths.set(absPath, targetPath);
|
|
16284
17388
|
}
|
|
16285
17389
|
} else if (stats.isSymbolicLink()) {
|
|
16286
|
-
const targetPath = follow ? await fsrealpath(
|
|
17390
|
+
const targetPath = follow ? await fsrealpath(path31) : path31;
|
|
16287
17391
|
if (this.fsw.closed)
|
|
16288
17392
|
return;
|
|
16289
17393
|
const parent = sp.dirname(wh.watchPath);
|
|
16290
17394
|
this.fsw._getWatchedDir(parent).add(wh.watchPath);
|
|
16291
17395
|
this.fsw._emit(EV.ADD, wh.watchPath, stats);
|
|
16292
|
-
closer = await this._handleDir(parent, stats, initialAdd, depth,
|
|
17396
|
+
closer = await this._handleDir(parent, stats, initialAdd, depth, path31, wh, targetPath);
|
|
16293
17397
|
if (this.fsw.closed)
|
|
16294
17398
|
return;
|
|
16295
17399
|
if (targetPath !== void 0) {
|
|
16296
|
-
this.fsw._symlinkPaths.set(sp.resolve(
|
|
17400
|
+
this.fsw._symlinkPaths.set(sp.resolve(path31), targetPath);
|
|
16297
17401
|
}
|
|
16298
17402
|
} else {
|
|
16299
17403
|
closer = this._handleFile(wh.watchPath, stats, initialAdd);
|
|
16300
17404
|
}
|
|
16301
17405
|
ready();
|
|
16302
17406
|
if (closer)
|
|
16303
|
-
this.fsw._addPathCloser(
|
|
17407
|
+
this.fsw._addPathCloser(path31, closer);
|
|
16304
17408
|
return false;
|
|
16305
17409
|
} catch (error) {
|
|
16306
17410
|
if (this.fsw._handleError(error)) {
|
|
16307
17411
|
ready();
|
|
16308
|
-
return
|
|
17412
|
+
return path31;
|
|
16309
17413
|
}
|
|
16310
17414
|
}
|
|
16311
17415
|
}
|
|
@@ -16348,24 +17452,24 @@ function createPattern(matcher) {
|
|
|
16348
17452
|
}
|
|
16349
17453
|
return () => false;
|
|
16350
17454
|
}
|
|
16351
|
-
function normalizePath2(
|
|
16352
|
-
if (typeof
|
|
17455
|
+
function normalizePath2(path31) {
|
|
17456
|
+
if (typeof path31 !== "string")
|
|
16353
17457
|
throw new Error("string expected");
|
|
16354
|
-
|
|
16355
|
-
|
|
17458
|
+
path31 = sp2.normalize(path31);
|
|
17459
|
+
path31 = path31.replace(/\\/g, "/");
|
|
16356
17460
|
let prepend = false;
|
|
16357
|
-
if (
|
|
17461
|
+
if (path31.startsWith("//"))
|
|
16358
17462
|
prepend = true;
|
|
16359
|
-
|
|
17463
|
+
path31 = path31.replace(DOUBLE_SLASH_RE, "/");
|
|
16360
17464
|
if (prepend)
|
|
16361
|
-
|
|
16362
|
-
return
|
|
17465
|
+
path31 = "/" + path31;
|
|
17466
|
+
return path31;
|
|
16363
17467
|
}
|
|
16364
17468
|
function matchPatterns(patterns, testString, stats) {
|
|
16365
|
-
const
|
|
17469
|
+
const path31 = normalizePath2(testString);
|
|
16366
17470
|
for (let index = 0; index < patterns.length; index++) {
|
|
16367
17471
|
const pattern = patterns[index];
|
|
16368
|
-
if (pattern(
|
|
17472
|
+
if (pattern(path31, stats)) {
|
|
16369
17473
|
return true;
|
|
16370
17474
|
}
|
|
16371
17475
|
}
|
|
@@ -16403,19 +17507,19 @@ var toUnix = (string) => {
|
|
|
16403
17507
|
}
|
|
16404
17508
|
return str;
|
|
16405
17509
|
};
|
|
16406
|
-
var normalizePathToUnix = (
|
|
16407
|
-
var normalizeIgnored = (cwd = "") => (
|
|
16408
|
-
if (typeof
|
|
16409
|
-
return normalizePathToUnix(sp2.isAbsolute(
|
|
17510
|
+
var normalizePathToUnix = (path31) => toUnix(sp2.normalize(toUnix(path31)));
|
|
17511
|
+
var normalizeIgnored = (cwd = "") => (path31) => {
|
|
17512
|
+
if (typeof path31 === "string") {
|
|
17513
|
+
return normalizePathToUnix(sp2.isAbsolute(path31) ? path31 : sp2.join(cwd, path31));
|
|
16410
17514
|
} else {
|
|
16411
|
-
return
|
|
17515
|
+
return path31;
|
|
16412
17516
|
}
|
|
16413
17517
|
};
|
|
16414
|
-
var getAbsolutePath = (
|
|
16415
|
-
if (sp2.isAbsolute(
|
|
16416
|
-
return
|
|
17518
|
+
var getAbsolutePath = (path31, cwd) => {
|
|
17519
|
+
if (sp2.isAbsolute(path31)) {
|
|
17520
|
+
return path31;
|
|
16417
17521
|
}
|
|
16418
|
-
return sp2.join(cwd,
|
|
17522
|
+
return sp2.join(cwd, path31);
|
|
16419
17523
|
};
|
|
16420
17524
|
var EMPTY_SET = Object.freeze(/* @__PURE__ */ new Set());
|
|
16421
17525
|
var DirEntry = class {
|
|
@@ -16480,10 +17584,10 @@ var WatchHelper = class {
|
|
|
16480
17584
|
dirParts;
|
|
16481
17585
|
followSymlinks;
|
|
16482
17586
|
statMethod;
|
|
16483
|
-
constructor(
|
|
17587
|
+
constructor(path31, follow, fsw) {
|
|
16484
17588
|
this.fsw = fsw;
|
|
16485
|
-
const watchPath =
|
|
16486
|
-
this.path =
|
|
17589
|
+
const watchPath = path31;
|
|
17590
|
+
this.path = path31 = path31.replace(REPLACER_RE, "");
|
|
16487
17591
|
this.watchPath = watchPath;
|
|
16488
17592
|
this.fullWatchPath = sp2.resolve(watchPath);
|
|
16489
17593
|
this.dirParts = [];
|
|
@@ -16623,20 +17727,20 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
16623
17727
|
this._closePromise = void 0;
|
|
16624
17728
|
let paths = unifyPaths(paths_);
|
|
16625
17729
|
if (cwd) {
|
|
16626
|
-
paths = paths.map((
|
|
16627
|
-
const absPath = getAbsolutePath(
|
|
17730
|
+
paths = paths.map((path31) => {
|
|
17731
|
+
const absPath = getAbsolutePath(path31, cwd);
|
|
16628
17732
|
return absPath;
|
|
16629
17733
|
});
|
|
16630
17734
|
}
|
|
16631
|
-
paths.forEach((
|
|
16632
|
-
this._removeIgnoredPath(
|
|
17735
|
+
paths.forEach((path31) => {
|
|
17736
|
+
this._removeIgnoredPath(path31);
|
|
16633
17737
|
});
|
|
16634
17738
|
this._userIgnored = void 0;
|
|
16635
17739
|
if (!this._readyCount)
|
|
16636
17740
|
this._readyCount = 0;
|
|
16637
17741
|
this._readyCount += paths.length;
|
|
16638
|
-
Promise.all(paths.map(async (
|
|
16639
|
-
const res = await this._nodeFsHandler._addToNodeFs(
|
|
17742
|
+
Promise.all(paths.map(async (path31) => {
|
|
17743
|
+
const res = await this._nodeFsHandler._addToNodeFs(path31, !_internal, void 0, 0, _origAdd);
|
|
16640
17744
|
if (res)
|
|
16641
17745
|
this._emitReady();
|
|
16642
17746
|
return res;
|
|
@@ -16658,17 +17762,17 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
16658
17762
|
return this;
|
|
16659
17763
|
const paths = unifyPaths(paths_);
|
|
16660
17764
|
const { cwd } = this.options;
|
|
16661
|
-
paths.forEach((
|
|
16662
|
-
if (!sp2.isAbsolute(
|
|
17765
|
+
paths.forEach((path31) => {
|
|
17766
|
+
if (!sp2.isAbsolute(path31) && !this._closers.has(path31)) {
|
|
16663
17767
|
if (cwd)
|
|
16664
|
-
|
|
16665
|
-
|
|
17768
|
+
path31 = sp2.join(cwd, path31);
|
|
17769
|
+
path31 = sp2.resolve(path31);
|
|
16666
17770
|
}
|
|
16667
|
-
this._closePath(
|
|
16668
|
-
this._addIgnoredPath(
|
|
16669
|
-
if (this._watched.has(
|
|
17771
|
+
this._closePath(path31);
|
|
17772
|
+
this._addIgnoredPath(path31);
|
|
17773
|
+
if (this._watched.has(path31)) {
|
|
16670
17774
|
this._addIgnoredPath({
|
|
16671
|
-
path:
|
|
17775
|
+
path: path31,
|
|
16672
17776
|
recursive: true
|
|
16673
17777
|
});
|
|
16674
17778
|
}
|
|
@@ -16732,38 +17836,38 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
16732
17836
|
* @param stats arguments to be passed with event
|
|
16733
17837
|
* @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag
|
|
16734
17838
|
*/
|
|
16735
|
-
async _emit(event,
|
|
17839
|
+
async _emit(event, path31, stats) {
|
|
16736
17840
|
if (this.closed)
|
|
16737
17841
|
return;
|
|
16738
17842
|
const opts = this.options;
|
|
16739
17843
|
if (isWindows)
|
|
16740
|
-
|
|
17844
|
+
path31 = sp2.normalize(path31);
|
|
16741
17845
|
if (opts.cwd)
|
|
16742
|
-
|
|
16743
|
-
const args = [
|
|
17846
|
+
path31 = sp2.relative(opts.cwd, path31);
|
|
17847
|
+
const args = [path31];
|
|
16744
17848
|
if (stats != null)
|
|
16745
17849
|
args.push(stats);
|
|
16746
17850
|
const awf = opts.awaitWriteFinish;
|
|
16747
17851
|
let pw;
|
|
16748
|
-
if (awf && (pw = this._pendingWrites.get(
|
|
17852
|
+
if (awf && (pw = this._pendingWrites.get(path31))) {
|
|
16749
17853
|
pw.lastChange = /* @__PURE__ */ new Date();
|
|
16750
17854
|
return this;
|
|
16751
17855
|
}
|
|
16752
17856
|
if (opts.atomic) {
|
|
16753
17857
|
if (event === EVENTS.UNLINK) {
|
|
16754
|
-
this._pendingUnlinks.set(
|
|
17858
|
+
this._pendingUnlinks.set(path31, [event, ...args]);
|
|
16755
17859
|
setTimeout(() => {
|
|
16756
|
-
this._pendingUnlinks.forEach((entry,
|
|
17860
|
+
this._pendingUnlinks.forEach((entry, path32) => {
|
|
16757
17861
|
this.emit(...entry);
|
|
16758
17862
|
this.emit(EVENTS.ALL, ...entry);
|
|
16759
|
-
this._pendingUnlinks.delete(
|
|
17863
|
+
this._pendingUnlinks.delete(path32);
|
|
16760
17864
|
});
|
|
16761
17865
|
}, typeof opts.atomic === "number" ? opts.atomic : 100);
|
|
16762
17866
|
return this;
|
|
16763
17867
|
}
|
|
16764
|
-
if (event === EVENTS.ADD && this._pendingUnlinks.has(
|
|
17868
|
+
if (event === EVENTS.ADD && this._pendingUnlinks.has(path31)) {
|
|
16765
17869
|
event = EVENTS.CHANGE;
|
|
16766
|
-
this._pendingUnlinks.delete(
|
|
17870
|
+
this._pendingUnlinks.delete(path31);
|
|
16767
17871
|
}
|
|
16768
17872
|
}
|
|
16769
17873
|
if (awf && (event === EVENTS.ADD || event === EVENTS.CHANGE) && this._readyEmitted) {
|
|
@@ -16781,16 +17885,16 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
16781
17885
|
this.emitWithAll(event, args);
|
|
16782
17886
|
}
|
|
16783
17887
|
};
|
|
16784
|
-
this._awaitWriteFinish(
|
|
17888
|
+
this._awaitWriteFinish(path31, awf.stabilityThreshold, event, awfEmit);
|
|
16785
17889
|
return this;
|
|
16786
17890
|
}
|
|
16787
17891
|
if (event === EVENTS.CHANGE) {
|
|
16788
|
-
const isThrottled = !this._throttle(EVENTS.CHANGE,
|
|
17892
|
+
const isThrottled = !this._throttle(EVENTS.CHANGE, path31, 50);
|
|
16789
17893
|
if (isThrottled)
|
|
16790
17894
|
return this;
|
|
16791
17895
|
}
|
|
16792
17896
|
if (opts.alwaysStat && stats === void 0 && (event === EVENTS.ADD || event === EVENTS.ADD_DIR || event === EVENTS.CHANGE)) {
|
|
16793
|
-
const fullPath = opts.cwd ? sp2.join(opts.cwd,
|
|
17897
|
+
const fullPath = opts.cwd ? sp2.join(opts.cwd, path31) : path31;
|
|
16794
17898
|
let stats2;
|
|
16795
17899
|
try {
|
|
16796
17900
|
stats2 = await stat3(fullPath);
|
|
@@ -16821,23 +17925,23 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
16821
17925
|
* @param timeout duration of time to suppress duplicate actions
|
|
16822
17926
|
* @returns tracking object or false if action should be suppressed
|
|
16823
17927
|
*/
|
|
16824
|
-
_throttle(actionType,
|
|
17928
|
+
_throttle(actionType, path31, timeout) {
|
|
16825
17929
|
if (!this._throttled.has(actionType)) {
|
|
16826
17930
|
this._throttled.set(actionType, /* @__PURE__ */ new Map());
|
|
16827
17931
|
}
|
|
16828
17932
|
const action = this._throttled.get(actionType);
|
|
16829
17933
|
if (!action)
|
|
16830
17934
|
throw new Error("invalid throttle");
|
|
16831
|
-
const actionPath = action.get(
|
|
17935
|
+
const actionPath = action.get(path31);
|
|
16832
17936
|
if (actionPath) {
|
|
16833
17937
|
actionPath.count++;
|
|
16834
17938
|
return false;
|
|
16835
17939
|
}
|
|
16836
17940
|
let timeoutObject;
|
|
16837
17941
|
const clear = () => {
|
|
16838
|
-
const item = action.get(
|
|
17942
|
+
const item = action.get(path31);
|
|
16839
17943
|
const count = item ? item.count : 0;
|
|
16840
|
-
action.delete(
|
|
17944
|
+
action.delete(path31);
|
|
16841
17945
|
clearTimeout(timeoutObject);
|
|
16842
17946
|
if (item)
|
|
16843
17947
|
clearTimeout(item.timeoutObject);
|
|
@@ -16845,7 +17949,7 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
16845
17949
|
};
|
|
16846
17950
|
timeoutObject = setTimeout(clear, timeout);
|
|
16847
17951
|
const thr = { timeoutObject, clear, count: 0 };
|
|
16848
|
-
action.set(
|
|
17952
|
+
action.set(path31, thr);
|
|
16849
17953
|
return thr;
|
|
16850
17954
|
}
|
|
16851
17955
|
_incrReadyCount() {
|
|
@@ -16859,44 +17963,44 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
16859
17963
|
* @param event
|
|
16860
17964
|
* @param awfEmit Callback to be called when ready for event to be emitted.
|
|
16861
17965
|
*/
|
|
16862
|
-
_awaitWriteFinish(
|
|
17966
|
+
_awaitWriteFinish(path31, threshold, event, awfEmit) {
|
|
16863
17967
|
const awf = this.options.awaitWriteFinish;
|
|
16864
17968
|
if (typeof awf !== "object")
|
|
16865
17969
|
return;
|
|
16866
17970
|
const pollInterval = awf.pollInterval;
|
|
16867
17971
|
let timeoutHandler;
|
|
16868
|
-
let fullPath =
|
|
16869
|
-
if (this.options.cwd && !sp2.isAbsolute(
|
|
16870
|
-
fullPath = sp2.join(this.options.cwd,
|
|
17972
|
+
let fullPath = path31;
|
|
17973
|
+
if (this.options.cwd && !sp2.isAbsolute(path31)) {
|
|
17974
|
+
fullPath = sp2.join(this.options.cwd, path31);
|
|
16871
17975
|
}
|
|
16872
17976
|
const now2 = /* @__PURE__ */ new Date();
|
|
16873
17977
|
const writes = this._pendingWrites;
|
|
16874
17978
|
function awaitWriteFinishFn(prevStat) {
|
|
16875
17979
|
statcb(fullPath, (err, curStat) => {
|
|
16876
|
-
if (err || !writes.has(
|
|
17980
|
+
if (err || !writes.has(path31)) {
|
|
16877
17981
|
if (err && err.code !== "ENOENT")
|
|
16878
17982
|
awfEmit(err);
|
|
16879
17983
|
return;
|
|
16880
17984
|
}
|
|
16881
17985
|
const now3 = Number(/* @__PURE__ */ new Date());
|
|
16882
17986
|
if (prevStat && curStat.size !== prevStat.size) {
|
|
16883
|
-
writes.get(
|
|
17987
|
+
writes.get(path31).lastChange = now3;
|
|
16884
17988
|
}
|
|
16885
|
-
const pw = writes.get(
|
|
17989
|
+
const pw = writes.get(path31);
|
|
16886
17990
|
const df = now3 - pw.lastChange;
|
|
16887
17991
|
if (df >= threshold) {
|
|
16888
|
-
writes.delete(
|
|
17992
|
+
writes.delete(path31);
|
|
16889
17993
|
awfEmit(void 0, curStat);
|
|
16890
17994
|
} else {
|
|
16891
17995
|
timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat);
|
|
16892
17996
|
}
|
|
16893
17997
|
});
|
|
16894
17998
|
}
|
|
16895
|
-
if (!writes.has(
|
|
16896
|
-
writes.set(
|
|
17999
|
+
if (!writes.has(path31)) {
|
|
18000
|
+
writes.set(path31, {
|
|
16897
18001
|
lastChange: now2,
|
|
16898
18002
|
cancelWait: () => {
|
|
16899
|
-
writes.delete(
|
|
18003
|
+
writes.delete(path31);
|
|
16900
18004
|
clearTimeout(timeoutHandler);
|
|
16901
18005
|
return event;
|
|
16902
18006
|
}
|
|
@@ -16907,8 +18011,8 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
16907
18011
|
/**
|
|
16908
18012
|
* Determines whether user has asked to ignore this path.
|
|
16909
18013
|
*/
|
|
16910
|
-
_isIgnored(
|
|
16911
|
-
if (this.options.atomic && DOT_RE.test(
|
|
18014
|
+
_isIgnored(path31, stats) {
|
|
18015
|
+
if (this.options.atomic && DOT_RE.test(path31))
|
|
16912
18016
|
return true;
|
|
16913
18017
|
if (!this._userIgnored) {
|
|
16914
18018
|
const { cwd } = this.options;
|
|
@@ -16918,17 +18022,17 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
16918
18022
|
const list = [...ignoredPaths.map(normalizeIgnored(cwd)), ...ignored];
|
|
16919
18023
|
this._userIgnored = anymatch(list, void 0);
|
|
16920
18024
|
}
|
|
16921
|
-
return this._userIgnored(
|
|
18025
|
+
return this._userIgnored(path31, stats);
|
|
16922
18026
|
}
|
|
16923
|
-
_isntIgnored(
|
|
16924
|
-
return !this._isIgnored(
|
|
18027
|
+
_isntIgnored(path31, stat5) {
|
|
18028
|
+
return !this._isIgnored(path31, stat5);
|
|
16925
18029
|
}
|
|
16926
18030
|
/**
|
|
16927
18031
|
* Provides a set of common helpers and properties relating to symlink handling.
|
|
16928
18032
|
* @param path file or directory pattern being watched
|
|
16929
18033
|
*/
|
|
16930
|
-
_getWatchHelpers(
|
|
16931
|
-
return new WatchHelper(
|
|
18034
|
+
_getWatchHelpers(path31) {
|
|
18035
|
+
return new WatchHelper(path31, this.options.followSymlinks, this);
|
|
16932
18036
|
}
|
|
16933
18037
|
// Directory helpers
|
|
16934
18038
|
// -----------------
|
|
@@ -16960,63 +18064,63 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
16960
18064
|
* @param item base path of item/directory
|
|
16961
18065
|
*/
|
|
16962
18066
|
_remove(directory, item, isDirectory) {
|
|
16963
|
-
const
|
|
16964
|
-
const fullPath = sp2.resolve(
|
|
16965
|
-
isDirectory = isDirectory != null ? isDirectory : this._watched.has(
|
|
16966
|
-
if (!this._throttle("remove",
|
|
18067
|
+
const path31 = sp2.join(directory, item);
|
|
18068
|
+
const fullPath = sp2.resolve(path31);
|
|
18069
|
+
isDirectory = isDirectory != null ? isDirectory : this._watched.has(path31) || this._watched.has(fullPath);
|
|
18070
|
+
if (!this._throttle("remove", path31, 100))
|
|
16967
18071
|
return;
|
|
16968
18072
|
if (!isDirectory && this._watched.size === 1) {
|
|
16969
18073
|
this.add(directory, item, true);
|
|
16970
18074
|
}
|
|
16971
|
-
const wp = this._getWatchedDir(
|
|
18075
|
+
const wp = this._getWatchedDir(path31);
|
|
16972
18076
|
const nestedDirectoryChildren = wp.getChildren();
|
|
16973
|
-
nestedDirectoryChildren.forEach((nested) => this._remove(
|
|
18077
|
+
nestedDirectoryChildren.forEach((nested) => this._remove(path31, nested));
|
|
16974
18078
|
const parent = this._getWatchedDir(directory);
|
|
16975
18079
|
const wasTracked = parent.has(item);
|
|
16976
18080
|
parent.remove(item);
|
|
16977
18081
|
if (this._symlinkPaths.has(fullPath)) {
|
|
16978
18082
|
this._symlinkPaths.delete(fullPath);
|
|
16979
18083
|
}
|
|
16980
|
-
let relPath =
|
|
18084
|
+
let relPath = path31;
|
|
16981
18085
|
if (this.options.cwd)
|
|
16982
|
-
relPath = sp2.relative(this.options.cwd,
|
|
18086
|
+
relPath = sp2.relative(this.options.cwd, path31);
|
|
16983
18087
|
if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
|
|
16984
18088
|
const event = this._pendingWrites.get(relPath).cancelWait();
|
|
16985
18089
|
if (event === EVENTS.ADD)
|
|
16986
18090
|
return;
|
|
16987
18091
|
}
|
|
16988
|
-
this._watched.delete(
|
|
18092
|
+
this._watched.delete(path31);
|
|
16989
18093
|
this._watched.delete(fullPath);
|
|
16990
18094
|
const eventName = isDirectory ? EVENTS.UNLINK_DIR : EVENTS.UNLINK;
|
|
16991
|
-
if (wasTracked && !this._isIgnored(
|
|
16992
|
-
this._emit(eventName,
|
|
16993
|
-
this._closePath(
|
|
18095
|
+
if (wasTracked && !this._isIgnored(path31))
|
|
18096
|
+
this._emit(eventName, path31);
|
|
18097
|
+
this._closePath(path31);
|
|
16994
18098
|
}
|
|
16995
18099
|
/**
|
|
16996
18100
|
* Closes all watchers for a path
|
|
16997
18101
|
*/
|
|
16998
|
-
_closePath(
|
|
16999
|
-
this._closeFile(
|
|
17000
|
-
const dir = sp2.dirname(
|
|
17001
|
-
this._getWatchedDir(dir).remove(sp2.basename(
|
|
18102
|
+
_closePath(path31) {
|
|
18103
|
+
this._closeFile(path31);
|
|
18104
|
+
const dir = sp2.dirname(path31);
|
|
18105
|
+
this._getWatchedDir(dir).remove(sp2.basename(path31));
|
|
17002
18106
|
}
|
|
17003
18107
|
/**
|
|
17004
18108
|
* Closes only file-specific watchers
|
|
17005
18109
|
*/
|
|
17006
|
-
_closeFile(
|
|
17007
|
-
const closers = this._closers.get(
|
|
18110
|
+
_closeFile(path31) {
|
|
18111
|
+
const closers = this._closers.get(path31);
|
|
17008
18112
|
if (!closers)
|
|
17009
18113
|
return;
|
|
17010
18114
|
closers.forEach((closer) => closer());
|
|
17011
|
-
this._closers.delete(
|
|
18115
|
+
this._closers.delete(path31);
|
|
17012
18116
|
}
|
|
17013
|
-
_addPathCloser(
|
|
18117
|
+
_addPathCloser(path31, closer) {
|
|
17014
18118
|
if (!closer)
|
|
17015
18119
|
return;
|
|
17016
|
-
let list = this._closers.get(
|
|
18120
|
+
let list = this._closers.get(path31);
|
|
17017
18121
|
if (!list) {
|
|
17018
18122
|
list = [];
|
|
17019
|
-
this._closers.set(
|
|
18123
|
+
this._closers.set(path31, list);
|
|
17020
18124
|
}
|
|
17021
18125
|
list.push(closer);
|
|
17022
18126
|
}
|
|
@@ -17046,11 +18150,11 @@ function watch(paths, options = {}) {
|
|
|
17046
18150
|
var chokidar_default = { watch, FSWatcher };
|
|
17047
18151
|
|
|
17048
18152
|
// src/watcher/file-watcher.ts
|
|
17049
|
-
import * as
|
|
18153
|
+
import * as path24 from "path";
|
|
17050
18154
|
|
|
17051
18155
|
// src/watcher/native-recursive-watcher.ts
|
|
17052
18156
|
import { watch as watch2 } from "fs";
|
|
17053
|
-
import * as
|
|
18157
|
+
import * as path22 from "path";
|
|
17054
18158
|
var NativeRecursiveWatcher = class {
|
|
17055
18159
|
constructor(root, onChange, options = {}) {
|
|
17056
18160
|
this.root = root;
|
|
@@ -17098,9 +18202,9 @@ var NativeRecursiveWatcher = class {
|
|
|
17098
18202
|
toAbsolutePath(filename) {
|
|
17099
18203
|
if (filename == null) return null;
|
|
17100
18204
|
const normalizedFilename = typeof filename === "string" ? filename : filename.toString();
|
|
17101
|
-
const absolutePath =
|
|
17102
|
-
const relativePath =
|
|
17103
|
-
const outsideRoot = relativePath === ".." || relativePath.startsWith(`..${
|
|
18205
|
+
const absolutePath = path22.resolve(this.root, normalizedFilename);
|
|
18206
|
+
const relativePath = path22.relative(this.root, absolutePath);
|
|
18207
|
+
const outsideRoot = relativePath === ".." || relativePath.startsWith(`..${path22.sep}`) || path22.isAbsolute(relativePath);
|
|
17104
18208
|
return outsideRoot ? null : absolutePath;
|
|
17105
18209
|
}
|
|
17106
18210
|
defaultWatchFactory = (root, listener, options) => watch2(root, options, listener);
|
|
@@ -17108,16 +18212,16 @@ var NativeRecursiveWatcher = class {
|
|
|
17108
18212
|
|
|
17109
18213
|
// src/watcher/snapshot.ts
|
|
17110
18214
|
import * as fsPromises4 from "fs/promises";
|
|
17111
|
-
import * as
|
|
18215
|
+
import * as path23 from "path";
|
|
17112
18216
|
async function buildFileSnapshotScan(projectRoot, config, configPaths = []) {
|
|
17113
|
-
const normalizedProjectRoot =
|
|
18217
|
+
const normalizedProjectRoot = path23.resolve(projectRoot);
|
|
17114
18218
|
const ignoreFilter = createIgnoreFilter(normalizedProjectRoot);
|
|
17115
18219
|
const includePatterns = [...config.include, ...config.additionalInclude ?? []];
|
|
17116
18220
|
const maxDepth = config.indexing?.maxDepth ?? -1;
|
|
17117
18221
|
const snapshot = /* @__PURE__ */ new Map();
|
|
17118
18222
|
const unreadablePrefixes = /* @__PURE__ */ new Set();
|
|
17119
18223
|
const includeFile = async (filePath) => {
|
|
17120
|
-
const normalizedPath2 =
|
|
18224
|
+
const normalizedPath2 = path23.resolve(filePath);
|
|
17121
18225
|
if (!shouldIncludeFile(normalizedPath2, normalizedProjectRoot, includePatterns, config.exclude, ignoreFilter)) return;
|
|
17122
18226
|
const stat5 = await readStatIfFile(normalizedPath2, unreadablePrefixes);
|
|
17123
18227
|
if (stat5) snapshot.set(normalizedPath2, { size: stat5.size, mtimeMs: stat5.mtimeMs });
|
|
@@ -17129,16 +18233,16 @@ async function buildFileSnapshotScan(projectRoot, config, configPaths = []) {
|
|
|
17129
18233
|
} catch (error) {
|
|
17130
18234
|
if (isMissingFsError(error)) return;
|
|
17131
18235
|
if (isPermissionFsError(error)) {
|
|
17132
|
-
unreadablePrefixes.add(
|
|
18236
|
+
unreadablePrefixes.add(path23.resolve(directoryPath));
|
|
17133
18237
|
return;
|
|
17134
18238
|
}
|
|
17135
18239
|
throw error;
|
|
17136
18240
|
}
|
|
17137
18241
|
for (const entry of entries) {
|
|
17138
|
-
const fullPath =
|
|
17139
|
-
const relativePath =
|
|
18242
|
+
const fullPath = path23.join(directoryPath, entry.name);
|
|
18243
|
+
const relativePath = path23.relative(normalizedProjectRoot, fullPath);
|
|
17140
18244
|
if (entry.isDirectory()) {
|
|
17141
|
-
if (hasFilteredPathSegment(relativePath,
|
|
18245
|
+
if (hasFilteredPathSegment(relativePath, path23.sep) || isRestrictedDirectory(relativePath, path23.sep)) continue;
|
|
17142
18246
|
if (ignoreFilter.ignores(relativePath)) continue;
|
|
17143
18247
|
if (maxDepth === -1 || depth < maxDepth) await walk(fullPath, depth + 1);
|
|
17144
18248
|
} else if (entry.isFile()) {
|
|
@@ -17151,19 +18255,19 @@ async function buildFileSnapshotScan(projectRoot, config, configPaths = []) {
|
|
|
17151
18255
|
return { entries: snapshot, unreadablePrefixes };
|
|
17152
18256
|
}
|
|
17153
18257
|
async function buildFileSnapshotForPathScan(projectRoot, config, configPaths, targetPath) {
|
|
17154
|
-
const normalizedProjectRoot =
|
|
17155
|
-
const normalizedTargetPath =
|
|
18258
|
+
const normalizedProjectRoot = path23.resolve(projectRoot);
|
|
18259
|
+
const normalizedTargetPath = path23.resolve(targetPath);
|
|
17156
18260
|
if (!isWithinPath(normalizedProjectRoot, normalizedTargetPath)) {
|
|
17157
18261
|
return { entries: /* @__PURE__ */ new Map(), unreadablePrefixes: /* @__PURE__ */ new Set() };
|
|
17158
18262
|
}
|
|
17159
18263
|
const ignoreFilter = createIgnoreFilter(normalizedProjectRoot);
|
|
17160
18264
|
const includePatterns = [...config.include, ...config.additionalInclude ?? []];
|
|
17161
18265
|
const maxDepth = config.indexing?.maxDepth ?? -1;
|
|
17162
|
-
const explicitConfigPaths = new Set(configPaths.map((configPath) =>
|
|
18266
|
+
const explicitConfigPaths = new Set(configPaths.map((configPath) => path23.resolve(configPath)));
|
|
17163
18267
|
const snapshot = /* @__PURE__ */ new Map();
|
|
17164
18268
|
const unreadablePrefixes = /* @__PURE__ */ new Set();
|
|
17165
18269
|
const includeFile = async (filePath) => {
|
|
17166
|
-
const normalizedPath2 =
|
|
18270
|
+
const normalizedPath2 = path23.resolve(filePath);
|
|
17167
18271
|
if (!explicitConfigPaths.has(normalizedPath2) && !shouldIncludeFile(
|
|
17168
18272
|
normalizedPath2,
|
|
17169
18273
|
normalizedProjectRoot,
|
|
@@ -17181,16 +18285,16 @@ async function buildFileSnapshotForPathScan(projectRoot, config, configPaths, ta
|
|
|
17181
18285
|
} catch (error) {
|
|
17182
18286
|
if (isMissingFsError(error)) return;
|
|
17183
18287
|
if (isPermissionFsError(error)) {
|
|
17184
|
-
unreadablePrefixes.add(
|
|
18288
|
+
unreadablePrefixes.add(path23.resolve(directoryPath));
|
|
17185
18289
|
return;
|
|
17186
18290
|
}
|
|
17187
18291
|
throw error;
|
|
17188
18292
|
}
|
|
17189
18293
|
for (const entry of entries) {
|
|
17190
|
-
const fullPath =
|
|
17191
|
-
const relativePath =
|
|
18294
|
+
const fullPath = path23.join(directoryPath, entry.name);
|
|
18295
|
+
const relativePath = path23.relative(normalizedProjectRoot, fullPath);
|
|
17192
18296
|
if (entry.isDirectory()) {
|
|
17193
|
-
if (hasFilteredPathSegment(relativePath,
|
|
18297
|
+
if (hasFilteredPathSegment(relativePath, path23.sep) || isRestrictedDirectory(relativePath, path23.sep)) continue;
|
|
17194
18298
|
if (ignoreFilter.ignores(relativePath)) continue;
|
|
17195
18299
|
if (maxDepth === -1 || depth < maxDepth) await walk(fullPath, depth + 1);
|
|
17196
18300
|
} else if (entry.isFile()) {
|
|
@@ -17214,7 +18318,7 @@ function completeFileSnapshot(previous, scan) {
|
|
|
17214
18318
|
return completed;
|
|
17215
18319
|
}
|
|
17216
18320
|
async function includeExplicitConfigPaths(snapshot, unreadablePrefixes, configPaths) {
|
|
17217
|
-
for (const configPath of [...new Set(configPaths.map((value) =>
|
|
18321
|
+
for (const configPath of [...new Set(configPaths.map((value) => path23.resolve(value)))]) {
|
|
17218
18322
|
if (snapshot.has(configPath)) continue;
|
|
17219
18323
|
const stat5 = await readStatIfFile(configPath, unreadablePrefixes);
|
|
17220
18324
|
if (stat5) snapshot.set(configPath, { size: stat5.size, mtimeMs: stat5.mtimeMs });
|
|
@@ -17224,12 +18328,12 @@ async function includeExplicitConfigPathsInPath(snapshot, unreadablePrefixes, co
|
|
|
17224
18328
|
await includeExplicitConfigPaths(
|
|
17225
18329
|
snapshot,
|
|
17226
18330
|
unreadablePrefixes,
|
|
17227
|
-
configPaths.filter((configPath) => isWithinPath(targetPath,
|
|
18331
|
+
configPaths.filter((configPath) => isWithinPath(targetPath, path23.resolve(configPath)))
|
|
17228
18332
|
);
|
|
17229
18333
|
}
|
|
17230
18334
|
function isWithinPath(parentPath, childPath) {
|
|
17231
|
-
const relativePath =
|
|
17232
|
-
return relativePath === "" || !relativePath.startsWith(`..${
|
|
18335
|
+
const relativePath = path23.relative(parentPath, childPath);
|
|
18336
|
+
return relativePath === "" || !relativePath.startsWith(`..${path23.sep}`) && relativePath !== ".." && !path23.isAbsolute(relativePath);
|
|
17233
18337
|
}
|
|
17234
18338
|
async function readStatIfFile(filePath, unreadablePrefixes) {
|
|
17235
18339
|
try {
|
|
@@ -17238,7 +18342,7 @@ async function readStatIfFile(filePath, unreadablePrefixes) {
|
|
|
17238
18342
|
} catch (error) {
|
|
17239
18343
|
if (isMissingFsError(error)) return null;
|
|
17240
18344
|
if (isPermissionFsError(error)) {
|
|
17241
|
-
unreadablePrefixes.add(
|
|
18345
|
+
unreadablePrefixes.add(path23.resolve(filePath));
|
|
17242
18346
|
return null;
|
|
17243
18347
|
}
|
|
17244
18348
|
throw error;
|
|
@@ -17375,8 +18479,8 @@ var FileWatcher = class {
|
|
|
17375
18479
|
this.createWatcher();
|
|
17376
18480
|
}
|
|
17377
18481
|
resetReady() {
|
|
17378
|
-
this.readyPromise = new Promise((
|
|
17379
|
-
this.resolveReady =
|
|
18482
|
+
this.readyPromise = new Promise((resolve18) => {
|
|
18483
|
+
this.resolveReady = resolve18;
|
|
17380
18484
|
});
|
|
17381
18485
|
this.startupReadySignals = 1;
|
|
17382
18486
|
}
|
|
@@ -17407,7 +18511,7 @@ var FileWatcher = class {
|
|
|
17407
18511
|
const resolvedWatchTargets = watchTargets ?? this.getFullChokidarWatchTargets();
|
|
17408
18512
|
const watcherOptions = {
|
|
17409
18513
|
ignored: (filePath) => {
|
|
17410
|
-
const relativePath =
|
|
18514
|
+
const relativePath = path24.relative(this.projectRoot, filePath);
|
|
17411
18515
|
if (!relativePath) return false;
|
|
17412
18516
|
if (this.isProjectConfigPathOrAncestor(relativePath)) {
|
|
17413
18517
|
return false;
|
|
@@ -17415,10 +18519,10 @@ var FileWatcher = class {
|
|
|
17415
18519
|
if (this.isOutsideProjectPath(relativePath)) {
|
|
17416
18520
|
return true;
|
|
17417
18521
|
}
|
|
17418
|
-
if (hasFilteredPathSegment(relativePath,
|
|
18522
|
+
if (hasFilteredPathSegment(relativePath, path24.sep)) {
|
|
17419
18523
|
return true;
|
|
17420
18524
|
}
|
|
17421
|
-
if (isRestrictedDirectory(relativePath,
|
|
18525
|
+
if (isRestrictedDirectory(relativePath, path24.sep)) {
|
|
17422
18526
|
return true;
|
|
17423
18527
|
}
|
|
17424
18528
|
if (ignoreFilter.ignores(relativePath)) {
|
|
@@ -17509,13 +18613,13 @@ var FileWatcher = class {
|
|
|
17509
18613
|
getExternalConfigWatchTargets() {
|
|
17510
18614
|
return [...new Set(
|
|
17511
18615
|
this.projectConfigPaths.filter((projectConfigPath) => {
|
|
17512
|
-
const relativeConfigPath =
|
|
18616
|
+
const relativeConfigPath = path24.relative(this.projectRoot, projectConfigPath);
|
|
17513
18617
|
return this.isOutsideProjectPath(relativeConfigPath);
|
|
17514
18618
|
}).map((projectConfigPath) => {
|
|
17515
|
-
if (
|
|
18619
|
+
if (existsSync14(projectConfigPath)) {
|
|
17516
18620
|
return projectConfigPath;
|
|
17517
18621
|
}
|
|
17518
|
-
return this.getNearestExistingDirectory(
|
|
18622
|
+
return this.getNearestExistingDirectory(path24.dirname(projectConfigPath));
|
|
17519
18623
|
})
|
|
17520
18624
|
)];
|
|
17521
18625
|
}
|
|
@@ -17577,7 +18681,7 @@ var FileWatcher = class {
|
|
|
17577
18681
|
}
|
|
17578
18682
|
scheduleNativeReconciliation(generation, filePath) {
|
|
17579
18683
|
if (!this.isCurrentNativeSetup(generation)) return;
|
|
17580
|
-
const requiresFullReconciliation = filePath ===
|
|
18684
|
+
const requiresFullReconciliation = filePath === path24.join(this.projectRoot, ".gitignore");
|
|
17581
18685
|
const invalidatedPath = requiresFullReconciliation ? null : filePath;
|
|
17582
18686
|
this.nativeInvalidatedPaths.set(invalidatedPath, invalidatedPath !== null);
|
|
17583
18687
|
if (this.nativeReconcileTimer) {
|
|
@@ -17672,23 +18776,23 @@ var FileWatcher = class {
|
|
|
17672
18776
|
this.scheduleFlush();
|
|
17673
18777
|
}
|
|
17674
18778
|
isProjectConfigPath(filePath) {
|
|
17675
|
-
const relativePath =
|
|
17676
|
-
const normalizedRelativePath =
|
|
18779
|
+
const relativePath = path24.relative(this.projectRoot, filePath);
|
|
18780
|
+
const normalizedRelativePath = path24.normalize(relativePath);
|
|
17677
18781
|
return this.getProjectConfigRelativePaths().some((configPath) => configPath === normalizedRelativePath);
|
|
17678
18782
|
}
|
|
17679
18783
|
isProjectConfigPathOrAncestor(relativePath) {
|
|
17680
|
-
const normalizedRelativePath =
|
|
18784
|
+
const normalizedRelativePath = path24.normalize(relativePath);
|
|
17681
18785
|
return this.getProjectConfigRelativePaths().some(
|
|
17682
|
-
(configPath) => configPath === normalizedRelativePath || configPath.startsWith(`${normalizedRelativePath}${
|
|
18786
|
+
(configPath) => configPath === normalizedRelativePath || configPath.startsWith(`${normalizedRelativePath}${path24.sep}`)
|
|
17683
18787
|
);
|
|
17684
18788
|
}
|
|
17685
18789
|
isOutsideProjectPath(relativePath) {
|
|
17686
|
-
return relativePath === ".." || relativePath.startsWith(`..${
|
|
18790
|
+
return relativePath === ".." || relativePath.startsWith(`..${path24.sep}`) || path24.isAbsolute(relativePath);
|
|
17687
18791
|
}
|
|
17688
18792
|
getNearestExistingDirectory(directoryPath) {
|
|
17689
18793
|
let candidate = directoryPath;
|
|
17690
|
-
while (!
|
|
17691
|
-
const parent =
|
|
18794
|
+
while (!existsSync14(candidate)) {
|
|
18795
|
+
const parent = path24.dirname(candidate);
|
|
17692
18796
|
if (parent === candidate) break;
|
|
17693
18797
|
candidate = parent;
|
|
17694
18798
|
}
|
|
@@ -17696,7 +18800,7 @@ var FileWatcher = class {
|
|
|
17696
18800
|
}
|
|
17697
18801
|
getProjectConfigRelativePaths() {
|
|
17698
18802
|
return this.projectConfigPaths.map(
|
|
17699
|
-
(configPath) =>
|
|
18803
|
+
(configPath) => path24.normalize(path24.relative(this.projectRoot, configPath))
|
|
17700
18804
|
);
|
|
17701
18805
|
}
|
|
17702
18806
|
getConfigPathStates() {
|
|
@@ -17754,7 +18858,7 @@ var FileWatcher = class {
|
|
|
17754
18858
|
return;
|
|
17755
18859
|
}
|
|
17756
18860
|
const changes = Array.from(this.pendingChanges.entries()).map(
|
|
17757
|
-
([
|
|
18861
|
+
([path31, type]) => ({ path: path31, type })
|
|
17758
18862
|
);
|
|
17759
18863
|
this.pendingChanges.clear();
|
|
17760
18864
|
try {
|
|
@@ -17800,7 +18904,7 @@ var FileWatcher = class {
|
|
|
17800
18904
|
};
|
|
17801
18905
|
|
|
17802
18906
|
// src/watcher/git-head-watcher.ts
|
|
17803
|
-
import * as
|
|
18907
|
+
import * as path25 from "path";
|
|
17804
18908
|
var GitHeadWatcher = class {
|
|
17805
18909
|
watcher = null;
|
|
17806
18910
|
projectRoot;
|
|
@@ -17822,13 +18926,13 @@ var GitHeadWatcher = class {
|
|
|
17822
18926
|
this.readyPromise = Promise.resolve();
|
|
17823
18927
|
return;
|
|
17824
18928
|
}
|
|
17825
|
-
this.readyPromise = new Promise((
|
|
17826
|
-
this.resolveReady =
|
|
18929
|
+
this.readyPromise = new Promise((resolve18) => {
|
|
18930
|
+
this.resolveReady = resolve18;
|
|
17827
18931
|
});
|
|
17828
18932
|
this.onBranchChange = handler;
|
|
17829
18933
|
this.currentBranch = getCurrentBranch(this.projectRoot);
|
|
17830
18934
|
const headPath = getHeadPath(this.projectRoot);
|
|
17831
|
-
const refsPath =
|
|
18935
|
+
const refsPath = path25.join(this.projectRoot, ".git", "refs", "heads");
|
|
17832
18936
|
this.watcher = chokidar_default.watch([headPath, refsPath], {
|
|
17833
18937
|
persistent: true,
|
|
17834
18938
|
ignoreInitial: true,
|
|
@@ -17896,7 +19000,9 @@ var GitHeadWatcher = class {
|
|
|
17896
19000
|
function createWatcherWithIndexer(getIndexer, projectRoot, config, host, options = {}) {
|
|
17897
19001
|
const fileWatcher = new FileWatcher(projectRoot, config, host, options);
|
|
17898
19002
|
const configPaths = getConfigPaths(projectRoot, host, options);
|
|
17899
|
-
configureAutoIndex(projectRoot, host, parseConfig(config), getIndexer
|
|
19003
|
+
configureAutoIndex(projectRoot, host, parseConfig(config), getIndexer, {
|
|
19004
|
+
synchronizeBackgroundWorker: false
|
|
19005
|
+
});
|
|
17900
19006
|
let stopped = false;
|
|
17901
19007
|
const requestReindex = () => {
|
|
17902
19008
|
if (stopped) return;
|
|
@@ -17916,7 +19022,9 @@ function createWatcherWithIndexer(getIndexer, projectRoot, config, host, options
|
|
|
17916
19022
|
const parsedConfig = options.configPath ? parseConfig(loadConfigFile(options.configPath)) : void 0;
|
|
17917
19023
|
const refreshedConfig = refreshIndexerForDirectory(projectRoot, host, parsedConfig);
|
|
17918
19024
|
if (refreshedConfig) {
|
|
17919
|
-
configureAutoIndex(projectRoot, host, refreshedConfig, getIndexer
|
|
19025
|
+
configureAutoIndex(projectRoot, host, refreshedConfig, getIndexer, {
|
|
19026
|
+
synchronizeBackgroundWorker: false
|
|
19027
|
+
});
|
|
17920
19028
|
}
|
|
17921
19029
|
}
|
|
17922
19030
|
requestReindex();
|
|
@@ -18692,7 +19800,7 @@ async function resolveCodebaseContextUnmeasured(projectRoot, host, input) {
|
|
|
18692
19800
|
const directory = input.directory ?? void 0;
|
|
18693
19801
|
const tokenBudget = input.tokenBudget ?? void 0;
|
|
18694
19802
|
if (from && to) {
|
|
18695
|
-
const
|
|
19803
|
+
const path31 = await getCallGraphPath(
|
|
18696
19804
|
projectRoot,
|
|
18697
19805
|
host,
|
|
18698
19806
|
from,
|
|
@@ -18701,25 +19809,25 @@ async function resolveCodebaseContextUnmeasured(projectRoot, host, input) {
|
|
|
18701
19809
|
fromFilePath,
|
|
18702
19810
|
toFilePath
|
|
18703
19811
|
);
|
|
18704
|
-
const pathText = formatCallGraphPathResult(
|
|
18705
|
-
if (
|
|
19812
|
+
const pathText = formatCallGraphPathResult(path31);
|
|
19813
|
+
if (path31.path.length > 0) {
|
|
18706
19814
|
const fitted2 = fitTextToContextBudget(
|
|
18707
19815
|
pathText,
|
|
18708
19816
|
tokenBudget
|
|
18709
19817
|
);
|
|
18710
19818
|
return {
|
|
18711
19819
|
text: fitted2.text,
|
|
18712
|
-
details: fittedDetails("path", fitted2,
|
|
19820
|
+
details: fittedDetails("path", fitted2, path31.path.length)
|
|
18713
19821
|
};
|
|
18714
19822
|
}
|
|
18715
|
-
if (
|
|
19823
|
+
if (path31.from.status !== "resolved" || path31.to.status !== "resolved") {
|
|
18716
19824
|
const fitted2 = fitTextToContextBudget(pathText, tokenBudget);
|
|
18717
19825
|
return {
|
|
18718
19826
|
text: fitted2.text,
|
|
18719
19827
|
details: fittedDetails("path", fitted2, 0)
|
|
18720
19828
|
};
|
|
18721
19829
|
}
|
|
18722
|
-
const resolvedFrom =
|
|
19830
|
+
const resolvedFrom = path31.from;
|
|
18723
19831
|
const { callers } = await getCallGraphData(projectRoot, host, {
|
|
18724
19832
|
name: to,
|
|
18725
19833
|
direction: "callers",
|
|
@@ -18843,6 +19951,7 @@ async function executeCodebaseEditContext(projectRoot, host, args) {
|
|
|
18843
19951
|
async function executeIndexCodebase(projectRoot, host, args, onProgress) {
|
|
18844
19952
|
const result = await runIndexCodebase(projectRoot, host, args, onProgress);
|
|
18845
19953
|
if (result.kind === "estimate") return { text: formatCostEstimate(result.estimate) };
|
|
19954
|
+
if (result.kind === "dryrun") return { text: formatDryRunEstimate(result.dryrun) };
|
|
18846
19955
|
if (result.kind === "busy") return { text: result.text, isError: true };
|
|
18847
19956
|
if (result.kind === "message") return { text: result.text };
|
|
18848
19957
|
return { text: formatIndexStats(result.stats, args.verbose ?? false) };
|
|
@@ -18879,7 +19988,7 @@ async function executeCallGraph(projectRoot, host, args) {
|
|
|
18879
19988
|
return { text: formatCallGraphResult(await getCallGraphData(projectRoot, host, args)) };
|
|
18880
19989
|
}
|
|
18881
19990
|
async function executeCallGraphPath(projectRoot, host, args) {
|
|
18882
|
-
const
|
|
19991
|
+
const path31 = await getCallGraphPath(
|
|
18883
19992
|
projectRoot,
|
|
18884
19993
|
host,
|
|
18885
19994
|
args.from,
|
|
@@ -18888,7 +19997,7 @@ async function executeCallGraphPath(projectRoot, host, args) {
|
|
|
18888
19997
|
args.fromFilePath,
|
|
18889
19998
|
args.toFilePath
|
|
18890
19999
|
);
|
|
18891
|
-
return { text: formatCallGraphPathResult(
|
|
20000
|
+
return { text: formatCallGraphPathResult(path31) };
|
|
18892
20001
|
}
|
|
18893
20002
|
async function executeCodeCommunities(projectRoot, host, args) {
|
|
18894
20003
|
const result = await getCodeCommunities(projectRoot, host, args);
|
|
@@ -18896,13 +20005,13 @@ async function executeCodeCommunities(projectRoot, host, args) {
|
|
|
18896
20005
|
}
|
|
18897
20006
|
|
|
18898
20007
|
// src/adapters/opencode/tools.ts
|
|
18899
|
-
import { writeFileSync as
|
|
18900
|
-
import * as
|
|
18901
|
-
import * as
|
|
20008
|
+
import { writeFileSync as writeFileSync5 } from "fs";
|
|
20009
|
+
import * as os8 from "os";
|
|
20010
|
+
import * as path28 from "path";
|
|
18902
20011
|
|
|
18903
20012
|
// src/tools/visualize/activity.ts
|
|
18904
20013
|
import { execFileSync } from "child_process";
|
|
18905
|
-
import * as
|
|
20014
|
+
import * as path26 from "path";
|
|
18906
20015
|
function attachRecentActivity(data, projectRoot) {
|
|
18907
20016
|
const activity = readGitActivity(projectRoot);
|
|
18908
20017
|
const changes = activity.size > 0 ? buildGitChanges(data, activity, projectRoot) : buildGraphChanges(data);
|
|
@@ -19064,7 +20173,7 @@ function normalizePath3(filePath) {
|
|
|
19064
20173
|
return filePath.replace(/\\/g, "/");
|
|
19065
20174
|
}
|
|
19066
20175
|
function toGitRelativePath(projectRoot, filePath) {
|
|
19067
|
-
const relativePath =
|
|
20176
|
+
const relativePath = path26.isAbsolute(filePath) ? path26.relative(projectRoot, filePath) : filePath;
|
|
19068
20177
|
return normalizePath3(relativePath);
|
|
19069
20178
|
}
|
|
19070
20179
|
|
|
@@ -19322,7 +20431,7 @@ render();
|
|
|
19322
20431
|
}
|
|
19323
20432
|
|
|
19324
20433
|
// src/tools/visualize/transform.ts
|
|
19325
|
-
import * as
|
|
20434
|
+
import * as path27 from "path";
|
|
19326
20435
|
|
|
19327
20436
|
// src/tools/visualize/modules.ts
|
|
19328
20437
|
var MAX_MODULES = 18;
|
|
@@ -19582,7 +20691,7 @@ function transformForVisualization(symbols, edges, options = {}) {
|
|
|
19582
20691
|
filePath: s.filePath,
|
|
19583
20692
|
kind: s.kind,
|
|
19584
20693
|
line: s.startLine,
|
|
19585
|
-
directory:
|
|
20694
|
+
directory: path27.dirname(s.filePath),
|
|
19586
20695
|
moduleId: "",
|
|
19587
20696
|
moduleLabel: ""
|
|
19588
20697
|
}));
|
|
@@ -19707,6 +20816,7 @@ var index_codebase = tool({
|
|
|
19707
20816
|
args: {
|
|
19708
20817
|
force: z3.boolean().optional().default(false).describe("Force reindex even if already indexed"),
|
|
19709
20818
|
estimateOnly: z3.boolean().optional().default(false).describe("Only show cost estimate without indexing"),
|
|
20819
|
+
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)."),
|
|
19710
20820
|
verbose: z3.boolean().optional().default(false).describe("Show detailed info about skipped files and parsing failures")
|
|
19711
20821
|
},
|
|
19712
20822
|
async execute(args, context) {
|
|
@@ -19910,8 +21020,8 @@ var index_visualize = tool({
|
|
|
19910
21020
|
return "No connected symbols found for visualization. Try including orphans with includeOrphans=true, or check that the call graph has resolved edges.";
|
|
19911
21021
|
}
|
|
19912
21022
|
const html = generateVisualizationHtml(vizData);
|
|
19913
|
-
const outputPath =
|
|
19914
|
-
|
|
21023
|
+
const outputPath = path28.join(os8.tmpdir(), `call-graph-${Date.now()}.html`);
|
|
21024
|
+
writeFileSync5(outputPath, html, "utf-8");
|
|
19915
21025
|
let result = `Temporal call graph visualization generated: ${outputPath}
|
|
19916
21026
|
|
|
19917
21027
|
`;
|
|
@@ -20022,8 +21132,8 @@ var MCP_TOOL_NAMES = [
|
|
|
20022
21132
|
];
|
|
20023
21133
|
|
|
20024
21134
|
// src/commands/loader.ts
|
|
20025
|
-
import { existsSync as
|
|
20026
|
-
import * as
|
|
21135
|
+
import { existsSync as existsSync15, readdirSync as readdirSync3, readFileSync as readFileSync10 } from "fs";
|
|
21136
|
+
import * as path29 from "path";
|
|
20027
21137
|
function parseFrontmatter(content) {
|
|
20028
21138
|
const frontmatterRegex = /^---\s*\n([\s\S]*?)\n---\s*\n([\s\S]*)$/;
|
|
20029
21139
|
const match = content.match(frontmatterRegex);
|
|
@@ -20044,21 +21154,21 @@ function parseFrontmatter(content) {
|
|
|
20044
21154
|
}
|
|
20045
21155
|
function loadCommandsFromDirectory(commandsDir) {
|
|
20046
21156
|
const commands = /* @__PURE__ */ new Map();
|
|
20047
|
-
if (!
|
|
21157
|
+
if (!existsSync15(commandsDir)) {
|
|
20048
21158
|
return commands;
|
|
20049
21159
|
}
|
|
20050
21160
|
const files = readdirSync3(commandsDir).filter((f) => f.endsWith(".md"));
|
|
20051
21161
|
for (const file of files) {
|
|
20052
|
-
const filePath =
|
|
21162
|
+
const filePath = path29.join(commandsDir, file);
|
|
20053
21163
|
let content;
|
|
20054
21164
|
try {
|
|
20055
|
-
content =
|
|
21165
|
+
content = readFileSync10(filePath, "utf-8");
|
|
20056
21166
|
} catch (error) {
|
|
20057
21167
|
const message = error instanceof Error ? error.message : String(error);
|
|
20058
21168
|
throw new Error(`Failed to load command file ${filePath}: ${message}`);
|
|
20059
21169
|
}
|
|
20060
21170
|
const { frontmatter, body } = parseFrontmatter(content);
|
|
20061
|
-
const name =
|
|
21171
|
+
const name = path29.basename(file, ".md");
|
|
20062
21172
|
const description = frontmatter.description || `Run the ${name} command`;
|
|
20063
21173
|
commands.set(name, {
|
|
20064
21174
|
description,
|
|
@@ -20307,6 +21417,7 @@ function assessRoutingIntent(text) {
|
|
|
20307
21417
|
};
|
|
20308
21418
|
}
|
|
20309
21419
|
function buildRoutingHint(assessment, status, includeGraphHandoff = false) {
|
|
21420
|
+
const hasSymbolCue = hasIdentifierShape(assessment.text) || containsQuotedIdentifier(assessment.text);
|
|
20310
21421
|
if (assessment.intent === "definition_lookup") {
|
|
20311
21422
|
if (!status || !status.indexed || status.compatibility?.compatible === false) {
|
|
20312
21423
|
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.";
|
|
@@ -20316,12 +21427,13 @@ function buildRoutingHint(assessment, status, includeGraphHandoff = false) {
|
|
|
20316
21427
|
if (assessment.intent !== "local_conceptual" && assessment.intent !== "local_broad_task") {
|
|
20317
21428
|
return null;
|
|
20318
21429
|
}
|
|
21430
|
+
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." : "";
|
|
20319
21431
|
if (!status || !status.indexed || status.compatibility?.compatible === false) {
|
|
20320
21432
|
const graphHandoff2 = includeGraphHandoff ? " Use graph tools after semantic discovery identifies relevant symbols." : "";
|
|
20321
|
-
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
|
|
21433
|
+
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}`;
|
|
20322
21434
|
}
|
|
20323
21435
|
const graphHandoff = includeGraphHandoff ? " before graph tools such as `call_graph`, `call_graph_path`, `pr_impact`, or OMO CodeGraph" : "";
|
|
20324
|
-
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
|
|
21436
|
+
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}`;
|
|
20325
21437
|
}
|
|
20326
21438
|
var RoutingHintController = class {
|
|
20327
21439
|
constructor(getStatus, maxSessions = 200, includeGraphHandoff = false) {
|
|
@@ -20363,7 +21475,7 @@ var RoutingHintController = class {
|
|
|
20363
21475
|
if (!state || !state.pendingHint) {
|
|
20364
21476
|
return;
|
|
20365
21477
|
}
|
|
20366
|
-
if (toolName === "codebase_context" || toolName === "codebase_peek" || toolName === "codebase_search" || toolName === "implementation_lookup" || toolName === "index_status" || toolName === "index_codebase") {
|
|
21478
|
+
if (toolName === "codebase_context" || toolName === "codebase_edit_context" || toolName === "codebase_peek" || toolName === "codebase_search" || toolName === "implementation_lookup" || toolName === "index_status" || toolName === "index_codebase") {
|
|
20367
21479
|
state.pendingHint = false;
|
|
20368
21480
|
state.updatedAt = Date.now();
|
|
20369
21481
|
this.sessionState.set(sessionID, state);
|
|
@@ -20391,42 +21503,13 @@ var RoutingHintController = class {
|
|
|
20391
21503
|
};
|
|
20392
21504
|
|
|
20393
21505
|
// src/adapters/opencode.ts
|
|
20394
|
-
var activeWatchers = /* @__PURE__ */ new Map();
|
|
20395
|
-
var watcherReplacementChains = /* @__PURE__ */ new Map();
|
|
20396
|
-
async function replaceActiveWatcher(projectRoot, createNextWatcher) {
|
|
20397
|
-
const chain = (watcherReplacementChains.get(projectRoot) ?? Promise.resolve()).catch(() => void 0).then(async () => {
|
|
20398
|
-
const existing = activeWatchers.get(projectRoot);
|
|
20399
|
-
if (existing) {
|
|
20400
|
-
try {
|
|
20401
|
-
await existing.stop();
|
|
20402
|
-
} catch (error) {
|
|
20403
|
-
console.error("[codebase-index] Failed to stop replaced watcher:", error);
|
|
20404
|
-
throw error;
|
|
20405
|
-
}
|
|
20406
|
-
if (activeWatchers.get(projectRoot) === existing) {
|
|
20407
|
-
activeWatchers.delete(projectRoot);
|
|
20408
|
-
}
|
|
20409
|
-
}
|
|
20410
|
-
if (createNextWatcher) {
|
|
20411
|
-
activeWatchers.set(projectRoot, createNextWatcher());
|
|
20412
|
-
}
|
|
20413
|
-
});
|
|
20414
|
-
watcherReplacementChains.set(projectRoot, chain);
|
|
20415
|
-
try {
|
|
20416
|
-
await chain;
|
|
20417
|
-
} finally {
|
|
20418
|
-
if (watcherReplacementChains.get(projectRoot) === chain) {
|
|
20419
|
-
watcherReplacementChains.delete(projectRoot);
|
|
20420
|
-
}
|
|
20421
|
-
}
|
|
20422
|
-
}
|
|
20423
21506
|
function getCommandsDir() {
|
|
20424
21507
|
let currentDir = process.cwd();
|
|
20425
21508
|
if (typeof import.meta !== "undefined" && import.meta.url) {
|
|
20426
|
-
currentDir =
|
|
21509
|
+
currentDir = path30.dirname(fileURLToPath2(import.meta.url));
|
|
20427
21510
|
}
|
|
20428
|
-
const packageRoot =
|
|
20429
|
-
return
|
|
21511
|
+
const packageRoot = path30.basename(currentDir) === "adapters" ? path30.join(currentDir, "..", "..") : path30.join(currentDir, "..");
|
|
21512
|
+
return path30.join(packageRoot, "commands");
|
|
20430
21513
|
}
|
|
20431
21514
|
function appendRoutingHints(output, hints, preferredRole) {
|
|
20432
21515
|
const preferredBucket = preferredRole === "developer" ? output.developer : output.system;
|
|
@@ -20452,8 +21535,9 @@ var plugin = async ({ directory, worktree }) => {
|
|
|
20452
21535
|
initializeTools2(projectRoot, config);
|
|
20453
21536
|
const getProjectIndexer = () => getIndexerForProject2(projectRoot);
|
|
20454
21537
|
const routingHints = config.search.routingHints ? new RoutingHintController(() => getProjectIndexer().getStatus(), 200, config.search.routingGraphHandoffHints) : null;
|
|
20455
|
-
const
|
|
20456
|
-
const
|
|
21538
|
+
const projectSafety = getProjectSafety(projectRoot, config);
|
|
21539
|
+
const isHomeDir = projectSafety.blockedReason === "home-directory";
|
|
21540
|
+
const isValidProject = projectSafety.safeToRun;
|
|
20457
21541
|
if (isHomeDir) {
|
|
20458
21542
|
console.warn(
|
|
20459
21543
|
`[codebase-index] Refusing to watch or index home directory "${projectRoot}". Open a specific project directory instead.`
|
|
@@ -20463,16 +21547,24 @@ var plugin = async ({ directory, worktree }) => {
|
|
|
20463
21547
|
`[codebase-index] Skipping file watching and auto-indexing: no project marker found in "${projectRoot}". Set "indexing.requireProjectMarker": false in config to override.`
|
|
20464
21548
|
);
|
|
20465
21549
|
}
|
|
20466
|
-
if (
|
|
20467
|
-
|
|
20468
|
-
|
|
20469
|
-
|
|
20470
|
-
await replaceActiveWatcher(
|
|
20471
|
-
projectRoot,
|
|
20472
|
-
() => createWatcherWithIndexer(getProjectIndexer, projectRoot, config, "opencode")
|
|
20473
|
-
);
|
|
21550
|
+
if (!isValidProject) {
|
|
21551
|
+
await stopBackgroundWorker(projectRoot, "opencode").catch((error) => {
|
|
21552
|
+
console.error("[codebase-index] Failed to stop unsafe OpenCode background worker:", error);
|
|
21553
|
+
});
|
|
20474
21554
|
} else {
|
|
20475
|
-
|
|
21555
|
+
const watcherFactoryForConfig = (refreshedConfig) => refreshedConfig.indexing.watchFiles ? () => createWatcherWithIndexer(getProjectIndexer, projectRoot, refreshedConfig, "opencode") : null;
|
|
21556
|
+
configureBackgroundWorker(projectRoot, "opencode", config, {
|
|
21557
|
+
startAutoIndex: (source, allowDisabledAutoIndex) => {
|
|
21558
|
+
startAutoIndexForBackgroundWorker(projectRoot, "opencode", source, allowDisabledAutoIndex);
|
|
21559
|
+
},
|
|
21560
|
+
stopAutoIndex: () => stopAutoIndexForBackgroundWorker(projectRoot, "opencode"),
|
|
21561
|
+
watcherFactory: watcherFactoryForConfig(config),
|
|
21562
|
+
watcherFactoryForConfig,
|
|
21563
|
+
replaceWatcher: true
|
|
21564
|
+
}, {
|
|
21565
|
+
restartAutoIndex: true
|
|
21566
|
+
});
|
|
21567
|
+
await waitForBackgroundWorkerStart(projectRoot, "opencode");
|
|
20476
21568
|
}
|
|
20477
21569
|
return {
|
|
20478
21570
|
tool: {
|