opencode-codebase-index 0.25.0 → 0.25.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/dist/cbi.cjs +1254 -258
- package/dist/cbi.cjs.map +1 -1
- package/dist/cbi.js +1318 -313
- package/dist/cbi.js.map +1 -1
- package/dist/cli.cjs +1617 -528
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +1654 -556
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +1519 -530
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1583 -585
- package/dist/index.js.map +1 -1
- package/dist/pi-extension.cjs +1492 -484
- package/dist/pi-extension.cjs.map +1 -1
- package/dist/pi-extension.js +1548 -531
- 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 +1 -1
package/dist/cli.js
CHANGED
|
@@ -491,7 +491,7 @@ var require_ignore = __commonJS({
|
|
|
491
491
|
// path matching.
|
|
492
492
|
// - check `string` either `MODE_IGNORE` or `MODE_CHECK_IGNORE`
|
|
493
493
|
// @returns {TestResult} true if a file is ignored
|
|
494
|
-
test(
|
|
494
|
+
test(path34, checkUnignored, mode) {
|
|
495
495
|
let ignored = false;
|
|
496
496
|
let unignored = false;
|
|
497
497
|
let matchedRule;
|
|
@@ -500,7 +500,7 @@ var require_ignore = __commonJS({
|
|
|
500
500
|
if (unignored === negative && ignored !== unignored || negative && !ignored && !unignored && !checkUnignored) {
|
|
501
501
|
return;
|
|
502
502
|
}
|
|
503
|
-
const matched = rule[mode].test(
|
|
503
|
+
const matched = rule[mode].test(path34);
|
|
504
504
|
if (!matched) {
|
|
505
505
|
return;
|
|
506
506
|
}
|
|
@@ -521,17 +521,17 @@ var require_ignore = __commonJS({
|
|
|
521
521
|
var throwError = (message, Ctor) => {
|
|
522
522
|
throw new Ctor(message);
|
|
523
523
|
};
|
|
524
|
-
var checkPath = (
|
|
525
|
-
if (!isString(
|
|
524
|
+
var checkPath = (path34, originalPath, doThrow) => {
|
|
525
|
+
if (!isString(path34)) {
|
|
526
526
|
return doThrow(
|
|
527
527
|
`path must be a string, but got \`${originalPath}\``,
|
|
528
528
|
TypeError
|
|
529
529
|
);
|
|
530
530
|
}
|
|
531
|
-
if (!
|
|
531
|
+
if (!path34) {
|
|
532
532
|
return doThrow(`path must not be empty`, TypeError);
|
|
533
533
|
}
|
|
534
|
-
if (checkPath.isNotRelative(
|
|
534
|
+
if (checkPath.isNotRelative(path34)) {
|
|
535
535
|
const r = "`path.relative()`d";
|
|
536
536
|
return doThrow(
|
|
537
537
|
`path should be a ${r} string, but got "${originalPath}"`,
|
|
@@ -540,7 +540,7 @@ var require_ignore = __commonJS({
|
|
|
540
540
|
}
|
|
541
541
|
return true;
|
|
542
542
|
};
|
|
543
|
-
var isNotRelative = (
|
|
543
|
+
var isNotRelative = (path34) => REGEX_TEST_INVALID_PATH.test(path34);
|
|
544
544
|
checkPath.isNotRelative = isNotRelative;
|
|
545
545
|
checkPath.convert = (p) => p;
|
|
546
546
|
var Ignore2 = class {
|
|
@@ -570,19 +570,19 @@ var require_ignore = __commonJS({
|
|
|
570
570
|
}
|
|
571
571
|
// @returns {TestResult}
|
|
572
572
|
_test(originalPath, cache, checkUnignored, slices) {
|
|
573
|
-
const
|
|
573
|
+
const path34 = originalPath && checkPath.convert(originalPath);
|
|
574
574
|
checkPath(
|
|
575
|
-
|
|
575
|
+
path34,
|
|
576
576
|
originalPath,
|
|
577
577
|
this._strictPathCheck ? throwError : RETURN_FALSE
|
|
578
578
|
);
|
|
579
|
-
return this._t(
|
|
579
|
+
return this._t(path34, cache, checkUnignored, slices);
|
|
580
580
|
}
|
|
581
|
-
checkIgnore(
|
|
582
|
-
if (!REGEX_TEST_TRAILING_SLASH.test(
|
|
583
|
-
return this.test(
|
|
581
|
+
checkIgnore(path34) {
|
|
582
|
+
if (!REGEX_TEST_TRAILING_SLASH.test(path34)) {
|
|
583
|
+
return this.test(path34);
|
|
584
584
|
}
|
|
585
|
-
const slices =
|
|
585
|
+
const slices = path34.split(SLASH2).filter(Boolean);
|
|
586
586
|
slices.pop();
|
|
587
587
|
if (slices.length) {
|
|
588
588
|
const parent = this._t(
|
|
@@ -595,18 +595,18 @@ var require_ignore = __commonJS({
|
|
|
595
595
|
return parent;
|
|
596
596
|
}
|
|
597
597
|
}
|
|
598
|
-
return this._rules.test(
|
|
598
|
+
return this._rules.test(path34, false, MODE_CHECK_IGNORE);
|
|
599
599
|
}
|
|
600
|
-
_t(
|
|
601
|
-
if (
|
|
602
|
-
return cache[
|
|
600
|
+
_t(path34, cache, checkUnignored, slices) {
|
|
601
|
+
if (path34 in cache) {
|
|
602
|
+
return cache[path34];
|
|
603
603
|
}
|
|
604
604
|
if (!slices) {
|
|
605
|
-
slices =
|
|
605
|
+
slices = path34.split(SLASH2).filter(Boolean);
|
|
606
606
|
}
|
|
607
607
|
slices.pop();
|
|
608
608
|
if (!slices.length) {
|
|
609
|
-
return cache[
|
|
609
|
+
return cache[path34] = this._rules.test(path34, checkUnignored, MODE_IGNORE);
|
|
610
610
|
}
|
|
611
611
|
const parent = this._t(
|
|
612
612
|
slices.join(SLASH2) + SLASH2,
|
|
@@ -614,29 +614,29 @@ var require_ignore = __commonJS({
|
|
|
614
614
|
checkUnignored,
|
|
615
615
|
slices
|
|
616
616
|
);
|
|
617
|
-
return cache[
|
|
617
|
+
return cache[path34] = parent.ignored ? parent : this._rules.test(path34, checkUnignored, MODE_IGNORE);
|
|
618
618
|
}
|
|
619
|
-
ignores(
|
|
620
|
-
return this._test(
|
|
619
|
+
ignores(path34) {
|
|
620
|
+
return this._test(path34, this._ignoreCache, false).ignored;
|
|
621
621
|
}
|
|
622
622
|
createFilter() {
|
|
623
|
-
return (
|
|
623
|
+
return (path34) => !this.ignores(path34);
|
|
624
624
|
}
|
|
625
625
|
filter(paths) {
|
|
626
626
|
return makeArray(paths).filter(this.createFilter());
|
|
627
627
|
}
|
|
628
628
|
// @returns {TestResult}
|
|
629
|
-
test(
|
|
630
|
-
return this._test(
|
|
629
|
+
test(path34) {
|
|
630
|
+
return this._test(path34, this._testCache, true);
|
|
631
631
|
}
|
|
632
632
|
};
|
|
633
633
|
var factory = (options) => new Ignore2(options);
|
|
634
|
-
var isPathValid = (
|
|
634
|
+
var isPathValid = (path34) => checkPath(path34 && checkPath.convert(path34), path34, RETURN_FALSE);
|
|
635
635
|
var setupWindows = () => {
|
|
636
636
|
const makePosix = (str) => /^\\\\\?\\/.test(str) || /["<>|\u0000-\u001F]+/u.test(str) ? str : str.replace(/\\/g, "/");
|
|
637
637
|
checkPath.convert = makePosix;
|
|
638
638
|
const REGEX_TEST_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i;
|
|
639
|
-
checkPath.isNotRelative = (
|
|
639
|
+
checkPath.isNotRelative = (path34) => REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path34) || isNotRelative(path34);
|
|
640
640
|
};
|
|
641
641
|
if (
|
|
642
642
|
// Detect `process` so that it can run in browsers.
|
|
@@ -653,9 +653,9 @@ var require_ignore = __commonJS({
|
|
|
653
653
|
|
|
654
654
|
// src/adapters/mcp/cli.ts
|
|
655
655
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
656
|
-
import { realpathSync as
|
|
657
|
-
import * as
|
|
658
|
-
import * as
|
|
656
|
+
import { realpathSync as realpathSync7, writeFileSync as writeFileSync7 } from "fs";
|
|
657
|
+
import * as os9 from "os";
|
|
658
|
+
import * as path33 from "path";
|
|
659
659
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
660
660
|
|
|
661
661
|
// src/config/constants.ts
|
|
@@ -1183,9 +1183,9 @@ import { mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
|
1183
1183
|
import * as path from "path";
|
|
1184
1184
|
|
|
1185
1185
|
// src/eval/report-formatters.ts
|
|
1186
|
-
function assertFiniteNumber(value,
|
|
1186
|
+
function assertFiniteNumber(value, path34) {
|
|
1187
1187
|
if (typeof value !== "number" || Number.isNaN(value) || !Number.isFinite(value)) {
|
|
1188
|
-
throw new Error(`${
|
|
1188
|
+
throw new Error(`${path34} must be a finite number`);
|
|
1189
1189
|
}
|
|
1190
1190
|
return value;
|
|
1191
1191
|
}
|
|
@@ -1424,8 +1424,8 @@ function buildPerQueryArtifact(perQuery) {
|
|
|
1424
1424
|
|
|
1425
1425
|
// src/eval/runner.ts
|
|
1426
1426
|
import * as crypto2 from "crypto";
|
|
1427
|
-
import { existsSync as
|
|
1428
|
-
import * as
|
|
1427
|
+
import { existsSync as existsSync15 } from "fs";
|
|
1428
|
+
import * as path24 from "path";
|
|
1429
1429
|
import { performance as performance3 } from "perf_hooks";
|
|
1430
1430
|
|
|
1431
1431
|
// src/indexer/index.ts
|
|
@@ -1457,7 +1457,7 @@ function pTimeout(promise, options) {
|
|
|
1457
1457
|
} = options;
|
|
1458
1458
|
let timer;
|
|
1459
1459
|
let abortHandler;
|
|
1460
|
-
const wrappedPromise = new Promise((
|
|
1460
|
+
const wrappedPromise = new Promise((resolve21, reject) => {
|
|
1461
1461
|
if (typeof milliseconds !== "number" || Math.sign(milliseconds) !== 1) {
|
|
1462
1462
|
throw new TypeError(`Expected \`milliseconds\` to be a positive number, got \`${milliseconds}\``);
|
|
1463
1463
|
}
|
|
@@ -1471,7 +1471,7 @@ function pTimeout(promise, options) {
|
|
|
1471
1471
|
};
|
|
1472
1472
|
signal.addEventListener("abort", abortHandler, { once: true });
|
|
1473
1473
|
}
|
|
1474
|
-
promise.then(
|
|
1474
|
+
promise.then(resolve21, reject);
|
|
1475
1475
|
if (milliseconds === Number.POSITIVE_INFINITY) {
|
|
1476
1476
|
return;
|
|
1477
1477
|
}
|
|
@@ -1479,7 +1479,7 @@ function pTimeout(promise, options) {
|
|
|
1479
1479
|
timer = customTimers.setTimeout.call(void 0, () => {
|
|
1480
1480
|
if (fallback) {
|
|
1481
1481
|
try {
|
|
1482
|
-
|
|
1482
|
+
resolve21(fallback());
|
|
1483
1483
|
} catch (error) {
|
|
1484
1484
|
reject(error);
|
|
1485
1485
|
}
|
|
@@ -1489,7 +1489,7 @@ function pTimeout(promise, options) {
|
|
|
1489
1489
|
promise.cancel();
|
|
1490
1490
|
}
|
|
1491
1491
|
if (message === false) {
|
|
1492
|
-
|
|
1492
|
+
resolve21();
|
|
1493
1493
|
} else if (message instanceof Error) {
|
|
1494
1494
|
reject(message);
|
|
1495
1495
|
} else {
|
|
@@ -1891,7 +1891,7 @@ var PQueue = class extends import_index.default {
|
|
|
1891
1891
|
// Assign unique ID if not provided
|
|
1892
1892
|
id: options.id ?? (this.#idAssigner++).toString()
|
|
1893
1893
|
};
|
|
1894
|
-
return new Promise((
|
|
1894
|
+
return new Promise((resolve21, reject) => {
|
|
1895
1895
|
const taskSymbol = /* @__PURE__ */ Symbol(`task-${options.id}`);
|
|
1896
1896
|
let cleanupQueueAbortHandler = () => void 0;
|
|
1897
1897
|
const run = async () => {
|
|
@@ -1931,7 +1931,7 @@ var PQueue = class extends import_index.default {
|
|
|
1931
1931
|
})]);
|
|
1932
1932
|
}
|
|
1933
1933
|
const result = await operation;
|
|
1934
|
-
|
|
1934
|
+
resolve21(result);
|
|
1935
1935
|
this.emit("completed", result);
|
|
1936
1936
|
} catch (error) {
|
|
1937
1937
|
reject(error);
|
|
@@ -2119,13 +2119,13 @@ var PQueue = class extends import_index.default {
|
|
|
2119
2119
|
});
|
|
2120
2120
|
}
|
|
2121
2121
|
async #onEvent(event, filter) {
|
|
2122
|
-
return new Promise((
|
|
2122
|
+
return new Promise((resolve21) => {
|
|
2123
2123
|
const listener = () => {
|
|
2124
2124
|
if (filter && !filter()) {
|
|
2125
2125
|
return;
|
|
2126
2126
|
}
|
|
2127
2127
|
this.off(event, listener);
|
|
2128
|
-
|
|
2128
|
+
resolve21();
|
|
2129
2129
|
};
|
|
2130
2130
|
this.on(event, listener);
|
|
2131
2131
|
});
|
|
@@ -2411,7 +2411,7 @@ async function onAttemptFailure({ error, attemptNumber, retriesConsumed, startTi
|
|
|
2411
2411
|
const finalDelay = Math.min(delayTime, remainingTime);
|
|
2412
2412
|
options.signal?.throwIfAborted();
|
|
2413
2413
|
if (finalDelay > 0) {
|
|
2414
|
-
await new Promise((
|
|
2414
|
+
await new Promise((resolve21, reject) => {
|
|
2415
2415
|
const onAbort = () => {
|
|
2416
2416
|
clearTimeout(timeoutToken);
|
|
2417
2417
|
options.signal?.removeEventListener("abort", onAbort);
|
|
@@ -2419,7 +2419,7 @@ async function onAttemptFailure({ error, attemptNumber, retriesConsumed, startTi
|
|
|
2419
2419
|
};
|
|
2420
2420
|
const timeoutToken = setTimeout(() => {
|
|
2421
2421
|
options.signal?.removeEventListener("abort", onAbort);
|
|
2422
|
-
|
|
2422
|
+
resolve21();
|
|
2423
2423
|
}, finalDelay);
|
|
2424
2424
|
if (options.unref) {
|
|
2425
2425
|
timeoutToken.unref?.();
|
|
@@ -2781,17 +2781,17 @@ function validateExternalUrl(urlString) {
|
|
|
2781
2781
|
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
2782
2782
|
return { valid: false, reason: `Blocked protocol: ${parsed.protocol}` };
|
|
2783
2783
|
}
|
|
2784
|
-
const
|
|
2785
|
-
if (BLOCKED_HOSTNAMES.has(
|
|
2786
|
-
return { valid: false, reason: `Blocked: cloud metadata service (${
|
|
2784
|
+
const hostname3 = parsed.hostname.toLowerCase();
|
|
2785
|
+
if (BLOCKED_HOSTNAMES.has(hostname3)) {
|
|
2786
|
+
return { valid: false, reason: `Blocked: cloud metadata service (${hostname3})` };
|
|
2787
2787
|
}
|
|
2788
2788
|
for (const pattern of BLOCKED_METADATA_IPS) {
|
|
2789
|
-
if (pattern.test(
|
|
2790
|
-
return { valid: false, reason: `Blocked: cloud metadata IP (${
|
|
2789
|
+
if (pattern.test(hostname3)) {
|
|
2790
|
+
return { valid: false, reason: `Blocked: cloud metadata IP (${hostname3})` };
|
|
2791
2791
|
}
|
|
2792
2792
|
}
|
|
2793
|
-
if (/^169\.254\./.test(
|
|
2794
|
-
return { valid: false, reason: `Blocked: link-local address (${
|
|
2793
|
+
if (/^169\.254\./.test(hostname3)) {
|
|
2794
|
+
return { valid: false, reason: `Blocked: link-local address (${hostname3})` };
|
|
2795
2795
|
}
|
|
2796
2796
|
return { valid: true };
|
|
2797
2797
|
}
|
|
@@ -3377,26 +3377,46 @@ function createIgnoreFilter(projectRoot) {
|
|
|
3377
3377
|
}
|
|
3378
3378
|
return ig;
|
|
3379
3379
|
}
|
|
3380
|
-
function
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3380
|
+
function toPosixRelativePath(relativePath) {
|
|
3381
|
+
return relativePath.split(path4.sep).join("/");
|
|
3382
|
+
}
|
|
3383
|
+
function matchesAnyGlob(filePath, patterns) {
|
|
3384
|
+
const normalized = toPosixRelativePath(filePath);
|
|
3385
|
+
return patterns.some((pattern) => matchGlob(normalized, pattern));
|
|
3386
|
+
}
|
|
3387
|
+
function isExcludedByPatterns(relativePath, excludePatterns) {
|
|
3388
|
+
return matchesAnyGlob(relativePath, excludePatterns);
|
|
3389
|
+
}
|
|
3390
|
+
function isExcludedDirectory(relativePath, excludePatterns) {
|
|
3391
|
+
const normalized = toPosixRelativePath(relativePath);
|
|
3392
|
+
if (matchesAnyGlob(normalized, excludePatterns)) {
|
|
3393
|
+
return true;
|
|
3387
3394
|
}
|
|
3388
3395
|
for (const pattern of excludePatterns) {
|
|
3389
|
-
|
|
3390
|
-
|
|
3396
|
+
const posixPattern = toPosixRelativePath(pattern).replace(/\/+$/, "");
|
|
3397
|
+
if (!posixPattern.endsWith("/**")) {
|
|
3398
|
+
continue;
|
|
3391
3399
|
}
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
if (matchGlob(relativePath, pattern)) {
|
|
3400
|
+
const directoryPattern = posixPattern.slice(0, -3);
|
|
3401
|
+
if (directoryPattern && matchesAnyGlob(normalized, [directoryPattern])) {
|
|
3395
3402
|
return true;
|
|
3396
3403
|
}
|
|
3397
3404
|
}
|
|
3398
3405
|
return false;
|
|
3399
3406
|
}
|
|
3407
|
+
function shouldIncludeFile(filePath, projectRoot, includePatterns, excludePatterns, ignoreFilter) {
|
|
3408
|
+
const relativePath = toPosixRelativePath(path4.relative(projectRoot, filePath));
|
|
3409
|
+
if (hasFilteredPathSegment(relativePath, "/")) {
|
|
3410
|
+
return false;
|
|
3411
|
+
}
|
|
3412
|
+
if (ignoreFilter.ignores(relativePath)) {
|
|
3413
|
+
return false;
|
|
3414
|
+
}
|
|
3415
|
+
if (isExcludedByPatterns(relativePath, excludePatterns)) {
|
|
3416
|
+
return false;
|
|
3417
|
+
}
|
|
3418
|
+
return matchesAnyGlob(relativePath, includePatterns);
|
|
3419
|
+
}
|
|
3400
3420
|
function matchGlob(filePath, pattern) {
|
|
3401
3421
|
if (pattern.startsWith("**/")) {
|
|
3402
3422
|
const withoutPrefix = pattern.slice(3);
|
|
@@ -3418,7 +3438,7 @@ async function* walkDirectory(dir, projectRoot, includePatterns, excludePatterns
|
|
|
3418
3438
|
const subdirs = [];
|
|
3419
3439
|
for (const entry of entries) {
|
|
3420
3440
|
const fullPath = path4.join(dir, entry.name);
|
|
3421
|
-
const relativePath = path4.relative(projectRoot, fullPath);
|
|
3441
|
+
const relativePath = toPosixRelativePath(path4.relative(projectRoot, fullPath));
|
|
3422
3442
|
if (isHiddenPathSegment(entry.name)) {
|
|
3423
3443
|
if (entry.isDirectory()) {
|
|
3424
3444
|
skipped.push({ path: relativePath, reason: "excluded" });
|
|
@@ -3436,6 +3456,10 @@ async function* walkDirectory(dir, projectRoot, includePatterns, excludePatterns
|
|
|
3436
3456
|
continue;
|
|
3437
3457
|
}
|
|
3438
3458
|
if (entry.isDirectory()) {
|
|
3459
|
+
if (isExcludedDirectory(relativePath, excludePatterns)) {
|
|
3460
|
+
skipped.push({ path: relativePath, reason: "excluded" });
|
|
3461
|
+
continue;
|
|
3462
|
+
}
|
|
3439
3463
|
subdirs.push({ fullPath, relativePath });
|
|
3440
3464
|
} else if (entry.isFile()) {
|
|
3441
3465
|
const stat5 = await fsPromises.stat(fullPath);
|
|
@@ -3443,20 +3467,11 @@ async function* walkDirectory(dir, projectRoot, includePatterns, excludePatterns
|
|
|
3443
3467
|
skipped.push({ path: relativePath, reason: "too_large" });
|
|
3444
3468
|
continue;
|
|
3445
3469
|
}
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
continue;
|
|
3450
|
-
}
|
|
3451
|
-
}
|
|
3452
|
-
let matched = false;
|
|
3453
|
-
for (const pattern of includePatterns) {
|
|
3454
|
-
if (matchGlob(relativePath, pattern)) {
|
|
3455
|
-
matched = true;
|
|
3456
|
-
break;
|
|
3457
|
-
}
|
|
3470
|
+
if (isExcludedByPatterns(relativePath, excludePatterns)) {
|
|
3471
|
+
skipped.push({ path: relativePath, reason: "excluded" });
|
|
3472
|
+
continue;
|
|
3458
3473
|
}
|
|
3459
|
-
if (
|
|
3474
|
+
if (matchesAnyGlob(relativePath, includePatterns)) {
|
|
3460
3475
|
filesInDir.push({ path: fullPath, size: stat5.size });
|
|
3461
3476
|
}
|
|
3462
3477
|
}
|
|
@@ -3467,7 +3482,7 @@ async function* walkDirectory(dir, projectRoot, includePatterns, excludePatterns
|
|
|
3467
3482
|
yield f;
|
|
3468
3483
|
}
|
|
3469
3484
|
for (let i = options.maxFilesPerDirectory; i < filesInDir.length; i++) {
|
|
3470
|
-
skipped.push({ path: path4.relative(projectRoot, filesInDir[i].path), reason: "excluded" });
|
|
3485
|
+
skipped.push({ path: toPosixRelativePath(path4.relative(projectRoot, filesInDir[i].path)), reason: "excluded" });
|
|
3471
3486
|
}
|
|
3472
3487
|
const canRecurse = options.maxDepth === -1 || currentDepth < options.maxDepth;
|
|
3473
3488
|
if (canRecurse) {
|
|
@@ -7087,8 +7102,8 @@ function pathSegmentsForAffinityMatch(filePath) {
|
|
|
7087
7102
|
if (segments.length === 0) {
|
|
7088
7103
|
return [];
|
|
7089
7104
|
}
|
|
7090
|
-
const
|
|
7091
|
-
const basenameWithoutExt =
|
|
7105
|
+
const basename9 = segments[segments.length - 1] ?? "";
|
|
7106
|
+
const basenameWithoutExt = basename9.replace(/\.[^/.]+$/u, "");
|
|
7092
7107
|
const normalizedSegments = segments.map((segment) => segment.toLowerCase());
|
|
7093
7108
|
return Array.from(/* @__PURE__ */ new Set([
|
|
7094
7109
|
...normalizedSegments,
|
|
@@ -7511,7 +7526,7 @@ function removeDeadReclaimMarker(lockPath, expectedOwner) {
|
|
|
7511
7526
|
return true;
|
|
7512
7527
|
}
|
|
7513
7528
|
function reclaimDeadOwner(indexPath, lockPath, expectedOwner) {
|
|
7514
|
-
const
|
|
7529
|
+
const reclaimPath2 = path13.join(lockPath, RECLAIM_DIRECTORY_NAME);
|
|
7515
7530
|
const reclaimOwner = {
|
|
7516
7531
|
pid: process.pid,
|
|
7517
7532
|
hostname: os5.hostname(),
|
|
@@ -7520,19 +7535,19 @@ function reclaimDeadOwner(indexPath, lockPath, expectedOwner) {
|
|
|
7520
7535
|
expectedOwnerToken: expectedOwner.token
|
|
7521
7536
|
};
|
|
7522
7537
|
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
7523
|
-
if (publishJsonDirectory(
|
|
7538
|
+
if (publishJsonDirectory(reclaimPath2, reclaimOwner)) break;
|
|
7524
7539
|
if (attempt === 0 && removeDeadReclaimMarker(lockPath, expectedOwner)) continue;
|
|
7525
7540
|
return false;
|
|
7526
7541
|
}
|
|
7527
7542
|
try {
|
|
7528
|
-
const currentReclaimer = readReclaimOwner(
|
|
7543
|
+
const currentReclaimer = readReclaimOwner(reclaimPath2);
|
|
7529
7544
|
const currentOwner = readDirectoryOwner(lockPath);
|
|
7530
7545
|
if (!currentReclaimer || !sameReclaimOwner(currentReclaimer, reclaimOwner) || !currentOwner || !sameOwner(currentOwner, expectedOwner) || getOwnerLiveness(currentOwner) !== "dead") {
|
|
7531
7546
|
return false;
|
|
7532
7547
|
}
|
|
7533
7548
|
publishRecoveryMarker(indexPath, expectedOwner);
|
|
7534
7549
|
const ownerBeforeQuarantine = readDirectoryOwner(lockPath);
|
|
7535
|
-
const reclaimerBeforeQuarantine = readReclaimOwner(
|
|
7550
|
+
const reclaimerBeforeQuarantine = readReclaimOwner(reclaimPath2);
|
|
7536
7551
|
if (!ownerBeforeQuarantine || !sameOwner(ownerBeforeQuarantine, expectedOwner) || getOwnerLiveness(ownerBeforeQuarantine) !== "dead" || !reclaimerBeforeQuarantine || !sameReclaimOwner(reclaimerBeforeQuarantine, reclaimOwner)) {
|
|
7537
7552
|
return false;
|
|
7538
7553
|
}
|
|
@@ -8748,6 +8763,17 @@ var Indexer = class _Indexer {
|
|
|
8748
8763
|
}
|
|
8749
8764
|
return path15.relative(this.projectRoot, canonicalFilePath).split(path15.sep).join("/");
|
|
8750
8765
|
}
|
|
8766
|
+
isStoredPathExcluded(storedPath) {
|
|
8767
|
+
let matchPath = storedPath.split(path15.sep).join("/");
|
|
8768
|
+
if (path15.isAbsolute(storedPath)) {
|
|
8769
|
+
const relativePath = path15.relative(this.projectRoot, storedPath).split(path15.sep).join("/");
|
|
8770
|
+
if (relativePath.startsWith("..") || path15.isAbsolute(relativePath)) {
|
|
8771
|
+
return false;
|
|
8772
|
+
}
|
|
8773
|
+
matchPath = relativePath;
|
|
8774
|
+
}
|
|
8775
|
+
return isExcludedByPatterns(matchPath, this.config.exclude);
|
|
8776
|
+
}
|
|
8751
8777
|
resolveStoredFilePath(filePath, rootPath = this.projectRoot) {
|
|
8752
8778
|
if (path15.isAbsolute(filePath)) {
|
|
8753
8779
|
return filePath;
|
|
@@ -9772,7 +9798,7 @@ var Indexer = class _Indexer {
|
|
|
9772
9798
|
await options.queue.onSizeLessThan(Math.max(1, options.providerRateLimits.concurrency));
|
|
9773
9799
|
const task = options.queue.add(async () => {
|
|
9774
9800
|
if (options.rateLimitState.backoffMs > 0) {
|
|
9775
|
-
await new Promise((
|
|
9801
|
+
await new Promise((resolve21) => setTimeout(resolve21, options.rateLimitState.backoffMs));
|
|
9776
9802
|
}
|
|
9777
9803
|
try {
|
|
9778
9804
|
const embeddingResult = await pRetry(
|
|
@@ -11149,7 +11175,7 @@ var Indexer = class _Indexer {
|
|
|
11149
11175
|
}
|
|
11150
11176
|
}
|
|
11151
11177
|
}
|
|
11152
|
-
const shouldRetryFailedPath = (filePath) => filePath !== null && currentFileHashes.has(filePath) && unchangedFilePaths.has(filePath);
|
|
11178
|
+
const shouldRetryFailedPath = (filePath) => filePath !== null && !this.isStoredPathExcluded(filePath) && currentFileHashes.has(filePath) && unchangedFilePaths.has(filePath);
|
|
11153
11179
|
const failedProcessing = this.prepareFailedBatchProcessing(scopedRoots, shouldRetryFailedPath);
|
|
11154
11180
|
const maxChunkTokens = getSafeEmbeddingChunkTokenLimit(configuredProviderInfo);
|
|
11155
11181
|
const providerRateLimits = this.getProviderRateLimits(configuredProviderInfo.provider);
|
|
@@ -12477,7 +12503,8 @@ var Indexer = class _Indexer {
|
|
|
12477
12503
|
const maxChunkTokens = getSafeEmbeddingChunkTokenLimit(configuredProviderInfo);
|
|
12478
12504
|
const providerRateLimits = this.getProviderRateLimits(configuredProviderInfo.provider);
|
|
12479
12505
|
const roots = this.config.scope === "global" ? this.getScopedRoots() : null;
|
|
12480
|
-
const
|
|
12506
|
+
const shouldProcessFailedPath = (filePath) => filePath === null || !this.isStoredPathExcluded(filePath);
|
|
12507
|
+
const failedProcessing = this.prepareFailedBatchProcessing(roots, shouldProcessFailedPath);
|
|
12481
12508
|
if (failedProcessing.latestById.size === 0) {
|
|
12482
12509
|
this.finalizeFailedBatchWriteState(failedProcessing.state);
|
|
12483
12510
|
return { succeeded: 0, failed: 0, remaining: 0 };
|
|
@@ -12490,7 +12517,7 @@ var Indexer = class _Indexer {
|
|
|
12490
12517
|
const retryableChunks = this.iterateLatestFailedChunks(
|
|
12491
12518
|
failedProcessing.latestById,
|
|
12492
12519
|
roots,
|
|
12493
|
-
|
|
12520
|
+
shouldProcessFailedPath,
|
|
12494
12521
|
maxChunkTokens
|
|
12495
12522
|
);
|
|
12496
12523
|
for (const retryBatch of iterateOrderedFileBatches(
|
|
@@ -12760,9 +12787,9 @@ var Indexer = class _Indexer {
|
|
|
12760
12787
|
this.requireReadableComponents(readIssues, "database");
|
|
12761
12788
|
let shortest = [];
|
|
12762
12789
|
for (const branchKey of this.getBranchCatalogKeys()) {
|
|
12763
|
-
const
|
|
12764
|
-
if (
|
|
12765
|
-
shortest =
|
|
12790
|
+
const path34 = database.findShortestPath(fromName, toName, branchKey, maxDepth);
|
|
12791
|
+
if (path34.length > 0 && (shortest.length === 0 || path34.length < shortest.length)) {
|
|
12792
|
+
shortest = path34;
|
|
12766
12793
|
}
|
|
12767
12794
|
}
|
|
12768
12795
|
return shortest.map((hop) => this.resolveFilePathRecord(hop));
|
|
@@ -12810,13 +12837,13 @@ var Indexer = class _Indexer {
|
|
|
12810
12837
|
}
|
|
12811
12838
|
}
|
|
12812
12839
|
if (!found) continue;
|
|
12813
|
-
const
|
|
12840
|
+
const path34 = [];
|
|
12814
12841
|
let currentSymbolId = toSymbolId;
|
|
12815
12842
|
while (true) {
|
|
12816
12843
|
const symbol = symbolsById.get(currentSymbolId);
|
|
12817
12844
|
if (!symbol) break;
|
|
12818
12845
|
const parent = parentBySymbolId.get(currentSymbolId);
|
|
12819
|
-
|
|
12846
|
+
path34.push({
|
|
12820
12847
|
symbolId: symbol.id,
|
|
12821
12848
|
symbolName: symbol.name,
|
|
12822
12849
|
filePath: symbol.filePath,
|
|
@@ -12826,9 +12853,9 @@ var Indexer = class _Indexer {
|
|
|
12826
12853
|
if (!parent) break;
|
|
12827
12854
|
currentSymbolId = parent.parentId;
|
|
12828
12855
|
}
|
|
12829
|
-
|
|
12830
|
-
if (
|
|
12831
|
-
shortest =
|
|
12856
|
+
path34.reverse();
|
|
12857
|
+
if (path34.length > 0 && (shortest.length === 0 || path34.length < shortest.length)) {
|
|
12858
|
+
shortest = path34;
|
|
12832
12859
|
}
|
|
12833
12860
|
}
|
|
12834
12861
|
return shortest.map((hop) => this.resolveFilePathRecord(hop));
|
|
@@ -13211,8 +13238,8 @@ var CODE_COMMUNITIES_DEFAULT_COUPLING_LIMIT = 20;
|
|
|
13211
13238
|
var CODE_COMMUNITIES_MAX_COUPLING_LIMIT = 100;
|
|
13212
13239
|
|
|
13213
13240
|
// src/tools/operations.ts
|
|
13214
|
-
import { existsSync as
|
|
13215
|
-
import * as
|
|
13241
|
+
import { existsSync as existsSync13, realpathSync as realpathSync6, statSync as statSync5 } from "fs";
|
|
13242
|
+
import * as path22 from "path";
|
|
13216
13243
|
|
|
13217
13244
|
// src/tools/knowledge-base-paths.ts
|
|
13218
13245
|
import * as path16 from "path";
|
|
@@ -13507,8 +13534,8 @@ function formatExactSearchHandoff(results) {
|
|
|
13507
13534
|
}
|
|
13508
13535
|
function formatContextEvidence(result, index) {
|
|
13509
13536
|
const symbol = result.name ? ` ${JSON.stringify(compactEvidenceValue(result.name, 80))}` : "";
|
|
13510
|
-
const
|
|
13511
|
-
return `[${index}] ${result.chunkType}${symbol} in ${
|
|
13537
|
+
const path34 = compactEvidenceValue(result.filePath, 120);
|
|
13538
|
+
return `[${index}] ${result.chunkType}${symbol} in ${path34}:${result.startLine}-${result.endLine} (score ${result.score.toFixed(2)})`;
|
|
13512
13539
|
}
|
|
13513
13540
|
function formatContextPack(heading, selected, candidateCount, duplicateCount, limitOmittedCount, budgetOmittedCount, includeExactSearchHandoff) {
|
|
13514
13541
|
const lines = selected.map((result, index) => formatContextEvidence(result, index + 1));
|
|
@@ -14150,9 +14177,907 @@ function formatEffectivenessMetrics(snapshot) {
|
|
|
14150
14177
|
}
|
|
14151
14178
|
|
|
14152
14179
|
// src/utils/auto-index.ts
|
|
14153
|
-
import { existsSync as
|
|
14180
|
+
import { existsSync as existsSync10, realpathSync as realpathSync5 } from "fs";
|
|
14181
|
+
import * as os7 from "os";
|
|
14182
|
+
import * as path18 from "path";
|
|
14183
|
+
|
|
14184
|
+
// src/utils/background-worker.ts
|
|
14185
|
+
import { createHash as createHash2, randomUUID as randomUUID2 } from "crypto";
|
|
14186
|
+
import {
|
|
14187
|
+
existsSync as existsSync9,
|
|
14188
|
+
lstatSync as lstatSync2,
|
|
14189
|
+
mkdirSync as mkdirSync5,
|
|
14190
|
+
readFileSync as readFileSync9,
|
|
14191
|
+
realpathSync as realpathSync4,
|
|
14192
|
+
renameSync as renameSync4,
|
|
14193
|
+
rmSync as rmSync3,
|
|
14194
|
+
writeFileSync as writeFileSync4
|
|
14195
|
+
} from "fs";
|
|
14154
14196
|
import * as os6 from "os";
|
|
14155
14197
|
import * as path17 from "path";
|
|
14198
|
+
var OWNER_FILE_NAME2 = "owner.json";
|
|
14199
|
+
var HEARTBEAT_FILE_PREFIX = "heartbeat.";
|
|
14200
|
+
var RECLAIM_DIRECTORY_NAME2 = "reclaim";
|
|
14201
|
+
var REFRESH_REQUEST_FILE_NAME = "refresh-request.json";
|
|
14202
|
+
var HEARTBEAT_INTERVAL_MS = 5e3;
|
|
14203
|
+
var STALE_LEASE_MS = 3e4;
|
|
14204
|
+
var RETRY_DELAY_MS = 5e3;
|
|
14205
|
+
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;
|
|
14206
|
+
var BackgroundWorkerStopError = class extends Error {
|
|
14207
|
+
constructor(watcherError, autoIndexError) {
|
|
14208
|
+
super("Failed to stop background worker");
|
|
14209
|
+
this.watcherError = watcherError;
|
|
14210
|
+
this.autoIndexError = autoIndexError;
|
|
14211
|
+
this.name = "BackgroundWorkerStopError";
|
|
14212
|
+
}
|
|
14213
|
+
watcherError;
|
|
14214
|
+
autoIndexError;
|
|
14215
|
+
};
|
|
14216
|
+
var workers = /* @__PURE__ */ new Map();
|
|
14217
|
+
var workerKeysByProject = /* @__PURE__ */ new Map();
|
|
14218
|
+
var workerReplacementBarriers = /* @__PURE__ */ new Map();
|
|
14219
|
+
function getErrorCode2(error) {
|
|
14220
|
+
return typeof error === "object" && error !== null && "code" in error ? String(error.code) : void 0;
|
|
14221
|
+
}
|
|
14222
|
+
function canonicalizePath(targetPath) {
|
|
14223
|
+
const resolved = path17.resolve(targetPath);
|
|
14224
|
+
if (existsSync9(resolved)) {
|
|
14225
|
+
try {
|
|
14226
|
+
return realpathSync4.native(resolved);
|
|
14227
|
+
} catch {
|
|
14228
|
+
return resolved;
|
|
14229
|
+
}
|
|
14230
|
+
}
|
|
14231
|
+
const parent = path17.dirname(resolved);
|
|
14232
|
+
if (parent === resolved) return resolved;
|
|
14233
|
+
return path17.join(canonicalizePath(parent), path17.basename(resolved));
|
|
14234
|
+
}
|
|
14235
|
+
function projectLookupKey(projectRoot, host) {
|
|
14236
|
+
return `${host}::${canonicalizePath(projectRoot)}`;
|
|
14237
|
+
}
|
|
14238
|
+
function getBackgroundWorkerProjectKey(projectRoot, host) {
|
|
14239
|
+
return projectLookupKey(projectRoot, host);
|
|
14240
|
+
}
|
|
14241
|
+
function resolveIdentity(projectRoot, config, host) {
|
|
14242
|
+
const canonicalProjectRoot = canonicalizePath(projectRoot);
|
|
14243
|
+
const canonicalIndexPath = canonicalizePath(resolveProjectIndexPath(projectRoot, config.scope, host));
|
|
14244
|
+
return {
|
|
14245
|
+
canonicalIndexPath,
|
|
14246
|
+
canonicalProjectRoot,
|
|
14247
|
+
key: `${canonicalIndexPath}::${canonicalProjectRoot}`
|
|
14248
|
+
};
|
|
14249
|
+
}
|
|
14250
|
+
function controllerKey(identity, host) {
|
|
14251
|
+
return `${identity.key}::${host}`;
|
|
14252
|
+
}
|
|
14253
|
+
function leaseDirectoryName(identity) {
|
|
14254
|
+
const hash = createHash2("sha256").update(identity.key).digest("hex").slice(0, 32);
|
|
14255
|
+
return `background-worker.${hash}.lease`;
|
|
14256
|
+
}
|
|
14257
|
+
function leasePathFor(identity) {
|
|
14258
|
+
return path17.join(identity.canonicalIndexPath, leaseDirectoryName(identity));
|
|
14259
|
+
}
|
|
14260
|
+
function parseOwner2(value) {
|
|
14261
|
+
if (typeof value !== "object" || value === null) return null;
|
|
14262
|
+
const candidate = value;
|
|
14263
|
+
if (candidate.version !== 1) return null;
|
|
14264
|
+
if (!Number.isInteger(candidate.pid) || (candidate.pid ?? 0) <= 0) return null;
|
|
14265
|
+
if (typeof candidate.hostname !== "string" || candidate.hostname.length === 0) return null;
|
|
14266
|
+
if (typeof candidate.startedAt !== "string" || Number.isNaN(Date.parse(candidate.startedAt))) return null;
|
|
14267
|
+
if (typeof candidate.heartbeatAt !== "string" || Number.isNaN(Date.parse(candidate.heartbeatAt))) return null;
|
|
14268
|
+
if (typeof candidate.projectRoot !== "string" || candidate.projectRoot.length === 0) return null;
|
|
14269
|
+
if (typeof candidate.indexPath !== "string" || candidate.indexPath.length === 0) return null;
|
|
14270
|
+
if (typeof candidate.token !== "string" || !UUID_PATTERN2.test(candidate.token)) return null;
|
|
14271
|
+
return candidate;
|
|
14272
|
+
}
|
|
14273
|
+
function parseHeartbeat(value, expectedToken) {
|
|
14274
|
+
if (typeof value !== "object" || value === null) return null;
|
|
14275
|
+
const candidate = value;
|
|
14276
|
+
if (candidate.version !== 1 || candidate.token !== expectedToken) return null;
|
|
14277
|
+
if (typeof candidate.heartbeatAt !== "string" || Number.isNaN(Date.parse(candidate.heartbeatAt))) return null;
|
|
14278
|
+
return candidate;
|
|
14279
|
+
}
|
|
14280
|
+
function parseReclaimOwner2(value) {
|
|
14281
|
+
if (typeof value !== "object" || value === null) return null;
|
|
14282
|
+
const candidate = value;
|
|
14283
|
+
if (candidate.version !== 1) return null;
|
|
14284
|
+
if (!Number.isInteger(candidate.pid) || (candidate.pid ?? 0) <= 0) return null;
|
|
14285
|
+
if (typeof candidate.hostname !== "string" || candidate.hostname.length === 0) return null;
|
|
14286
|
+
if (typeof candidate.startedAt !== "string" || Number.isNaN(Date.parse(candidate.startedAt))) return null;
|
|
14287
|
+
if (typeof candidate.token !== "string" || !UUID_PATTERN2.test(candidate.token)) return null;
|
|
14288
|
+
if (candidate.expectedOwnerToken !== null && (typeof candidate.expectedOwnerToken !== "string" || !UUID_PATTERN2.test(candidate.expectedOwnerToken))) return null;
|
|
14289
|
+
return candidate;
|
|
14290
|
+
}
|
|
14291
|
+
function heartbeatPath(leasePath, token) {
|
|
14292
|
+
return path17.join(leasePath, `${HEARTBEAT_FILE_PREFIX}${token}.json`);
|
|
14293
|
+
}
|
|
14294
|
+
function reclaimPath(leasePath) {
|
|
14295
|
+
return path17.join(leasePath, RECLAIM_DIRECTORY_NAME2);
|
|
14296
|
+
}
|
|
14297
|
+
function refreshRequestPath(leasePath) {
|
|
14298
|
+
return path17.join(leasePath, REFRESH_REQUEST_FILE_NAME);
|
|
14299
|
+
}
|
|
14300
|
+
function readLeaseOwner(leasePath) {
|
|
14301
|
+
try {
|
|
14302
|
+
return parseOwner2(JSON.parse(readFileSync9(path17.join(leasePath, OWNER_FILE_NAME2), "utf-8")));
|
|
14303
|
+
} catch {
|
|
14304
|
+
return null;
|
|
14305
|
+
}
|
|
14306
|
+
}
|
|
14307
|
+
function readOwner(leasePath) {
|
|
14308
|
+
const owner = readLeaseOwner(leasePath);
|
|
14309
|
+
if (!owner) return null;
|
|
14310
|
+
try {
|
|
14311
|
+
const heartbeat = parseHeartbeat(
|
|
14312
|
+
JSON.parse(readFileSync9(heartbeatPath(leasePath, owner.token), "utf-8")),
|
|
14313
|
+
owner.token
|
|
14314
|
+
);
|
|
14315
|
+
return heartbeat ? { ...owner, heartbeatAt: heartbeat.heartbeatAt } : owner;
|
|
14316
|
+
} catch {
|
|
14317
|
+
return owner;
|
|
14318
|
+
}
|
|
14319
|
+
}
|
|
14320
|
+
function readReclaimOwner2(leasePath) {
|
|
14321
|
+
try {
|
|
14322
|
+
return parseReclaimOwner2(JSON.parse(readFileSync9(path17.join(reclaimPath(leasePath), OWNER_FILE_NAME2), "utf-8")));
|
|
14323
|
+
} catch {
|
|
14324
|
+
return null;
|
|
14325
|
+
}
|
|
14326
|
+
}
|
|
14327
|
+
function ownerLiveness(owner) {
|
|
14328
|
+
if (owner.hostname !== os6.hostname()) return "unknown";
|
|
14329
|
+
try {
|
|
14330
|
+
process.kill(owner.pid, 0);
|
|
14331
|
+
return "alive";
|
|
14332
|
+
} catch (error) {
|
|
14333
|
+
const code = getErrorCode2(error);
|
|
14334
|
+
if (code === "ESRCH") return "dead";
|
|
14335
|
+
if (code === "EPERM") return "alive";
|
|
14336
|
+
return "unknown";
|
|
14337
|
+
}
|
|
14338
|
+
}
|
|
14339
|
+
function isHeartbeatExpired(owner) {
|
|
14340
|
+
return Date.now() - Date.parse(owner.heartbeatAt) >= STALE_LEASE_MS;
|
|
14341
|
+
}
|
|
14342
|
+
function sameOwner2(left, right) {
|
|
14343
|
+
return left.pid === right.pid && left.hostname === right.hostname && left.token === right.token;
|
|
14344
|
+
}
|
|
14345
|
+
function writeHeartbeat(leasePath, owner) {
|
|
14346
|
+
const targetPath = heartbeatPath(leasePath, owner.token);
|
|
14347
|
+
const temporaryPath = `${targetPath}.tmp.${process.pid}.${owner.token}.${randomUUID2()}`;
|
|
14348
|
+
const heartbeat = {
|
|
14349
|
+
version: 1,
|
|
14350
|
+
token: owner.token,
|
|
14351
|
+
heartbeatAt: owner.heartbeatAt
|
|
14352
|
+
};
|
|
14353
|
+
try {
|
|
14354
|
+
writeFileSync4(temporaryPath, JSON.stringify(heartbeat), {
|
|
14355
|
+
encoding: "utf-8",
|
|
14356
|
+
flag: "wx",
|
|
14357
|
+
mode: 384
|
|
14358
|
+
});
|
|
14359
|
+
renameSync4(temporaryPath, targetPath);
|
|
14360
|
+
const currentOwner = readLeaseOwner(leasePath);
|
|
14361
|
+
return currentOwner !== null && sameOwner2(currentOwner, owner);
|
|
14362
|
+
} finally {
|
|
14363
|
+
if (existsSync9(temporaryPath)) rmSync3(temporaryPath, { force: true });
|
|
14364
|
+
}
|
|
14365
|
+
}
|
|
14366
|
+
function requestRefreshFromLeader(leasePath, allowDisabledAutoIndex) {
|
|
14367
|
+
const requestPath = refreshRequestPath(leasePath);
|
|
14368
|
+
const temporaryPath = `${requestPath}.tmp.${process.pid}.${randomUUID2()}`;
|
|
14369
|
+
try {
|
|
14370
|
+
const request = {
|
|
14371
|
+
allowDisabledAutoIndex,
|
|
14372
|
+
requestedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
14373
|
+
version: 1
|
|
14374
|
+
};
|
|
14375
|
+
writeFileSync4(temporaryPath, JSON.stringify(request), {
|
|
14376
|
+
encoding: "utf-8",
|
|
14377
|
+
flag: "wx",
|
|
14378
|
+
mode: 384
|
|
14379
|
+
});
|
|
14380
|
+
renameSync4(temporaryPath, requestPath);
|
|
14381
|
+
} catch (error) {
|
|
14382
|
+
if (getErrorCode2(error) !== "ENOENT") {
|
|
14383
|
+
console.error("[codebase-index] Failed to request background index refresh from the project worker:", error);
|
|
14384
|
+
}
|
|
14385
|
+
} finally {
|
|
14386
|
+
if (existsSync9(temporaryPath)) rmSync3(temporaryPath, { force: true });
|
|
14387
|
+
}
|
|
14388
|
+
}
|
|
14389
|
+
function consumeRefreshRequest(leasePath) {
|
|
14390
|
+
const requestPath = refreshRequestPath(leasePath);
|
|
14391
|
+
const claimedPath = `${requestPath}.handling.${process.pid}.${randomUUID2()}`;
|
|
14392
|
+
try {
|
|
14393
|
+
renameSync4(requestPath, claimedPath);
|
|
14394
|
+
} catch (error) {
|
|
14395
|
+
if (getErrorCode2(error) === "ENOENT") return null;
|
|
14396
|
+
throw error;
|
|
14397
|
+
}
|
|
14398
|
+
try {
|
|
14399
|
+
const value = JSON.parse(readFileSync9(claimedPath, "utf-8"));
|
|
14400
|
+
return {
|
|
14401
|
+
allowDisabledAutoIndex: value.version === 1 && value.allowDisabledAutoIndex === true,
|
|
14402
|
+
requestedAt: typeof value.requestedAt === "string" ? value.requestedAt : (/* @__PURE__ */ new Date()).toISOString(),
|
|
14403
|
+
version: 1
|
|
14404
|
+
};
|
|
14405
|
+
} catch {
|
|
14406
|
+
return { allowDisabledAutoIndex: false, requestedAt: (/* @__PURE__ */ new Date()).toISOString(), version: 1 };
|
|
14407
|
+
} finally {
|
|
14408
|
+
rmSync3(claimedPath, { force: true });
|
|
14409
|
+
}
|
|
14410
|
+
}
|
|
14411
|
+
function publishLease(leasePath, owner) {
|
|
14412
|
+
const candidatePath = `${leasePath}.candidate.${process.pid}.${owner.token}`;
|
|
14413
|
+
try {
|
|
14414
|
+
mkdirSync5(candidatePath, { mode: 448 });
|
|
14415
|
+
} catch (error) {
|
|
14416
|
+
if (getErrorCode2(error) === "ENOENT") return false;
|
|
14417
|
+
throw error;
|
|
14418
|
+
}
|
|
14419
|
+
try {
|
|
14420
|
+
writeFileSync4(path17.join(candidatePath, OWNER_FILE_NAME2), JSON.stringify(owner), {
|
|
14421
|
+
encoding: "utf-8",
|
|
14422
|
+
flag: "wx",
|
|
14423
|
+
mode: 384
|
|
14424
|
+
});
|
|
14425
|
+
if (existsSync9(leasePath)) return false;
|
|
14426
|
+
try {
|
|
14427
|
+
renameSync4(candidatePath, leasePath);
|
|
14428
|
+
return true;
|
|
14429
|
+
} catch (error) {
|
|
14430
|
+
if (existsSync9(leasePath) || getErrorCode2(error) === "ENOENT") return false;
|
|
14431
|
+
throw error;
|
|
14432
|
+
}
|
|
14433
|
+
} finally {
|
|
14434
|
+
if (existsSync9(candidatePath)) rmSync3(candidatePath, { recursive: true, force: true });
|
|
14435
|
+
}
|
|
14436
|
+
}
|
|
14437
|
+
function sameReclaimOwner2(left, right) {
|
|
14438
|
+
return left.pid === right.pid && left.hostname === right.hostname && left.token === right.token && left.expectedOwnerToken === right.expectedOwnerToken;
|
|
14439
|
+
}
|
|
14440
|
+
function reclaimerLiveness(owner) {
|
|
14441
|
+
return ownerLiveness(owner);
|
|
14442
|
+
}
|
|
14443
|
+
function isReclaimMarkerExpired(leasePath, owner) {
|
|
14444
|
+
const startedAt = owner ? Date.parse(owner.startedAt) : (() => {
|
|
14445
|
+
try {
|
|
14446
|
+
return lstatSync2(reclaimPath(leasePath)).mtimeMs;
|
|
14447
|
+
} catch {
|
|
14448
|
+
return Date.now();
|
|
14449
|
+
}
|
|
14450
|
+
})();
|
|
14451
|
+
return Date.now() - startedAt >= STALE_LEASE_MS;
|
|
14452
|
+
}
|
|
14453
|
+
function hasActiveReclaimMarker(leasePath, owner) {
|
|
14454
|
+
const marker = readReclaimOwner2(leasePath);
|
|
14455
|
+
return marker !== null && marker.expectedOwnerToken === owner.token && (marker.hostname !== os6.hostname() || ownerLiveness(owner) !== "alive");
|
|
14456
|
+
}
|
|
14457
|
+
function publishReclaimMarker(leasePath, expectedOwner) {
|
|
14458
|
+
const markerPath = reclaimPath(leasePath);
|
|
14459
|
+
const owner = {
|
|
14460
|
+
version: 1,
|
|
14461
|
+
pid: process.pid,
|
|
14462
|
+
hostname: os6.hostname(),
|
|
14463
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
14464
|
+
token: randomUUID2(),
|
|
14465
|
+
expectedOwnerToken: expectedOwner?.token ?? null
|
|
14466
|
+
};
|
|
14467
|
+
try {
|
|
14468
|
+
mkdirSync5(markerPath, { mode: 448 });
|
|
14469
|
+
} catch (error) {
|
|
14470
|
+
if (getErrorCode2(error) === "EEXIST" || getErrorCode2(error) === "ENOENT") return null;
|
|
14471
|
+
throw error;
|
|
14472
|
+
}
|
|
14473
|
+
try {
|
|
14474
|
+
writeFileSync4(path17.join(markerPath, OWNER_FILE_NAME2), JSON.stringify(owner), {
|
|
14475
|
+
encoding: "utf-8",
|
|
14476
|
+
flag: "wx",
|
|
14477
|
+
mode: 384
|
|
14478
|
+
});
|
|
14479
|
+
return owner;
|
|
14480
|
+
} catch (error) {
|
|
14481
|
+
rmSync3(markerPath, { recursive: true, force: true });
|
|
14482
|
+
throw error;
|
|
14483
|
+
}
|
|
14484
|
+
}
|
|
14485
|
+
function removeExpiredReclaimMarker(leasePath, expectedOwner) {
|
|
14486
|
+
const marker = readReclaimOwner2(leasePath);
|
|
14487
|
+
const markerPath = reclaimPath(leasePath);
|
|
14488
|
+
if (!existsSync9(markerPath)) return false;
|
|
14489
|
+
if (marker && marker.expectedOwnerToken !== (expectedOwner?.token ?? null)) return false;
|
|
14490
|
+
if (marker && (reclaimerLiveness(marker) === "alive" || !isReclaimMarkerExpired(leasePath, marker))) return false;
|
|
14491
|
+
if (!marker && !isReclaimMarkerExpired(leasePath, null)) return false;
|
|
14492
|
+
const staleMarkerPath = `${markerPath}.stale.${marker?.pid ?? process.pid}.${marker?.token ?? randomUUID2()}.${randomUUID2()}`;
|
|
14493
|
+
try {
|
|
14494
|
+
renameSync4(markerPath, staleMarkerPath);
|
|
14495
|
+
} catch (error) {
|
|
14496
|
+
if (getErrorCode2(error) === "ENOENT") return false;
|
|
14497
|
+
throw error;
|
|
14498
|
+
}
|
|
14499
|
+
try {
|
|
14500
|
+
let claimedMarker = null;
|
|
14501
|
+
try {
|
|
14502
|
+
claimedMarker = parseReclaimOwner2(
|
|
14503
|
+
JSON.parse(readFileSync9(path17.join(staleMarkerPath, OWNER_FILE_NAME2), "utf-8"))
|
|
14504
|
+
);
|
|
14505
|
+
} catch {
|
|
14506
|
+
claimedMarker = null;
|
|
14507
|
+
}
|
|
14508
|
+
const markerMatches = marker ? claimedMarker !== null && sameReclaimOwner2(claimedMarker, marker) : claimedMarker === null;
|
|
14509
|
+
if (!markerMatches || !canReclaimLease(leasePath, expectedOwner)) {
|
|
14510
|
+
if (!existsSync9(markerPath) && existsSync9(staleMarkerPath)) renameSync4(staleMarkerPath, markerPath);
|
|
14511
|
+
return false;
|
|
14512
|
+
}
|
|
14513
|
+
rmSync3(staleMarkerPath, { recursive: true, force: true });
|
|
14514
|
+
return true;
|
|
14515
|
+
} catch (error) {
|
|
14516
|
+
if (getErrorCode2(error) === "ENOENT") return false;
|
|
14517
|
+
throw error;
|
|
14518
|
+
}
|
|
14519
|
+
}
|
|
14520
|
+
function canReclaimLease(leasePath, expectedOwner) {
|
|
14521
|
+
if (!existsSync9(leasePath)) return false;
|
|
14522
|
+
if (!expectedOwner) return false;
|
|
14523
|
+
const currentOwner = readOwner(leasePath);
|
|
14524
|
+
if (!currentOwner || !sameOwner2(currentOwner, expectedOwner)) return false;
|
|
14525
|
+
if (currentOwner.hostname === os6.hostname()) {
|
|
14526
|
+
return ownerLiveness(currentOwner) === "dead";
|
|
14527
|
+
}
|
|
14528
|
+
return isHeartbeatExpired(currentOwner);
|
|
14529
|
+
}
|
|
14530
|
+
function reclaimLease(leasePath, expectedOwner) {
|
|
14531
|
+
let marker = null;
|
|
14532
|
+
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
14533
|
+
marker = publishReclaimMarker(leasePath, expectedOwner);
|
|
14534
|
+
if (marker) break;
|
|
14535
|
+
if (attempt === 0 && removeExpiredReclaimMarker(leasePath, expectedOwner)) continue;
|
|
14536
|
+
return false;
|
|
14537
|
+
}
|
|
14538
|
+
if (!marker) return false;
|
|
14539
|
+
const markerPath = reclaimPath(leasePath);
|
|
14540
|
+
try {
|
|
14541
|
+
const currentMarker = readReclaimOwner2(leasePath);
|
|
14542
|
+
if (!currentMarker || !sameReclaimOwner2(currentMarker, marker) || !canReclaimLease(leasePath, expectedOwner)) {
|
|
14543
|
+
return false;
|
|
14544
|
+
}
|
|
14545
|
+
const stalePath = `${leasePath}.stale.${process.pid}.${marker.token}`;
|
|
14546
|
+
renameSync4(leasePath, stalePath);
|
|
14547
|
+
const quarantinedOwner = readOwner(stalePath);
|
|
14548
|
+
const quarantinedMarker = readReclaimOwner2(stalePath);
|
|
14549
|
+
if (!quarantinedMarker || !sameReclaimOwner2(quarantinedMarker, marker) || expectedOwner !== null && (!quarantinedOwner || !sameOwner2(quarantinedOwner, expectedOwner))) {
|
|
14550
|
+
if (!existsSync9(leasePath) && existsSync9(stalePath)) renameSync4(stalePath, leasePath);
|
|
14551
|
+
return false;
|
|
14552
|
+
}
|
|
14553
|
+
rmSync3(stalePath, { recursive: true, force: true });
|
|
14554
|
+
return true;
|
|
14555
|
+
} catch (error) {
|
|
14556
|
+
if (getErrorCode2(error) === "ENOENT") return false;
|
|
14557
|
+
throw error;
|
|
14558
|
+
} finally {
|
|
14559
|
+
const currentMarker = readReclaimOwner2(leasePath);
|
|
14560
|
+
if (currentMarker && sameReclaimOwner2(currentMarker, marker)) {
|
|
14561
|
+
rmSync3(markerPath, { recursive: true, force: true });
|
|
14562
|
+
}
|
|
14563
|
+
}
|
|
14564
|
+
}
|
|
14565
|
+
function acquireLease(identity) {
|
|
14566
|
+
mkdirSync5(identity.canonicalIndexPath, { recursive: true, mode: 448 });
|
|
14567
|
+
const canonicalIndexPath = realpathSync4.native(identity.canonicalIndexPath);
|
|
14568
|
+
const leasePath = path17.join(canonicalIndexPath, leaseDirectoryName({ ...identity, canonicalIndexPath }));
|
|
14569
|
+
for (let attempt = 0; attempt < 4; attempt += 1) {
|
|
14570
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
14571
|
+
const owner = {
|
|
14572
|
+
version: 1,
|
|
14573
|
+
pid: process.pid,
|
|
14574
|
+
hostname: os6.hostname(),
|
|
14575
|
+
startedAt: timestamp,
|
|
14576
|
+
heartbeatAt: timestamp,
|
|
14577
|
+
projectRoot: identity.canonicalProjectRoot,
|
|
14578
|
+
indexPath: canonicalIndexPath,
|
|
14579
|
+
token: randomUUID2()
|
|
14580
|
+
};
|
|
14581
|
+
if (publishLease(leasePath, owner)) {
|
|
14582
|
+
return { leasePath, owner };
|
|
14583
|
+
}
|
|
14584
|
+
const existingOwner = readOwner(leasePath);
|
|
14585
|
+
if (existingOwner) {
|
|
14586
|
+
if (canReclaimLease(leasePath, existingOwner) && reclaimLease(leasePath, existingOwner)) continue;
|
|
14587
|
+
return null;
|
|
14588
|
+
}
|
|
14589
|
+
return null;
|
|
14590
|
+
}
|
|
14591
|
+
return null;
|
|
14592
|
+
}
|
|
14593
|
+
function releaseLease(lease) {
|
|
14594
|
+
const currentOwner = readOwner(lease.leasePath);
|
|
14595
|
+
if (!currentOwner || !sameOwner2(currentOwner, lease.owner)) return false;
|
|
14596
|
+
const releasePath = `${lease.leasePath}.release.${lease.owner.pid}.${lease.owner.token}`;
|
|
14597
|
+
try {
|
|
14598
|
+
renameSync4(lease.leasePath, releasePath);
|
|
14599
|
+
} catch (error) {
|
|
14600
|
+
if (getErrorCode2(error) === "ENOENT") return false;
|
|
14601
|
+
throw error;
|
|
14602
|
+
}
|
|
14603
|
+
const claimedOwner = readOwner(releasePath);
|
|
14604
|
+
if (!claimedOwner || !sameOwner2(claimedOwner, lease.owner)) {
|
|
14605
|
+
if (!existsSync9(lease.leasePath) && existsSync9(releasePath)) {
|
|
14606
|
+
renameSync4(releasePath, lease.leasePath);
|
|
14607
|
+
}
|
|
14608
|
+
return false;
|
|
14609
|
+
}
|
|
14610
|
+
rmSync3(releasePath, { recursive: true, force: true });
|
|
14611
|
+
return true;
|
|
14612
|
+
}
|
|
14613
|
+
var BackgroundWorkerController = class {
|
|
14614
|
+
constructor(projectRoot, host, config, hooks, identity) {
|
|
14615
|
+
this.projectRoot = projectRoot;
|
|
14616
|
+
this.host = host;
|
|
14617
|
+
this.config = config;
|
|
14618
|
+
this.hooks = hooks;
|
|
14619
|
+
this.identity = identity;
|
|
14620
|
+
}
|
|
14621
|
+
projectRoot;
|
|
14622
|
+
host;
|
|
14623
|
+
config;
|
|
14624
|
+
hooks;
|
|
14625
|
+
identity;
|
|
14626
|
+
lease = null;
|
|
14627
|
+
watcher = null;
|
|
14628
|
+
leaderReady = Promise.resolve();
|
|
14629
|
+
heartbeatTimer = null;
|
|
14630
|
+
retryTimer = null;
|
|
14631
|
+
teardownRetryTimer = null;
|
|
14632
|
+
transition = Promise.resolve();
|
|
14633
|
+
stopPromise = null;
|
|
14634
|
+
stopped = false;
|
|
14635
|
+
stopping = false;
|
|
14636
|
+
losingLeadership = false;
|
|
14637
|
+
restartAfterStop = false;
|
|
14638
|
+
leaderWorkStopped = false;
|
|
14639
|
+
startingLeaderWork = false;
|
|
14640
|
+
stopAutoIndexOnTeardown = true;
|
|
14641
|
+
autoIndexStarted = false;
|
|
14642
|
+
reportedError = null;
|
|
14643
|
+
update(config, hooks, options) {
|
|
14644
|
+
const autoIndexWasEnabled = this.config.indexing.autoIndex;
|
|
14645
|
+
const shouldReplaceWatcher = this.watcher !== null && hooks.watcherFactory !== void 0 && (hooks.watcherFactory === null || hooks.replaceWatcher === true);
|
|
14646
|
+
this.config = config;
|
|
14647
|
+
this.hooks = {
|
|
14648
|
+
...this.hooks,
|
|
14649
|
+
...hooks,
|
|
14650
|
+
watcherFactory: hooks.watcherFactory === void 0 ? this.hooks.watcherFactory : hooks.watcherFactory,
|
|
14651
|
+
watcherFactoryForConfig: hooks.watcherFactoryForConfig === void 0 ? this.hooks.watcherFactoryForConfig : hooks.watcherFactoryForConfig
|
|
14652
|
+
};
|
|
14653
|
+
if (autoIndexWasEnabled && !config.indexing.autoIndex || options.restartAutoIndex === true && config.indexing.autoIndex && !this.startingLeaderWork) {
|
|
14654
|
+
this.autoIndexStarted = false;
|
|
14655
|
+
}
|
|
14656
|
+
if (!this.canRun()) {
|
|
14657
|
+
void this.stop().catch((error) => {
|
|
14658
|
+
console.error("[codebase-index] Failed to stop background worker after disabling automatic work:", error);
|
|
14659
|
+
});
|
|
14660
|
+
return;
|
|
14661
|
+
}
|
|
14662
|
+
if (shouldReplaceWatcher) {
|
|
14663
|
+
void this.enqueue(async () => {
|
|
14664
|
+
const watcher = this.watcher;
|
|
14665
|
+
if (watcher) {
|
|
14666
|
+
await watcher.stop();
|
|
14667
|
+
if (this.watcher === watcher) this.watcher = null;
|
|
14668
|
+
}
|
|
14669
|
+
if (this.lease && !this.stopped) this.startLeaderWork();
|
|
14670
|
+
}).catch((error) => {
|
|
14671
|
+
console.error("[codebase-index] Failed to replace background file watcher:", error);
|
|
14672
|
+
});
|
|
14673
|
+
}
|
|
14674
|
+
this.start();
|
|
14675
|
+
}
|
|
14676
|
+
startAfter(activation) {
|
|
14677
|
+
this.transition = activation.catch(() => void 0);
|
|
14678
|
+
this.start();
|
|
14679
|
+
}
|
|
14680
|
+
start() {
|
|
14681
|
+
if (!this.canRun() || this.losingLeadership) return;
|
|
14682
|
+
if (this.stopping) {
|
|
14683
|
+
this.restartAfterStop = true;
|
|
14684
|
+
return;
|
|
14685
|
+
}
|
|
14686
|
+
this.stopped = false;
|
|
14687
|
+
void this.enqueue(async () => {
|
|
14688
|
+
if (this.stopped || this.stopping || this.losingLeadership || !this.canRun()) return;
|
|
14689
|
+
if (!this.lease) {
|
|
14690
|
+
try {
|
|
14691
|
+
this.lease = acquireLease(this.identity);
|
|
14692
|
+
this.reportedError = null;
|
|
14693
|
+
} catch (error) {
|
|
14694
|
+
this.reportAcquireError(error);
|
|
14695
|
+
this.scheduleRetry();
|
|
14696
|
+
return;
|
|
14697
|
+
}
|
|
14698
|
+
}
|
|
14699
|
+
if (!this.lease) {
|
|
14700
|
+
this.scheduleRetry();
|
|
14701
|
+
return;
|
|
14702
|
+
}
|
|
14703
|
+
this.startHeartbeat();
|
|
14704
|
+
this.startLeaderWork();
|
|
14705
|
+
});
|
|
14706
|
+
}
|
|
14707
|
+
waitForStart() {
|
|
14708
|
+
return this.transition.catch(() => void 0).then(() => this.leaderReady);
|
|
14709
|
+
}
|
|
14710
|
+
requestRefresh(allowDisabledAutoIndex = false) {
|
|
14711
|
+
this.start();
|
|
14712
|
+
if (!this.isLeader()) {
|
|
14713
|
+
requestRefreshFromLeader(leasePathFor(this.identity), allowDisabledAutoIndex);
|
|
14714
|
+
return;
|
|
14715
|
+
}
|
|
14716
|
+
void this.enqueue(async () => {
|
|
14717
|
+
if (this.stopped || !this.lease) return;
|
|
14718
|
+
this.hooks.startAutoIndex("retrieval", allowDisabledAutoIndex);
|
|
14719
|
+
});
|
|
14720
|
+
}
|
|
14721
|
+
isLeader() {
|
|
14722
|
+
return this.lease !== null && !this.stopping && !this.losingLeadership;
|
|
14723
|
+
}
|
|
14724
|
+
isStopping() {
|
|
14725
|
+
return this.stopping;
|
|
14726
|
+
}
|
|
14727
|
+
getHooksForConfig(config) {
|
|
14728
|
+
const watcherFactoryForConfig = this.hooks.watcherFactoryForConfig;
|
|
14729
|
+
if (!watcherFactoryForConfig) return this.hooks;
|
|
14730
|
+
return {
|
|
14731
|
+
...this.hooks,
|
|
14732
|
+
watcherFactory: watcherFactoryForConfig(config),
|
|
14733
|
+
replaceWatcher: true
|
|
14734
|
+
};
|
|
14735
|
+
}
|
|
14736
|
+
attachWatcher(watcherFactory, watcherFactoryForConfig) {
|
|
14737
|
+
if (this.hooks.watcherFactory !== void 0) return;
|
|
14738
|
+
this.hooks = {
|
|
14739
|
+
...this.hooks,
|
|
14740
|
+
watcherFactory,
|
|
14741
|
+
watcherFactoryForConfig: watcherFactoryForConfig ?? this.hooks.watcherFactoryForConfig
|
|
14742
|
+
};
|
|
14743
|
+
this.start();
|
|
14744
|
+
}
|
|
14745
|
+
async stop(stopAutoIndex = true) {
|
|
14746
|
+
if (this.stopPromise) return this.stopPromise;
|
|
14747
|
+
this.stopped = true;
|
|
14748
|
+
this.stopping = true;
|
|
14749
|
+
this.stopAutoIndexOnTeardown &&= stopAutoIndex;
|
|
14750
|
+
this.clearRetryTimer();
|
|
14751
|
+
const attempt = this.enqueue(async () => {
|
|
14752
|
+
try {
|
|
14753
|
+
const lease = this.lease;
|
|
14754
|
+
if (this.leaderWorkStopped) {
|
|
14755
|
+
if (lease) {
|
|
14756
|
+
this.releaseStoppedLease(lease);
|
|
14757
|
+
} else {
|
|
14758
|
+
this.finishStoppedLease();
|
|
14759
|
+
}
|
|
14760
|
+
return;
|
|
14761
|
+
}
|
|
14762
|
+
const hadLeaderWork = lease !== null || this.watcher !== null || this.autoIndexStarted;
|
|
14763
|
+
const stopped = await this.stopLeaderWork(hadLeaderWork && this.stopAutoIndexOnTeardown);
|
|
14764
|
+
if (!lease) {
|
|
14765
|
+
this.finishStoppedLease();
|
|
14766
|
+
return;
|
|
14767
|
+
}
|
|
14768
|
+
if (!stopped.completed) {
|
|
14769
|
+
this.releaseLeaseWhenAutoIndexStops(lease, stopped.completion);
|
|
14770
|
+
return;
|
|
14771
|
+
}
|
|
14772
|
+
this.leaderWorkStopped = true;
|
|
14773
|
+
this.releaseStoppedLease(lease);
|
|
14774
|
+
} catch (error) {
|
|
14775
|
+
this.scheduleTeardownRetry();
|
|
14776
|
+
throw error;
|
|
14777
|
+
}
|
|
14778
|
+
});
|
|
14779
|
+
const completion = attempt.finally(() => {
|
|
14780
|
+
if (this.stopPromise === completion) this.stopPromise = null;
|
|
14781
|
+
});
|
|
14782
|
+
this.stopPromise = completion;
|
|
14783
|
+
return completion;
|
|
14784
|
+
}
|
|
14785
|
+
canRun() {
|
|
14786
|
+
return this.config.indexing.autoIndex || this.hooks.watcherFactory != null;
|
|
14787
|
+
}
|
|
14788
|
+
enqueue(operation) {
|
|
14789
|
+
const next = this.transition.catch(() => void 0).then(operation);
|
|
14790
|
+
this.transition = next;
|
|
14791
|
+
return next;
|
|
14792
|
+
}
|
|
14793
|
+
startLeaderWork() {
|
|
14794
|
+
if (this.stopped || this.stopping || this.losingLeadership) return;
|
|
14795
|
+
this.startingLeaderWork = true;
|
|
14796
|
+
try {
|
|
14797
|
+
if (this.config.indexing.autoIndex && !this.autoIndexStarted) {
|
|
14798
|
+
this.autoIndexStarted = true;
|
|
14799
|
+
this.hooks.startAutoIndex("startup");
|
|
14800
|
+
}
|
|
14801
|
+
if (!this.watcher && this.hooks.watcherFactory) {
|
|
14802
|
+
try {
|
|
14803
|
+
const watcher = this.hooks.watcherFactory();
|
|
14804
|
+
this.watcher = watcher;
|
|
14805
|
+
this.leaderReady = watcher.whenReady?.().catch((error) => {
|
|
14806
|
+
console.error("[codebase-index] Failed while waiting for background file watcher startup:", error);
|
|
14807
|
+
}) ?? Promise.resolve();
|
|
14808
|
+
} catch (error) {
|
|
14809
|
+
console.error("[codebase-index] Failed to start background file watcher:", error);
|
|
14810
|
+
this.leaderReady = Promise.resolve();
|
|
14811
|
+
}
|
|
14812
|
+
}
|
|
14813
|
+
} finally {
|
|
14814
|
+
this.startingLeaderWork = false;
|
|
14815
|
+
}
|
|
14816
|
+
}
|
|
14817
|
+
async stopLeaderWork(stopAutoIndex) {
|
|
14818
|
+
const watcher = this.watcher;
|
|
14819
|
+
let watcherError;
|
|
14820
|
+
if (watcher) {
|
|
14821
|
+
try {
|
|
14822
|
+
await watcher.stop();
|
|
14823
|
+
if (this.watcher === watcher) this.watcher = null;
|
|
14824
|
+
} catch (error) {
|
|
14825
|
+
watcherError = error;
|
|
14826
|
+
}
|
|
14827
|
+
}
|
|
14828
|
+
let autoIndexError;
|
|
14829
|
+
let autoIndexStop = {
|
|
14830
|
+
completed: true,
|
|
14831
|
+
completion: Promise.resolve()
|
|
14832
|
+
};
|
|
14833
|
+
if (stopAutoIndex) {
|
|
14834
|
+
try {
|
|
14835
|
+
autoIndexStop = await this.hooks.stopAutoIndex();
|
|
14836
|
+
this.autoIndexStarted = false;
|
|
14837
|
+
} catch (error) {
|
|
14838
|
+
autoIndexError = error;
|
|
14839
|
+
}
|
|
14840
|
+
}
|
|
14841
|
+
if (watcherError !== void 0 || autoIndexError !== void 0) {
|
|
14842
|
+
throw new BackgroundWorkerStopError(watcherError, autoIndexError);
|
|
14843
|
+
}
|
|
14844
|
+
return autoIndexStop;
|
|
14845
|
+
}
|
|
14846
|
+
releaseLeaseWhenAutoIndexStops(lease, completion) {
|
|
14847
|
+
void completion.then(
|
|
14848
|
+
() => {
|
|
14849
|
+
void this.enqueue(async () => {
|
|
14850
|
+
if (this.lease !== lease || !this.stopping) return;
|
|
14851
|
+
this.leaderWorkStopped = true;
|
|
14852
|
+
this.releaseStoppedLease(lease);
|
|
14853
|
+
}).catch((error) => {
|
|
14854
|
+
console.error("[codebase-index] Failed to release background worker lease after automatic indexing stopped:", error);
|
|
14855
|
+
this.scheduleTeardownRetry();
|
|
14856
|
+
});
|
|
14857
|
+
},
|
|
14858
|
+
(error) => {
|
|
14859
|
+
console.error("[codebase-index] Failed while waiting for automatic indexing to stop:", error);
|
|
14860
|
+
this.scheduleTeardownRetry();
|
|
14861
|
+
}
|
|
14862
|
+
);
|
|
14863
|
+
}
|
|
14864
|
+
releaseStoppedLease(lease) {
|
|
14865
|
+
if (this.lease !== lease) {
|
|
14866
|
+
this.finishStoppedLease();
|
|
14867
|
+
return;
|
|
14868
|
+
}
|
|
14869
|
+
releaseLease(lease);
|
|
14870
|
+
this.lease = null;
|
|
14871
|
+
this.finishStoppedLease();
|
|
14872
|
+
}
|
|
14873
|
+
finishStoppedLease() {
|
|
14874
|
+
this.leaderWorkStopped = false;
|
|
14875
|
+
this.stopAutoIndexOnTeardown = true;
|
|
14876
|
+
this.stopping = false;
|
|
14877
|
+
this.clearTimers();
|
|
14878
|
+
this.restartAfterTeardown();
|
|
14879
|
+
if (!this.stopped || this.stopping) return;
|
|
14880
|
+
const projectKey = projectLookupKey(this.projectRoot, this.host);
|
|
14881
|
+
const key = controllerKey(this.identity, this.host);
|
|
14882
|
+
if (workers.get(key) === this) workers.delete(key);
|
|
14883
|
+
if (workerKeysByProject.get(projectKey) === key) workerKeysByProject.delete(projectKey);
|
|
14884
|
+
}
|
|
14885
|
+
startHeartbeat() {
|
|
14886
|
+
if (this.heartbeatTimer) return;
|
|
14887
|
+
const heartbeat = () => {
|
|
14888
|
+
void this.heartbeat();
|
|
14889
|
+
};
|
|
14890
|
+
this.heartbeatTimer = setInterval(heartbeat, HEARTBEAT_INTERVAL_MS);
|
|
14891
|
+
this.heartbeatTimer.unref?.();
|
|
14892
|
+
}
|
|
14893
|
+
async heartbeat() {
|
|
14894
|
+
const lease = this.lease;
|
|
14895
|
+
if (!lease || this.losingLeadership || this.stopped && !this.stopping) return;
|
|
14896
|
+
if (hasActiveReclaimMarker(lease.leasePath, lease.owner)) {
|
|
14897
|
+
await this.loseLeadership();
|
|
14898
|
+
return;
|
|
14899
|
+
}
|
|
14900
|
+
const currentOwner = readOwner(lease.leasePath);
|
|
14901
|
+
if (!currentOwner || !sameOwner2(currentOwner, lease.owner)) {
|
|
14902
|
+
await this.loseLeadership();
|
|
14903
|
+
return;
|
|
14904
|
+
}
|
|
14905
|
+
try {
|
|
14906
|
+
const nextOwner = { ...lease.owner, heartbeatAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
14907
|
+
if (!writeHeartbeat(lease.leasePath, nextOwner)) {
|
|
14908
|
+
await this.loseLeadership();
|
|
14909
|
+
return;
|
|
14910
|
+
}
|
|
14911
|
+
lease.owner = nextOwner;
|
|
14912
|
+
const refreshRequest = !this.stopping ? consumeRefreshRequest(lease.leasePath) : null;
|
|
14913
|
+
if (refreshRequest) {
|
|
14914
|
+
this.hooks.startAutoIndex("retrieval", refreshRequest.allowDisabledAutoIndex);
|
|
14915
|
+
}
|
|
14916
|
+
} catch (error) {
|
|
14917
|
+
const ownerAfterError = readOwner(lease.leasePath);
|
|
14918
|
+
if (hasActiveReclaimMarker(lease.leasePath, lease.owner) || !ownerAfterError || !sameOwner2(ownerAfterError, lease.owner)) {
|
|
14919
|
+
await this.loseLeadership();
|
|
14920
|
+
return;
|
|
14921
|
+
}
|
|
14922
|
+
console.error("[codebase-index] Failed to renew background worker lease:", error);
|
|
14923
|
+
}
|
|
14924
|
+
}
|
|
14925
|
+
async loseLeadership() {
|
|
14926
|
+
if (this.losingLeadership) return;
|
|
14927
|
+
this.losingLeadership = true;
|
|
14928
|
+
this.clearHeartbeat();
|
|
14929
|
+
await this.enqueue(async () => this.stopAfterLeadershipLoss());
|
|
14930
|
+
}
|
|
14931
|
+
async stopAfterLeadershipLoss() {
|
|
14932
|
+
const lease = this.lease;
|
|
14933
|
+
if (!lease) {
|
|
14934
|
+
this.losingLeadership = false;
|
|
14935
|
+
return;
|
|
14936
|
+
}
|
|
14937
|
+
try {
|
|
14938
|
+
const stopped = await this.stopLeaderWork(true);
|
|
14939
|
+
this.lease = null;
|
|
14940
|
+
this.losingLeadership = false;
|
|
14941
|
+
if (stopped.completed) {
|
|
14942
|
+
this.scheduleRetry();
|
|
14943
|
+
} else {
|
|
14944
|
+
void stopped.completion.then(() => this.scheduleRetry());
|
|
14945
|
+
}
|
|
14946
|
+
} catch (error) {
|
|
14947
|
+
console.error("[codebase-index] Failed to stop background work after losing its lease:", error);
|
|
14948
|
+
this.scheduleLostLeadershipTeardownRetry();
|
|
14949
|
+
}
|
|
14950
|
+
}
|
|
14951
|
+
scheduleRetry() {
|
|
14952
|
+
if (this.stopped || !this.canRun() || this.retryTimer) return;
|
|
14953
|
+
this.retryTimer = setTimeout(() => {
|
|
14954
|
+
this.retryTimer = null;
|
|
14955
|
+
this.start();
|
|
14956
|
+
}, RETRY_DELAY_MS);
|
|
14957
|
+
this.retryTimer.unref?.();
|
|
14958
|
+
}
|
|
14959
|
+
scheduleTeardownRetry() {
|
|
14960
|
+
if (!this.stopping || this.teardownRetryTimer) return;
|
|
14961
|
+
this.teardownRetryTimer = setTimeout(() => {
|
|
14962
|
+
this.teardownRetryTimer = null;
|
|
14963
|
+
void this.stop(this.stopAutoIndexOnTeardown).catch((error) => {
|
|
14964
|
+
console.error("[codebase-index] Failed to retry background worker teardown:", error);
|
|
14965
|
+
});
|
|
14966
|
+
}, RETRY_DELAY_MS);
|
|
14967
|
+
this.teardownRetryTimer.unref?.();
|
|
14968
|
+
}
|
|
14969
|
+
restartAfterTeardown() {
|
|
14970
|
+
if (!this.restartAfterStop || !this.canRun() || this.losingLeadership) return;
|
|
14971
|
+
this.restartAfterStop = false;
|
|
14972
|
+
this.stopped = false;
|
|
14973
|
+
this.start();
|
|
14974
|
+
}
|
|
14975
|
+
scheduleLostLeadershipTeardownRetry() {
|
|
14976
|
+
if (this.stopped || !this.losingLeadership || this.retryTimer) return;
|
|
14977
|
+
this.retryTimer = setTimeout(() => {
|
|
14978
|
+
this.retryTimer = null;
|
|
14979
|
+
void this.enqueue(async () => this.stopAfterLeadershipLoss());
|
|
14980
|
+
}, RETRY_DELAY_MS);
|
|
14981
|
+
this.retryTimer.unref?.();
|
|
14982
|
+
}
|
|
14983
|
+
clearHeartbeat() {
|
|
14984
|
+
if (!this.heartbeatTimer) return;
|
|
14985
|
+
clearInterval(this.heartbeatTimer);
|
|
14986
|
+
this.heartbeatTimer = null;
|
|
14987
|
+
}
|
|
14988
|
+
clearTimers() {
|
|
14989
|
+
this.clearHeartbeat();
|
|
14990
|
+
this.clearRetryTimer();
|
|
14991
|
+
if (this.teardownRetryTimer) {
|
|
14992
|
+
clearTimeout(this.teardownRetryTimer);
|
|
14993
|
+
this.teardownRetryTimer = null;
|
|
14994
|
+
}
|
|
14995
|
+
}
|
|
14996
|
+
clearRetryTimer() {
|
|
14997
|
+
if (!this.retryTimer) return;
|
|
14998
|
+
clearTimeout(this.retryTimer);
|
|
14999
|
+
this.retryTimer = null;
|
|
15000
|
+
}
|
|
15001
|
+
reportAcquireError(error) {
|
|
15002
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
15003
|
+
if (this.reportedError === message) return;
|
|
15004
|
+
this.reportedError = message;
|
|
15005
|
+
console.error("[codebase-index] Failed to acquire background worker lease:", error);
|
|
15006
|
+
}
|
|
15007
|
+
};
|
|
15008
|
+
function configureBackgroundWorker(projectRoot, host, config, hooks, options = {}) {
|
|
15009
|
+
const projectKey = projectLookupKey(projectRoot, host);
|
|
15010
|
+
const identity = resolveIdentity(projectRoot, config, host);
|
|
15011
|
+
const key = controllerKey(identity, host);
|
|
15012
|
+
const previousKey = workerKeysByProject.get(projectKey);
|
|
15013
|
+
if (previousKey && previousKey !== key) {
|
|
15014
|
+
const previous = workers.get(previousKey);
|
|
15015
|
+
const previousBarrier = workerReplacementBarriers.get(projectKey) ?? Promise.resolve();
|
|
15016
|
+
const stopPrevious = previous?.stop(options.stopPreviousAutoIndex ?? true) ?? Promise.resolve();
|
|
15017
|
+
const activation = Promise.all([previousBarrier, stopPrevious]).then(() => void 0);
|
|
15018
|
+
workerReplacementBarriers.set(projectKey, activation);
|
|
15019
|
+
workers.delete(previousKey);
|
|
15020
|
+
const worker2 = new BackgroundWorkerController(projectRoot, host, config, hooks, identity);
|
|
15021
|
+
worker2.startAfter(activation);
|
|
15022
|
+
workers.set(key, worker2);
|
|
15023
|
+
workerKeysByProject.set(projectKey, key);
|
|
15024
|
+
return;
|
|
15025
|
+
}
|
|
15026
|
+
let worker = workers.get(key);
|
|
15027
|
+
if (!worker) {
|
|
15028
|
+
worker = new BackgroundWorkerController(projectRoot, host, config, hooks, identity);
|
|
15029
|
+
workers.set(key, worker);
|
|
15030
|
+
} else {
|
|
15031
|
+
worker.update(config, hooks, options);
|
|
15032
|
+
}
|
|
15033
|
+
workerKeysByProject.set(projectKey, key);
|
|
15034
|
+
worker.start();
|
|
15035
|
+
}
|
|
15036
|
+
function attachBackgroundWorkerWatcher(projectRoot, host, watcherFactory, watcherFactoryForConfig) {
|
|
15037
|
+
const key = workerKeysByProject.get(projectLookupKey(projectRoot, host));
|
|
15038
|
+
workers.get(key ?? "")?.attachWatcher(watcherFactory, watcherFactoryForConfig);
|
|
15039
|
+
}
|
|
15040
|
+
function updateBackgroundWorkerConfig(projectRoot, host, config) {
|
|
15041
|
+
const projectKey = projectLookupKey(projectRoot, host);
|
|
15042
|
+
const key = workerKeysByProject.get(projectKey);
|
|
15043
|
+
const worker = key ? workers.get(key) : void 0;
|
|
15044
|
+
if (!worker) return;
|
|
15045
|
+
configureBackgroundWorker(projectRoot, host, config, worker.getHooksForConfig(config), {
|
|
15046
|
+
stopPreviousAutoIndex: false,
|
|
15047
|
+
restartAutoIndex: true
|
|
15048
|
+
});
|
|
15049
|
+
}
|
|
15050
|
+
function requestBackgroundWorker(projectRoot, host) {
|
|
15051
|
+
const key = workerKeysByProject.get(projectLookupKey(projectRoot, host));
|
|
15052
|
+
workers.get(key ?? "")?.start();
|
|
15053
|
+
}
|
|
15054
|
+
function waitForBackgroundWorkerStart(projectRoot, host) {
|
|
15055
|
+
const key = workerKeysByProject.get(projectLookupKey(projectRoot, host));
|
|
15056
|
+
return workers.get(key ?? "")?.waitForStart() ?? Promise.resolve();
|
|
15057
|
+
}
|
|
15058
|
+
function requestBackgroundWorkerRefresh(projectRoot, host, allowDisabledAutoIndex = false) {
|
|
15059
|
+
const key = workerKeysByProject.get(projectLookupKey(projectRoot, host));
|
|
15060
|
+
workers.get(key ?? "")?.requestRefresh(allowDisabledAutoIndex);
|
|
15061
|
+
}
|
|
15062
|
+
function isBackgroundWorkerManaged(projectRoot, host) {
|
|
15063
|
+
const key = workerKeysByProject.get(projectLookupKey(projectRoot, host));
|
|
15064
|
+
return key !== void 0 && workers.has(key);
|
|
15065
|
+
}
|
|
15066
|
+
function isBackgroundWorkerLeader(projectRoot, host) {
|
|
15067
|
+
const key = workerKeysByProject.get(projectLookupKey(projectRoot, host));
|
|
15068
|
+
return key !== void 0 && workers.get(key)?.isLeader() === true;
|
|
15069
|
+
}
|
|
15070
|
+
function isBackgroundWorkerStopping(projectRoot, host) {
|
|
15071
|
+
const key = workerKeysByProject.get(projectLookupKey(projectRoot, host));
|
|
15072
|
+
return key !== void 0 && workers.get(key)?.isStopping() === true;
|
|
15073
|
+
}
|
|
15074
|
+
async function stopBackgroundWorker(projectRoot, host) {
|
|
15075
|
+
const projectKey = projectLookupKey(projectRoot, host);
|
|
15076
|
+
const key = workerKeysByProject.get(projectKey);
|
|
15077
|
+
const worker = key ? workers.get(key) : void 0;
|
|
15078
|
+
if (!worker) return;
|
|
15079
|
+
await worker.stop();
|
|
15080
|
+
}
|
|
14156
15081
|
|
|
14157
15082
|
// src/utils/power-source.ts
|
|
14158
15083
|
import * as childProcess from "child_process";
|
|
@@ -14162,7 +15087,7 @@ function getErrorMessage4(error) {
|
|
|
14162
15087
|
return error instanceof Error ? error.message : String(error);
|
|
14163
15088
|
}
|
|
14164
15089
|
function runCommand(file, args, options) {
|
|
14165
|
-
return new Promise((
|
|
15090
|
+
return new Promise((resolve21, reject) => {
|
|
14166
15091
|
childProcess.execFile(
|
|
14167
15092
|
file,
|
|
14168
15093
|
args,
|
|
@@ -14172,7 +15097,7 @@ function runCommand(file, args, options) {
|
|
|
14172
15097
|
reject(error);
|
|
14173
15098
|
return;
|
|
14174
15099
|
}
|
|
14175
|
-
|
|
15100
|
+
resolve21(stdout);
|
|
14176
15101
|
}
|
|
14177
15102
|
);
|
|
14178
15103
|
});
|
|
@@ -14264,29 +15189,29 @@ var AutoIndexCancelledError = class extends Error {
|
|
|
14264
15189
|
function now() {
|
|
14265
15190
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
14266
15191
|
}
|
|
14267
|
-
function
|
|
14268
|
-
const resolved =
|
|
14269
|
-
if (
|
|
15192
|
+
function canonicalizePath2(targetPath) {
|
|
15193
|
+
const resolved = path18.resolve(targetPath);
|
|
15194
|
+
if (existsSync10(resolved)) {
|
|
14270
15195
|
try {
|
|
14271
|
-
return
|
|
15196
|
+
return realpathSync5.native(resolved);
|
|
14272
15197
|
} catch {
|
|
14273
15198
|
return resolved;
|
|
14274
15199
|
}
|
|
14275
15200
|
}
|
|
14276
|
-
const parent =
|
|
15201
|
+
const parent = path18.dirname(resolved);
|
|
14277
15202
|
if (parent === resolved) return resolved;
|
|
14278
|
-
return
|
|
15203
|
+
return path18.join(canonicalizePath2(parent), path18.basename(resolved));
|
|
14279
15204
|
}
|
|
14280
15205
|
function isHomeDirectory(projectRoot) {
|
|
14281
|
-
return
|
|
15206
|
+
return canonicalizePath2(projectRoot) === canonicalizePath2(os7.homedir());
|
|
14282
15207
|
}
|
|
14283
|
-
function
|
|
14284
|
-
return `${host}::${
|
|
15208
|
+
function projectLookupKey2(projectRoot, host) {
|
|
15209
|
+
return `${host}::${canonicalizePath2(projectRoot)}`;
|
|
14285
15210
|
}
|
|
14286
15211
|
function coordinatorKey(projectRoot, config, host) {
|
|
14287
|
-
const canonicalProjectRoot =
|
|
15212
|
+
const canonicalProjectRoot = canonicalizePath2(projectRoot);
|
|
14288
15213
|
const indexPath = resolveProjectIndexPath(projectRoot, config.scope, host);
|
|
14289
|
-
return `${
|
|
15214
|
+
return `${canonicalizePath2(indexPath)}::${canonicalProjectRoot}`;
|
|
14290
15215
|
}
|
|
14291
15216
|
function getProjectSafety(projectRoot, config) {
|
|
14292
15217
|
if (isHomeDirectory(projectRoot)) {
|
|
@@ -14317,10 +15242,10 @@ function safeFailureMessage(error) {
|
|
|
14317
15242
|
}
|
|
14318
15243
|
function cancellableDelay(delayMs, signal) {
|
|
14319
15244
|
if (signal.aborted) return Promise.reject(new AutoIndexCancelledError());
|
|
14320
|
-
return new Promise((
|
|
15245
|
+
return new Promise((resolve21, reject) => {
|
|
14321
15246
|
const timer = setTimeout(() => {
|
|
14322
15247
|
signal.removeEventListener("abort", onAbort);
|
|
14323
|
-
|
|
15248
|
+
resolve21();
|
|
14324
15249
|
}, delayMs);
|
|
14325
15250
|
timer.unref?.();
|
|
14326
15251
|
const onAbort = () => {
|
|
@@ -14332,18 +15257,44 @@ function cancellableDelay(delayMs, signal) {
|
|
|
14332
15257
|
}
|
|
14333
15258
|
function withTimeout(promise, timeoutMs) {
|
|
14334
15259
|
if (timeoutMs <= 0) return Promise.resolve(void 0);
|
|
14335
|
-
return new Promise((
|
|
14336
|
-
const timer = setTimeout(() =>
|
|
15260
|
+
return new Promise((resolve21) => {
|
|
15261
|
+
const timer = setTimeout(() => resolve21(void 0), timeoutMs);
|
|
14337
15262
|
timer.unref?.();
|
|
14338
15263
|
void promise.then((value) => {
|
|
14339
15264
|
clearTimeout(timer);
|
|
14340
|
-
|
|
15265
|
+
resolve21(value);
|
|
14341
15266
|
}, () => {
|
|
14342
15267
|
clearTimeout(timer);
|
|
14343
|
-
|
|
15268
|
+
resolve21(void 0);
|
|
14344
15269
|
});
|
|
14345
15270
|
});
|
|
14346
15271
|
}
|
|
15272
|
+
function settlesWithin(promise, timeoutMs) {
|
|
15273
|
+
if (timeoutMs <= 0) return Promise.resolve(false);
|
|
15274
|
+
return new Promise((resolve21) => {
|
|
15275
|
+
let settled = false;
|
|
15276
|
+
const timer = setTimeout(() => {
|
|
15277
|
+
if (settled) return;
|
|
15278
|
+
settled = true;
|
|
15279
|
+
resolve21(false);
|
|
15280
|
+
}, timeoutMs);
|
|
15281
|
+
timer.unref?.();
|
|
15282
|
+
void promise.then(
|
|
15283
|
+
() => {
|
|
15284
|
+
if (settled) return;
|
|
15285
|
+
settled = true;
|
|
15286
|
+
clearTimeout(timer);
|
|
15287
|
+
resolve21(true);
|
|
15288
|
+
},
|
|
15289
|
+
() => {
|
|
15290
|
+
if (settled) return;
|
|
15291
|
+
settled = true;
|
|
15292
|
+
clearTimeout(timer);
|
|
15293
|
+
resolve21(true);
|
|
15294
|
+
}
|
|
15295
|
+
);
|
|
15296
|
+
});
|
|
15297
|
+
}
|
|
14347
15298
|
function requestPriority(request) {
|
|
14348
15299
|
if (request.force) return 4;
|
|
14349
15300
|
if (request.source === "manual") return 3;
|
|
@@ -14354,6 +15305,7 @@ function mergeRequests(current, next) {
|
|
|
14354
15305
|
if (!current) return next;
|
|
14355
15306
|
const preferred = requestPriority(next) > requestPriority(current) ? next : current;
|
|
14356
15307
|
return {
|
|
15308
|
+
allowDisabledAutoIndex: current.allowDisabledAutoIndex || next.allowDisabledAutoIndex,
|
|
14357
15309
|
checkFreshness: current.checkFreshness && next.checkFreshness,
|
|
14358
15310
|
force: current.force || next.force,
|
|
14359
15311
|
onProgress: next.onProgress ?? current.onProgress,
|
|
@@ -14415,11 +15367,11 @@ var AutoIndexCoordinator = class {
|
|
|
14415
15367
|
progress: this.status.progress ? { ...this.status.progress } : void 0
|
|
14416
15368
|
};
|
|
14417
15369
|
}
|
|
14418
|
-
start(source) {
|
|
15370
|
+
start(source, allowDisabledAutoIndex = false) {
|
|
14419
15371
|
this.refreshSafety();
|
|
14420
|
-
if (!this.registration.config.indexing.autoIndex || !this.registration.safeToRun) return null;
|
|
15372
|
+
if (!this.registration.config.indexing.autoIndex && !allowDisabledAutoIndex || !this.registration.safeToRun) return null;
|
|
14421
15373
|
if (this.status.state === "failed") return this.inFlight;
|
|
14422
|
-
return this.request({ checkFreshness: true, force: false, source });
|
|
15374
|
+
return this.request({ allowDisabledAutoIndex, checkFreshness: true, force: false, source });
|
|
14423
15375
|
}
|
|
14424
15376
|
request(request) {
|
|
14425
15377
|
if (this.stopped) {
|
|
@@ -14494,13 +15446,15 @@ var AutoIndexCoordinator = class {
|
|
|
14494
15446
|
retryAttempt: void 0
|
|
14495
15447
|
});
|
|
14496
15448
|
const inFlight = this.inFlight;
|
|
14497
|
-
|
|
14498
|
-
|
|
14499
|
-
|
|
14500
|
-
} else {
|
|
14501
|
-
await withTimeout(inFlight, SHUTDOWN_WAIT_MS);
|
|
14502
|
-
}
|
|
15449
|
+
const completion = inFlight ? inFlight.then(() => void 0, () => void 0) : Promise.resolve();
|
|
15450
|
+
if (!inFlight) {
|
|
15451
|
+
return { completed: true, completion };
|
|
14503
15452
|
}
|
|
15453
|
+
if (waitForCompletion) {
|
|
15454
|
+
await completion;
|
|
15455
|
+
return { completed: true, completion };
|
|
15456
|
+
}
|
|
15457
|
+
return { completed: await settlesWithin(completion, SHUTDOWN_WAIT_MS), completion };
|
|
14504
15458
|
}
|
|
14505
15459
|
startRequest(request) {
|
|
14506
15460
|
if (this.stopped || !this.canRun(request)) {
|
|
@@ -14689,7 +15643,7 @@ var AutoIndexCoordinator = class {
|
|
|
14689
15643
|
if (request.source === "manual" || request.source === "watcher") {
|
|
14690
15644
|
return true;
|
|
14691
15645
|
}
|
|
14692
|
-
return this.registration.safeToRun && this.registration.config.indexing.autoIndex;
|
|
15646
|
+
return this.registration.safeToRun && (this.registration.config.indexing.autoIndex || request.allowDisabledAutoIndex === true);
|
|
14693
15647
|
}
|
|
14694
15648
|
shouldDeferForBattery(request) {
|
|
14695
15649
|
return this.registration.backgroundIndexingPolicy !== null && (request.source === "startup" || request.source === "watcher");
|
|
@@ -14722,17 +15676,17 @@ var AutoIndexCoordinator = class {
|
|
|
14722
15676
|
}
|
|
14723
15677
|
}
|
|
14724
15678
|
waitForBatteryRetry(delayMs) {
|
|
14725
|
-
return new Promise((
|
|
15679
|
+
return new Promise((resolve21) => {
|
|
14726
15680
|
const timer = setTimeout(() => {
|
|
14727
15681
|
if (this.batteryRetryTimer === timer) {
|
|
14728
15682
|
this.batteryRetryTimer = null;
|
|
14729
15683
|
this.resolveBatteryRetry = null;
|
|
14730
15684
|
}
|
|
14731
|
-
|
|
15685
|
+
resolve21();
|
|
14732
15686
|
}, delayMs);
|
|
14733
15687
|
timer.unref?.();
|
|
14734
15688
|
this.batteryRetryTimer = timer;
|
|
14735
|
-
this.resolveBatteryRetry =
|
|
15689
|
+
this.resolveBatteryRetry = resolve21;
|
|
14736
15690
|
});
|
|
14737
15691
|
}
|
|
14738
15692
|
cancelBatteryRetry() {
|
|
@@ -14740,9 +15694,9 @@ var AutoIndexCoordinator = class {
|
|
|
14740
15694
|
clearTimeout(this.batteryRetryTimer);
|
|
14741
15695
|
this.batteryRetryTimer = null;
|
|
14742
15696
|
}
|
|
14743
|
-
const
|
|
15697
|
+
const resolve21 = this.resolveBatteryRetry;
|
|
14744
15698
|
this.resolveBatteryRetry = null;
|
|
14745
|
-
|
|
15699
|
+
resolve21?.();
|
|
14746
15700
|
}
|
|
14747
15701
|
finishBatteryCheck(batteryCheck) {
|
|
14748
15702
|
if (this.batteryCheck !== batteryCheck) return;
|
|
@@ -14755,12 +15709,25 @@ var AutoIndexCoordinator = class {
|
|
|
14755
15709
|
}
|
|
14756
15710
|
};
|
|
14757
15711
|
function getCoordinator(projectRoot, host) {
|
|
14758
|
-
const key = coordinatorKeysByProject.get(
|
|
15712
|
+
const key = coordinatorKeysByProject.get(projectLookupKey2(projectRoot, host));
|
|
14759
15713
|
return key ? coordinators.get(key) ?? null : null;
|
|
14760
15714
|
}
|
|
14761
|
-
function
|
|
14762
|
-
|
|
15715
|
+
function synchronizeBackgroundWorker(projectRoot, host, config, safeToRun) {
|
|
15716
|
+
if (safeToRun) {
|
|
15717
|
+
updateBackgroundWorkerConfig(projectRoot, host, config);
|
|
15718
|
+
return;
|
|
15719
|
+
}
|
|
15720
|
+
void stopBackgroundWorker(projectRoot, host).catch((error) => {
|
|
15721
|
+
console.error("[codebase-index] Failed to stop background worker after project safety changed:", error);
|
|
15722
|
+
});
|
|
15723
|
+
}
|
|
15724
|
+
function configureAutoIndex(projectRoot, host, config, getIndexer, options = {}) {
|
|
15725
|
+
const projectKey = projectLookupKey2(projectRoot, host);
|
|
14763
15726
|
const safety = getProjectSafety(projectRoot, config);
|
|
15727
|
+
const synchronizeWorker = options.synchronizeBackgroundWorker ?? true;
|
|
15728
|
+
if (options.preserveManagedWorker === true && isBackgroundWorkerManaged(projectRoot, host)) {
|
|
15729
|
+
return;
|
|
15730
|
+
}
|
|
14764
15731
|
const registration = {
|
|
14765
15732
|
backgroundIndexingPolicy: createBackgroundIndexingPolicy(
|
|
14766
15733
|
config.indexing.pauseBackgroundIndexingOnBattery
|
|
@@ -14778,6 +15745,9 @@ function configureAutoIndex(projectRoot, host, config, getIndexer) {
|
|
|
14778
15745
|
const stopPrevious = previousCoordinator?.stop(true) ?? Promise.resolve();
|
|
14779
15746
|
const activation = Promise.all([previousBarrier, stopPrevious]).then(() => void 0);
|
|
14780
15747
|
coordinatorReplacementBarriers.set(projectKey, activation);
|
|
15748
|
+
if (synchronizeWorker) {
|
|
15749
|
+
synchronizeBackgroundWorker(projectRoot, host, config, safety.safeToRun);
|
|
15750
|
+
}
|
|
14781
15751
|
coordinators.delete(previousKey);
|
|
14782
15752
|
const coordinator2 = new AutoIndexCoordinator(registration);
|
|
14783
15753
|
coordinator2.activateAfter(activation);
|
|
@@ -14793,11 +15763,17 @@ function configureAutoIndex(projectRoot, host, config, getIndexer) {
|
|
|
14793
15763
|
coordinator.update(registration);
|
|
14794
15764
|
}
|
|
14795
15765
|
coordinatorKeysByProject.set(projectKey, key);
|
|
15766
|
+
if (synchronizeWorker) {
|
|
15767
|
+
synchronizeBackgroundWorker(projectRoot, host, config, safety.safeToRun);
|
|
15768
|
+
}
|
|
14796
15769
|
}
|
|
14797
|
-
function
|
|
14798
|
-
return getCoordinator(projectRoot, host)?.start(source) ?? null;
|
|
15770
|
+
function startAutoIndexForBackgroundWorker(projectRoot, host, source = "startup", allowDisabledAutoIndex = false) {
|
|
15771
|
+
return getCoordinator(projectRoot, host)?.start(source, allowDisabledAutoIndex) ?? null;
|
|
14799
15772
|
}
|
|
14800
15773
|
function requestBackgroundIndex(projectRoot, host) {
|
|
15774
|
+
if (isBackgroundWorkerManaged(projectRoot, host) && !isBackgroundWorkerLeader(projectRoot, host)) {
|
|
15775
|
+
return null;
|
|
15776
|
+
}
|
|
14801
15777
|
return getCoordinator(projectRoot, host)?.request({
|
|
14802
15778
|
checkFreshness: false,
|
|
14803
15779
|
force: false,
|
|
@@ -14837,15 +15813,23 @@ async function waitForAutoIndexForRetrieval(projectRoot, host) {
|
|
|
14837
15813
|
};
|
|
14838
15814
|
}
|
|
14839
15815
|
try {
|
|
14840
|
-
|
|
15816
|
+
const readiness = await getSearchReadiness(coordinator);
|
|
15817
|
+
if (readiness.searchable) {
|
|
15818
|
+
return { ready: true };
|
|
15819
|
+
}
|
|
15820
|
+
if (readiness.blocked) return unavailableSnapshotResult(readiness.reason);
|
|
14841
15821
|
} catch {
|
|
14842
15822
|
}
|
|
14843
|
-
const job =
|
|
15823
|
+
const job = startRetrievalRefresh(projectRoot, host, coordinator);
|
|
14844
15824
|
if (job) {
|
|
14845
15825
|
await withTimeout(job, coordinator.getWaitMs());
|
|
15826
|
+
} else if (isBackgroundWorkerManaged(projectRoot, host)) {
|
|
15827
|
+
await waitForPublishedSnapshot(coordinator, coordinator.getWaitMs());
|
|
14846
15828
|
}
|
|
14847
15829
|
try {
|
|
14848
|
-
|
|
15830
|
+
const readiness = await getSearchReadiness(coordinator);
|
|
15831
|
+
if (readiness.searchable) return { ready: true };
|
|
15832
|
+
if (readiness.blocked) return unavailableSnapshotResult(readiness.reason);
|
|
14849
15833
|
} catch {
|
|
14850
15834
|
}
|
|
14851
15835
|
const status = coordinator.snapshot();
|
|
@@ -14866,31 +15850,62 @@ async function waitForAutoIndexForRetrieval(projectRoot, host) {
|
|
|
14866
15850
|
text: `Automatic indexing is ${status.state}. Retry shortly or call index_status for progress. You can also run index_codebase explicitly.`
|
|
14867
15851
|
};
|
|
14868
15852
|
}
|
|
14869
|
-
async function
|
|
14870
|
-
|
|
15853
|
+
async function stopAutoIndexForBackgroundWorker(projectRoot, host, waitForCompletion = false) {
|
|
15854
|
+
const coordinator = getCoordinator(projectRoot, host);
|
|
15855
|
+
if (!coordinator) {
|
|
15856
|
+
return { completed: true, completion: Promise.resolve() };
|
|
15857
|
+
}
|
|
15858
|
+
return coordinator.stop(waitForCompletion);
|
|
14871
15859
|
}
|
|
14872
|
-
async function
|
|
15860
|
+
async function getSearchReadiness(coordinator) {
|
|
14873
15861
|
const indexer = coordinator.getIndexer();
|
|
14874
15862
|
if (indexer.getIndexFreshness) {
|
|
14875
15863
|
const freshness = await indexer.getIndexFreshness();
|
|
14876
|
-
|
|
15864
|
+
const searchable = freshness.readable && freshness.current && freshness.reason === "current";
|
|
15865
|
+
return {
|
|
15866
|
+
blocked: freshness.reason === "unreadable" || freshness.reason === "incompatible" || freshness.reason === "failed-batches" || freshness.reason === "migration-required",
|
|
15867
|
+
reason: freshness.reason,
|
|
15868
|
+
searchable
|
|
15869
|
+
};
|
|
15870
|
+
}
|
|
15871
|
+
const indexed = (await indexer.getStatus()).indexed;
|
|
15872
|
+
return { blocked: false, searchable: indexed };
|
|
15873
|
+
}
|
|
15874
|
+
function unavailableSnapshotResult(reason) {
|
|
15875
|
+
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.";
|
|
15876
|
+
return {
|
|
15877
|
+
ready: false,
|
|
15878
|
+
text: `${detail} Run index_codebase before retrying retrieval.`
|
|
15879
|
+
};
|
|
15880
|
+
}
|
|
15881
|
+
function startRetrievalRefresh(projectRoot, host, coordinator) {
|
|
15882
|
+
if (isBackgroundWorkerManaged(projectRoot, host)) {
|
|
15883
|
+
requestBackgroundWorkerRefresh(projectRoot, host, true);
|
|
15884
|
+
return isBackgroundWorkerLeader(projectRoot, host) ? coordinator.currentJob() : null;
|
|
15885
|
+
}
|
|
15886
|
+
return coordinator.start("retrieval") ?? coordinator.currentJob();
|
|
15887
|
+
}
|
|
15888
|
+
async function waitForPublishedSnapshot(coordinator, waitMs) {
|
|
15889
|
+
const deadline = Date.now() + waitMs;
|
|
15890
|
+
while (Date.now() < deadline) {
|
|
15891
|
+
if ((await getSearchReadiness(coordinator)).searchable) return;
|
|
15892
|
+
await new Promise((resolve21) => setTimeout(resolve21, Math.min(250, deadline - Date.now())));
|
|
14877
15893
|
}
|
|
14878
|
-
return (await indexer.getStatus()).indexed;
|
|
14879
15894
|
}
|
|
14880
15895
|
|
|
14881
15896
|
// src/tools/config-state.ts
|
|
14882
|
-
import { existsSync as
|
|
14883
|
-
import * as
|
|
15897
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync6, writeFileSync as writeFileSync5 } from "fs";
|
|
15898
|
+
import * as path21 from "path";
|
|
14884
15899
|
|
|
14885
15900
|
// src/config/merger.ts
|
|
14886
|
-
import { existsSync as
|
|
14887
|
-
import * as
|
|
15901
|
+
import { existsSync as existsSync11, readFileSync as readFileSync10 } from "fs";
|
|
15902
|
+
import * as path20 from "path";
|
|
14888
15903
|
|
|
14889
15904
|
// src/config/rebase.ts
|
|
14890
|
-
import * as
|
|
15905
|
+
import * as path19 from "path";
|
|
14891
15906
|
function isWithinRoot(rootDir, targetPath) {
|
|
14892
|
-
const relativePath =
|
|
14893
|
-
return relativePath === "" || !relativePath.startsWith("..") && !
|
|
15907
|
+
const relativePath = path19.relative(rootDir, targetPath);
|
|
15908
|
+
return relativePath === "" || !relativePath.startsWith("..") && !path19.isAbsolute(relativePath);
|
|
14894
15909
|
}
|
|
14895
15910
|
function rebasePathEntries(values, fromDir, toDir) {
|
|
14896
15911
|
if (!Array.isArray(values)) {
|
|
@@ -14898,10 +15913,10 @@ function rebasePathEntries(values, fromDir, toDir) {
|
|
|
14898
15913
|
}
|
|
14899
15914
|
return values.filter((value) => typeof value === "string").map((value) => {
|
|
14900
15915
|
const trimmed = value.trim();
|
|
14901
|
-
if (!trimmed ||
|
|
15916
|
+
if (!trimmed || path19.isAbsolute(trimmed)) {
|
|
14902
15917
|
return trimmed;
|
|
14903
15918
|
}
|
|
14904
|
-
return normalizePathSeparators(
|
|
15919
|
+
return normalizePathSeparators(path19.normalize(path19.relative(toDir, path19.resolve(fromDir, trimmed))));
|
|
14905
15920
|
}).filter(Boolean);
|
|
14906
15921
|
}
|
|
14907
15922
|
function resolveInheritedKnowledgeBaseEntries(values, sourceRoot, targetRoot) {
|
|
@@ -14913,17 +15928,17 @@ function resolveInheritedKnowledgeBaseEntries(values, sourceRoot, targetRoot) {
|
|
|
14913
15928
|
if (!trimmed) {
|
|
14914
15929
|
return trimmed;
|
|
14915
15930
|
}
|
|
14916
|
-
if (
|
|
15931
|
+
if (path19.isAbsolute(trimmed)) {
|
|
14917
15932
|
if (isWithinRoot(sourceRoot, trimmed)) {
|
|
14918
|
-
return normalizePathSeparators(
|
|
15933
|
+
return normalizePathSeparators(path19.normalize(path19.relative(sourceRoot, trimmed) || "."));
|
|
14919
15934
|
}
|
|
14920
|
-
return
|
|
15935
|
+
return path19.normalize(trimmed);
|
|
14921
15936
|
}
|
|
14922
|
-
const resolvedFromSource =
|
|
15937
|
+
const resolvedFromSource = path19.resolve(sourceRoot, trimmed);
|
|
14923
15938
|
if (isWithinRoot(sourceRoot, resolvedFromSource)) {
|
|
14924
|
-
return normalizePathSeparators(
|
|
15939
|
+
return normalizePathSeparators(path19.normalize(trimmed));
|
|
14925
15940
|
}
|
|
14926
|
-
return normalizePathSeparators(
|
|
15941
|
+
return normalizePathSeparators(path19.normalize(path19.relative(targetRoot, resolvedFromSource)));
|
|
14927
15942
|
}).filter(Boolean);
|
|
14928
15943
|
}
|
|
14929
15944
|
|
|
@@ -14961,8 +15976,8 @@ function mergeUniqueStringArray(values) {
|
|
|
14961
15976
|
return [...new Set(values.map((value) => String(value).trim()))];
|
|
14962
15977
|
}
|
|
14963
15978
|
function normalizeKnowledgeBasePath2(value) {
|
|
14964
|
-
let normalized =
|
|
14965
|
-
const root =
|
|
15979
|
+
let normalized = path20.normalize(String(value).trim());
|
|
15980
|
+
const root = path20.parse(normalized).root;
|
|
14966
15981
|
while (normalized.length > root.length && /[\\/]$/.test(normalized)) {
|
|
14967
15982
|
normalized = normalized.slice(0, -1);
|
|
14968
15983
|
}
|
|
@@ -14996,11 +16011,11 @@ function validateConfigLayerShape(rawConfig, filePath) {
|
|
|
14996
16011
|
return rawConfig;
|
|
14997
16012
|
}
|
|
14998
16013
|
function loadJsonFile(filePath) {
|
|
14999
|
-
if (!
|
|
16014
|
+
if (!existsSync11(filePath)) {
|
|
15000
16015
|
return null;
|
|
15001
16016
|
}
|
|
15002
16017
|
try {
|
|
15003
|
-
const content =
|
|
16018
|
+
const content = readFileSync10(filePath, "utf-8");
|
|
15004
16019
|
return validateConfigLayerShape(JSON.parse(content), filePath);
|
|
15005
16020
|
} catch (error) {
|
|
15006
16021
|
if (error instanceof Error && error.message.startsWith("Config file ")) {
|
|
@@ -15020,7 +16035,7 @@ function loadProjectConfigLayer(projectRoot, host) {
|
|
|
15020
16035
|
return {};
|
|
15021
16036
|
}
|
|
15022
16037
|
const normalizedConfig = { ...projectConfig };
|
|
15023
|
-
const projectConfigBaseDir =
|
|
16038
|
+
const projectConfigBaseDir = path20.dirname(path20.dirname(projectConfigPath));
|
|
15024
16039
|
if (Array.isArray(normalizedConfig.knowledgeBases)) {
|
|
15025
16040
|
normalizedConfig.knowledgeBases = resolveInheritedKnowledgeBaseEntries(
|
|
15026
16041
|
normalizedConfig.knowledgeBases,
|
|
@@ -15110,10 +16125,10 @@ function loadEditableConfig(projectRoot, host) {
|
|
|
15110
16125
|
}
|
|
15111
16126
|
function saveConfig(projectRoot, config, host) {
|
|
15112
16127
|
const configPath = getConfigPath(projectRoot, host);
|
|
15113
|
-
const configDir =
|
|
15114
|
-
const configBaseDir =
|
|
15115
|
-
if (!
|
|
15116
|
-
|
|
16128
|
+
const configDir = path21.dirname(configPath);
|
|
16129
|
+
const configBaseDir = path21.dirname(configDir);
|
|
16130
|
+
if (!existsSync12(configDir)) {
|
|
16131
|
+
mkdirSync6(configDir, { recursive: true });
|
|
15117
16132
|
}
|
|
15118
16133
|
const serializableConfig = { ...config };
|
|
15119
16134
|
if (Array.isArray(serializableConfig.knowledgeBases)) {
|
|
@@ -15121,7 +16136,7 @@ function saveConfig(projectRoot, config, host) {
|
|
|
15121
16136
|
(kb) => serializeConfigPathValue(kb, configBaseDir)
|
|
15122
16137
|
);
|
|
15123
16138
|
}
|
|
15124
|
-
|
|
16139
|
+
writeFileSync5(configPath, JSON.stringify(serializableConfig, null, 2) + "\n", "utf-8");
|
|
15125
16140
|
}
|
|
15126
16141
|
|
|
15127
16142
|
// src/tools/operation-runtime.ts
|
|
@@ -15200,15 +16215,24 @@ function getOrCreateIndexer(projectRoot, host) {
|
|
|
15200
16215
|
}
|
|
15201
16216
|
const indexer = new Indexer(projectRoot, config, host);
|
|
15202
16217
|
indexerCache.set(key, indexer);
|
|
15203
|
-
configureAutoIndex(projectRoot, host, config, () => getOrCreateIndexer(projectRoot, host)
|
|
16218
|
+
configureAutoIndex(projectRoot, host, config, () => getOrCreateIndexer(projectRoot, host), {
|
|
16219
|
+
preserveManagedWorker: true,
|
|
16220
|
+
synchronizeBackgroundWorker: false
|
|
16221
|
+
});
|
|
15204
16222
|
return indexer;
|
|
15205
16223
|
}
|
|
15206
|
-
function initializeTools(projectRoot, config, host) {
|
|
16224
|
+
function initializeTools(projectRoot, config, host, options = {}) {
|
|
15207
16225
|
defaultProjectRoots.set(host, projectRoot);
|
|
15208
16226
|
const key = getIndexerCacheKey(projectRoot, host);
|
|
16227
|
+
if (options.preserveManagedWorker === true && isBackgroundWorkerManaged(projectRoot, host) && indexerCache.has(key)) {
|
|
16228
|
+
return;
|
|
16229
|
+
}
|
|
15209
16230
|
configCache.set(key, config);
|
|
15210
16231
|
indexerCache.set(key, new Indexer(projectRoot, config, host));
|
|
15211
|
-
configureAutoIndex(projectRoot, host, config, () => getOrCreateIndexer(projectRoot, host)
|
|
16232
|
+
configureAutoIndex(projectRoot, host, config, () => getOrCreateIndexer(projectRoot, host), {
|
|
16233
|
+
preserveManagedWorker: options.preserveManagedWorker,
|
|
16234
|
+
synchronizeBackgroundWorker: false
|
|
16235
|
+
});
|
|
15212
16236
|
}
|
|
15213
16237
|
function getIndexerForProject(projectRoot, host) {
|
|
15214
16238
|
const root = getProjectRoot(projectRoot, host);
|
|
@@ -15222,7 +16246,9 @@ function refreshIndexerForDirectory(projectRoot, host, config = parseConfig(load
|
|
|
15222
16246
|
const key = getIndexerCacheKey(projectRoot, host);
|
|
15223
16247
|
configCache.set(key, config);
|
|
15224
16248
|
indexerCache.set(key, new Indexer(projectRoot, config, host));
|
|
15225
|
-
configureAutoIndex(projectRoot, host, config, () => getOrCreateIndexer(projectRoot, host)
|
|
16249
|
+
configureAutoIndex(projectRoot, host, config, () => getOrCreateIndexer(projectRoot, host), {
|
|
16250
|
+
synchronizeBackgroundWorker: true
|
|
16251
|
+
});
|
|
15226
16252
|
return config;
|
|
15227
16253
|
}
|
|
15228
16254
|
var AutoIndexRetrievalUnavailableError = class extends Error {
|
|
@@ -15249,7 +16275,7 @@ function trimOrUndefined(value) {
|
|
|
15249
16275
|
return normalized || void 0;
|
|
15250
16276
|
}
|
|
15251
16277
|
function normalizeCallGraphPath(value) {
|
|
15252
|
-
let normalized =
|
|
16278
|
+
let normalized = path22.posix.normalize(value.trim().replaceAll("\\", "/"));
|
|
15253
16279
|
if (normalized.startsWith("./")) {
|
|
15254
16280
|
normalized = normalized.slice(2);
|
|
15255
16281
|
}
|
|
@@ -15442,12 +16468,12 @@ async function getCallGraphPath(projectRoot, host, from, to, maxDepth, fromFileP
|
|
|
15442
16468
|
if (fromResolution.status !== "resolved" || toResolution.status !== "resolved") {
|
|
15443
16469
|
return { from: fromResolution, to: toResolution, path: [] };
|
|
15444
16470
|
}
|
|
15445
|
-
const
|
|
16471
|
+
const path34 = await indexer.findCallPathBySymbolIds(
|
|
15446
16472
|
fromResolution.symbolId,
|
|
15447
16473
|
toResolution.symbolId,
|
|
15448
16474
|
maxDepth
|
|
15449
16475
|
);
|
|
15450
|
-
return { from: fromResolution, to: toResolution, path:
|
|
16476
|
+
return { from: fromResolution, to: toResolution, path: path34 };
|
|
15451
16477
|
}
|
|
15452
16478
|
async function runIndexCodebase(projectRoot, host, args, onProgress) {
|
|
15453
16479
|
const root = getProjectRoot(projectRoot, host);
|
|
@@ -15645,15 +16671,15 @@ async function getIndexLogs(projectRoot, host, args) {
|
|
|
15645
16671
|
function addKnowledgeBase(projectRoot, host, knowledgeBasePath) {
|
|
15646
16672
|
const root = getProjectRoot(projectRoot, host);
|
|
15647
16673
|
const inputPath = knowledgeBasePath.trim();
|
|
15648
|
-
const normalizedPath3 =
|
|
15649
|
-
|
|
16674
|
+
const normalizedPath3 = path22.resolve(
|
|
16675
|
+
path22.isAbsolute(inputPath) ? inputPath : resolveKnowledgeBasePath(inputPath, root)
|
|
15650
16676
|
);
|
|
15651
|
-
if (!
|
|
16677
|
+
if (!existsSync13(normalizedPath3)) {
|
|
15652
16678
|
return `Error: Directory does not exist: ${normalizedPath3}`;
|
|
15653
16679
|
}
|
|
15654
16680
|
let realPath;
|
|
15655
16681
|
try {
|
|
15656
|
-
realPath =
|
|
16682
|
+
realPath = realpathSync6(normalizedPath3);
|
|
15657
16683
|
} catch {
|
|
15658
16684
|
return `Error: Cannot resolve path: ${normalizedPath3}`;
|
|
15659
16685
|
}
|
|
@@ -15682,7 +16708,7 @@ function addKnowledgeBase(projectRoot, host, knowledgeBasePath) {
|
|
|
15682
16708
|
}
|
|
15683
16709
|
}
|
|
15684
16710
|
for (const dotDir of sensitiveDotDirs) {
|
|
15685
|
-
const sensitiveDir =
|
|
16711
|
+
const sensitiveDir = path22.join(homeDir, dotDir);
|
|
15686
16712
|
if (sensitiveDir && (realPath === sensitiveDir || realPath.startsWith(`${sensitiveDir}/`))) {
|
|
15687
16713
|
return `Error: Adding sensitive directory as knowledge base is not allowed: ${normalizedPath3}`;
|
|
15688
16714
|
}
|
|
@@ -15728,7 +16754,7 @@ function listKnowledgeBases(projectRoot, host) {
|
|
|
15728
16754
|
for (let i = 0; i < knowledgeBases.length; i++) {
|
|
15729
16755
|
const kb = knowledgeBases[i];
|
|
15730
16756
|
const resolvedPath = resolveKnowledgeBasePath(kb, root);
|
|
15731
|
-
const exists =
|
|
16757
|
+
const exists = existsSync13(resolvedPath);
|
|
15732
16758
|
result += `[${i + 1}] ${kb}
|
|
15733
16759
|
`;
|
|
15734
16760
|
result += ` Resolved: ${resolvedPath}
|
|
@@ -15745,7 +16771,7 @@ function listKnowledgeBases(projectRoot, host) {
|
|
|
15745
16771
|
}
|
|
15746
16772
|
result += "\n";
|
|
15747
16773
|
}
|
|
15748
|
-
const hasHostConfig =
|
|
16774
|
+
const hasHostConfig = existsSync13(path22.join(root, getHostProjectConfigRelativePath(host)));
|
|
15749
16775
|
if (hasHostConfig) {
|
|
15750
16776
|
result += `
|
|
15751
16777
|
Config sources: 1 file(s).`;
|
|
@@ -16218,7 +17244,7 @@ async function resolveCodebaseContextUnmeasured(projectRoot, host, input) {
|
|
|
16218
17244
|
const directory = input.directory ?? void 0;
|
|
16219
17245
|
const tokenBudget = input.tokenBudget ?? void 0;
|
|
16220
17246
|
if (from && to) {
|
|
16221
|
-
const
|
|
17247
|
+
const path34 = await getCallGraphPath(
|
|
16222
17248
|
projectRoot,
|
|
16223
17249
|
host,
|
|
16224
17250
|
from,
|
|
@@ -16227,25 +17253,25 @@ async function resolveCodebaseContextUnmeasured(projectRoot, host, input) {
|
|
|
16227
17253
|
fromFilePath,
|
|
16228
17254
|
toFilePath
|
|
16229
17255
|
);
|
|
16230
|
-
const pathText = formatCallGraphPathResult(
|
|
16231
|
-
if (
|
|
17256
|
+
const pathText = formatCallGraphPathResult(path34);
|
|
17257
|
+
if (path34.path.length > 0) {
|
|
16232
17258
|
const fitted2 = fitTextToContextBudget(
|
|
16233
17259
|
pathText,
|
|
16234
17260
|
tokenBudget
|
|
16235
17261
|
);
|
|
16236
17262
|
return {
|
|
16237
17263
|
text: fitted2.text,
|
|
16238
|
-
details: fittedDetails("path", fitted2,
|
|
17264
|
+
details: fittedDetails("path", fitted2, path34.path.length)
|
|
16239
17265
|
};
|
|
16240
17266
|
}
|
|
16241
|
-
if (
|
|
17267
|
+
if (path34.from.status !== "resolved" || path34.to.status !== "resolved") {
|
|
16242
17268
|
const fitted2 = fitTextToContextBudget(pathText, tokenBudget);
|
|
16243
17269
|
return {
|
|
16244
17270
|
text: fitted2.text,
|
|
16245
17271
|
details: fittedDetails("path", fitted2, 0)
|
|
16246
17272
|
};
|
|
16247
17273
|
}
|
|
16248
|
-
const resolvedFrom =
|
|
17274
|
+
const resolvedFrom = path34.from;
|
|
16249
17275
|
const { callers } = await getCallGraphData(projectRoot, host, {
|
|
16250
17276
|
name: to,
|
|
16251
17277
|
direction: "callers",
|
|
@@ -16723,9 +17749,9 @@ function getRelevantEvidence(query) {
|
|
|
16723
17749
|
});
|
|
16724
17750
|
}
|
|
16725
17751
|
if (query.expected.acceptableFiles) {
|
|
16726
|
-
for (const
|
|
17752
|
+
for (const path34 of query.expected.acceptableFiles) {
|
|
16727
17753
|
legacyEvidence.push({
|
|
16728
|
-
path:
|
|
17754
|
+
path: path34,
|
|
16729
17755
|
...query.expected.symbol !== void 0 ? { symbol: query.expected.symbol } : {},
|
|
16730
17756
|
relevance: 1
|
|
16731
17757
|
});
|
|
@@ -17047,9 +18073,9 @@ function computeEvalMetrics(queries, perQuery, embeddingCallCount, embeddingToke
|
|
|
17047
18073
|
}
|
|
17048
18074
|
|
|
17049
18075
|
// src/eval/runner-config.ts
|
|
17050
|
-
import { existsSync as
|
|
17051
|
-
import * as
|
|
17052
|
-
import * as
|
|
18076
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync7, readFileSync as readFileSync11, rmSync as rmSync4, writeFileSync as writeFileSync6 } from "fs";
|
|
18077
|
+
import * as os8 from "os";
|
|
18078
|
+
import * as path23 from "path";
|
|
17053
18079
|
function isRecord2(value) {
|
|
17054
18080
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
17055
18081
|
}
|
|
@@ -17083,7 +18109,7 @@ function validateEvalConfigShape(rawConfig, filePath) {
|
|
|
17083
18109
|
}
|
|
17084
18110
|
function parseJsonConfigFile(filePath) {
|
|
17085
18111
|
try {
|
|
17086
|
-
return validateEvalConfigShape(JSON.parse(
|
|
18112
|
+
return validateEvalConfigShape(JSON.parse(readFileSync11(filePath, "utf-8")), filePath);
|
|
17087
18113
|
} catch (error) {
|
|
17088
18114
|
if (error instanceof Error && error.message.startsWith("Eval config at ")) {
|
|
17089
18115
|
throw error;
|
|
@@ -17093,20 +18119,20 @@ function parseJsonConfigFile(filePath) {
|
|
|
17093
18119
|
}
|
|
17094
18120
|
}
|
|
17095
18121
|
function toAbsolute(projectRoot, maybeRelative) {
|
|
17096
|
-
return
|
|
18122
|
+
return path23.isAbsolute(maybeRelative) ? maybeRelative : path23.join(projectRoot, maybeRelative);
|
|
17097
18123
|
}
|
|
17098
18124
|
function isProjectScopedConfigPath(configPath) {
|
|
17099
|
-
return
|
|
18125
|
+
return path23.basename(configPath) === "codebase-index.json" && path23.basename(path23.dirname(configPath)) === ".opencode";
|
|
17100
18126
|
}
|
|
17101
18127
|
function normalizeEvalConfigKnowledgeBases(rawConfig, projectRoot, resolvedConfigPath) {
|
|
17102
18128
|
const config = rawConfig && typeof rawConfig === "object" ? { ...rawConfig } : {};
|
|
17103
18129
|
const rebaseEntries = (values) => isProjectScopedConfigPath(resolvedConfigPath) ? resolveInheritedKnowledgeBaseEntries(
|
|
17104
18130
|
values,
|
|
17105
|
-
|
|
18131
|
+
path23.dirname(path23.dirname(resolvedConfigPath)),
|
|
17106
18132
|
projectRoot
|
|
17107
18133
|
) : rebasePathEntries(
|
|
17108
18134
|
values,
|
|
17109
|
-
|
|
18135
|
+
path23.dirname(resolvedConfigPath),
|
|
17110
18136
|
projectRoot
|
|
17111
18137
|
);
|
|
17112
18138
|
if (Array.isArray(config.knowledgeBases)) {
|
|
@@ -17119,7 +18145,7 @@ function normalizeEvalConfigKnowledgeBases(rawConfig, projectRoot, resolvedConfi
|
|
|
17119
18145
|
}
|
|
17120
18146
|
function loadRawConfig(projectRoot, configPath) {
|
|
17121
18147
|
const fromPath = configPath ? toAbsolute(projectRoot, configPath) : null;
|
|
17122
|
-
if (fromPath &&
|
|
18148
|
+
if (fromPath && existsSync14(fromPath)) {
|
|
17123
18149
|
return normalizeEvalConfigKnowledgeBases(
|
|
17124
18150
|
parseJsonConfigFile(fromPath),
|
|
17125
18151
|
projectRoot,
|
|
@@ -17127,15 +18153,15 @@ function loadRawConfig(projectRoot, configPath) {
|
|
|
17127
18153
|
);
|
|
17128
18154
|
}
|
|
17129
18155
|
const projectConfig = resolveProjectConfigPath(projectRoot, "opencode");
|
|
17130
|
-
if (
|
|
18156
|
+
if (existsSync14(projectConfig)) {
|
|
17131
18157
|
return normalizeEvalConfigKnowledgeBases(
|
|
17132
18158
|
parseJsonConfigFile(projectConfig),
|
|
17133
18159
|
projectRoot,
|
|
17134
18160
|
projectConfig
|
|
17135
18161
|
);
|
|
17136
18162
|
}
|
|
17137
|
-
const globalConfig =
|
|
17138
|
-
if (
|
|
18163
|
+
const globalConfig = path23.join(os8.homedir(), ".config", "opencode", "codebase-index.json");
|
|
18164
|
+
if (existsSync14(globalConfig)) {
|
|
17139
18165
|
return parseJsonConfigFile(globalConfig);
|
|
17140
18166
|
}
|
|
17141
18167
|
return {};
|
|
@@ -17144,24 +18170,24 @@ function getIndexRootPath(projectRoot, scope) {
|
|
|
17144
18170
|
return scope === "global" ? getGlobalIndexPath("opencode") : resolveProjectIndexPath(projectRoot, scope, "opencode");
|
|
17145
18171
|
}
|
|
17146
18172
|
function getLocalProjectIndexRoot(projectRoot) {
|
|
17147
|
-
return
|
|
18173
|
+
return path23.join(projectRoot, ".opencode", "index");
|
|
17148
18174
|
}
|
|
17149
18175
|
function getLocalProjectConfigPath(projectRoot) {
|
|
17150
|
-
return
|
|
18176
|
+
return path23.join(projectRoot, ".opencode", "codebase-index.json");
|
|
17151
18177
|
}
|
|
17152
18178
|
function clearIndexRoot(projectRoot, scope) {
|
|
17153
18179
|
const indexRoot = scope === "global" ? getIndexRootPath(projectRoot, scope) : getLocalProjectIndexRoot(projectRoot);
|
|
17154
|
-
if (
|
|
17155
|
-
|
|
18180
|
+
if (existsSync14(indexRoot)) {
|
|
18181
|
+
rmSync4(indexRoot, { recursive: true, force: true });
|
|
17156
18182
|
}
|
|
17157
18183
|
}
|
|
17158
18184
|
function ensureLocalEvalProjectConfig(projectRoot, configPath) {
|
|
17159
18185
|
const localConfigPath = getLocalProjectConfigPath(projectRoot);
|
|
17160
18186
|
const resolvedConfigPath = configPath ? toAbsolute(projectRoot, configPath) : resolveProjectConfigPath(projectRoot, "opencode");
|
|
17161
|
-
if (!configPath &&
|
|
18187
|
+
if (!configPath && existsSync14(localConfigPath)) {
|
|
17162
18188
|
return localConfigPath;
|
|
17163
18189
|
}
|
|
17164
|
-
if (!
|
|
18190
|
+
if (!existsSync14(resolvedConfigPath) || resolvedConfigPath === localConfigPath) {
|
|
17165
18191
|
return resolvedConfigPath;
|
|
17166
18192
|
}
|
|
17167
18193
|
const sourceConfig = normalizeEvalConfigKnowledgeBases(
|
|
@@ -17169,8 +18195,8 @@ function ensureLocalEvalProjectConfig(projectRoot, configPath) {
|
|
|
17169
18195
|
projectRoot,
|
|
17170
18196
|
resolvedConfigPath
|
|
17171
18197
|
);
|
|
17172
|
-
|
|
17173
|
-
|
|
18198
|
+
mkdirSync7(path23.dirname(localConfigPath), { recursive: true });
|
|
18199
|
+
writeFileSync6(localConfigPath, JSON.stringify(sourceConfig, null, 2), "utf-8");
|
|
17174
18200
|
return localConfigPath;
|
|
17175
18201
|
}
|
|
17176
18202
|
function loadParsedConfig(projectRoot, configPath) {
|
|
@@ -17203,9 +18229,9 @@ function getEmbeddingCostPer1MTokens(embeddingProvider) {
|
|
|
17203
18229
|
}
|
|
17204
18230
|
|
|
17205
18231
|
// src/eval/schema.ts
|
|
17206
|
-
import { readFileSync as
|
|
18232
|
+
import { readFileSync as readFileSync12 } from "fs";
|
|
17207
18233
|
function parseJsonFile(filePath) {
|
|
17208
|
-
const content =
|
|
18234
|
+
const content = readFileSync12(filePath, "utf-8");
|
|
17209
18235
|
try {
|
|
17210
18236
|
return JSON.parse(content);
|
|
17211
18237
|
} catch (error) {
|
|
@@ -17222,68 +18248,68 @@ function isStringArray4(value) {
|
|
|
17222
18248
|
function isNonEmptyString(value) {
|
|
17223
18249
|
return typeof value === "string" && value.trim().length > 0;
|
|
17224
18250
|
}
|
|
17225
|
-
function asPositiveNumber(value,
|
|
18251
|
+
function asPositiveNumber(value, path34) {
|
|
17226
18252
|
if (typeof value !== "number" || Number.isNaN(value) || value < 0) {
|
|
17227
|
-
throw new Error(`${
|
|
18253
|
+
throw new Error(`${path34} must be a non-negative number`);
|
|
17228
18254
|
}
|
|
17229
18255
|
return value;
|
|
17230
18256
|
}
|
|
17231
|
-
function parseQueryType(value,
|
|
18257
|
+
function parseQueryType(value, path34) {
|
|
17232
18258
|
if (value === "definition" || value === "implementation-intent" || value === "similarity" || value === "keyword-heavy" || value === "conceptual") {
|
|
17233
18259
|
return value;
|
|
17234
18260
|
}
|
|
17235
18261
|
throw new Error(
|
|
17236
|
-
`${
|
|
18262
|
+
`${path34} must be one of: definition, implementation-intent, similarity, keyword-heavy, conceptual`
|
|
17237
18263
|
);
|
|
17238
18264
|
}
|
|
17239
|
-
function parseExpectedRoute(value,
|
|
18265
|
+
function parseExpectedRoute(value, path34) {
|
|
17240
18266
|
if (value === void 0) return void 0;
|
|
17241
18267
|
if (value === "search" || value === "definition") return value;
|
|
17242
|
-
throw new Error(`${
|
|
18268
|
+
throw new Error(`${path34} must be one of: search, definition`);
|
|
17243
18269
|
}
|
|
17244
|
-
function parseExpectedOutcome(value,
|
|
18270
|
+
function parseExpectedOutcome(value, path34) {
|
|
17245
18271
|
if (value === void 0) return void 0;
|
|
17246
18272
|
if (value === "results" || value === "no-results") {
|
|
17247
18273
|
return value;
|
|
17248
18274
|
}
|
|
17249
|
-
throw new Error(`${
|
|
18275
|
+
throw new Error(`${path34} must be one of: results, no-results`);
|
|
17250
18276
|
}
|
|
17251
|
-
function parseRecoveryExpectation(value,
|
|
18277
|
+
function parseRecoveryExpectation(value, path34) {
|
|
17252
18278
|
if (value === void 0) return void 0;
|
|
17253
18279
|
if (value === "none" || value === "filter-relaxed") {
|
|
17254
18280
|
return value;
|
|
17255
18281
|
}
|
|
17256
|
-
throw new Error(`${
|
|
18282
|
+
throw new Error(`${path34} must be one of: none, filter-relaxed`);
|
|
17257
18283
|
}
|
|
17258
|
-
function parseQueryDifficulty(value,
|
|
18284
|
+
function parseQueryDifficulty(value, path34) {
|
|
17259
18285
|
if (value === void 0) return void 0;
|
|
17260
18286
|
if (value === "easy" || value === "medium" || value === "hard") {
|
|
17261
18287
|
return value;
|
|
17262
18288
|
}
|
|
17263
|
-
throw new Error(`${
|
|
18289
|
+
throw new Error(`${path34} must be one of: easy, medium, hard`);
|
|
17264
18290
|
}
|
|
17265
|
-
function parseQueryTags(value,
|
|
18291
|
+
function parseQueryTags(value, path34) {
|
|
17266
18292
|
if (value === void 0) return void 0;
|
|
17267
18293
|
if (!isStringArray4(value) || value.some((tag) => tag.trim().length === 0)) {
|
|
17268
|
-
throw new Error(`${
|
|
18294
|
+
throw new Error(`${path34} must be an array of non-empty strings`);
|
|
17269
18295
|
}
|
|
17270
18296
|
if (value.length > 16) {
|
|
17271
|
-
throw new Error(`${
|
|
18297
|
+
throw new Error(`${path34} must contain at most 16 tags`);
|
|
17272
18298
|
}
|
|
17273
18299
|
return value;
|
|
17274
18300
|
}
|
|
17275
|
-
function parseQueryArgs(value,
|
|
18301
|
+
function parseQueryArgs(value, path34) {
|
|
17276
18302
|
if (value === void 0) return void 0;
|
|
17277
18303
|
if (!isRecord3(value)) {
|
|
17278
|
-
throw new Error(`${
|
|
17279
|
-
}
|
|
17280
|
-
const symbol = parseStringOrUndefined(value.symbol, `${
|
|
17281
|
-
const filePath = parseStringOrUndefined(value.filePath, `${
|
|
17282
|
-
const fileType = parseStringOrUndefined(value.fileType, `${
|
|
17283
|
-
const directory = parseStringOrUndefined(value.directory, `${
|
|
17284
|
-
const callerLimit = parsePositiveIntegerOrUndefined(value.callerLimit, `${
|
|
17285
|
-
const calleeLimit = parsePositiveIntegerOrUndefined(value.calleeLimit, `${
|
|
17286
|
-
const tokenBudget = parsePositiveIntegerOrUndefined(value.tokenBudget, `${
|
|
18304
|
+
throw new Error(`${path34} must be an object`);
|
|
18305
|
+
}
|
|
18306
|
+
const symbol = parseStringOrUndefined(value.symbol, `${path34}.symbol`);
|
|
18307
|
+
const filePath = parseStringOrUndefined(value.filePath, `${path34}.filePath`);
|
|
18308
|
+
const fileType = parseStringOrUndefined(value.fileType, `${path34}.fileType`);
|
|
18309
|
+
const directory = parseStringOrUndefined(value.directory, `${path34}.directory`);
|
|
18310
|
+
const callerLimit = parsePositiveIntegerOrUndefined(value.callerLimit, `${path34}.callerLimit`);
|
|
18311
|
+
const calleeLimit = parsePositiveIntegerOrUndefined(value.calleeLimit, `${path34}.calleeLimit`);
|
|
18312
|
+
const tokenBudget = parsePositiveIntegerOrUndefined(value.tokenBudget, `${path34}.tokenBudget`);
|
|
17287
18313
|
return {
|
|
17288
18314
|
...symbol !== void 0 ? { symbol } : {},
|
|
17289
18315
|
...filePath !== void 0 ? { filePath } : {},
|
|
@@ -17294,50 +18320,50 @@ function parseQueryArgs(value, path33) {
|
|
|
17294
18320
|
...tokenBudget !== void 0 ? { tokenBudget } : {}
|
|
17295
18321
|
};
|
|
17296
18322
|
}
|
|
17297
|
-
function parsePositiveIntegerOrUndefined(value,
|
|
18323
|
+
function parsePositiveIntegerOrUndefined(value, path34) {
|
|
17298
18324
|
if (value === void 0 || value === null) return void 0;
|
|
17299
18325
|
if (typeof value !== "number" || !Number.isInteger(value) || value <= 0) {
|
|
17300
|
-
throw new Error(`${
|
|
18326
|
+
throw new Error(`${path34} must be a positive integer`);
|
|
17301
18327
|
}
|
|
17302
18328
|
return value;
|
|
17303
18329
|
}
|
|
17304
18330
|
var SEMVER_VERSION_PATTERN = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
|
|
17305
|
-
function parseSemanticVersion(value,
|
|
18331
|
+
function parseSemanticVersion(value, path34) {
|
|
17306
18332
|
if (!isNonEmptyString(value)) {
|
|
17307
|
-
throw new Error(`${
|
|
18333
|
+
throw new Error(`${path34} must be a non-empty string`);
|
|
17308
18334
|
}
|
|
17309
18335
|
if (!SEMVER_VERSION_PATTERN.test(value)) {
|
|
17310
|
-
throw new Error(`${
|
|
18336
|
+
throw new Error(`${path34} must be a valid semantic version (MAJOR.MINOR.PATCH)`);
|
|
17311
18337
|
}
|
|
17312
18338
|
return value;
|
|
17313
18339
|
}
|
|
17314
|
-
function parseRetrievalMode(value,
|
|
18340
|
+
function parseRetrievalMode(value, path34) {
|
|
17315
18341
|
if (value === void 0 || value === "search") return "search";
|
|
17316
18342
|
if (value === "context" || value === "edit-context") return value;
|
|
17317
|
-
throw new Error(`${
|
|
18343
|
+
throw new Error(`${path34} must be one of: search, context, edit-context`);
|
|
17318
18344
|
}
|
|
17319
|
-
function parseStringOrUndefined(value,
|
|
18345
|
+
function parseStringOrUndefined(value, path34) {
|
|
17320
18346
|
if (value === void 0 || value === null) return void 0;
|
|
17321
18347
|
if (!isNonEmptyString(value)) {
|
|
17322
|
-
throw new Error(`${
|
|
18348
|
+
throw new Error(`${path34} must be a non-empty string`);
|
|
17323
18349
|
}
|
|
17324
18350
|
return value;
|
|
17325
18351
|
}
|
|
17326
|
-
function parseGradedEvidence(value,
|
|
18352
|
+
function parseGradedEvidence(value, path34) {
|
|
17327
18353
|
if (value === void 0) return [];
|
|
17328
18354
|
if (!Array.isArray(value)) {
|
|
17329
|
-
throw new Error(`${
|
|
18355
|
+
throw new Error(`${path34} must be an array`);
|
|
17330
18356
|
}
|
|
17331
18357
|
return value.map((entry, index) => {
|
|
17332
18358
|
if (!isRecord3(entry)) {
|
|
17333
|
-
throw new Error(`${
|
|
18359
|
+
throw new Error(`${path34}[${index}] must be an object`);
|
|
17334
18360
|
}
|
|
17335
|
-
const evidencePath = parseStringOrUndefined(entry.path, `${
|
|
18361
|
+
const evidencePath = parseStringOrUndefined(entry.path, `${path34}[${index}].path`);
|
|
17336
18362
|
if (evidencePath === void 0) {
|
|
17337
|
-
throw new Error(`${
|
|
18363
|
+
throw new Error(`${path34}[${index}].path is required`);
|
|
17338
18364
|
}
|
|
17339
|
-
const symbol = parseStringOrUndefined(entry.symbol, `${
|
|
17340
|
-
const relevance = parseEvidenceRelevance(entry.relevance, `${
|
|
18365
|
+
const symbol = parseStringOrUndefined(entry.symbol, `${path34}[${index}].symbol`);
|
|
18366
|
+
const relevance = parseEvidenceRelevance(entry.relevance, `${path34}[${index}].relevance`);
|
|
17341
18367
|
return {
|
|
17342
18368
|
path: evidencePath,
|
|
17343
18369
|
...symbol !== void 0 ? { symbol } : {},
|
|
@@ -17345,27 +18371,27 @@ function parseGradedEvidence(value, path33) {
|
|
|
17345
18371
|
};
|
|
17346
18372
|
});
|
|
17347
18373
|
}
|
|
17348
|
-
function parseEvidenceRelevance(value,
|
|
18374
|
+
function parseEvidenceRelevance(value, path34) {
|
|
17349
18375
|
if (value === void 0) {
|
|
17350
|
-
throw new Error(`${
|
|
18376
|
+
throw new Error(`${path34} is required`);
|
|
17351
18377
|
}
|
|
17352
18378
|
if (value !== 1 && value !== 2 && value !== 3) {
|
|
17353
|
-
throw new Error(`${
|
|
18379
|
+
throw new Error(`${path34} must be 1, 2, or 3`);
|
|
17354
18380
|
}
|
|
17355
18381
|
return value;
|
|
17356
18382
|
}
|
|
17357
|
-
function parseExpectedGraphNeighbor(value,
|
|
18383
|
+
function parseExpectedGraphNeighbor(value, path34) {
|
|
17358
18384
|
if (value === void 0) return void 0;
|
|
17359
18385
|
if (!isRecord3(value)) {
|
|
17360
|
-
throw new Error(`${
|
|
18386
|
+
throw new Error(`${path34} must be an object`);
|
|
17361
18387
|
}
|
|
17362
18388
|
if (value.direction !== "caller" && value.direction !== "callee") {
|
|
17363
|
-
throw new Error(`${
|
|
18389
|
+
throw new Error(`${path34}.direction must be one of: caller, callee`);
|
|
17364
18390
|
}
|
|
17365
|
-
const filePath = parseStringOrUndefined(value.filePath, `${
|
|
17366
|
-
const symbol = parseStringOrUndefined(value.symbol, `${
|
|
18391
|
+
const filePath = parseStringOrUndefined(value.filePath, `${path34}.filePath`);
|
|
18392
|
+
const symbol = parseStringOrUndefined(value.symbol, `${path34}.symbol`);
|
|
17367
18393
|
if (filePath === void 0 && symbol === void 0) {
|
|
17368
|
-
throw new Error(`${
|
|
18394
|
+
throw new Error(`${path34} must include filePath or symbol`);
|
|
17369
18395
|
}
|
|
17370
18396
|
return {
|
|
17371
18397
|
direction: value.direction,
|
|
@@ -17373,9 +18399,9 @@ function parseExpectedGraphNeighbor(value, path33) {
|
|
|
17373
18399
|
...symbol !== void 0 ? { symbol } : {}
|
|
17374
18400
|
};
|
|
17375
18401
|
}
|
|
17376
|
-
function parseExpected(input,
|
|
18402
|
+
function parseExpected(input, path34) {
|
|
17377
18403
|
if (!isRecord3(input)) {
|
|
17378
|
-
throw new Error(`${
|
|
18404
|
+
throw new Error(`${path34} must be an object`);
|
|
17379
18405
|
}
|
|
17380
18406
|
const filePathRaw = input.filePath;
|
|
17381
18407
|
const acceptableFilesRaw = input.acceptableFiles;
|
|
@@ -17386,29 +18412,29 @@ function parseExpected(input, path33) {
|
|
|
17386
18412
|
const recoveryExpectationRaw = input.recoveryExpectation;
|
|
17387
18413
|
const gradedEvidenceRaw = input.gradedEvidence;
|
|
17388
18414
|
const graphNeighborRaw = input.graphNeighbor;
|
|
17389
|
-
const filePath = parseStringOrUndefined(filePathRaw, `${
|
|
18415
|
+
const filePath = parseStringOrUndefined(filePathRaw, `${path34}.filePath`);
|
|
17390
18416
|
const acceptableFiles = isStringArray4(acceptableFilesRaw) ? acceptableFilesRaw : void 0;
|
|
17391
|
-
const gradedEvidence = parseGradedEvidence(gradedEvidenceRaw, `${
|
|
17392
|
-
const graphNeighbor = parseExpectedGraphNeighbor(graphNeighborRaw, `${
|
|
17393
|
-
const expectedOutcome = parseExpectedOutcome(expectedOutcomeRaw, `${
|
|
18417
|
+
const gradedEvidence = parseGradedEvidence(gradedEvidenceRaw, `${path34}.gradedEvidence`);
|
|
18418
|
+
const graphNeighbor = parseExpectedGraphNeighbor(graphNeighborRaw, `${path34}.graphNeighbor`);
|
|
18419
|
+
const expectedOutcome = parseExpectedOutcome(expectedOutcomeRaw, `${path34}.expectedOutcome`);
|
|
17394
18420
|
if (expectedOutcome !== "no-results" && !filePath && (!acceptableFiles || acceptableFiles.length === 0) && gradedEvidence.length === 0) {
|
|
17395
18421
|
throw new Error(
|
|
17396
|
-
`${
|
|
18422
|
+
`${path34} must include expected.filePath, expected.acceptableFiles, or expected.gradedEvidence`
|
|
17397
18423
|
);
|
|
17398
18424
|
}
|
|
17399
18425
|
if (acceptableFilesRaw !== void 0 && !isStringArray4(acceptableFilesRaw)) {
|
|
17400
|
-
throw new Error(`${
|
|
18426
|
+
throw new Error(`${path34}.acceptableFiles must be an array of strings`);
|
|
17401
18427
|
}
|
|
17402
18428
|
if (symbolRaw !== void 0 && typeof symbolRaw !== "string") {
|
|
17403
|
-
throw new Error(`${
|
|
18429
|
+
throw new Error(`${path34}.symbol must be a string when provided`);
|
|
17404
18430
|
}
|
|
17405
18431
|
if (branchRaw !== void 0 && typeof branchRaw !== "string") {
|
|
17406
|
-
throw new Error(`${
|
|
18432
|
+
throw new Error(`${path34}.branch must be a string when provided`);
|
|
17407
18433
|
}
|
|
17408
|
-
const expectedRoute = parseExpectedRoute(expectedRouteRaw, `${
|
|
18434
|
+
const expectedRoute = parseExpectedRoute(expectedRouteRaw, `${path34}.expectedRoute`);
|
|
17409
18435
|
const recoveryExpectation = parseRecoveryExpectation(
|
|
17410
18436
|
recoveryExpectationRaw,
|
|
17411
|
-
`${
|
|
18437
|
+
`${path34}.recoveryExpectation`
|
|
17412
18438
|
);
|
|
17413
18439
|
return {
|
|
17414
18440
|
filePath,
|
|
@@ -17422,13 +18448,13 @@ function parseExpected(input, path33) {
|
|
|
17422
18448
|
...graphNeighbor !== void 0 ? { graphNeighbor } : {}
|
|
17423
18449
|
};
|
|
17424
18450
|
}
|
|
17425
|
-
function parseQueryLanguage(value,
|
|
17426
|
-
return parseStringOrUndefined(value,
|
|
18451
|
+
function parseQueryLanguage(value, path34) {
|
|
18452
|
+
return parseStringOrUndefined(value, path34);
|
|
17427
18453
|
}
|
|
17428
18454
|
function parseQuery(input, index) {
|
|
17429
|
-
const
|
|
18455
|
+
const path34 = `queries[${index}]`;
|
|
17430
18456
|
if (!isRecord3(input)) {
|
|
17431
|
-
throw new Error(`${
|
|
18457
|
+
throw new Error(`${path34} must be an object`);
|
|
17432
18458
|
}
|
|
17433
18459
|
const id = input.id;
|
|
17434
18460
|
const query = input.query;
|
|
@@ -17440,21 +18466,21 @@ function parseQuery(input, index) {
|
|
|
17440
18466
|
const tags = input.tags;
|
|
17441
18467
|
const args = input.args;
|
|
17442
18468
|
if (typeof id !== "string" || id.trim().length === 0) {
|
|
17443
|
-
throw new Error(`${
|
|
18469
|
+
throw new Error(`${path34}.id must be a non-empty string`);
|
|
17444
18470
|
}
|
|
17445
18471
|
if (typeof query !== "string" || query.trim().length === 0) {
|
|
17446
|
-
throw new Error(`${
|
|
18472
|
+
throw new Error(`${path34}.query must be a non-empty string`);
|
|
17447
18473
|
}
|
|
17448
18474
|
return {
|
|
17449
18475
|
id,
|
|
17450
18476
|
query,
|
|
17451
|
-
queryType: parseQueryType(queryType, `${
|
|
17452
|
-
retrievalMode: parseRetrievalMode(retrievalMode, `${
|
|
17453
|
-
language: parseQueryLanguage(language, `${
|
|
17454
|
-
difficulty: parseQueryDifficulty(difficulty, `${
|
|
17455
|
-
args: parseQueryArgs(args, `${
|
|
17456
|
-
tags: parseQueryTags(tags, `${
|
|
17457
|
-
expected: parseExpected(expected, `${
|
|
18477
|
+
queryType: parseQueryType(queryType, `${path34}.queryType`),
|
|
18478
|
+
retrievalMode: parseRetrievalMode(retrievalMode, `${path34}.retrievalMode`),
|
|
18479
|
+
language: parseQueryLanguage(language, `${path34}.language`),
|
|
18480
|
+
difficulty: parseQueryDifficulty(difficulty, `${path34}.difficulty`),
|
|
18481
|
+
args: parseQueryArgs(args, `${path34}.args`),
|
|
18482
|
+
tags: parseQueryTags(tags, `${path34}.tags`),
|
|
18483
|
+
expected: parseExpected(expected, `${path34}.expected`)
|
|
17458
18484
|
};
|
|
17459
18485
|
}
|
|
17460
18486
|
function parseGoldenDataset(raw, sourceLabel) {
|
|
@@ -17870,13 +18896,13 @@ async function runEvaluation(options) {
|
|
|
17870
18896
|
};
|
|
17871
18897
|
const outputDir = createRunDirectory(toAbsolute(options.projectRoot, options.outputRoot));
|
|
17872
18898
|
const perQueryArtifact = buildPerQueryArtifact(perQuery);
|
|
17873
|
-
writeJson(
|
|
17874
|
-
writeJson(
|
|
18899
|
+
writeJson(path24.join(outputDir, "summary.json"), summary);
|
|
18900
|
+
writeJson(path24.join(outputDir, "per-query.json"), perQueryArtifact);
|
|
17875
18901
|
let comparison;
|
|
17876
18902
|
if (againstPath) {
|
|
17877
18903
|
const baseline = loadSummary(againstPath);
|
|
17878
18904
|
comparison = compareSummaries(summary, baseline, againstPath);
|
|
17879
|
-
writeJson(
|
|
18905
|
+
writeJson(path24.join(outputDir, "compare.json"), comparison);
|
|
17880
18906
|
}
|
|
17881
18907
|
let gate;
|
|
17882
18908
|
if (options.ciMode) {
|
|
@@ -17886,10 +18912,10 @@ async function runEvaluation(options) {
|
|
|
17886
18912
|
const budget = loadBudget(budgetPath);
|
|
17887
18913
|
if (!comparison && budget.baselinePath) {
|
|
17888
18914
|
const resolvedBaseline = toAbsolute(options.projectRoot, budget.baselinePath);
|
|
17889
|
-
if (
|
|
18915
|
+
if (existsSync15(resolvedBaseline)) {
|
|
17890
18916
|
const baselineSummary = loadSummary(resolvedBaseline);
|
|
17891
18917
|
comparison = compareSummaries(summary, baselineSummary, resolvedBaseline);
|
|
17892
|
-
writeJson(
|
|
18918
|
+
writeJson(path24.join(outputDir, "compare.json"), comparison);
|
|
17893
18919
|
} else if (budget.failOnMissingBaseline) {
|
|
17894
18920
|
throw new Error(
|
|
17895
18921
|
`Budget baseline is missing: ${resolvedBaseline}. Set failOnMissingBaseline=false to allow CI run without baseline.`
|
|
@@ -17899,7 +18925,7 @@ async function runEvaluation(options) {
|
|
|
17899
18925
|
gate = evaluateBudgetGate(budget, summary, comparison);
|
|
17900
18926
|
}
|
|
17901
18927
|
const markdown = createSummaryMarkdown(summary, comparison, gate);
|
|
17902
|
-
writeText(
|
|
18928
|
+
writeText(path24.join(outputDir, "summary.md"), markdown);
|
|
17903
18929
|
return { outputDir, summary, perQuery, comparison, gate };
|
|
17904
18930
|
} finally {
|
|
17905
18931
|
await indexer.close();
|
|
@@ -17957,23 +18983,23 @@ async function runSweep(options, sweep) {
|
|
|
17957
18983
|
bestByMrrAt10,
|
|
17958
18984
|
bestByP95Latency
|
|
17959
18985
|
};
|
|
17960
|
-
writeJson(
|
|
18986
|
+
writeJson(path24.join(outputDir, "compare.json"), aggregate);
|
|
17961
18987
|
const md = createSummaryMarkdown(
|
|
17962
18988
|
bestByHitAt5?.summary ?? runs[0].summary,
|
|
17963
18989
|
bestByHitAt5?.comparison,
|
|
17964
18990
|
void 0,
|
|
17965
18991
|
aggregate
|
|
17966
18992
|
);
|
|
17967
|
-
writeText(
|
|
17968
|
-
writeJson(
|
|
18993
|
+
writeText(path24.join(outputDir, "summary.md"), md);
|
|
18994
|
+
writeJson(path24.join(outputDir, "summary.json"), bestByHitAt5?.summary ?? runs[0].summary);
|
|
17969
18995
|
return { outputDir, aggregate };
|
|
17970
18996
|
}
|
|
17971
18997
|
|
|
17972
18998
|
// src/eval/cli.ts
|
|
17973
|
-
import * as
|
|
18999
|
+
import * as path26 from "path";
|
|
17974
19000
|
|
|
17975
19001
|
// src/eval/cli-parser.ts
|
|
17976
|
-
import * as
|
|
19002
|
+
import * as path25 from "path";
|
|
17977
19003
|
function printUsage() {
|
|
17978
19004
|
console.log(`
|
|
17979
19005
|
Usage:
|
|
@@ -18045,12 +19071,12 @@ function parseEvalArgs(argv, cwd) {
|
|
|
18045
19071
|
const arg = argv[i];
|
|
18046
19072
|
const next = argv[i + 1];
|
|
18047
19073
|
if (arg === "--project" && next) {
|
|
18048
|
-
parsed.projectRoot =
|
|
19074
|
+
parsed.projectRoot = path25.resolve(cwd, next);
|
|
18049
19075
|
i += 1;
|
|
18050
19076
|
continue;
|
|
18051
19077
|
}
|
|
18052
19078
|
if (arg === "--config" && next) {
|
|
18053
|
-
parsed.configPath =
|
|
19079
|
+
parsed.configPath = path25.resolve(cwd, next);
|
|
18054
19080
|
i += 1;
|
|
18055
19081
|
continue;
|
|
18056
19082
|
}
|
|
@@ -18246,22 +19272,22 @@ async function handleEvalCommand(args, cwd) {
|
|
|
18246
19272
|
if (!parsed.againstPath.endsWith(".json")) {
|
|
18247
19273
|
throw new Error("eval diff --against must point to a summary JSON file");
|
|
18248
19274
|
}
|
|
18249
|
-
const currentSummary = loadSummary(
|
|
19275
|
+
const currentSummary = loadSummary(path26.resolve(parsed.projectRoot, currentPath), {
|
|
18250
19276
|
allowLegacyDiversityMetrics: true
|
|
18251
19277
|
});
|
|
18252
|
-
const baselineSummary = loadSummary(
|
|
19278
|
+
const baselineSummary = loadSummary(path26.resolve(parsed.projectRoot, parsed.againstPath), {
|
|
18253
19279
|
allowLegacyDiversityMetrics: true
|
|
18254
19280
|
});
|
|
18255
19281
|
const comparison = compareSummaries(
|
|
18256
19282
|
currentSummary,
|
|
18257
19283
|
baselineSummary,
|
|
18258
|
-
|
|
19284
|
+
path26.resolve(parsed.projectRoot, parsed.againstPath)
|
|
18259
19285
|
);
|
|
18260
|
-
const outputDir = createRunDirectory(
|
|
19286
|
+
const outputDir = createRunDirectory(path26.resolve(parsed.projectRoot, parsed.outputRoot));
|
|
18261
19287
|
const summaryMd = createSummaryMarkdown(currentSummary, comparison);
|
|
18262
|
-
writeJson(
|
|
18263
|
-
writeText(
|
|
18264
|
-
writeJson(
|
|
19288
|
+
writeJson(path26.join(outputDir, "compare.json"), comparison);
|
|
19289
|
+
writeText(path26.join(outputDir, "summary.md"), summaryMd);
|
|
19290
|
+
writeJson(path26.join(outputDir, "summary.json"), currentSummary);
|
|
18265
19291
|
console.log(`Eval diff complete. Artifacts: ${outputDir}`);
|
|
18266
19292
|
return 0;
|
|
18267
19293
|
}
|
|
@@ -18272,9 +19298,9 @@ async function handleEvalCommand(args, cwd) {
|
|
|
18272
19298
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
18273
19299
|
|
|
18274
19300
|
// src/package-metadata.ts
|
|
18275
|
-
import { readFileSync as
|
|
19301
|
+
import { readFileSync as readFileSync13 } from "fs";
|
|
18276
19302
|
function getPackageVersion() {
|
|
18277
|
-
const raw = JSON.parse(
|
|
19303
|
+
const raw = JSON.parse(readFileSync13(new URL("../package.json", import.meta.url), "utf-8"));
|
|
18278
19304
|
if (raw && typeof raw === "object" && "version" in raw && typeof raw.version === "string") {
|
|
18279
19305
|
return raw.version;
|
|
18280
19306
|
}
|
|
@@ -18422,7 +19448,7 @@ async function executeCallGraph(projectRoot, host, args) {
|
|
|
18422
19448
|
return { text: formatCallGraphResult(await getCallGraphData(projectRoot, host, args)) };
|
|
18423
19449
|
}
|
|
18424
19450
|
async function executeCallGraphPath(projectRoot, host, args) {
|
|
18425
|
-
const
|
|
19451
|
+
const path34 = await getCallGraphPath(
|
|
18426
19452
|
projectRoot,
|
|
18427
19453
|
host,
|
|
18428
19454
|
args.from,
|
|
@@ -18431,7 +19457,7 @@ async function executeCallGraphPath(projectRoot, host, args) {
|
|
|
18431
19457
|
args.fromFilePath,
|
|
18432
19458
|
args.toFilePath
|
|
18433
19459
|
);
|
|
18434
|
-
return { text: formatCallGraphPathResult(
|
|
19460
|
+
return { text: formatCallGraphPathResult(path34) };
|
|
18435
19461
|
}
|
|
18436
19462
|
async function executeCodeCommunities(projectRoot, host, args) {
|
|
18437
19463
|
const result = await getCodeCommunities(projectRoot, host, args);
|
|
@@ -18926,10 +19952,65 @@ ${formatSearchResults(results)}` }] };
|
|
|
18926
19952
|
}
|
|
18927
19953
|
|
|
18928
19954
|
// src/adapters/mcp/server.ts
|
|
19955
|
+
var mcpWorkerReferences = /* @__PURE__ */ new Map();
|
|
19956
|
+
var mcpWorkerTeardowns = /* @__PURE__ */ new Map();
|
|
19957
|
+
function retainMcpBackgroundWorker(projectRoot, host) {
|
|
19958
|
+
const key = getBackgroundWorkerProjectKey(projectRoot, host);
|
|
19959
|
+
mcpWorkerReferences.set(key, (mcpWorkerReferences.get(key) ?? 0) + 1);
|
|
19960
|
+
}
|
|
19961
|
+
async function releaseMcpBackgroundWorker(projectRoot, host) {
|
|
19962
|
+
const key = getBackgroundWorkerProjectKey(projectRoot, host);
|
|
19963
|
+
const references = mcpWorkerReferences.get(key) ?? 0;
|
|
19964
|
+
if (references > 1) {
|
|
19965
|
+
mcpWorkerReferences.set(key, references - 1);
|
|
19966
|
+
return;
|
|
19967
|
+
}
|
|
19968
|
+
mcpWorkerReferences.delete(key);
|
|
19969
|
+
const teardown = stopBackgroundWorker(projectRoot, host);
|
|
19970
|
+
mcpWorkerTeardowns.set(key, teardown);
|
|
19971
|
+
try {
|
|
19972
|
+
await teardown;
|
|
19973
|
+
} finally {
|
|
19974
|
+
if (mcpWorkerTeardowns.get(key) === teardown) {
|
|
19975
|
+
mcpWorkerTeardowns.delete(key);
|
|
19976
|
+
}
|
|
19977
|
+
}
|
|
19978
|
+
}
|
|
18929
19979
|
function getServerInstructions(host) {
|
|
18930
19980
|
const hostText = `host ${host}`;
|
|
18931
19981
|
return `This MCP server is the preferred codebase-understanding path for ${hostText}. Start a repository task with index_status when index readiness or freshness is unknown. Use codebase_context as the preferred first entry point because it returns a token-budgeted location pack and routes to definitions or call-graph helpers when symbol intent is present. For code changes with a known or suspected symbol target, optionally call codebase_edit_context as a compact pre-edit step for bounded source plus direct callers and callees before broad file reads. Keep the default tokenBudget for normal discovery, then use implementation_lookup, codebase_search, or a targeted file read only for selected locations that need source content. Use codebase_peek for direct conceptual location lookup. For exact identifiers or exhaustive matches, use grep. After identifying symbols, use call_graph or call_graph_path to trace dependencies. If the index is unavailable, run index_codebase, then retry the retrieval tool.`;
|
|
18932
19982
|
}
|
|
19983
|
+
function configureMcpBackgroundWorker(projectRoot, config, host, watcherFactory, watcherFactoryForConfig) {
|
|
19984
|
+
if (!getProjectSafety(projectRoot, config).safeToRun) {
|
|
19985
|
+
return { managesWorker: false };
|
|
19986
|
+
}
|
|
19987
|
+
if (isBackgroundWorkerManaged(projectRoot, host)) {
|
|
19988
|
+
const key = getBackgroundWorkerProjectKey(projectRoot, host);
|
|
19989
|
+
if ((mcpWorkerReferences.get(key) ?? 0) === 0 && !mcpWorkerTeardowns.has(key)) {
|
|
19990
|
+
return { managesWorker: false };
|
|
19991
|
+
}
|
|
19992
|
+
if (watcherFactory !== void 0) {
|
|
19993
|
+
attachBackgroundWorkerWatcher(projectRoot, host, watcherFactory, watcherFactoryForConfig);
|
|
19994
|
+
}
|
|
19995
|
+
if (mcpWorkerTeardowns.has(key) || isBackgroundWorkerStopping(projectRoot, host)) {
|
|
19996
|
+
requestBackgroundWorker(projectRoot, host);
|
|
19997
|
+
}
|
|
19998
|
+
return { managesWorker: true };
|
|
19999
|
+
}
|
|
20000
|
+
configureBackgroundWorker(projectRoot, host, config, {
|
|
20001
|
+
startAutoIndex: (source, allowDisabledAutoIndex) => {
|
|
20002
|
+
startAutoIndexForBackgroundWorker(projectRoot, host, source, allowDisabledAutoIndex);
|
|
20003
|
+
},
|
|
20004
|
+
stopAutoIndex: () => stopAutoIndexForBackgroundWorker(projectRoot, host),
|
|
20005
|
+
watcherFactory,
|
|
20006
|
+
watcherFactoryForConfig
|
|
20007
|
+
});
|
|
20008
|
+
return { managesWorker: true };
|
|
20009
|
+
}
|
|
20010
|
+
function attachMcpBackgroundWatcher(projectRoot, config, host, watcherFactory, watcherFactoryForConfig) {
|
|
20011
|
+
configureMcpBackgroundWorker(projectRoot, config, host, watcherFactory, watcherFactoryForConfig);
|
|
20012
|
+
return waitForBackgroundWorkerStart(projectRoot, host);
|
|
20013
|
+
}
|
|
18933
20014
|
function createMcpServer(projectRoot, config, host) {
|
|
18934
20015
|
const server = new McpServer({
|
|
18935
20016
|
name: MCP_SERVER_CURRENT_NAME,
|
|
@@ -18937,11 +20018,14 @@ function createMcpServer(projectRoot, config, host) {
|
|
|
18937
20018
|
}, {
|
|
18938
20019
|
instructions: getServerInstructions(host)
|
|
18939
20020
|
});
|
|
18940
|
-
initializeTools(projectRoot, config, host);
|
|
18941
|
-
|
|
20021
|
+
initializeTools(projectRoot, config, host, { preserveManagedWorker: true });
|
|
20022
|
+
const backgroundWorker = configureMcpBackgroundWorker(projectRoot, config, host);
|
|
20023
|
+
if (backgroundWorker.managesWorker) {
|
|
20024
|
+
retainMcpBackgroundWorker(projectRoot, host);
|
|
20025
|
+
}
|
|
18942
20026
|
let stopCoordinationPromise = null;
|
|
18943
20027
|
const stopCoordination = () => {
|
|
18944
|
-
stopCoordinationPromise ??=
|
|
20028
|
+
stopCoordinationPromise ??= backgroundWorker.managesWorker ? releaseMcpBackgroundWorker(projectRoot, host) : Promise.resolve();
|
|
18945
20029
|
return stopCoordinationPromise;
|
|
18946
20030
|
};
|
|
18947
20031
|
const closeProtocol = server.server.close.bind(server.server);
|
|
@@ -18957,7 +20041,9 @@ function createMcpServer(projectRoot, config, host) {
|
|
|
18957
20041
|
const onServerClose = server.server.onclose;
|
|
18958
20042
|
server.server.onclose = () => {
|
|
18959
20043
|
onServerClose?.();
|
|
18960
|
-
void stopCoordination()
|
|
20044
|
+
void stopCoordination().catch((error) => {
|
|
20045
|
+
console.error("[codebase-index] Failed to stop MCP background worker after transport close:", error);
|
|
20046
|
+
});
|
|
18961
20047
|
};
|
|
18962
20048
|
registerMcpTools(server, {
|
|
18963
20049
|
projectRoot,
|
|
@@ -18968,7 +20054,7 @@ function createMcpServer(projectRoot, config, host) {
|
|
|
18968
20054
|
}
|
|
18969
20055
|
|
|
18970
20056
|
// src/watcher/file-watcher.ts
|
|
18971
|
-
import { existsSync as
|
|
20057
|
+
import { existsSync as existsSync16, statSync as statSync6 } from "fs";
|
|
18972
20058
|
|
|
18973
20059
|
// node_modules/chokidar/index.js
|
|
18974
20060
|
import { EventEmitter as EventEmitter2 } from "events";
|
|
@@ -19060,7 +20146,7 @@ var ReaddirpStream = class extends Readable {
|
|
|
19060
20146
|
this._directoryFilter = normalizeFilter(opts.directoryFilter);
|
|
19061
20147
|
const statMethod = opts.lstat ? lstat : stat;
|
|
19062
20148
|
if (wantBigintFsStats) {
|
|
19063
|
-
this._stat = (
|
|
20149
|
+
this._stat = (path34) => statMethod(path34, { bigint: true });
|
|
19064
20150
|
} else {
|
|
19065
20151
|
this._stat = statMethod;
|
|
19066
20152
|
}
|
|
@@ -19085,8 +20171,8 @@ var ReaddirpStream = class extends Readable {
|
|
|
19085
20171
|
const par = this.parent;
|
|
19086
20172
|
const fil = par && par.files;
|
|
19087
20173
|
if (fil && fil.length > 0) {
|
|
19088
|
-
const { path:
|
|
19089
|
-
const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent,
|
|
20174
|
+
const { path: path34, depth } = par;
|
|
20175
|
+
const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path34));
|
|
19090
20176
|
const awaited = await Promise.all(slice);
|
|
19091
20177
|
for (const entry of awaited) {
|
|
19092
20178
|
if (!entry)
|
|
@@ -19126,21 +20212,21 @@ var ReaddirpStream = class extends Readable {
|
|
|
19126
20212
|
this.reading = false;
|
|
19127
20213
|
}
|
|
19128
20214
|
}
|
|
19129
|
-
async _exploreDir(
|
|
20215
|
+
async _exploreDir(path34, depth) {
|
|
19130
20216
|
let files;
|
|
19131
20217
|
try {
|
|
19132
|
-
files = await readdir(
|
|
20218
|
+
files = await readdir(path34, this._rdOptions);
|
|
19133
20219
|
} catch (error) {
|
|
19134
20220
|
this._onError(error);
|
|
19135
20221
|
}
|
|
19136
|
-
return { files, depth, path:
|
|
20222
|
+
return { files, depth, path: path34 };
|
|
19137
20223
|
}
|
|
19138
|
-
async _formatEntry(dirent,
|
|
20224
|
+
async _formatEntry(dirent, path34) {
|
|
19139
20225
|
let entry;
|
|
19140
|
-
const
|
|
20226
|
+
const basename9 = this._isDirent ? dirent.name : dirent;
|
|
19141
20227
|
try {
|
|
19142
|
-
const fullPath = presolve(pjoin(
|
|
19143
|
-
entry = { path: prelative(this._root, fullPath), fullPath, basename:
|
|
20228
|
+
const fullPath = presolve(pjoin(path34, basename9));
|
|
20229
|
+
entry = { path: prelative(this._root, fullPath), fullPath, basename: basename9 };
|
|
19144
20230
|
entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
|
|
19145
20231
|
} catch (err) {
|
|
19146
20232
|
this._onError(err);
|
|
@@ -19539,16 +20625,16 @@ var delFromSet = (main, prop, item) => {
|
|
|
19539
20625
|
};
|
|
19540
20626
|
var isEmptySet = (val) => val instanceof Set ? val.size === 0 : !val;
|
|
19541
20627
|
var FsWatchInstances = /* @__PURE__ */ new Map();
|
|
19542
|
-
function createFsWatchInstance(
|
|
20628
|
+
function createFsWatchInstance(path34, options, listener, errHandler, emitRaw) {
|
|
19543
20629
|
const handleEvent = (rawEvent, evPath) => {
|
|
19544
|
-
listener(
|
|
19545
|
-
emitRaw(rawEvent, evPath, { watchedPath:
|
|
19546
|
-
if (evPath &&
|
|
19547
|
-
fsWatchBroadcast(sp.resolve(
|
|
20630
|
+
listener(path34);
|
|
20631
|
+
emitRaw(rawEvent, evPath, { watchedPath: path34 });
|
|
20632
|
+
if (evPath && path34 !== evPath) {
|
|
20633
|
+
fsWatchBroadcast(sp.resolve(path34, evPath), KEY_LISTENERS, sp.join(path34, evPath));
|
|
19548
20634
|
}
|
|
19549
20635
|
};
|
|
19550
20636
|
try {
|
|
19551
|
-
return fs_watch(
|
|
20637
|
+
return fs_watch(path34, {
|
|
19552
20638
|
persistent: options.persistent
|
|
19553
20639
|
}, handleEvent);
|
|
19554
20640
|
} catch (error) {
|
|
@@ -19564,12 +20650,12 @@ var fsWatchBroadcast = (fullPath, listenerType, val1, val2, val3) => {
|
|
|
19564
20650
|
listener(val1, val2, val3);
|
|
19565
20651
|
});
|
|
19566
20652
|
};
|
|
19567
|
-
var setFsWatchListener = (
|
|
20653
|
+
var setFsWatchListener = (path34, fullPath, options, handlers) => {
|
|
19568
20654
|
const { listener, errHandler, rawEmitter } = handlers;
|
|
19569
20655
|
let cont = FsWatchInstances.get(fullPath);
|
|
19570
20656
|
let watcher;
|
|
19571
20657
|
if (!options.persistent) {
|
|
19572
|
-
watcher = createFsWatchInstance(
|
|
20658
|
+
watcher = createFsWatchInstance(path34, options, listener, errHandler, rawEmitter);
|
|
19573
20659
|
if (!watcher)
|
|
19574
20660
|
return;
|
|
19575
20661
|
return watcher.close.bind(watcher);
|
|
@@ -19580,7 +20666,7 @@ var setFsWatchListener = (path33, fullPath, options, handlers) => {
|
|
|
19580
20666
|
addAndConvert(cont, KEY_RAW, rawEmitter);
|
|
19581
20667
|
} else {
|
|
19582
20668
|
watcher = createFsWatchInstance(
|
|
19583
|
-
|
|
20669
|
+
path34,
|
|
19584
20670
|
options,
|
|
19585
20671
|
fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS),
|
|
19586
20672
|
errHandler,
|
|
@@ -19595,7 +20681,7 @@ var setFsWatchListener = (path33, fullPath, options, handlers) => {
|
|
|
19595
20681
|
cont.watcherUnusable = true;
|
|
19596
20682
|
if (isWindows && error.code === "EPERM") {
|
|
19597
20683
|
try {
|
|
19598
|
-
const fd = await open(
|
|
20684
|
+
const fd = await open(path34, "r");
|
|
19599
20685
|
await fd.close();
|
|
19600
20686
|
broadcastErr(error);
|
|
19601
20687
|
} catch (err) {
|
|
@@ -19626,7 +20712,7 @@ var setFsWatchListener = (path33, fullPath, options, handlers) => {
|
|
|
19626
20712
|
};
|
|
19627
20713
|
};
|
|
19628
20714
|
var FsWatchFileInstances = /* @__PURE__ */ new Map();
|
|
19629
|
-
var setFsWatchFileListener = (
|
|
20715
|
+
var setFsWatchFileListener = (path34, fullPath, options, handlers) => {
|
|
19630
20716
|
const { listener, rawEmitter } = handlers;
|
|
19631
20717
|
let cont = FsWatchFileInstances.get(fullPath);
|
|
19632
20718
|
const copts = cont && cont.options;
|
|
@@ -19648,7 +20734,7 @@ var setFsWatchFileListener = (path33, fullPath, options, handlers) => {
|
|
|
19648
20734
|
});
|
|
19649
20735
|
const currmtime = curr.mtimeMs;
|
|
19650
20736
|
if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {
|
|
19651
|
-
foreach(cont.listeners, (listener2) => listener2(
|
|
20737
|
+
foreach(cont.listeners, (listener2) => listener2(path34, curr));
|
|
19652
20738
|
}
|
|
19653
20739
|
})
|
|
19654
20740
|
};
|
|
@@ -19678,13 +20764,13 @@ var NodeFsHandler = class {
|
|
|
19678
20764
|
* @param listener on fs change
|
|
19679
20765
|
* @returns closer for the watcher instance
|
|
19680
20766
|
*/
|
|
19681
|
-
_watchWithNodeFs(
|
|
20767
|
+
_watchWithNodeFs(path34, listener) {
|
|
19682
20768
|
const opts = this.fsw.options;
|
|
19683
|
-
const directory = sp.dirname(
|
|
19684
|
-
const
|
|
20769
|
+
const directory = sp.dirname(path34);
|
|
20770
|
+
const basename9 = sp.basename(path34);
|
|
19685
20771
|
const parent = this.fsw._getWatchedDir(directory);
|
|
19686
|
-
parent.add(
|
|
19687
|
-
const absolutePath = sp.resolve(
|
|
20772
|
+
parent.add(basename9);
|
|
20773
|
+
const absolutePath = sp.resolve(path34);
|
|
19688
20774
|
const options = {
|
|
19689
20775
|
persistent: opts.persistent
|
|
19690
20776
|
};
|
|
@@ -19693,13 +20779,13 @@ var NodeFsHandler = class {
|
|
|
19693
20779
|
let closer;
|
|
19694
20780
|
if (opts.usePolling) {
|
|
19695
20781
|
const enableBin = opts.interval !== opts.binaryInterval;
|
|
19696
|
-
options.interval = enableBin && isBinaryPath(
|
|
19697
|
-
closer = setFsWatchFileListener(
|
|
20782
|
+
options.interval = enableBin && isBinaryPath(basename9) ? opts.binaryInterval : opts.interval;
|
|
20783
|
+
closer = setFsWatchFileListener(path34, absolutePath, options, {
|
|
19698
20784
|
listener,
|
|
19699
20785
|
rawEmitter: this.fsw._emitRaw
|
|
19700
20786
|
});
|
|
19701
20787
|
} else {
|
|
19702
|
-
closer = setFsWatchListener(
|
|
20788
|
+
closer = setFsWatchListener(path34, absolutePath, options, {
|
|
19703
20789
|
listener,
|
|
19704
20790
|
errHandler: this._boundHandleError,
|
|
19705
20791
|
rawEmitter: this.fsw._emitRaw
|
|
@@ -19715,13 +20801,13 @@ var NodeFsHandler = class {
|
|
|
19715
20801
|
if (this.fsw.closed) {
|
|
19716
20802
|
return;
|
|
19717
20803
|
}
|
|
19718
|
-
const
|
|
19719
|
-
const
|
|
19720
|
-
const parent = this.fsw._getWatchedDir(
|
|
20804
|
+
const dirname16 = sp.dirname(file);
|
|
20805
|
+
const basename9 = sp.basename(file);
|
|
20806
|
+
const parent = this.fsw._getWatchedDir(dirname16);
|
|
19721
20807
|
let prevStats = stats;
|
|
19722
|
-
if (parent.has(
|
|
20808
|
+
if (parent.has(basename9))
|
|
19723
20809
|
return;
|
|
19724
|
-
const listener = async (
|
|
20810
|
+
const listener = async (path34, newStats) => {
|
|
19725
20811
|
if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5))
|
|
19726
20812
|
return;
|
|
19727
20813
|
if (!newStats || newStats.mtimeMs === 0) {
|
|
@@ -19735,18 +20821,18 @@ var NodeFsHandler = class {
|
|
|
19735
20821
|
this.fsw._emit(EV.CHANGE, file, newStats2);
|
|
19736
20822
|
}
|
|
19737
20823
|
if ((isMacos || isLinux || isFreeBSD) && prevStats.ino !== newStats2.ino) {
|
|
19738
|
-
this.fsw._closeFile(
|
|
20824
|
+
this.fsw._closeFile(path34);
|
|
19739
20825
|
prevStats = newStats2;
|
|
19740
20826
|
const closer2 = this._watchWithNodeFs(file, listener);
|
|
19741
20827
|
if (closer2)
|
|
19742
|
-
this.fsw._addPathCloser(
|
|
20828
|
+
this.fsw._addPathCloser(path34, closer2);
|
|
19743
20829
|
} else {
|
|
19744
20830
|
prevStats = newStats2;
|
|
19745
20831
|
}
|
|
19746
20832
|
} catch (error) {
|
|
19747
|
-
this.fsw._remove(
|
|
20833
|
+
this.fsw._remove(dirname16, basename9);
|
|
19748
20834
|
}
|
|
19749
|
-
} else if (parent.has(
|
|
20835
|
+
} else if (parent.has(basename9)) {
|
|
19750
20836
|
const at = newStats.atimeMs;
|
|
19751
20837
|
const mt = newStats.mtimeMs;
|
|
19752
20838
|
if (!at || at <= mt || mt !== prevStats.mtimeMs) {
|
|
@@ -19771,7 +20857,7 @@ var NodeFsHandler = class {
|
|
|
19771
20857
|
* @param item basename of this item
|
|
19772
20858
|
* @returns true if no more processing is needed for this entry.
|
|
19773
20859
|
*/
|
|
19774
|
-
async _handleSymlink(entry, directory,
|
|
20860
|
+
async _handleSymlink(entry, directory, path34, item) {
|
|
19775
20861
|
if (this.fsw.closed) {
|
|
19776
20862
|
return;
|
|
19777
20863
|
}
|
|
@@ -19781,7 +20867,7 @@ var NodeFsHandler = class {
|
|
|
19781
20867
|
this.fsw._incrReadyCount();
|
|
19782
20868
|
let linkPath;
|
|
19783
20869
|
try {
|
|
19784
|
-
linkPath = await fsrealpath(
|
|
20870
|
+
linkPath = await fsrealpath(path34);
|
|
19785
20871
|
} catch (e) {
|
|
19786
20872
|
this.fsw._emitReady();
|
|
19787
20873
|
return true;
|
|
@@ -19791,12 +20877,12 @@ var NodeFsHandler = class {
|
|
|
19791
20877
|
if (dir.has(item)) {
|
|
19792
20878
|
if (this.fsw._symlinkPaths.get(full) !== linkPath) {
|
|
19793
20879
|
this.fsw._symlinkPaths.set(full, linkPath);
|
|
19794
|
-
this.fsw._emit(EV.CHANGE,
|
|
20880
|
+
this.fsw._emit(EV.CHANGE, path34, entry.stats);
|
|
19795
20881
|
}
|
|
19796
20882
|
} else {
|
|
19797
20883
|
dir.add(item);
|
|
19798
20884
|
this.fsw._symlinkPaths.set(full, linkPath);
|
|
19799
|
-
this.fsw._emit(EV.ADD,
|
|
20885
|
+
this.fsw._emit(EV.ADD, path34, entry.stats);
|
|
19800
20886
|
}
|
|
19801
20887
|
this.fsw._emitReady();
|
|
19802
20888
|
return true;
|
|
@@ -19826,9 +20912,9 @@ var NodeFsHandler = class {
|
|
|
19826
20912
|
return;
|
|
19827
20913
|
}
|
|
19828
20914
|
const item = entry.path;
|
|
19829
|
-
let
|
|
20915
|
+
let path34 = sp.join(directory, item);
|
|
19830
20916
|
current.add(item);
|
|
19831
|
-
if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory,
|
|
20917
|
+
if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path34, item)) {
|
|
19832
20918
|
return;
|
|
19833
20919
|
}
|
|
19834
20920
|
if (this.fsw.closed) {
|
|
@@ -19837,11 +20923,11 @@ var NodeFsHandler = class {
|
|
|
19837
20923
|
}
|
|
19838
20924
|
if (item === target || !target && !previous.has(item)) {
|
|
19839
20925
|
this.fsw._incrReadyCount();
|
|
19840
|
-
|
|
19841
|
-
this._addToNodeFs(
|
|
20926
|
+
path34 = sp.join(dir, sp.relative(dir, path34));
|
|
20927
|
+
this._addToNodeFs(path34, initialAdd, wh, depth + 1);
|
|
19842
20928
|
}
|
|
19843
20929
|
}).on(EV.ERROR, this._boundHandleError);
|
|
19844
|
-
return new Promise((
|
|
20930
|
+
return new Promise((resolve21, reject) => {
|
|
19845
20931
|
if (!stream)
|
|
19846
20932
|
return reject();
|
|
19847
20933
|
stream.once(STR_END, () => {
|
|
@@ -19850,7 +20936,7 @@ var NodeFsHandler = class {
|
|
|
19850
20936
|
return;
|
|
19851
20937
|
}
|
|
19852
20938
|
const wasThrottled = throttler ? throttler.clear() : false;
|
|
19853
|
-
|
|
20939
|
+
resolve21(void 0);
|
|
19854
20940
|
previous.getChildren().filter((item) => {
|
|
19855
20941
|
return item !== directory && !current.has(item);
|
|
19856
20942
|
}).forEach((item) => {
|
|
@@ -19907,13 +20993,13 @@ var NodeFsHandler = class {
|
|
|
19907
20993
|
* @param depth Child path actually targeted for watch
|
|
19908
20994
|
* @param target Child path actually targeted for watch
|
|
19909
20995
|
*/
|
|
19910
|
-
async _addToNodeFs(
|
|
20996
|
+
async _addToNodeFs(path34, initialAdd, priorWh, depth, target) {
|
|
19911
20997
|
const ready = this.fsw._emitReady;
|
|
19912
|
-
if (this.fsw._isIgnored(
|
|
20998
|
+
if (this.fsw._isIgnored(path34) || this.fsw.closed) {
|
|
19913
20999
|
ready();
|
|
19914
21000
|
return false;
|
|
19915
21001
|
}
|
|
19916
|
-
const wh = this.fsw._getWatchHelpers(
|
|
21002
|
+
const wh = this.fsw._getWatchHelpers(path34);
|
|
19917
21003
|
if (priorWh) {
|
|
19918
21004
|
wh.filterPath = (entry) => priorWh.filterPath(entry);
|
|
19919
21005
|
wh.filterDir = (entry) => priorWh.filterDir(entry);
|
|
@@ -19929,8 +21015,8 @@ var NodeFsHandler = class {
|
|
|
19929
21015
|
const follow = this.fsw.options.followSymlinks;
|
|
19930
21016
|
let closer;
|
|
19931
21017
|
if (stats.isDirectory()) {
|
|
19932
|
-
const absPath = sp.resolve(
|
|
19933
|
-
const targetPath = follow ? await fsrealpath(
|
|
21018
|
+
const absPath = sp.resolve(path34);
|
|
21019
|
+
const targetPath = follow ? await fsrealpath(path34) : path34;
|
|
19934
21020
|
if (this.fsw.closed)
|
|
19935
21021
|
return;
|
|
19936
21022
|
closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
|
|
@@ -19940,29 +21026,29 @@ var NodeFsHandler = class {
|
|
|
19940
21026
|
this.fsw._symlinkPaths.set(absPath, targetPath);
|
|
19941
21027
|
}
|
|
19942
21028
|
} else if (stats.isSymbolicLink()) {
|
|
19943
|
-
const targetPath = follow ? await fsrealpath(
|
|
21029
|
+
const targetPath = follow ? await fsrealpath(path34) : path34;
|
|
19944
21030
|
if (this.fsw.closed)
|
|
19945
21031
|
return;
|
|
19946
21032
|
const parent = sp.dirname(wh.watchPath);
|
|
19947
21033
|
this.fsw._getWatchedDir(parent).add(wh.watchPath);
|
|
19948
21034
|
this.fsw._emit(EV.ADD, wh.watchPath, stats);
|
|
19949
|
-
closer = await this._handleDir(parent, stats, initialAdd, depth,
|
|
21035
|
+
closer = await this._handleDir(parent, stats, initialAdd, depth, path34, wh, targetPath);
|
|
19950
21036
|
if (this.fsw.closed)
|
|
19951
21037
|
return;
|
|
19952
21038
|
if (targetPath !== void 0) {
|
|
19953
|
-
this.fsw._symlinkPaths.set(sp.resolve(
|
|
21039
|
+
this.fsw._symlinkPaths.set(sp.resolve(path34), targetPath);
|
|
19954
21040
|
}
|
|
19955
21041
|
} else {
|
|
19956
21042
|
closer = this._handleFile(wh.watchPath, stats, initialAdd);
|
|
19957
21043
|
}
|
|
19958
21044
|
ready();
|
|
19959
21045
|
if (closer)
|
|
19960
|
-
this.fsw._addPathCloser(
|
|
21046
|
+
this.fsw._addPathCloser(path34, closer);
|
|
19961
21047
|
return false;
|
|
19962
21048
|
} catch (error) {
|
|
19963
21049
|
if (this.fsw._handleError(error)) {
|
|
19964
21050
|
ready();
|
|
19965
|
-
return
|
|
21051
|
+
return path34;
|
|
19966
21052
|
}
|
|
19967
21053
|
}
|
|
19968
21054
|
}
|
|
@@ -20005,24 +21091,24 @@ function createPattern(matcher) {
|
|
|
20005
21091
|
}
|
|
20006
21092
|
return () => false;
|
|
20007
21093
|
}
|
|
20008
|
-
function normalizePath3(
|
|
20009
|
-
if (typeof
|
|
21094
|
+
function normalizePath3(path34) {
|
|
21095
|
+
if (typeof path34 !== "string")
|
|
20010
21096
|
throw new Error("string expected");
|
|
20011
|
-
|
|
20012
|
-
|
|
21097
|
+
path34 = sp2.normalize(path34);
|
|
21098
|
+
path34 = path34.replace(/\\/g, "/");
|
|
20013
21099
|
let prepend = false;
|
|
20014
|
-
if (
|
|
21100
|
+
if (path34.startsWith("//"))
|
|
20015
21101
|
prepend = true;
|
|
20016
|
-
|
|
21102
|
+
path34 = path34.replace(DOUBLE_SLASH_RE, "/");
|
|
20017
21103
|
if (prepend)
|
|
20018
|
-
|
|
20019
|
-
return
|
|
21104
|
+
path34 = "/" + path34;
|
|
21105
|
+
return path34;
|
|
20020
21106
|
}
|
|
20021
21107
|
function matchPatterns(patterns, testString, stats) {
|
|
20022
|
-
const
|
|
21108
|
+
const path34 = normalizePath3(testString);
|
|
20023
21109
|
for (let index = 0; index < patterns.length; index++) {
|
|
20024
21110
|
const pattern = patterns[index];
|
|
20025
|
-
if (pattern(
|
|
21111
|
+
if (pattern(path34, stats)) {
|
|
20026
21112
|
return true;
|
|
20027
21113
|
}
|
|
20028
21114
|
}
|
|
@@ -20060,19 +21146,19 @@ var toUnix = (string) => {
|
|
|
20060
21146
|
}
|
|
20061
21147
|
return str;
|
|
20062
21148
|
};
|
|
20063
|
-
var normalizePathToUnix = (
|
|
20064
|
-
var normalizeIgnored = (cwd = "") => (
|
|
20065
|
-
if (typeof
|
|
20066
|
-
return normalizePathToUnix(sp2.isAbsolute(
|
|
21149
|
+
var normalizePathToUnix = (path34) => toUnix(sp2.normalize(toUnix(path34)));
|
|
21150
|
+
var normalizeIgnored = (cwd = "") => (path34) => {
|
|
21151
|
+
if (typeof path34 === "string") {
|
|
21152
|
+
return normalizePathToUnix(sp2.isAbsolute(path34) ? path34 : sp2.join(cwd, path34));
|
|
20067
21153
|
} else {
|
|
20068
|
-
return
|
|
21154
|
+
return path34;
|
|
20069
21155
|
}
|
|
20070
21156
|
};
|
|
20071
|
-
var getAbsolutePath = (
|
|
20072
|
-
if (sp2.isAbsolute(
|
|
20073
|
-
return
|
|
21157
|
+
var getAbsolutePath = (path34, cwd) => {
|
|
21158
|
+
if (sp2.isAbsolute(path34)) {
|
|
21159
|
+
return path34;
|
|
20074
21160
|
}
|
|
20075
|
-
return sp2.join(cwd,
|
|
21161
|
+
return sp2.join(cwd, path34);
|
|
20076
21162
|
};
|
|
20077
21163
|
var EMPTY_SET = Object.freeze(/* @__PURE__ */ new Set());
|
|
20078
21164
|
var DirEntry = class {
|
|
@@ -20137,10 +21223,10 @@ var WatchHelper = class {
|
|
|
20137
21223
|
dirParts;
|
|
20138
21224
|
followSymlinks;
|
|
20139
21225
|
statMethod;
|
|
20140
|
-
constructor(
|
|
21226
|
+
constructor(path34, follow, fsw) {
|
|
20141
21227
|
this.fsw = fsw;
|
|
20142
|
-
const watchPath =
|
|
20143
|
-
this.path =
|
|
21228
|
+
const watchPath = path34;
|
|
21229
|
+
this.path = path34 = path34.replace(REPLACER_RE, "");
|
|
20144
21230
|
this.watchPath = watchPath;
|
|
20145
21231
|
this.fullWatchPath = sp2.resolve(watchPath);
|
|
20146
21232
|
this.dirParts = [];
|
|
@@ -20280,20 +21366,20 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
20280
21366
|
this._closePromise = void 0;
|
|
20281
21367
|
let paths = unifyPaths(paths_);
|
|
20282
21368
|
if (cwd) {
|
|
20283
|
-
paths = paths.map((
|
|
20284
|
-
const absPath = getAbsolutePath(
|
|
21369
|
+
paths = paths.map((path34) => {
|
|
21370
|
+
const absPath = getAbsolutePath(path34, cwd);
|
|
20285
21371
|
return absPath;
|
|
20286
21372
|
});
|
|
20287
21373
|
}
|
|
20288
|
-
paths.forEach((
|
|
20289
|
-
this._removeIgnoredPath(
|
|
21374
|
+
paths.forEach((path34) => {
|
|
21375
|
+
this._removeIgnoredPath(path34);
|
|
20290
21376
|
});
|
|
20291
21377
|
this._userIgnored = void 0;
|
|
20292
21378
|
if (!this._readyCount)
|
|
20293
21379
|
this._readyCount = 0;
|
|
20294
21380
|
this._readyCount += paths.length;
|
|
20295
|
-
Promise.all(paths.map(async (
|
|
20296
|
-
const res = await this._nodeFsHandler._addToNodeFs(
|
|
21381
|
+
Promise.all(paths.map(async (path34) => {
|
|
21382
|
+
const res = await this._nodeFsHandler._addToNodeFs(path34, !_internal, void 0, 0, _origAdd);
|
|
20297
21383
|
if (res)
|
|
20298
21384
|
this._emitReady();
|
|
20299
21385
|
return res;
|
|
@@ -20315,17 +21401,17 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
20315
21401
|
return this;
|
|
20316
21402
|
const paths = unifyPaths(paths_);
|
|
20317
21403
|
const { cwd } = this.options;
|
|
20318
|
-
paths.forEach((
|
|
20319
|
-
if (!sp2.isAbsolute(
|
|
21404
|
+
paths.forEach((path34) => {
|
|
21405
|
+
if (!sp2.isAbsolute(path34) && !this._closers.has(path34)) {
|
|
20320
21406
|
if (cwd)
|
|
20321
|
-
|
|
20322
|
-
|
|
21407
|
+
path34 = sp2.join(cwd, path34);
|
|
21408
|
+
path34 = sp2.resolve(path34);
|
|
20323
21409
|
}
|
|
20324
|
-
this._closePath(
|
|
20325
|
-
this._addIgnoredPath(
|
|
20326
|
-
if (this._watched.has(
|
|
21410
|
+
this._closePath(path34);
|
|
21411
|
+
this._addIgnoredPath(path34);
|
|
21412
|
+
if (this._watched.has(path34)) {
|
|
20327
21413
|
this._addIgnoredPath({
|
|
20328
|
-
path:
|
|
21414
|
+
path: path34,
|
|
20329
21415
|
recursive: true
|
|
20330
21416
|
});
|
|
20331
21417
|
}
|
|
@@ -20389,38 +21475,38 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
20389
21475
|
* @param stats arguments to be passed with event
|
|
20390
21476
|
* @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag
|
|
20391
21477
|
*/
|
|
20392
|
-
async _emit(event,
|
|
21478
|
+
async _emit(event, path34, stats) {
|
|
20393
21479
|
if (this.closed)
|
|
20394
21480
|
return;
|
|
20395
21481
|
const opts = this.options;
|
|
20396
21482
|
if (isWindows)
|
|
20397
|
-
|
|
21483
|
+
path34 = sp2.normalize(path34);
|
|
20398
21484
|
if (opts.cwd)
|
|
20399
|
-
|
|
20400
|
-
const args = [
|
|
21485
|
+
path34 = sp2.relative(opts.cwd, path34);
|
|
21486
|
+
const args = [path34];
|
|
20401
21487
|
if (stats != null)
|
|
20402
21488
|
args.push(stats);
|
|
20403
21489
|
const awf = opts.awaitWriteFinish;
|
|
20404
21490
|
let pw;
|
|
20405
|
-
if (awf && (pw = this._pendingWrites.get(
|
|
21491
|
+
if (awf && (pw = this._pendingWrites.get(path34))) {
|
|
20406
21492
|
pw.lastChange = /* @__PURE__ */ new Date();
|
|
20407
21493
|
return this;
|
|
20408
21494
|
}
|
|
20409
21495
|
if (opts.atomic) {
|
|
20410
21496
|
if (event === EVENTS.UNLINK) {
|
|
20411
|
-
this._pendingUnlinks.set(
|
|
21497
|
+
this._pendingUnlinks.set(path34, [event, ...args]);
|
|
20412
21498
|
setTimeout(() => {
|
|
20413
|
-
this._pendingUnlinks.forEach((entry,
|
|
21499
|
+
this._pendingUnlinks.forEach((entry, path35) => {
|
|
20414
21500
|
this.emit(...entry);
|
|
20415
21501
|
this.emit(EVENTS.ALL, ...entry);
|
|
20416
|
-
this._pendingUnlinks.delete(
|
|
21502
|
+
this._pendingUnlinks.delete(path35);
|
|
20417
21503
|
});
|
|
20418
21504
|
}, typeof opts.atomic === "number" ? opts.atomic : 100);
|
|
20419
21505
|
return this;
|
|
20420
21506
|
}
|
|
20421
|
-
if (event === EVENTS.ADD && this._pendingUnlinks.has(
|
|
21507
|
+
if (event === EVENTS.ADD && this._pendingUnlinks.has(path34)) {
|
|
20422
21508
|
event = EVENTS.CHANGE;
|
|
20423
|
-
this._pendingUnlinks.delete(
|
|
21509
|
+
this._pendingUnlinks.delete(path34);
|
|
20424
21510
|
}
|
|
20425
21511
|
}
|
|
20426
21512
|
if (awf && (event === EVENTS.ADD || event === EVENTS.CHANGE) && this._readyEmitted) {
|
|
@@ -20438,16 +21524,16 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
20438
21524
|
this.emitWithAll(event, args);
|
|
20439
21525
|
}
|
|
20440
21526
|
};
|
|
20441
|
-
this._awaitWriteFinish(
|
|
21527
|
+
this._awaitWriteFinish(path34, awf.stabilityThreshold, event, awfEmit);
|
|
20442
21528
|
return this;
|
|
20443
21529
|
}
|
|
20444
21530
|
if (event === EVENTS.CHANGE) {
|
|
20445
|
-
const isThrottled = !this._throttle(EVENTS.CHANGE,
|
|
21531
|
+
const isThrottled = !this._throttle(EVENTS.CHANGE, path34, 50);
|
|
20446
21532
|
if (isThrottled)
|
|
20447
21533
|
return this;
|
|
20448
21534
|
}
|
|
20449
21535
|
if (opts.alwaysStat && stats === void 0 && (event === EVENTS.ADD || event === EVENTS.ADD_DIR || event === EVENTS.CHANGE)) {
|
|
20450
|
-
const fullPath = opts.cwd ? sp2.join(opts.cwd,
|
|
21536
|
+
const fullPath = opts.cwd ? sp2.join(opts.cwd, path34) : path34;
|
|
20451
21537
|
let stats2;
|
|
20452
21538
|
try {
|
|
20453
21539
|
stats2 = await stat3(fullPath);
|
|
@@ -20478,23 +21564,23 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
20478
21564
|
* @param timeout duration of time to suppress duplicate actions
|
|
20479
21565
|
* @returns tracking object or false if action should be suppressed
|
|
20480
21566
|
*/
|
|
20481
|
-
_throttle(actionType,
|
|
21567
|
+
_throttle(actionType, path34, timeout) {
|
|
20482
21568
|
if (!this._throttled.has(actionType)) {
|
|
20483
21569
|
this._throttled.set(actionType, /* @__PURE__ */ new Map());
|
|
20484
21570
|
}
|
|
20485
21571
|
const action = this._throttled.get(actionType);
|
|
20486
21572
|
if (!action)
|
|
20487
21573
|
throw new Error("invalid throttle");
|
|
20488
|
-
const actionPath = action.get(
|
|
21574
|
+
const actionPath = action.get(path34);
|
|
20489
21575
|
if (actionPath) {
|
|
20490
21576
|
actionPath.count++;
|
|
20491
21577
|
return false;
|
|
20492
21578
|
}
|
|
20493
21579
|
let timeoutObject;
|
|
20494
21580
|
const clear = () => {
|
|
20495
|
-
const item = action.get(
|
|
21581
|
+
const item = action.get(path34);
|
|
20496
21582
|
const count = item ? item.count : 0;
|
|
20497
|
-
action.delete(
|
|
21583
|
+
action.delete(path34);
|
|
20498
21584
|
clearTimeout(timeoutObject);
|
|
20499
21585
|
if (item)
|
|
20500
21586
|
clearTimeout(item.timeoutObject);
|
|
@@ -20502,7 +21588,7 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
20502
21588
|
};
|
|
20503
21589
|
timeoutObject = setTimeout(clear, timeout);
|
|
20504
21590
|
const thr = { timeoutObject, clear, count: 0 };
|
|
20505
|
-
action.set(
|
|
21591
|
+
action.set(path34, thr);
|
|
20506
21592
|
return thr;
|
|
20507
21593
|
}
|
|
20508
21594
|
_incrReadyCount() {
|
|
@@ -20516,44 +21602,44 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
20516
21602
|
* @param event
|
|
20517
21603
|
* @param awfEmit Callback to be called when ready for event to be emitted.
|
|
20518
21604
|
*/
|
|
20519
|
-
_awaitWriteFinish(
|
|
21605
|
+
_awaitWriteFinish(path34, threshold, event, awfEmit) {
|
|
20520
21606
|
const awf = this.options.awaitWriteFinish;
|
|
20521
21607
|
if (typeof awf !== "object")
|
|
20522
21608
|
return;
|
|
20523
21609
|
const pollInterval = awf.pollInterval;
|
|
20524
21610
|
let timeoutHandler;
|
|
20525
|
-
let fullPath =
|
|
20526
|
-
if (this.options.cwd && !sp2.isAbsolute(
|
|
20527
|
-
fullPath = sp2.join(this.options.cwd,
|
|
21611
|
+
let fullPath = path34;
|
|
21612
|
+
if (this.options.cwd && !sp2.isAbsolute(path34)) {
|
|
21613
|
+
fullPath = sp2.join(this.options.cwd, path34);
|
|
20528
21614
|
}
|
|
20529
21615
|
const now2 = /* @__PURE__ */ new Date();
|
|
20530
21616
|
const writes = this._pendingWrites;
|
|
20531
21617
|
function awaitWriteFinishFn(prevStat) {
|
|
20532
21618
|
statcb(fullPath, (err, curStat) => {
|
|
20533
|
-
if (err || !writes.has(
|
|
21619
|
+
if (err || !writes.has(path34)) {
|
|
20534
21620
|
if (err && err.code !== "ENOENT")
|
|
20535
21621
|
awfEmit(err);
|
|
20536
21622
|
return;
|
|
20537
21623
|
}
|
|
20538
21624
|
const now3 = Number(/* @__PURE__ */ new Date());
|
|
20539
21625
|
if (prevStat && curStat.size !== prevStat.size) {
|
|
20540
|
-
writes.get(
|
|
21626
|
+
writes.get(path34).lastChange = now3;
|
|
20541
21627
|
}
|
|
20542
|
-
const pw = writes.get(
|
|
21628
|
+
const pw = writes.get(path34);
|
|
20543
21629
|
const df = now3 - pw.lastChange;
|
|
20544
21630
|
if (df >= threshold) {
|
|
20545
|
-
writes.delete(
|
|
21631
|
+
writes.delete(path34);
|
|
20546
21632
|
awfEmit(void 0, curStat);
|
|
20547
21633
|
} else {
|
|
20548
21634
|
timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat);
|
|
20549
21635
|
}
|
|
20550
21636
|
});
|
|
20551
21637
|
}
|
|
20552
|
-
if (!writes.has(
|
|
20553
|
-
writes.set(
|
|
21638
|
+
if (!writes.has(path34)) {
|
|
21639
|
+
writes.set(path34, {
|
|
20554
21640
|
lastChange: now2,
|
|
20555
21641
|
cancelWait: () => {
|
|
20556
|
-
writes.delete(
|
|
21642
|
+
writes.delete(path34);
|
|
20557
21643
|
clearTimeout(timeoutHandler);
|
|
20558
21644
|
return event;
|
|
20559
21645
|
}
|
|
@@ -20564,8 +21650,8 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
20564
21650
|
/**
|
|
20565
21651
|
* Determines whether user has asked to ignore this path.
|
|
20566
21652
|
*/
|
|
20567
|
-
_isIgnored(
|
|
20568
|
-
if (this.options.atomic && DOT_RE.test(
|
|
21653
|
+
_isIgnored(path34, stats) {
|
|
21654
|
+
if (this.options.atomic && DOT_RE.test(path34))
|
|
20569
21655
|
return true;
|
|
20570
21656
|
if (!this._userIgnored) {
|
|
20571
21657
|
const { cwd } = this.options;
|
|
@@ -20575,17 +21661,17 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
20575
21661
|
const list = [...ignoredPaths.map(normalizeIgnored(cwd)), ...ignored];
|
|
20576
21662
|
this._userIgnored = anymatch(list, void 0);
|
|
20577
21663
|
}
|
|
20578
|
-
return this._userIgnored(
|
|
21664
|
+
return this._userIgnored(path34, stats);
|
|
20579
21665
|
}
|
|
20580
|
-
_isntIgnored(
|
|
20581
|
-
return !this._isIgnored(
|
|
21666
|
+
_isntIgnored(path34, stat5) {
|
|
21667
|
+
return !this._isIgnored(path34, stat5);
|
|
20582
21668
|
}
|
|
20583
21669
|
/**
|
|
20584
21670
|
* Provides a set of common helpers and properties relating to symlink handling.
|
|
20585
21671
|
* @param path file or directory pattern being watched
|
|
20586
21672
|
*/
|
|
20587
|
-
_getWatchHelpers(
|
|
20588
|
-
return new WatchHelper(
|
|
21673
|
+
_getWatchHelpers(path34) {
|
|
21674
|
+
return new WatchHelper(path34, this.options.followSymlinks, this);
|
|
20589
21675
|
}
|
|
20590
21676
|
// Directory helpers
|
|
20591
21677
|
// -----------------
|
|
@@ -20617,63 +21703,63 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
20617
21703
|
* @param item base path of item/directory
|
|
20618
21704
|
*/
|
|
20619
21705
|
_remove(directory, item, isDirectory) {
|
|
20620
|
-
const
|
|
20621
|
-
const fullPath = sp2.resolve(
|
|
20622
|
-
isDirectory = isDirectory != null ? isDirectory : this._watched.has(
|
|
20623
|
-
if (!this._throttle("remove",
|
|
21706
|
+
const path34 = sp2.join(directory, item);
|
|
21707
|
+
const fullPath = sp2.resolve(path34);
|
|
21708
|
+
isDirectory = isDirectory != null ? isDirectory : this._watched.has(path34) || this._watched.has(fullPath);
|
|
21709
|
+
if (!this._throttle("remove", path34, 100))
|
|
20624
21710
|
return;
|
|
20625
21711
|
if (!isDirectory && this._watched.size === 1) {
|
|
20626
21712
|
this.add(directory, item, true);
|
|
20627
21713
|
}
|
|
20628
|
-
const wp = this._getWatchedDir(
|
|
21714
|
+
const wp = this._getWatchedDir(path34);
|
|
20629
21715
|
const nestedDirectoryChildren = wp.getChildren();
|
|
20630
|
-
nestedDirectoryChildren.forEach((nested) => this._remove(
|
|
21716
|
+
nestedDirectoryChildren.forEach((nested) => this._remove(path34, nested));
|
|
20631
21717
|
const parent = this._getWatchedDir(directory);
|
|
20632
21718
|
const wasTracked = parent.has(item);
|
|
20633
21719
|
parent.remove(item);
|
|
20634
21720
|
if (this._symlinkPaths.has(fullPath)) {
|
|
20635
21721
|
this._symlinkPaths.delete(fullPath);
|
|
20636
21722
|
}
|
|
20637
|
-
let relPath =
|
|
21723
|
+
let relPath = path34;
|
|
20638
21724
|
if (this.options.cwd)
|
|
20639
|
-
relPath = sp2.relative(this.options.cwd,
|
|
21725
|
+
relPath = sp2.relative(this.options.cwd, path34);
|
|
20640
21726
|
if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
|
|
20641
21727
|
const event = this._pendingWrites.get(relPath).cancelWait();
|
|
20642
21728
|
if (event === EVENTS.ADD)
|
|
20643
21729
|
return;
|
|
20644
21730
|
}
|
|
20645
|
-
this._watched.delete(
|
|
21731
|
+
this._watched.delete(path34);
|
|
20646
21732
|
this._watched.delete(fullPath);
|
|
20647
21733
|
const eventName = isDirectory ? EVENTS.UNLINK_DIR : EVENTS.UNLINK;
|
|
20648
|
-
if (wasTracked && !this._isIgnored(
|
|
20649
|
-
this._emit(eventName,
|
|
20650
|
-
this._closePath(
|
|
21734
|
+
if (wasTracked && !this._isIgnored(path34))
|
|
21735
|
+
this._emit(eventName, path34);
|
|
21736
|
+
this._closePath(path34);
|
|
20651
21737
|
}
|
|
20652
21738
|
/**
|
|
20653
21739
|
* Closes all watchers for a path
|
|
20654
21740
|
*/
|
|
20655
|
-
_closePath(
|
|
20656
|
-
this._closeFile(
|
|
20657
|
-
const dir = sp2.dirname(
|
|
20658
|
-
this._getWatchedDir(dir).remove(sp2.basename(
|
|
21741
|
+
_closePath(path34) {
|
|
21742
|
+
this._closeFile(path34);
|
|
21743
|
+
const dir = sp2.dirname(path34);
|
|
21744
|
+
this._getWatchedDir(dir).remove(sp2.basename(path34));
|
|
20659
21745
|
}
|
|
20660
21746
|
/**
|
|
20661
21747
|
* Closes only file-specific watchers
|
|
20662
21748
|
*/
|
|
20663
|
-
_closeFile(
|
|
20664
|
-
const closers = this._closers.get(
|
|
21749
|
+
_closeFile(path34) {
|
|
21750
|
+
const closers = this._closers.get(path34);
|
|
20665
21751
|
if (!closers)
|
|
20666
21752
|
return;
|
|
20667
21753
|
closers.forEach((closer) => closer());
|
|
20668
|
-
this._closers.delete(
|
|
21754
|
+
this._closers.delete(path34);
|
|
20669
21755
|
}
|
|
20670
|
-
_addPathCloser(
|
|
21756
|
+
_addPathCloser(path34, closer) {
|
|
20671
21757
|
if (!closer)
|
|
20672
21758
|
return;
|
|
20673
|
-
let list = this._closers.get(
|
|
21759
|
+
let list = this._closers.get(path34);
|
|
20674
21760
|
if (!list) {
|
|
20675
21761
|
list = [];
|
|
20676
|
-
this._closers.set(
|
|
21762
|
+
this._closers.set(path34, list);
|
|
20677
21763
|
}
|
|
20678
21764
|
list.push(closer);
|
|
20679
21765
|
}
|
|
@@ -20703,11 +21789,11 @@ function watch(paths, options = {}) {
|
|
|
20703
21789
|
var chokidar_default = { watch, FSWatcher };
|
|
20704
21790
|
|
|
20705
21791
|
// src/watcher/file-watcher.ts
|
|
20706
|
-
import * as
|
|
21792
|
+
import * as path29 from "path";
|
|
20707
21793
|
|
|
20708
21794
|
// src/watcher/native-recursive-watcher.ts
|
|
20709
21795
|
import { watch as watch2 } from "fs";
|
|
20710
|
-
import * as
|
|
21796
|
+
import * as path27 from "path";
|
|
20711
21797
|
var NativeRecursiveWatcher = class {
|
|
20712
21798
|
constructor(root, onChange, options = {}) {
|
|
20713
21799
|
this.root = root;
|
|
@@ -20755,9 +21841,9 @@ var NativeRecursiveWatcher = class {
|
|
|
20755
21841
|
toAbsolutePath(filename) {
|
|
20756
21842
|
if (filename == null) return null;
|
|
20757
21843
|
const normalizedFilename = typeof filename === "string" ? filename : filename.toString();
|
|
20758
|
-
const absolutePath =
|
|
20759
|
-
const relativePath =
|
|
20760
|
-
const outsideRoot = relativePath === ".." || relativePath.startsWith(`..${
|
|
21844
|
+
const absolutePath = path27.resolve(this.root, normalizedFilename);
|
|
21845
|
+
const relativePath = path27.relative(this.root, absolutePath);
|
|
21846
|
+
const outsideRoot = relativePath === ".." || relativePath.startsWith(`..${path27.sep}`) || path27.isAbsolute(relativePath);
|
|
20761
21847
|
return outsideRoot ? null : absolutePath;
|
|
20762
21848
|
}
|
|
20763
21849
|
defaultWatchFactory = (root, listener, options) => watch2(root, options, listener);
|
|
@@ -20765,16 +21851,16 @@ var NativeRecursiveWatcher = class {
|
|
|
20765
21851
|
|
|
20766
21852
|
// src/watcher/snapshot.ts
|
|
20767
21853
|
import * as fsPromises4 from "fs/promises";
|
|
20768
|
-
import * as
|
|
21854
|
+
import * as path28 from "path";
|
|
20769
21855
|
async function buildFileSnapshotScan(projectRoot, config, configPaths = []) {
|
|
20770
|
-
const normalizedProjectRoot =
|
|
21856
|
+
const normalizedProjectRoot = path28.resolve(projectRoot);
|
|
20771
21857
|
const ignoreFilter = createIgnoreFilter(normalizedProjectRoot);
|
|
20772
21858
|
const includePatterns = [...config.include, ...config.additionalInclude ?? []];
|
|
20773
21859
|
const maxDepth = config.indexing?.maxDepth ?? -1;
|
|
20774
21860
|
const snapshot = /* @__PURE__ */ new Map();
|
|
20775
21861
|
const unreadablePrefixes = /* @__PURE__ */ new Set();
|
|
20776
21862
|
const includeFile = async (filePath) => {
|
|
20777
|
-
const normalizedPath3 =
|
|
21863
|
+
const normalizedPath3 = path28.resolve(filePath);
|
|
20778
21864
|
if (!shouldIncludeFile(normalizedPath3, normalizedProjectRoot, includePatterns, config.exclude, ignoreFilter)) return;
|
|
20779
21865
|
const stat5 = await readStatIfFile(normalizedPath3, unreadablePrefixes);
|
|
20780
21866
|
if (stat5) snapshot.set(normalizedPath3, { size: stat5.size, mtimeMs: stat5.mtimeMs });
|
|
@@ -20786,16 +21872,16 @@ async function buildFileSnapshotScan(projectRoot, config, configPaths = []) {
|
|
|
20786
21872
|
} catch (error) {
|
|
20787
21873
|
if (isMissingFsError(error)) return;
|
|
20788
21874
|
if (isPermissionFsError(error)) {
|
|
20789
|
-
unreadablePrefixes.add(
|
|
21875
|
+
unreadablePrefixes.add(path28.resolve(directoryPath));
|
|
20790
21876
|
return;
|
|
20791
21877
|
}
|
|
20792
21878
|
throw error;
|
|
20793
21879
|
}
|
|
20794
21880
|
for (const entry of entries) {
|
|
20795
|
-
const fullPath =
|
|
20796
|
-
const relativePath =
|
|
21881
|
+
const fullPath = path28.join(directoryPath, entry.name);
|
|
21882
|
+
const relativePath = path28.relative(normalizedProjectRoot, fullPath);
|
|
20797
21883
|
if (entry.isDirectory()) {
|
|
20798
|
-
if (hasFilteredPathSegment(relativePath,
|
|
21884
|
+
if (hasFilteredPathSegment(relativePath, path28.sep) || isRestrictedDirectory(relativePath, path28.sep)) continue;
|
|
20799
21885
|
if (ignoreFilter.ignores(relativePath)) continue;
|
|
20800
21886
|
if (maxDepth === -1 || depth < maxDepth) await walk(fullPath, depth + 1);
|
|
20801
21887
|
} else if (entry.isFile()) {
|
|
@@ -20808,19 +21894,19 @@ async function buildFileSnapshotScan(projectRoot, config, configPaths = []) {
|
|
|
20808
21894
|
return { entries: snapshot, unreadablePrefixes };
|
|
20809
21895
|
}
|
|
20810
21896
|
async function buildFileSnapshotForPathScan(projectRoot, config, configPaths, targetPath) {
|
|
20811
|
-
const normalizedProjectRoot =
|
|
20812
|
-
const normalizedTargetPath =
|
|
21897
|
+
const normalizedProjectRoot = path28.resolve(projectRoot);
|
|
21898
|
+
const normalizedTargetPath = path28.resolve(targetPath);
|
|
20813
21899
|
if (!isWithinPath(normalizedProjectRoot, normalizedTargetPath)) {
|
|
20814
21900
|
return { entries: /* @__PURE__ */ new Map(), unreadablePrefixes: /* @__PURE__ */ new Set() };
|
|
20815
21901
|
}
|
|
20816
21902
|
const ignoreFilter = createIgnoreFilter(normalizedProjectRoot);
|
|
20817
21903
|
const includePatterns = [...config.include, ...config.additionalInclude ?? []];
|
|
20818
21904
|
const maxDepth = config.indexing?.maxDepth ?? -1;
|
|
20819
|
-
const explicitConfigPaths = new Set(configPaths.map((configPath) =>
|
|
21905
|
+
const explicitConfigPaths = new Set(configPaths.map((configPath) => path28.resolve(configPath)));
|
|
20820
21906
|
const snapshot = /* @__PURE__ */ new Map();
|
|
20821
21907
|
const unreadablePrefixes = /* @__PURE__ */ new Set();
|
|
20822
21908
|
const includeFile = async (filePath) => {
|
|
20823
|
-
const normalizedPath3 =
|
|
21909
|
+
const normalizedPath3 = path28.resolve(filePath);
|
|
20824
21910
|
if (!explicitConfigPaths.has(normalizedPath3) && !shouldIncludeFile(
|
|
20825
21911
|
normalizedPath3,
|
|
20826
21912
|
normalizedProjectRoot,
|
|
@@ -20838,16 +21924,16 @@ async function buildFileSnapshotForPathScan(projectRoot, config, configPaths, ta
|
|
|
20838
21924
|
} catch (error) {
|
|
20839
21925
|
if (isMissingFsError(error)) return;
|
|
20840
21926
|
if (isPermissionFsError(error)) {
|
|
20841
|
-
unreadablePrefixes.add(
|
|
21927
|
+
unreadablePrefixes.add(path28.resolve(directoryPath));
|
|
20842
21928
|
return;
|
|
20843
21929
|
}
|
|
20844
21930
|
throw error;
|
|
20845
21931
|
}
|
|
20846
21932
|
for (const entry of entries) {
|
|
20847
|
-
const fullPath =
|
|
20848
|
-
const relativePath =
|
|
21933
|
+
const fullPath = path28.join(directoryPath, entry.name);
|
|
21934
|
+
const relativePath = path28.relative(normalizedProjectRoot, fullPath);
|
|
20849
21935
|
if (entry.isDirectory()) {
|
|
20850
|
-
if (hasFilteredPathSegment(relativePath,
|
|
21936
|
+
if (hasFilteredPathSegment(relativePath, path28.sep) || isRestrictedDirectory(relativePath, path28.sep)) continue;
|
|
20851
21937
|
if (ignoreFilter.ignores(relativePath)) continue;
|
|
20852
21938
|
if (maxDepth === -1 || depth < maxDepth) await walk(fullPath, depth + 1);
|
|
20853
21939
|
} else if (entry.isFile()) {
|
|
@@ -20871,7 +21957,7 @@ function completeFileSnapshot(previous, scan) {
|
|
|
20871
21957
|
return completed;
|
|
20872
21958
|
}
|
|
20873
21959
|
async function includeExplicitConfigPaths(snapshot, unreadablePrefixes, configPaths) {
|
|
20874
|
-
for (const configPath of [...new Set(configPaths.map((value) =>
|
|
21960
|
+
for (const configPath of [...new Set(configPaths.map((value) => path28.resolve(value)))]) {
|
|
20875
21961
|
if (snapshot.has(configPath)) continue;
|
|
20876
21962
|
const stat5 = await readStatIfFile(configPath, unreadablePrefixes);
|
|
20877
21963
|
if (stat5) snapshot.set(configPath, { size: stat5.size, mtimeMs: stat5.mtimeMs });
|
|
@@ -20881,12 +21967,12 @@ async function includeExplicitConfigPathsInPath(snapshot, unreadablePrefixes, co
|
|
|
20881
21967
|
await includeExplicitConfigPaths(
|
|
20882
21968
|
snapshot,
|
|
20883
21969
|
unreadablePrefixes,
|
|
20884
|
-
configPaths.filter((configPath) => isWithinPath(targetPath,
|
|
21970
|
+
configPaths.filter((configPath) => isWithinPath(targetPath, path28.resolve(configPath)))
|
|
20885
21971
|
);
|
|
20886
21972
|
}
|
|
20887
21973
|
function isWithinPath(parentPath, childPath) {
|
|
20888
|
-
const relativePath =
|
|
20889
|
-
return relativePath === "" || !relativePath.startsWith(`..${
|
|
21974
|
+
const relativePath = path28.relative(parentPath, childPath);
|
|
21975
|
+
return relativePath === "" || !relativePath.startsWith(`..${path28.sep}`) && relativePath !== ".." && !path28.isAbsolute(relativePath);
|
|
20890
21976
|
}
|
|
20891
21977
|
async function readStatIfFile(filePath, unreadablePrefixes) {
|
|
20892
21978
|
try {
|
|
@@ -20895,7 +21981,7 @@ async function readStatIfFile(filePath, unreadablePrefixes) {
|
|
|
20895
21981
|
} catch (error) {
|
|
20896
21982
|
if (isMissingFsError(error)) return null;
|
|
20897
21983
|
if (isPermissionFsError(error)) {
|
|
20898
|
-
unreadablePrefixes.add(
|
|
21984
|
+
unreadablePrefixes.add(path28.resolve(filePath));
|
|
20899
21985
|
return null;
|
|
20900
21986
|
}
|
|
20901
21987
|
throw error;
|
|
@@ -21032,8 +22118,8 @@ var FileWatcher = class {
|
|
|
21032
22118
|
this.createWatcher();
|
|
21033
22119
|
}
|
|
21034
22120
|
resetReady() {
|
|
21035
|
-
this.readyPromise = new Promise((
|
|
21036
|
-
this.resolveReady =
|
|
22121
|
+
this.readyPromise = new Promise((resolve21) => {
|
|
22122
|
+
this.resolveReady = resolve21;
|
|
21037
22123
|
});
|
|
21038
22124
|
this.startupReadySignals = 1;
|
|
21039
22125
|
}
|
|
@@ -21064,7 +22150,7 @@ var FileWatcher = class {
|
|
|
21064
22150
|
const resolvedWatchTargets = watchTargets ?? this.getFullChokidarWatchTargets();
|
|
21065
22151
|
const watcherOptions = {
|
|
21066
22152
|
ignored: (filePath) => {
|
|
21067
|
-
const relativePath =
|
|
22153
|
+
const relativePath = path29.relative(this.projectRoot, filePath);
|
|
21068
22154
|
if (!relativePath) return false;
|
|
21069
22155
|
if (this.isProjectConfigPathOrAncestor(relativePath)) {
|
|
21070
22156
|
return false;
|
|
@@ -21072,10 +22158,10 @@ var FileWatcher = class {
|
|
|
21072
22158
|
if (this.isOutsideProjectPath(relativePath)) {
|
|
21073
22159
|
return true;
|
|
21074
22160
|
}
|
|
21075
|
-
if (hasFilteredPathSegment(relativePath,
|
|
22161
|
+
if (hasFilteredPathSegment(relativePath, path29.sep)) {
|
|
21076
22162
|
return true;
|
|
21077
22163
|
}
|
|
21078
|
-
if (isRestrictedDirectory(relativePath,
|
|
22164
|
+
if (isRestrictedDirectory(relativePath, path29.sep)) {
|
|
21079
22165
|
return true;
|
|
21080
22166
|
}
|
|
21081
22167
|
if (ignoreFilter.ignores(relativePath)) {
|
|
@@ -21166,13 +22252,13 @@ var FileWatcher = class {
|
|
|
21166
22252
|
getExternalConfigWatchTargets() {
|
|
21167
22253
|
return [...new Set(
|
|
21168
22254
|
this.projectConfigPaths.filter((projectConfigPath) => {
|
|
21169
|
-
const relativeConfigPath =
|
|
22255
|
+
const relativeConfigPath = path29.relative(this.projectRoot, projectConfigPath);
|
|
21170
22256
|
return this.isOutsideProjectPath(relativeConfigPath);
|
|
21171
22257
|
}).map((projectConfigPath) => {
|
|
21172
|
-
if (
|
|
22258
|
+
if (existsSync16(projectConfigPath)) {
|
|
21173
22259
|
return projectConfigPath;
|
|
21174
22260
|
}
|
|
21175
|
-
return this.getNearestExistingDirectory(
|
|
22261
|
+
return this.getNearestExistingDirectory(path29.dirname(projectConfigPath));
|
|
21176
22262
|
})
|
|
21177
22263
|
)];
|
|
21178
22264
|
}
|
|
@@ -21234,7 +22320,7 @@ var FileWatcher = class {
|
|
|
21234
22320
|
}
|
|
21235
22321
|
scheduleNativeReconciliation(generation, filePath) {
|
|
21236
22322
|
if (!this.isCurrentNativeSetup(generation)) return;
|
|
21237
|
-
const requiresFullReconciliation = filePath ===
|
|
22323
|
+
const requiresFullReconciliation = filePath === path29.join(this.projectRoot, ".gitignore");
|
|
21238
22324
|
const invalidatedPath = requiresFullReconciliation ? null : filePath;
|
|
21239
22325
|
this.nativeInvalidatedPaths.set(invalidatedPath, invalidatedPath !== null);
|
|
21240
22326
|
if (this.nativeReconcileTimer) {
|
|
@@ -21329,23 +22415,23 @@ var FileWatcher = class {
|
|
|
21329
22415
|
this.scheduleFlush();
|
|
21330
22416
|
}
|
|
21331
22417
|
isProjectConfigPath(filePath) {
|
|
21332
|
-
const relativePath =
|
|
21333
|
-
const normalizedRelativePath =
|
|
22418
|
+
const relativePath = path29.relative(this.projectRoot, filePath);
|
|
22419
|
+
const normalizedRelativePath = path29.normalize(relativePath);
|
|
21334
22420
|
return this.getProjectConfigRelativePaths().some((configPath) => configPath === normalizedRelativePath);
|
|
21335
22421
|
}
|
|
21336
22422
|
isProjectConfigPathOrAncestor(relativePath) {
|
|
21337
|
-
const normalizedRelativePath =
|
|
22423
|
+
const normalizedRelativePath = path29.normalize(relativePath);
|
|
21338
22424
|
return this.getProjectConfigRelativePaths().some(
|
|
21339
|
-
(configPath) => configPath === normalizedRelativePath || configPath.startsWith(`${normalizedRelativePath}${
|
|
22425
|
+
(configPath) => configPath === normalizedRelativePath || configPath.startsWith(`${normalizedRelativePath}${path29.sep}`)
|
|
21340
22426
|
);
|
|
21341
22427
|
}
|
|
21342
22428
|
isOutsideProjectPath(relativePath) {
|
|
21343
|
-
return relativePath === ".." || relativePath.startsWith(`..${
|
|
22429
|
+
return relativePath === ".." || relativePath.startsWith(`..${path29.sep}`) || path29.isAbsolute(relativePath);
|
|
21344
22430
|
}
|
|
21345
22431
|
getNearestExistingDirectory(directoryPath) {
|
|
21346
22432
|
let candidate = directoryPath;
|
|
21347
|
-
while (!
|
|
21348
|
-
const parent =
|
|
22433
|
+
while (!existsSync16(candidate)) {
|
|
22434
|
+
const parent = path29.dirname(candidate);
|
|
21349
22435
|
if (parent === candidate) break;
|
|
21350
22436
|
candidate = parent;
|
|
21351
22437
|
}
|
|
@@ -21353,7 +22439,7 @@ var FileWatcher = class {
|
|
|
21353
22439
|
}
|
|
21354
22440
|
getProjectConfigRelativePaths() {
|
|
21355
22441
|
return this.projectConfigPaths.map(
|
|
21356
|
-
(configPath) =>
|
|
22442
|
+
(configPath) => path29.normalize(path29.relative(this.projectRoot, configPath))
|
|
21357
22443
|
);
|
|
21358
22444
|
}
|
|
21359
22445
|
getConfigPathStates() {
|
|
@@ -21411,7 +22497,7 @@ var FileWatcher = class {
|
|
|
21411
22497
|
return;
|
|
21412
22498
|
}
|
|
21413
22499
|
const changes = Array.from(this.pendingChanges.entries()).map(
|
|
21414
|
-
([
|
|
22500
|
+
([path34, type]) => ({ path: path34, type })
|
|
21415
22501
|
);
|
|
21416
22502
|
this.pendingChanges.clear();
|
|
21417
22503
|
try {
|
|
@@ -21457,7 +22543,7 @@ var FileWatcher = class {
|
|
|
21457
22543
|
};
|
|
21458
22544
|
|
|
21459
22545
|
// src/watcher/git-head-watcher.ts
|
|
21460
|
-
import * as
|
|
22546
|
+
import * as path30 from "path";
|
|
21461
22547
|
var GitHeadWatcher = class {
|
|
21462
22548
|
watcher = null;
|
|
21463
22549
|
projectRoot;
|
|
@@ -21479,13 +22565,13 @@ var GitHeadWatcher = class {
|
|
|
21479
22565
|
this.readyPromise = Promise.resolve();
|
|
21480
22566
|
return;
|
|
21481
22567
|
}
|
|
21482
|
-
this.readyPromise = new Promise((
|
|
21483
|
-
this.resolveReady =
|
|
22568
|
+
this.readyPromise = new Promise((resolve21) => {
|
|
22569
|
+
this.resolveReady = resolve21;
|
|
21484
22570
|
});
|
|
21485
22571
|
this.onBranchChange = handler;
|
|
21486
22572
|
this.currentBranch = getCurrentBranch(this.projectRoot);
|
|
21487
22573
|
const headPath = getHeadPath(this.projectRoot);
|
|
21488
|
-
const refsPath =
|
|
22574
|
+
const refsPath = path30.join(this.projectRoot, ".git", "refs", "heads");
|
|
21489
22575
|
this.watcher = chokidar_default.watch([headPath, refsPath], {
|
|
21490
22576
|
persistent: true,
|
|
21491
22577
|
ignoreInitial: true,
|
|
@@ -21553,7 +22639,9 @@ var GitHeadWatcher = class {
|
|
|
21553
22639
|
function createWatcherWithIndexer(getIndexer, projectRoot, config, host, options = {}) {
|
|
21554
22640
|
const fileWatcher = new FileWatcher(projectRoot, config, host, options);
|
|
21555
22641
|
const configPaths = getConfigPaths(projectRoot, host, options);
|
|
21556
|
-
configureAutoIndex(projectRoot, host, parseConfig(config), getIndexer
|
|
22642
|
+
configureAutoIndex(projectRoot, host, parseConfig(config), getIndexer, {
|
|
22643
|
+
synchronizeBackgroundWorker: false
|
|
22644
|
+
});
|
|
21557
22645
|
let stopped = false;
|
|
21558
22646
|
const requestReindex = () => {
|
|
21559
22647
|
if (stopped) return;
|
|
@@ -21573,7 +22661,9 @@ function createWatcherWithIndexer(getIndexer, projectRoot, config, host, options
|
|
|
21573
22661
|
const parsedConfig = options.configPath ? parseConfig(loadConfigFile(options.configPath)) : void 0;
|
|
21574
22662
|
const refreshedConfig = refreshIndexerForDirectory(projectRoot, host, parsedConfig);
|
|
21575
22663
|
if (refreshedConfig) {
|
|
21576
|
-
configureAutoIndex(projectRoot, host, refreshedConfig, getIndexer
|
|
22664
|
+
configureAutoIndex(projectRoot, host, refreshedConfig, getIndexer, {
|
|
22665
|
+
synchronizeBackgroundWorker: false
|
|
22666
|
+
});
|
|
21577
22667
|
}
|
|
21578
22668
|
}
|
|
21579
22669
|
requestReindex();
|
|
@@ -21621,7 +22711,7 @@ function getConfigPaths(projectRoot, host, options) {
|
|
|
21621
22711
|
|
|
21622
22712
|
// src/tools/visualize/activity.ts
|
|
21623
22713
|
import { execFileSync } from "child_process";
|
|
21624
|
-
import * as
|
|
22714
|
+
import * as path31 from "path";
|
|
21625
22715
|
function attachRecentActivity(data, projectRoot) {
|
|
21626
22716
|
const activity = readGitActivity(projectRoot);
|
|
21627
22717
|
const changes = activity.size > 0 ? buildGitChanges(data, activity, projectRoot) : buildGraphChanges(data);
|
|
@@ -21783,7 +22873,7 @@ function normalizePath4(filePath) {
|
|
|
21783
22873
|
return filePath.replace(/\\/g, "/");
|
|
21784
22874
|
}
|
|
21785
22875
|
function toGitRelativePath(projectRoot, filePath) {
|
|
21786
|
-
const relativePath =
|
|
22876
|
+
const relativePath = path31.isAbsolute(filePath) ? path31.relative(projectRoot, filePath) : filePath;
|
|
21787
22877
|
return normalizePath4(relativePath);
|
|
21788
22878
|
}
|
|
21789
22879
|
|
|
@@ -22041,7 +23131,7 @@ render();
|
|
|
22041
23131
|
}
|
|
22042
23132
|
|
|
22043
23133
|
// src/tools/visualize/transform.ts
|
|
22044
|
-
import * as
|
|
23134
|
+
import * as path32 from "path";
|
|
22045
23135
|
|
|
22046
23136
|
// src/tools/visualize/modules.ts
|
|
22047
23137
|
var MAX_MODULES = 18;
|
|
@@ -22301,7 +23391,7 @@ function transformForVisualization(symbols, edges, options = {}) {
|
|
|
22301
23391
|
filePath: s.filePath,
|
|
22302
23392
|
kind: s.kind,
|
|
22303
23393
|
line: s.startLine,
|
|
22304
|
-
directory:
|
|
23394
|
+
directory: path32.dirname(s.filePath),
|
|
22305
23395
|
moduleId: "",
|
|
22306
23396
|
moduleLabel: ""
|
|
22307
23397
|
}));
|
|
@@ -22329,9 +23419,9 @@ function parseArgs(argv) {
|
|
|
22329
23419
|
let host = "opencode";
|
|
22330
23420
|
for (let i = 2; i < argv.length; i++) {
|
|
22331
23421
|
if (argv[i] === "--project" && argv[i + 1]) {
|
|
22332
|
-
project =
|
|
23422
|
+
project = path33.resolve(argv[++i]);
|
|
22333
23423
|
} else if (argv[i] === "--config" && argv[i + 1]) {
|
|
22334
|
-
config =
|
|
23424
|
+
config = path33.resolve(argv[++i]);
|
|
22335
23425
|
} else if (argv[i] === "--host" && argv[i + 1]) {
|
|
22336
23426
|
host = parseHostMode(argv[++i]);
|
|
22337
23427
|
} else if (argv[i] === "--host") {
|
|
@@ -22359,7 +23449,7 @@ function parseIndexArgs(argv, cwd) {
|
|
|
22359
23449
|
if (!arg.startsWith("--project=")) {
|
|
22360
23450
|
i += 1;
|
|
22361
23451
|
}
|
|
22362
|
-
project =
|
|
23452
|
+
project = path33.resolve(cwd, value);
|
|
22363
23453
|
continue;
|
|
22364
23454
|
}
|
|
22365
23455
|
if (arg === "--config" || arg.startsWith("--config=")) {
|
|
@@ -22370,7 +23460,7 @@ function parseIndexArgs(argv, cwd) {
|
|
|
22370
23460
|
if (!arg.startsWith("--config=")) {
|
|
22371
23461
|
i += 1;
|
|
22372
23462
|
}
|
|
22373
|
-
config =
|
|
23463
|
+
config = path33.resolve(cwd, value);
|
|
22374
23464
|
continue;
|
|
22375
23465
|
}
|
|
22376
23466
|
if (arg === "--host" || arg.startsWith("--host=")) {
|
|
@@ -22430,7 +23520,7 @@ Progress and diagnostics are written to stderr. Final index output is written to
|
|
|
22430
23520
|
);
|
|
22431
23521
|
}
|
|
22432
23522
|
function isCliEntrypoint(moduleUrl, argvPath) {
|
|
22433
|
-
return argvPath !== void 0 &&
|
|
23523
|
+
return argvPath !== void 0 && realpathSync7(fileURLToPath2(moduleUrl)) === realpathSync7(argvPath);
|
|
22434
23524
|
}
|
|
22435
23525
|
function parseVisualizeArgs(argv, cwd) {
|
|
22436
23526
|
let project = cwd;
|
|
@@ -22440,7 +23530,7 @@ function parseVisualizeArgs(argv, cwd) {
|
|
|
22440
23530
|
for (let i = 0; i < argv.length; i++) {
|
|
22441
23531
|
const arg = argv[i];
|
|
22442
23532
|
if (arg === "--project" && argv[i + 1]) {
|
|
22443
|
-
project =
|
|
23533
|
+
project = path33.resolve(argv[++i]);
|
|
22444
23534
|
} else if (arg === "--max" && argv[i + 1]) {
|
|
22445
23535
|
maxNodes = Number(argv[++i]);
|
|
22446
23536
|
} else if (arg.startsWith("--max=") || arg.startsWith("max=")) {
|
|
@@ -22477,8 +23567,8 @@ async function handleVisualizeCommand(argv, cwd) {
|
|
|
22477
23567
|
console.error("No connected symbols found. Retry with: npm run visualize -- orphans");
|
|
22478
23568
|
return 1;
|
|
22479
23569
|
}
|
|
22480
|
-
const outputPath =
|
|
22481
|
-
|
|
23570
|
+
const outputPath = path33.join(os9.tmpdir(), `call-graph-${Date.now()}.html`);
|
|
23571
|
+
writeFileSync7(outputPath, generateVisualizationHtml(vizData), "utf-8");
|
|
22482
23572
|
console.log(`Temporal call graph visualization generated: ${outputPath}`);
|
|
22483
23573
|
console.log(`Nodes: ${vizData.nodes.length} | Edges: ${vizData.edges.length}`);
|
|
22484
23574
|
console.log(`Recent change lenses: ${vizData.changes?.length ?? 0}`);
|
|
@@ -22509,7 +23599,6 @@ async function runMcpCli(argv) {
|
|
|
22509
23599
|
const config = parseConfig(rawConfig);
|
|
22510
23600
|
const server = createMcpServer(args.project, config, args.host);
|
|
22511
23601
|
const transport = new StdioServerTransport();
|
|
22512
|
-
let watcher = null;
|
|
22513
23602
|
let shutdownPromise;
|
|
22514
23603
|
const onServerClose = server.server.onclose;
|
|
22515
23604
|
const shutdown = () => {
|
|
@@ -22523,16 +23612,19 @@ async function runMcpCli(argv) {
|
|
|
22523
23612
|
shutdownPromise = (async () => {
|
|
22524
23613
|
let exitCode = 0;
|
|
22525
23614
|
try {
|
|
22526
|
-
await
|
|
22527
|
-
} catch (error) {
|
|
22528
|
-
exitCode = 1;
|
|
22529
|
-
console.error("Failed to stop MCP file watcher cleanly:", error);
|
|
22530
|
-
}
|
|
22531
|
-
try {
|
|
22532
|
-
await stopAutoIndex(args.project, args.host);
|
|
23615
|
+
await stopBackgroundWorker(args.project, args.host);
|
|
22533
23616
|
} catch (error) {
|
|
22534
23617
|
exitCode = 1;
|
|
22535
|
-
|
|
23618
|
+
if (error instanceof BackgroundWorkerStopError) {
|
|
23619
|
+
if (error.watcherError !== void 0) {
|
|
23620
|
+
console.error("Failed to stop MCP file watcher cleanly:", error.watcherError);
|
|
23621
|
+
}
|
|
23622
|
+
if (error.autoIndexError !== void 0) {
|
|
23623
|
+
console.error("Failed to stop automatic indexing cleanly:", error.autoIndexError);
|
|
23624
|
+
}
|
|
23625
|
+
} else {
|
|
23626
|
+
console.error("Failed to stop automatic indexing cleanly:", error);
|
|
23627
|
+
}
|
|
22536
23628
|
}
|
|
22537
23629
|
try {
|
|
22538
23630
|
await server.close();
|
|
@@ -22561,19 +23653,25 @@ async function runMcpCli(argv) {
|
|
|
22561
23653
|
process.once("SIGHUP", requestShutdown);
|
|
22562
23654
|
process.once("SIGTERM", requestShutdown);
|
|
22563
23655
|
}
|
|
22564
|
-
await server.connect(transport);
|
|
22565
|
-
if (shutdownPromise) return;
|
|
22566
23656
|
const isHomeDir = isHomeDirectory(args.project);
|
|
22567
23657
|
const isValidProject = !isHomeDir && (!config.indexing.requireProjectMarker || hasProjectMarker(args.project));
|
|
22568
|
-
|
|
22569
|
-
|
|
22570
|
-
|
|
22571
|
-
|
|
22572
|
-
|
|
22573
|
-
|
|
22574
|
-
|
|
22575
|
-
|
|
22576
|
-
|
|
23658
|
+
const watcherFactoryForConfig = (refreshedConfig) => refreshedConfig.indexing.watchFiles && !isHomeDirectory(args.project) && (!refreshedConfig.indexing.requireProjectMarker || hasProjectMarker(args.project)) ? () => createWatcherWithIndexer(
|
|
23659
|
+
() => getIndexerForProject(args.project, args.host),
|
|
23660
|
+
args.project,
|
|
23661
|
+
refreshedConfig,
|
|
23662
|
+
args.host,
|
|
23663
|
+
args.config ? { configPath: args.config } : {}
|
|
23664
|
+
) : null;
|
|
23665
|
+
await server.connect(transport);
|
|
23666
|
+
if (shutdownPromise) return;
|
|
23667
|
+
await attachMcpBackgroundWatcher(
|
|
23668
|
+
args.project,
|
|
23669
|
+
config,
|
|
23670
|
+
args.host,
|
|
23671
|
+
config.indexing.watchFiles && isValidProject ? watcherFactoryForConfig(config) : null,
|
|
23672
|
+
watcherFactoryForConfig
|
|
23673
|
+
);
|
|
23674
|
+
if (shutdownPromise) return;
|
|
22577
23675
|
}
|
|
22578
23676
|
function printIndexProgress(onProgress, title, metadata) {
|
|
22579
23677
|
const details = Object.entries(metadata).filter(([, value]) => value !== void 0 && value !== null).map(([key, value]) => `${key}=${isSensitiveKey(key) ? "[REDACTED]" : String(value)}`).join(" ");
|