opencode-codebase-index 0.24.0 → 0.25.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/README.md +10 -0
- package/dist/cbi.cjs +15788 -0
- package/dist/cbi.cjs.map +1 -0
- package/dist/cbi.js +15791 -0
- package/dist/cbi.js.map +1 -0
- package/dist/cli.cjs +1847 -660
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +1881 -685
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +1673 -590
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1680 -588
- package/dist/index.js.map +1 -1
- package/dist/pi-extension.cjs +1585 -485
- package/dist/pi-extension.cjs.map +1 -1
- package/dist/pi-extension.js +1641 -532
- package/dist/pi-extension.js.map +1 -1
- package/native/codebase-index-native.darwin-arm64.node +0 -0
- package/native/codebase-index-native.darwin-x64.node +0 -0
- package/native/codebase-index-native.linux-arm64-gnu.node +0 -0
- package/native/codebase-index-native.linux-x64-gnu.node +0 -0
- package/native/codebase-index-native.win32-x64-msvc.node +0 -0
- package/package.json +3 -2
package/dist/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) {
|
|
@@ -3596,6 +3611,26 @@ function formatCostEstimate(estimate) {
|
|
|
3596
3611
|
\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518
|
|
3597
3612
|
`;
|
|
3598
3613
|
}
|
|
3614
|
+
function formatDryRunEstimate(estimate) {
|
|
3615
|
+
return `Dry run: parsed the file set to measure the embedding workload. No embedding requests were made and the index was not changed.
|
|
3616
|
+
|
|
3617
|
+
Files to embed: ${estimate.filesCount.toLocaleString()}
|
|
3618
|
+
Chunks to embed: ${estimate.chunksCount.toLocaleString()}
|
|
3619
|
+
Tokens to embed: ${estimate.tokensToEmbed.toLocaleString()}
|
|
3620
|
+
|
|
3621
|
+
The "Tokens to embed" value uses the local estimateTokens(text) = ceil(len/4). It
|
|
3622
|
+
matches the live "Tokens used" counter only for providers that report usage on the
|
|
3623
|
+
same basis (ollama); for providers that report a server tokenizer count (OpenAI,
|
|
3624
|
+
Gemini, custom) it is only an estimate.
|
|
3625
|
+
|
|
3626
|
+
For a matching provider and a project-scoped force index, the force pass clears its
|
|
3627
|
+
own cached embeddings, so the live counter climbs to this number. A force index on a
|
|
3628
|
+
shared global index can reuse cached embeddings from other projects, and an
|
|
3629
|
+
incremental index counts cached chunks that are not re-embedded; in both cases this
|
|
3630
|
+
number is an upper bound on the live counter, so a progress percent against this
|
|
3631
|
+
total tops out below 100%.
|
|
3632
|
+
`;
|
|
3633
|
+
}
|
|
3599
3634
|
function formatBytes(bytes) {
|
|
3600
3635
|
if (bytes === 0) return "0 B";
|
|
3601
3636
|
const k = 1024;
|
|
@@ -6820,6 +6855,9 @@ var CALL_GRAPH_SYMBOL_CHUNK_TYPES = /* @__PURE__ */ new Set([
|
|
|
6820
6855
|
"enum_declaration",
|
|
6821
6856
|
"function_definition",
|
|
6822
6857
|
"class_definition",
|
|
6858
|
+
// Ruby module/class symbols that are declaration-bearing and navigable.
|
|
6859
|
+
"class",
|
|
6860
|
+
"module",
|
|
6823
6861
|
"class_specifier",
|
|
6824
6862
|
"struct_specifier",
|
|
6825
6863
|
"namespace_definition",
|
|
@@ -7064,8 +7102,8 @@ function pathSegmentsForAffinityMatch(filePath) {
|
|
|
7064
7102
|
if (segments.length === 0) {
|
|
7065
7103
|
return [];
|
|
7066
7104
|
}
|
|
7067
|
-
const
|
|
7068
|
-
const basenameWithoutExt =
|
|
7105
|
+
const basename9 = segments[segments.length - 1] ?? "";
|
|
7106
|
+
const basenameWithoutExt = basename9.replace(/\.[^/.]+$/u, "");
|
|
7069
7107
|
const normalizedSegments = segments.map((segment) => segment.toLowerCase());
|
|
7070
7108
|
return Array.from(/* @__PURE__ */ new Set([
|
|
7071
7109
|
...normalizedSegments,
|
|
@@ -7488,7 +7526,7 @@ function removeDeadReclaimMarker(lockPath, expectedOwner) {
|
|
|
7488
7526
|
return true;
|
|
7489
7527
|
}
|
|
7490
7528
|
function reclaimDeadOwner(indexPath, lockPath, expectedOwner) {
|
|
7491
|
-
const
|
|
7529
|
+
const reclaimPath2 = path13.join(lockPath, RECLAIM_DIRECTORY_NAME);
|
|
7492
7530
|
const reclaimOwner = {
|
|
7493
7531
|
pid: process.pid,
|
|
7494
7532
|
hostname: os5.hostname(),
|
|
@@ -7497,19 +7535,19 @@ function reclaimDeadOwner(indexPath, lockPath, expectedOwner) {
|
|
|
7497
7535
|
expectedOwnerToken: expectedOwner.token
|
|
7498
7536
|
};
|
|
7499
7537
|
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
7500
|
-
if (publishJsonDirectory(
|
|
7538
|
+
if (publishJsonDirectory(reclaimPath2, reclaimOwner)) break;
|
|
7501
7539
|
if (attempt === 0 && removeDeadReclaimMarker(lockPath, expectedOwner)) continue;
|
|
7502
7540
|
return false;
|
|
7503
7541
|
}
|
|
7504
7542
|
try {
|
|
7505
|
-
const currentReclaimer = readReclaimOwner(
|
|
7543
|
+
const currentReclaimer = readReclaimOwner(reclaimPath2);
|
|
7506
7544
|
const currentOwner = readDirectoryOwner(lockPath);
|
|
7507
7545
|
if (!currentReclaimer || !sameReclaimOwner(currentReclaimer, reclaimOwner) || !currentOwner || !sameOwner(currentOwner, expectedOwner) || getOwnerLiveness(currentOwner) !== "dead") {
|
|
7508
7546
|
return false;
|
|
7509
7547
|
}
|
|
7510
7548
|
publishRecoveryMarker(indexPath, expectedOwner);
|
|
7511
7549
|
const ownerBeforeQuarantine = readDirectoryOwner(lockPath);
|
|
7512
|
-
const reclaimerBeforeQuarantine = readReclaimOwner(
|
|
7550
|
+
const reclaimerBeforeQuarantine = readReclaimOwner(reclaimPath2);
|
|
7513
7551
|
if (!ownerBeforeQuarantine || !sameOwner(ownerBeforeQuarantine, expectedOwner) || getOwnerLiveness(ownerBeforeQuarantine) !== "dead" || !reclaimerBeforeQuarantine || !sameReclaimOwner(reclaimerBeforeQuarantine, reclaimOwner)) {
|
|
7514
7552
|
return false;
|
|
7515
7553
|
}
|
|
@@ -8725,6 +8763,17 @@ var Indexer = class _Indexer {
|
|
|
8725
8763
|
}
|
|
8726
8764
|
return path15.relative(this.projectRoot, canonicalFilePath).split(path15.sep).join("/");
|
|
8727
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
|
+
}
|
|
8728
8777
|
resolveStoredFilePath(filePath, rootPath = this.projectRoot) {
|
|
8729
8778
|
if (path15.isAbsolute(filePath)) {
|
|
8730
8779
|
return filePath;
|
|
@@ -9749,7 +9798,7 @@ var Indexer = class _Indexer {
|
|
|
9749
9798
|
await options.queue.onSizeLessThan(Math.max(1, options.providerRateLimits.concurrency));
|
|
9750
9799
|
const task = options.queue.add(async () => {
|
|
9751
9800
|
if (options.rateLimitState.backoffMs > 0) {
|
|
9752
|
-
await new Promise((
|
|
9801
|
+
await new Promise((resolve21) => setTimeout(resolve21, options.rateLimitState.backoffMs));
|
|
9753
9802
|
}
|
|
9754
9803
|
try {
|
|
9755
9804
|
const embeddingResult = await pRetry(
|
|
@@ -10866,6 +10915,70 @@ var Indexer = class _Indexer {
|
|
|
10866
10915
|
);
|
|
10867
10916
|
return createCostEstimate(files, configuredProviderInfo);
|
|
10868
10917
|
}
|
|
10918
|
+
// Dry-run counterpart to index()/forceIndex(): parse the real file set and sum
|
|
10919
|
+
// estimateTokens over the embedding text of every indexable chunk, without
|
|
10920
|
+
// calling the embedding provider or writing to the index. Read-only and
|
|
10921
|
+
// lock-free (mirrors estimateCost). The token sum is the exact value "Tokens
|
|
10922
|
+
// used" climbs to for a force index (cache bypassed); for an incremental it is
|
|
10923
|
+
// an upper bound because cached chunks are counted here but not re-embedded.
|
|
10924
|
+
// Used by index_codebase(dryRun:true) to give a stable, monotonic progress
|
|
10925
|
+
// denominator that matches the live "Tokens used" basis.
|
|
10926
|
+
async dryRunCost() {
|
|
10927
|
+
const { configuredProviderInfo } = await this.ensureInitialized();
|
|
10928
|
+
const maxChunkTokens = getSafeEmbeddingChunkTokenLimit(configuredProviderInfo);
|
|
10929
|
+
const includePatterns = [...this.config.include, ...this.config.additionalInclude];
|
|
10930
|
+
const { files } = await collectFiles(
|
|
10931
|
+
this.materializedProjectRoot,
|
|
10932
|
+
includePatterns,
|
|
10933
|
+
this.config.exclude,
|
|
10934
|
+
this.config.indexing.maxFileSize,
|
|
10935
|
+
this.getMaterializedKnowledgeBases(),
|
|
10936
|
+
{ maxDepth: this.config.indexing.maxDepth, maxFilesPerDirectory: this.config.indexing.maxFilesPerDirectory }
|
|
10937
|
+
);
|
|
10938
|
+
let filesCount = 0;
|
|
10939
|
+
let chunksCount = 0;
|
|
10940
|
+
let tokensToEmbed = 0;
|
|
10941
|
+
for (const batch of iterateOrderedFileBatches(files, (f) => f.size, this.fileBatchLimits)) {
|
|
10942
|
+
const loadedFiles = await Promise.all(batch.map(async (f) => {
|
|
10943
|
+
try {
|
|
10944
|
+
return {
|
|
10945
|
+
path: this.toStoredFilePath(f.path),
|
|
10946
|
+
content: await fsPromises3.readFile(f.path, "utf-8")
|
|
10947
|
+
};
|
|
10948
|
+
} catch {
|
|
10949
|
+
return null;
|
|
10950
|
+
}
|
|
10951
|
+
}));
|
|
10952
|
+
const readable = loadedFiles.filter(
|
|
10953
|
+
(f) => f !== null
|
|
10954
|
+
);
|
|
10955
|
+
filesCount += readable.length;
|
|
10956
|
+
const contentByPath = new Map(readable.map((f) => [f.path, f.content]));
|
|
10957
|
+
const parsedFiles = parseFiles(readable, this.config.indexing.linesPerChunk);
|
|
10958
|
+
for (const parsed of parsedFiles) {
|
|
10959
|
+
let chunksToProcess = parsed.chunks;
|
|
10960
|
+
if (this.config.indexing.fallbackToTextOnMaxChunks && chunksToProcess.length > this.config.indexing.maxChunksPerFile) {
|
|
10961
|
+
const content = contentByPath.get(parsed.path);
|
|
10962
|
+
if (content !== void 0) {
|
|
10963
|
+
chunksToProcess = parseFileAsText(parsed.path, content, this.config.indexing.linesPerChunk);
|
|
10964
|
+
}
|
|
10965
|
+
}
|
|
10966
|
+
chunksToProcess = selectIndexableChunks(
|
|
10967
|
+
chunksToProcess,
|
|
10968
|
+
this.config.indexing.maxChunksPerFile,
|
|
10969
|
+
this.config.indexing.semanticOnly
|
|
10970
|
+
);
|
|
10971
|
+
for (const chunk of chunksToProcess) {
|
|
10972
|
+
const texts = createEmbeddingTexts(chunk, parsed.path, maxChunkTokens);
|
|
10973
|
+
chunksCount += 1;
|
|
10974
|
+
for (const text of texts) {
|
|
10975
|
+
tokensToEmbed += estimateTokens2(text);
|
|
10976
|
+
}
|
|
10977
|
+
}
|
|
10978
|
+
}
|
|
10979
|
+
}
|
|
10980
|
+
return { filesCount, chunksCount, tokensToEmbed };
|
|
10981
|
+
}
|
|
10869
10982
|
async index(onProgress) {
|
|
10870
10983
|
return this.withIndexMutationLease("index", async (recoveredOwners) => {
|
|
10871
10984
|
return this.indexUnlocked(onProgress, recoveredOwners);
|
|
@@ -11062,7 +11175,7 @@ var Indexer = class _Indexer {
|
|
|
11062
11175
|
}
|
|
11063
11176
|
}
|
|
11064
11177
|
}
|
|
11065
|
-
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);
|
|
11066
11179
|
const failedProcessing = this.prepareFailedBatchProcessing(scopedRoots, shouldRetryFailedPath);
|
|
11067
11180
|
const maxChunkTokens = getSafeEmbeddingChunkTokenLimit(configuredProviderInfo);
|
|
11068
11181
|
const providerRateLimits = this.getProviderRateLimits(configuredProviderInfo.provider);
|
|
@@ -12390,7 +12503,8 @@ var Indexer = class _Indexer {
|
|
|
12390
12503
|
const maxChunkTokens = getSafeEmbeddingChunkTokenLimit(configuredProviderInfo);
|
|
12391
12504
|
const providerRateLimits = this.getProviderRateLimits(configuredProviderInfo.provider);
|
|
12392
12505
|
const roots = this.config.scope === "global" ? this.getScopedRoots() : null;
|
|
12393
|
-
const
|
|
12506
|
+
const shouldProcessFailedPath = (filePath) => filePath === null || !this.isStoredPathExcluded(filePath);
|
|
12507
|
+
const failedProcessing = this.prepareFailedBatchProcessing(roots, shouldProcessFailedPath);
|
|
12394
12508
|
if (failedProcessing.latestById.size === 0) {
|
|
12395
12509
|
this.finalizeFailedBatchWriteState(failedProcessing.state);
|
|
12396
12510
|
return { succeeded: 0, failed: 0, remaining: 0 };
|
|
@@ -12403,7 +12517,7 @@ var Indexer = class _Indexer {
|
|
|
12403
12517
|
const retryableChunks = this.iterateLatestFailedChunks(
|
|
12404
12518
|
failedProcessing.latestById,
|
|
12405
12519
|
roots,
|
|
12406
|
-
|
|
12520
|
+
shouldProcessFailedPath,
|
|
12407
12521
|
maxChunkTokens
|
|
12408
12522
|
);
|
|
12409
12523
|
for (const retryBatch of iterateOrderedFileBatches(
|
|
@@ -12673,9 +12787,9 @@ var Indexer = class _Indexer {
|
|
|
12673
12787
|
this.requireReadableComponents(readIssues, "database");
|
|
12674
12788
|
let shortest = [];
|
|
12675
12789
|
for (const branchKey of this.getBranchCatalogKeys()) {
|
|
12676
|
-
const
|
|
12677
|
-
if (
|
|
12678
|
-
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;
|
|
12679
12793
|
}
|
|
12680
12794
|
}
|
|
12681
12795
|
return shortest.map((hop) => this.resolveFilePathRecord(hop));
|
|
@@ -12723,13 +12837,13 @@ var Indexer = class _Indexer {
|
|
|
12723
12837
|
}
|
|
12724
12838
|
}
|
|
12725
12839
|
if (!found) continue;
|
|
12726
|
-
const
|
|
12840
|
+
const path34 = [];
|
|
12727
12841
|
let currentSymbolId = toSymbolId;
|
|
12728
12842
|
while (true) {
|
|
12729
12843
|
const symbol = symbolsById.get(currentSymbolId);
|
|
12730
12844
|
if (!symbol) break;
|
|
12731
12845
|
const parent = parentBySymbolId.get(currentSymbolId);
|
|
12732
|
-
|
|
12846
|
+
path34.push({
|
|
12733
12847
|
symbolId: symbol.id,
|
|
12734
12848
|
symbolName: symbol.name,
|
|
12735
12849
|
filePath: symbol.filePath,
|
|
@@ -12739,9 +12853,9 @@ var Indexer = class _Indexer {
|
|
|
12739
12853
|
if (!parent) break;
|
|
12740
12854
|
currentSymbolId = parent.parentId;
|
|
12741
12855
|
}
|
|
12742
|
-
|
|
12743
|
-
if (
|
|
12744
|
-
shortest =
|
|
12856
|
+
path34.reverse();
|
|
12857
|
+
if (path34.length > 0 && (shortest.length === 0 || path34.length < shortest.length)) {
|
|
12858
|
+
shortest = path34;
|
|
12745
12859
|
}
|
|
12746
12860
|
}
|
|
12747
12861
|
return shortest.map((hop) => this.resolveFilePathRecord(hop));
|
|
@@ -13124,8 +13238,8 @@ var CODE_COMMUNITIES_DEFAULT_COUPLING_LIMIT = 20;
|
|
|
13124
13238
|
var CODE_COMMUNITIES_MAX_COUPLING_LIMIT = 100;
|
|
13125
13239
|
|
|
13126
13240
|
// src/tools/operations.ts
|
|
13127
|
-
import { existsSync as
|
|
13128
|
-
import * as
|
|
13241
|
+
import { existsSync as existsSync13, realpathSync as realpathSync6, statSync as statSync5 } from "fs";
|
|
13242
|
+
import * as path22 from "path";
|
|
13129
13243
|
|
|
13130
13244
|
// src/tools/knowledge-base-paths.ts
|
|
13131
13245
|
import * as path16 from "path";
|
|
@@ -13420,8 +13534,8 @@ function formatExactSearchHandoff(results) {
|
|
|
13420
13534
|
}
|
|
13421
13535
|
function formatContextEvidence(result, index) {
|
|
13422
13536
|
const symbol = result.name ? ` ${JSON.stringify(compactEvidenceValue(result.name, 80))}` : "";
|
|
13423
|
-
const
|
|
13424
|
-
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)})`;
|
|
13425
13539
|
}
|
|
13426
13540
|
function formatContextPack(heading, selected, candidateCount, duplicateCount, limitOmittedCount, budgetOmittedCount, includeExactSearchHandoff) {
|
|
13427
13541
|
const lines = selected.map((result, index) => formatContextEvidence(result, index + 1));
|
|
@@ -14063,119 +14177,47 @@ function formatEffectivenessMetrics(snapshot) {
|
|
|
14063
14177
|
}
|
|
14064
14178
|
|
|
14065
14179
|
// src/utils/auto-index.ts
|
|
14066
|
-
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";
|
|
14067
14196
|
import * as os6 from "os";
|
|
14068
14197
|
import * as path17 from "path";
|
|
14069
|
-
|
|
14070
|
-
|
|
14071
|
-
|
|
14072
|
-
var
|
|
14073
|
-
var
|
|
14074
|
-
|
|
14075
|
-
|
|
14076
|
-
}
|
|
14077
|
-
|
|
14078
|
-
|
|
14079
|
-
|
|
14080
|
-
|
|
14081
|
-
|
|
14082
|
-
|
|
14083
|
-
|
|
14084
|
-
|
|
14085
|
-
|
|
14086
|
-
return;
|
|
14087
|
-
}
|
|
14088
|
-
resolve20(stdout);
|
|
14089
|
-
}
|
|
14090
|
-
);
|
|
14091
|
-
});
|
|
14092
|
-
}
|
|
14093
|
-
function parseMacOsPowerSource(output) {
|
|
14094
|
-
const match = output.match(/Now drawing from '([^']+)'/i);
|
|
14095
|
-
if (!match) {
|
|
14096
|
-
return "unknown";
|
|
14097
|
-
}
|
|
14098
|
-
const source = match[1].toLowerCase();
|
|
14099
|
-
if (source === "battery power") {
|
|
14100
|
-
return "battery";
|
|
14101
|
-
}
|
|
14102
|
-
if (source === "ac power") {
|
|
14103
|
-
return "ac";
|
|
14104
|
-
}
|
|
14105
|
-
return "unknown";
|
|
14106
|
-
}
|
|
14107
|
-
async function readMacOsPowerSource(commandRunner = runCommand) {
|
|
14108
|
-
const output = await commandRunner(
|
|
14109
|
-
"/usr/bin/pmset",
|
|
14110
|
-
["-g", "batt"],
|
|
14111
|
-
{ timeoutMs: PMSET_TIMEOUT_MS }
|
|
14112
|
-
);
|
|
14113
|
-
return parseMacOsPowerSource(output);
|
|
14114
|
-
}
|
|
14115
|
-
var MacOsBackgroundIndexingPolicy = class {
|
|
14116
|
-
constructor(readPowerSource, recheckDelayMs) {
|
|
14117
|
-
this.readPowerSource = readPowerSource;
|
|
14118
|
-
this.recheckDelayMs = recheckDelayMs;
|
|
14119
|
-
}
|
|
14120
|
-
readPowerSource;
|
|
14121
|
-
recheckDelayMs;
|
|
14122
|
-
lastPaused = null;
|
|
14123
|
-
reportedFailure = false;
|
|
14124
|
-
isPaused() {
|
|
14125
|
-
return this.checkPowerSource();
|
|
14126
|
-
}
|
|
14127
|
-
async checkPowerSource() {
|
|
14128
|
-
try {
|
|
14129
|
-
const source = await this.readPowerSource();
|
|
14130
|
-
if (source === "unknown") {
|
|
14131
|
-
throw new Error("pmset returned an unrecognized power source");
|
|
14132
|
-
}
|
|
14133
|
-
this.reportedFailure = false;
|
|
14134
|
-
const paused = source === "battery";
|
|
14135
|
-
if (paused && this.lastPaused !== true) {
|
|
14136
|
-
console.warn("[codebase-index] Background indexing paused while macOS is using battery power.");
|
|
14137
|
-
} else if (!paused && this.lastPaused === true) {
|
|
14138
|
-
console.warn("[codebase-index] AC power detected; resuming pending background indexing.");
|
|
14139
|
-
}
|
|
14140
|
-
this.lastPaused = paused;
|
|
14141
|
-
return paused;
|
|
14142
|
-
} catch (error) {
|
|
14143
|
-
if (!this.reportedFailure) {
|
|
14144
|
-
console.error(
|
|
14145
|
-
`[codebase-index] Failed to determine the macOS power source; background indexing will continue: ${getErrorMessage4(error)}`
|
|
14146
|
-
);
|
|
14147
|
-
this.reportedFailure = true;
|
|
14148
|
-
}
|
|
14149
|
-
this.lastPaused = false;
|
|
14150
|
-
return false;
|
|
14151
|
-
}
|
|
14152
|
-
}
|
|
14153
|
-
};
|
|
14154
|
-
function createBackgroundIndexingPolicy(pauseOnBattery, options = {}) {
|
|
14155
|
-
const platform2 = options.platform ?? process.platform;
|
|
14156
|
-
if (!pauseOnBattery || platform2 !== "darwin") {
|
|
14157
|
-
return null;
|
|
14158
|
-
}
|
|
14159
|
-
return new MacOsBackgroundIndexingPolicy(
|
|
14160
|
-
options.readPowerSource ?? readMacOsPowerSource,
|
|
14161
|
-
options.recheckDelayMs ?? POWER_SOURCE_RECHECK_DELAY_MS
|
|
14162
|
-
);
|
|
14163
|
-
}
|
|
14164
|
-
|
|
14165
|
-
// src/utils/auto-index.ts
|
|
14166
|
-
var MAX_RETRY_DELAY_MS = 1e4;
|
|
14167
|
-
var SHUTDOWN_WAIT_MS = 2e3;
|
|
14168
|
-
var coordinators = /* @__PURE__ */ new Map();
|
|
14169
|
-
var coordinatorKeysByProject = /* @__PURE__ */ new Map();
|
|
14170
|
-
var coordinatorReplacementBarriers = /* @__PURE__ */ new Map();
|
|
14171
|
-
var AutoIndexCancelledError = class extends Error {
|
|
14172
|
-
constructor() {
|
|
14173
|
-
super("Auto-index coordination was cancelled");
|
|
14174
|
-
this.name = "AutoIndexCancelledError";
|
|
14175
|
-
}
|
|
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;
|
|
14176
14215
|
};
|
|
14177
|
-
|
|
14178
|
-
|
|
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;
|
|
14179
14221
|
}
|
|
14180
14222
|
function canonicalizePath(targetPath) {
|
|
14181
14223
|
const resolved = path17.resolve(targetPath);
|
|
@@ -14190,50 +14232,1020 @@ function canonicalizePath(targetPath) {
|
|
|
14190
14232
|
if (parent === resolved) return resolved;
|
|
14191
14233
|
return path17.join(canonicalizePath(parent), path17.basename(resolved));
|
|
14192
14234
|
}
|
|
14193
|
-
function isHomeDirectory(projectRoot) {
|
|
14194
|
-
return canonicalizePath(projectRoot) === canonicalizePath(os6.homedir());
|
|
14195
|
-
}
|
|
14196
14235
|
function projectLookupKey(projectRoot, host) {
|
|
14197
14236
|
return `${host}::${canonicalizePath(projectRoot)}`;
|
|
14198
14237
|
}
|
|
14199
|
-
function
|
|
14238
|
+
function getBackgroundWorkerProjectKey(projectRoot, host) {
|
|
14239
|
+
return projectLookupKey(projectRoot, host);
|
|
14240
|
+
}
|
|
14241
|
+
function resolveIdentity(projectRoot, config, host) {
|
|
14200
14242
|
const canonicalProjectRoot = canonicalizePath(projectRoot);
|
|
14201
|
-
const
|
|
14202
|
-
return
|
|
14243
|
+
const canonicalIndexPath = canonicalizePath(resolveProjectIndexPath(projectRoot, config.scope, host));
|
|
14244
|
+
return {
|
|
14245
|
+
canonicalIndexPath,
|
|
14246
|
+
canonicalProjectRoot,
|
|
14247
|
+
key: `${canonicalIndexPath}::${canonicalProjectRoot}`
|
|
14248
|
+
};
|
|
14203
14249
|
}
|
|
14204
|
-
function
|
|
14205
|
-
|
|
14206
|
-
|
|
14207
|
-
|
|
14208
|
-
|
|
14209
|
-
|
|
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;
|
|
14210
14305
|
}
|
|
14211
|
-
return { safeToRun: true };
|
|
14212
14306
|
}
|
|
14213
|
-
function
|
|
14214
|
-
|
|
14215
|
-
if (
|
|
14216
|
-
|
|
14217
|
-
|
|
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;
|
|
14218
14318
|
}
|
|
14219
|
-
|
|
14220
|
-
|
|
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;
|
|
14221
14325
|
}
|
|
14222
|
-
if (progress.phase === "storing") return 95;
|
|
14223
|
-
return 0;
|
|
14224
14326
|
}
|
|
14225
|
-
function
|
|
14226
|
-
if (
|
|
14227
|
-
|
|
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";
|
|
14228
14337
|
}
|
|
14229
|
-
return "Automatic indexing failed. Check the embedding provider configuration, then run index_codebase.";
|
|
14230
14338
|
}
|
|
14231
|
-
function
|
|
14232
|
-
|
|
14233
|
-
|
|
14234
|
-
|
|
14235
|
-
|
|
14236
|
-
|
|
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
|
+
}
|
|
15081
|
+
|
|
15082
|
+
// src/utils/power-source.ts
|
|
15083
|
+
import * as childProcess from "child_process";
|
|
15084
|
+
var POWER_SOURCE_RECHECK_DELAY_MS = 6e4;
|
|
15085
|
+
var PMSET_TIMEOUT_MS = 5e3;
|
|
15086
|
+
function getErrorMessage4(error) {
|
|
15087
|
+
return error instanceof Error ? error.message : String(error);
|
|
15088
|
+
}
|
|
15089
|
+
function runCommand(file, args, options) {
|
|
15090
|
+
return new Promise((resolve21, reject) => {
|
|
15091
|
+
childProcess.execFile(
|
|
15092
|
+
file,
|
|
15093
|
+
args,
|
|
15094
|
+
{ encoding: "utf8", timeout: options.timeoutMs },
|
|
15095
|
+
(error, stdout) => {
|
|
15096
|
+
if (error) {
|
|
15097
|
+
reject(error);
|
|
15098
|
+
return;
|
|
15099
|
+
}
|
|
15100
|
+
resolve21(stdout);
|
|
15101
|
+
}
|
|
15102
|
+
);
|
|
15103
|
+
});
|
|
15104
|
+
}
|
|
15105
|
+
function parseMacOsPowerSource(output) {
|
|
15106
|
+
const match = output.match(/Now drawing from '([^']+)'/i);
|
|
15107
|
+
if (!match) {
|
|
15108
|
+
return "unknown";
|
|
15109
|
+
}
|
|
15110
|
+
const source = match[1].toLowerCase();
|
|
15111
|
+
if (source === "battery power") {
|
|
15112
|
+
return "battery";
|
|
15113
|
+
}
|
|
15114
|
+
if (source === "ac power") {
|
|
15115
|
+
return "ac";
|
|
15116
|
+
}
|
|
15117
|
+
return "unknown";
|
|
15118
|
+
}
|
|
15119
|
+
async function readMacOsPowerSource(commandRunner = runCommand) {
|
|
15120
|
+
const output = await commandRunner(
|
|
15121
|
+
"/usr/bin/pmset",
|
|
15122
|
+
["-g", "batt"],
|
|
15123
|
+
{ timeoutMs: PMSET_TIMEOUT_MS }
|
|
15124
|
+
);
|
|
15125
|
+
return parseMacOsPowerSource(output);
|
|
15126
|
+
}
|
|
15127
|
+
var MacOsBackgroundIndexingPolicy = class {
|
|
15128
|
+
constructor(readPowerSource, recheckDelayMs) {
|
|
15129
|
+
this.readPowerSource = readPowerSource;
|
|
15130
|
+
this.recheckDelayMs = recheckDelayMs;
|
|
15131
|
+
}
|
|
15132
|
+
readPowerSource;
|
|
15133
|
+
recheckDelayMs;
|
|
15134
|
+
lastPaused = null;
|
|
15135
|
+
reportedFailure = false;
|
|
15136
|
+
isPaused() {
|
|
15137
|
+
return this.checkPowerSource();
|
|
15138
|
+
}
|
|
15139
|
+
async checkPowerSource() {
|
|
15140
|
+
try {
|
|
15141
|
+
const source = await this.readPowerSource();
|
|
15142
|
+
if (source === "unknown") {
|
|
15143
|
+
throw new Error("pmset returned an unrecognized power source");
|
|
15144
|
+
}
|
|
15145
|
+
this.reportedFailure = false;
|
|
15146
|
+
const paused = source === "battery";
|
|
15147
|
+
if (paused && this.lastPaused !== true) {
|
|
15148
|
+
console.warn("[codebase-index] Background indexing paused while macOS is using battery power.");
|
|
15149
|
+
} else if (!paused && this.lastPaused === true) {
|
|
15150
|
+
console.warn("[codebase-index] AC power detected; resuming pending background indexing.");
|
|
15151
|
+
}
|
|
15152
|
+
this.lastPaused = paused;
|
|
15153
|
+
return paused;
|
|
15154
|
+
} catch (error) {
|
|
15155
|
+
if (!this.reportedFailure) {
|
|
15156
|
+
console.error(
|
|
15157
|
+
`[codebase-index] Failed to determine the macOS power source; background indexing will continue: ${getErrorMessage4(error)}`
|
|
15158
|
+
);
|
|
15159
|
+
this.reportedFailure = true;
|
|
15160
|
+
}
|
|
15161
|
+
this.lastPaused = false;
|
|
15162
|
+
return false;
|
|
15163
|
+
}
|
|
15164
|
+
}
|
|
15165
|
+
};
|
|
15166
|
+
function createBackgroundIndexingPolicy(pauseOnBattery, options = {}) {
|
|
15167
|
+
const platform2 = options.platform ?? process.platform;
|
|
15168
|
+
if (!pauseOnBattery || platform2 !== "darwin") {
|
|
15169
|
+
return null;
|
|
15170
|
+
}
|
|
15171
|
+
return new MacOsBackgroundIndexingPolicy(
|
|
15172
|
+
options.readPowerSource ?? readMacOsPowerSource,
|
|
15173
|
+
options.recheckDelayMs ?? POWER_SOURCE_RECHECK_DELAY_MS
|
|
15174
|
+
);
|
|
15175
|
+
}
|
|
15176
|
+
|
|
15177
|
+
// src/utils/auto-index.ts
|
|
15178
|
+
var MAX_RETRY_DELAY_MS = 1e4;
|
|
15179
|
+
var SHUTDOWN_WAIT_MS = 2e3;
|
|
15180
|
+
var coordinators = /* @__PURE__ */ new Map();
|
|
15181
|
+
var coordinatorKeysByProject = /* @__PURE__ */ new Map();
|
|
15182
|
+
var coordinatorReplacementBarriers = /* @__PURE__ */ new Map();
|
|
15183
|
+
var AutoIndexCancelledError = class extends Error {
|
|
15184
|
+
constructor() {
|
|
15185
|
+
super("Auto-index coordination was cancelled");
|
|
15186
|
+
this.name = "AutoIndexCancelledError";
|
|
15187
|
+
}
|
|
15188
|
+
};
|
|
15189
|
+
function now() {
|
|
15190
|
+
return (/* @__PURE__ */ new Date()).toISOString();
|
|
15191
|
+
}
|
|
15192
|
+
function canonicalizePath2(targetPath) {
|
|
15193
|
+
const resolved = path18.resolve(targetPath);
|
|
15194
|
+
if (existsSync10(resolved)) {
|
|
15195
|
+
try {
|
|
15196
|
+
return realpathSync5.native(resolved);
|
|
15197
|
+
} catch {
|
|
15198
|
+
return resolved;
|
|
15199
|
+
}
|
|
15200
|
+
}
|
|
15201
|
+
const parent = path18.dirname(resolved);
|
|
15202
|
+
if (parent === resolved) return resolved;
|
|
15203
|
+
return path18.join(canonicalizePath2(parent), path18.basename(resolved));
|
|
15204
|
+
}
|
|
15205
|
+
function isHomeDirectory(projectRoot) {
|
|
15206
|
+
return canonicalizePath2(projectRoot) === canonicalizePath2(os7.homedir());
|
|
15207
|
+
}
|
|
15208
|
+
function projectLookupKey2(projectRoot, host) {
|
|
15209
|
+
return `${host}::${canonicalizePath2(projectRoot)}`;
|
|
15210
|
+
}
|
|
15211
|
+
function coordinatorKey(projectRoot, config, host) {
|
|
15212
|
+
const canonicalProjectRoot = canonicalizePath2(projectRoot);
|
|
15213
|
+
const indexPath = resolveProjectIndexPath(projectRoot, config.scope, host);
|
|
15214
|
+
return `${canonicalizePath2(indexPath)}::${canonicalProjectRoot}`;
|
|
15215
|
+
}
|
|
15216
|
+
function getProjectSafety(projectRoot, config) {
|
|
15217
|
+
if (isHomeDirectory(projectRoot)) {
|
|
15218
|
+
return { safeToRun: false, blockedReason: "home-directory" };
|
|
15219
|
+
}
|
|
15220
|
+
if (config.indexing.requireProjectMarker && !hasProjectMarker(projectRoot)) {
|
|
15221
|
+
return { safeToRun: false, blockedReason: "project-marker-missing" };
|
|
15222
|
+
}
|
|
15223
|
+
return { safeToRun: true };
|
|
15224
|
+
}
|
|
15225
|
+
function calculatePercentage2(progress) {
|
|
15226
|
+
if (progress.phase === "scanning") return 0;
|
|
15227
|
+
if (progress.phase === "complete") return 100;
|
|
15228
|
+
if (progress.phase === "parsing") {
|
|
15229
|
+
return progress.totalFiles === 0 ? 5 : Math.round(5 + progress.filesProcessed / progress.totalFiles * 15);
|
|
15230
|
+
}
|
|
15231
|
+
if (progress.phase === "embedding") {
|
|
15232
|
+
return progress.totalChunks === 0 ? 20 : Math.round(20 + progress.chunksProcessed / progress.totalChunks * 70);
|
|
15233
|
+
}
|
|
15234
|
+
if (progress.phase === "storing") return 95;
|
|
15235
|
+
return 0;
|
|
15236
|
+
}
|
|
15237
|
+
function safeFailureMessage(error) {
|
|
15238
|
+
if (isTransientIndexLockContention(error)) {
|
|
15239
|
+
return "Another index process remained busy after the configured retries.";
|
|
15240
|
+
}
|
|
15241
|
+
return "Automatic indexing failed. Check the embedding provider configuration, then run index_codebase.";
|
|
15242
|
+
}
|
|
15243
|
+
function cancellableDelay(delayMs, signal) {
|
|
15244
|
+
if (signal.aborted) return Promise.reject(new AutoIndexCancelledError());
|
|
15245
|
+
return new Promise((resolve21, reject) => {
|
|
15246
|
+
const timer = setTimeout(() => {
|
|
15247
|
+
signal.removeEventListener("abort", onAbort);
|
|
15248
|
+
resolve21();
|
|
14237
15249
|
}, delayMs);
|
|
14238
15250
|
timer.unref?.();
|
|
14239
15251
|
const onAbort = () => {
|
|
@@ -14245,18 +15257,44 @@ function cancellableDelay(delayMs, signal) {
|
|
|
14245
15257
|
}
|
|
14246
15258
|
function withTimeout(promise, timeoutMs) {
|
|
14247
15259
|
if (timeoutMs <= 0) return Promise.resolve(void 0);
|
|
14248
|
-
return new Promise((
|
|
14249
|
-
const timer = setTimeout(() =>
|
|
15260
|
+
return new Promise((resolve21) => {
|
|
15261
|
+
const timer = setTimeout(() => resolve21(void 0), timeoutMs);
|
|
14250
15262
|
timer.unref?.();
|
|
14251
15263
|
void promise.then((value) => {
|
|
14252
15264
|
clearTimeout(timer);
|
|
14253
|
-
|
|
15265
|
+
resolve21(value);
|
|
14254
15266
|
}, () => {
|
|
14255
15267
|
clearTimeout(timer);
|
|
14256
|
-
|
|
15268
|
+
resolve21(void 0);
|
|
14257
15269
|
});
|
|
14258
15270
|
});
|
|
14259
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
|
+
}
|
|
14260
15298
|
function requestPriority(request) {
|
|
14261
15299
|
if (request.force) return 4;
|
|
14262
15300
|
if (request.source === "manual") return 3;
|
|
@@ -14267,6 +15305,7 @@ function mergeRequests(current, next) {
|
|
|
14267
15305
|
if (!current) return next;
|
|
14268
15306
|
const preferred = requestPriority(next) > requestPriority(current) ? next : current;
|
|
14269
15307
|
return {
|
|
15308
|
+
allowDisabledAutoIndex: current.allowDisabledAutoIndex || next.allowDisabledAutoIndex,
|
|
14270
15309
|
checkFreshness: current.checkFreshness && next.checkFreshness,
|
|
14271
15310
|
force: current.force || next.force,
|
|
14272
15311
|
onProgress: next.onProgress ?? current.onProgress,
|
|
@@ -14328,11 +15367,11 @@ var AutoIndexCoordinator = class {
|
|
|
14328
15367
|
progress: this.status.progress ? { ...this.status.progress } : void 0
|
|
14329
15368
|
};
|
|
14330
15369
|
}
|
|
14331
|
-
start(source) {
|
|
15370
|
+
start(source, allowDisabledAutoIndex = false) {
|
|
14332
15371
|
this.refreshSafety();
|
|
14333
|
-
if (!this.registration.config.indexing.autoIndex || !this.registration.safeToRun) return null;
|
|
15372
|
+
if (!this.registration.config.indexing.autoIndex && !allowDisabledAutoIndex || !this.registration.safeToRun) return null;
|
|
14334
15373
|
if (this.status.state === "failed") return this.inFlight;
|
|
14335
|
-
return this.request({ checkFreshness: true, force: false, source });
|
|
15374
|
+
return this.request({ allowDisabledAutoIndex, checkFreshness: true, force: false, source });
|
|
14336
15375
|
}
|
|
14337
15376
|
request(request) {
|
|
14338
15377
|
if (this.stopped) {
|
|
@@ -14407,13 +15446,15 @@ var AutoIndexCoordinator = class {
|
|
|
14407
15446
|
retryAttempt: void 0
|
|
14408
15447
|
});
|
|
14409
15448
|
const inFlight = this.inFlight;
|
|
14410
|
-
|
|
14411
|
-
|
|
14412
|
-
|
|
14413
|
-
} else {
|
|
14414
|
-
await withTimeout(inFlight, SHUTDOWN_WAIT_MS);
|
|
14415
|
-
}
|
|
15449
|
+
const completion = inFlight ? inFlight.then(() => void 0, () => void 0) : Promise.resolve();
|
|
15450
|
+
if (!inFlight) {
|
|
15451
|
+
return { completed: true, completion };
|
|
14416
15452
|
}
|
|
15453
|
+
if (waitForCompletion) {
|
|
15454
|
+
await completion;
|
|
15455
|
+
return { completed: true, completion };
|
|
15456
|
+
}
|
|
15457
|
+
return { completed: await settlesWithin(completion, SHUTDOWN_WAIT_MS), completion };
|
|
14417
15458
|
}
|
|
14418
15459
|
startRequest(request) {
|
|
14419
15460
|
if (this.stopped || !this.canRun(request)) {
|
|
@@ -14602,7 +15643,7 @@ var AutoIndexCoordinator = class {
|
|
|
14602
15643
|
if (request.source === "manual" || request.source === "watcher") {
|
|
14603
15644
|
return true;
|
|
14604
15645
|
}
|
|
14605
|
-
return this.registration.safeToRun && this.registration.config.indexing.autoIndex;
|
|
15646
|
+
return this.registration.safeToRun && (this.registration.config.indexing.autoIndex || request.allowDisabledAutoIndex === true);
|
|
14606
15647
|
}
|
|
14607
15648
|
shouldDeferForBattery(request) {
|
|
14608
15649
|
return this.registration.backgroundIndexingPolicy !== null && (request.source === "startup" || request.source === "watcher");
|
|
@@ -14635,17 +15676,17 @@ var AutoIndexCoordinator = class {
|
|
|
14635
15676
|
}
|
|
14636
15677
|
}
|
|
14637
15678
|
waitForBatteryRetry(delayMs) {
|
|
14638
|
-
return new Promise((
|
|
15679
|
+
return new Promise((resolve21) => {
|
|
14639
15680
|
const timer = setTimeout(() => {
|
|
14640
15681
|
if (this.batteryRetryTimer === timer) {
|
|
14641
15682
|
this.batteryRetryTimer = null;
|
|
14642
15683
|
this.resolveBatteryRetry = null;
|
|
14643
15684
|
}
|
|
14644
|
-
|
|
15685
|
+
resolve21();
|
|
14645
15686
|
}, delayMs);
|
|
14646
15687
|
timer.unref?.();
|
|
14647
15688
|
this.batteryRetryTimer = timer;
|
|
14648
|
-
this.resolveBatteryRetry =
|
|
15689
|
+
this.resolveBatteryRetry = resolve21;
|
|
14649
15690
|
});
|
|
14650
15691
|
}
|
|
14651
15692
|
cancelBatteryRetry() {
|
|
@@ -14653,9 +15694,9 @@ var AutoIndexCoordinator = class {
|
|
|
14653
15694
|
clearTimeout(this.batteryRetryTimer);
|
|
14654
15695
|
this.batteryRetryTimer = null;
|
|
14655
15696
|
}
|
|
14656
|
-
const
|
|
15697
|
+
const resolve21 = this.resolveBatteryRetry;
|
|
14657
15698
|
this.resolveBatteryRetry = null;
|
|
14658
|
-
|
|
15699
|
+
resolve21?.();
|
|
14659
15700
|
}
|
|
14660
15701
|
finishBatteryCheck(batteryCheck) {
|
|
14661
15702
|
if (this.batteryCheck !== batteryCheck) return;
|
|
@@ -14668,12 +15709,25 @@ var AutoIndexCoordinator = class {
|
|
|
14668
15709
|
}
|
|
14669
15710
|
};
|
|
14670
15711
|
function getCoordinator(projectRoot, host) {
|
|
14671
|
-
const key = coordinatorKeysByProject.get(
|
|
15712
|
+
const key = coordinatorKeysByProject.get(projectLookupKey2(projectRoot, host));
|
|
14672
15713
|
return key ? coordinators.get(key) ?? null : null;
|
|
14673
15714
|
}
|
|
14674
|
-
function
|
|
14675
|
-
|
|
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);
|
|
14676
15726
|
const safety = getProjectSafety(projectRoot, config);
|
|
15727
|
+
const synchronizeWorker = options.synchronizeBackgroundWorker ?? true;
|
|
15728
|
+
if (options.preserveManagedWorker === true && isBackgroundWorkerManaged(projectRoot, host)) {
|
|
15729
|
+
return;
|
|
15730
|
+
}
|
|
14677
15731
|
const registration = {
|
|
14678
15732
|
backgroundIndexingPolicy: createBackgroundIndexingPolicy(
|
|
14679
15733
|
config.indexing.pauseBackgroundIndexingOnBattery
|
|
@@ -14691,6 +15745,9 @@ function configureAutoIndex(projectRoot, host, config, getIndexer) {
|
|
|
14691
15745
|
const stopPrevious = previousCoordinator?.stop(true) ?? Promise.resolve();
|
|
14692
15746
|
const activation = Promise.all([previousBarrier, stopPrevious]).then(() => void 0);
|
|
14693
15747
|
coordinatorReplacementBarriers.set(projectKey, activation);
|
|
15748
|
+
if (synchronizeWorker) {
|
|
15749
|
+
synchronizeBackgroundWorker(projectRoot, host, config, safety.safeToRun);
|
|
15750
|
+
}
|
|
14694
15751
|
coordinators.delete(previousKey);
|
|
14695
15752
|
const coordinator2 = new AutoIndexCoordinator(registration);
|
|
14696
15753
|
coordinator2.activateAfter(activation);
|
|
@@ -14706,11 +15763,17 @@ function configureAutoIndex(projectRoot, host, config, getIndexer) {
|
|
|
14706
15763
|
coordinator.update(registration);
|
|
14707
15764
|
}
|
|
14708
15765
|
coordinatorKeysByProject.set(projectKey, key);
|
|
15766
|
+
if (synchronizeWorker) {
|
|
15767
|
+
synchronizeBackgroundWorker(projectRoot, host, config, safety.safeToRun);
|
|
15768
|
+
}
|
|
14709
15769
|
}
|
|
14710
|
-
function
|
|
14711
|
-
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;
|
|
14712
15772
|
}
|
|
14713
15773
|
function requestBackgroundIndex(projectRoot, host) {
|
|
15774
|
+
if (isBackgroundWorkerManaged(projectRoot, host) && !isBackgroundWorkerLeader(projectRoot, host)) {
|
|
15775
|
+
return null;
|
|
15776
|
+
}
|
|
14714
15777
|
return getCoordinator(projectRoot, host)?.request({
|
|
14715
15778
|
checkFreshness: false,
|
|
14716
15779
|
force: false,
|
|
@@ -14750,15 +15813,23 @@ async function waitForAutoIndexForRetrieval(projectRoot, host) {
|
|
|
14750
15813
|
};
|
|
14751
15814
|
}
|
|
14752
15815
|
try {
|
|
14753
|
-
|
|
15816
|
+
const readiness = await getSearchReadiness(coordinator);
|
|
15817
|
+
if (readiness.searchable) {
|
|
15818
|
+
return { ready: true };
|
|
15819
|
+
}
|
|
15820
|
+
if (readiness.blocked) return unavailableSnapshotResult(readiness.reason);
|
|
14754
15821
|
} catch {
|
|
14755
15822
|
}
|
|
14756
|
-
const job =
|
|
15823
|
+
const job = startRetrievalRefresh(projectRoot, host, coordinator);
|
|
14757
15824
|
if (job) {
|
|
14758
15825
|
await withTimeout(job, coordinator.getWaitMs());
|
|
15826
|
+
} else if (isBackgroundWorkerManaged(projectRoot, host)) {
|
|
15827
|
+
await waitForPublishedSnapshot(coordinator, coordinator.getWaitMs());
|
|
14759
15828
|
}
|
|
14760
15829
|
try {
|
|
14761
|
-
|
|
15830
|
+
const readiness = await getSearchReadiness(coordinator);
|
|
15831
|
+
if (readiness.searchable) return { ready: true };
|
|
15832
|
+
if (readiness.blocked) return unavailableSnapshotResult(readiness.reason);
|
|
14762
15833
|
} catch {
|
|
14763
15834
|
}
|
|
14764
15835
|
const status = coordinator.snapshot();
|
|
@@ -14779,31 +15850,62 @@ async function waitForAutoIndexForRetrieval(projectRoot, host) {
|
|
|
14779
15850
|
text: `Automatic indexing is ${status.state}. Retry shortly or call index_status for progress. You can also run index_codebase explicitly.`
|
|
14780
15851
|
};
|
|
14781
15852
|
}
|
|
14782
|
-
async function
|
|
14783
|
-
|
|
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);
|
|
14784
15859
|
}
|
|
14785
|
-
async function
|
|
15860
|
+
async function getSearchReadiness(coordinator) {
|
|
14786
15861
|
const indexer = coordinator.getIndexer();
|
|
14787
15862
|
if (indexer.getIndexFreshness) {
|
|
14788
15863
|
const freshness = await indexer.getIndexFreshness();
|
|
14789
|
-
|
|
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())));
|
|
14790
15893
|
}
|
|
14791
|
-
return (await indexer.getStatus()).indexed;
|
|
14792
15894
|
}
|
|
14793
15895
|
|
|
14794
15896
|
// src/tools/config-state.ts
|
|
14795
|
-
import { existsSync as
|
|
14796
|
-
import * as
|
|
15897
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync6, writeFileSync as writeFileSync5 } from "fs";
|
|
15898
|
+
import * as path21 from "path";
|
|
14797
15899
|
|
|
14798
15900
|
// src/config/merger.ts
|
|
14799
|
-
import { existsSync as
|
|
14800
|
-
import * as
|
|
15901
|
+
import { existsSync as existsSync11, readFileSync as readFileSync10 } from "fs";
|
|
15902
|
+
import * as path20 from "path";
|
|
14801
15903
|
|
|
14802
15904
|
// src/config/rebase.ts
|
|
14803
|
-
import * as
|
|
15905
|
+
import * as path19 from "path";
|
|
14804
15906
|
function isWithinRoot(rootDir, targetPath) {
|
|
14805
|
-
const relativePath =
|
|
14806
|
-
return relativePath === "" || !relativePath.startsWith("..") && !
|
|
15907
|
+
const relativePath = path19.relative(rootDir, targetPath);
|
|
15908
|
+
return relativePath === "" || !relativePath.startsWith("..") && !path19.isAbsolute(relativePath);
|
|
14807
15909
|
}
|
|
14808
15910
|
function rebasePathEntries(values, fromDir, toDir) {
|
|
14809
15911
|
if (!Array.isArray(values)) {
|
|
@@ -14811,10 +15913,10 @@ function rebasePathEntries(values, fromDir, toDir) {
|
|
|
14811
15913
|
}
|
|
14812
15914
|
return values.filter((value) => typeof value === "string").map((value) => {
|
|
14813
15915
|
const trimmed = value.trim();
|
|
14814
|
-
if (!trimmed ||
|
|
15916
|
+
if (!trimmed || path19.isAbsolute(trimmed)) {
|
|
14815
15917
|
return trimmed;
|
|
14816
15918
|
}
|
|
14817
|
-
return normalizePathSeparators(
|
|
15919
|
+
return normalizePathSeparators(path19.normalize(path19.relative(toDir, path19.resolve(fromDir, trimmed))));
|
|
14818
15920
|
}).filter(Boolean);
|
|
14819
15921
|
}
|
|
14820
15922
|
function resolveInheritedKnowledgeBaseEntries(values, sourceRoot, targetRoot) {
|
|
@@ -14826,17 +15928,17 @@ function resolveInheritedKnowledgeBaseEntries(values, sourceRoot, targetRoot) {
|
|
|
14826
15928
|
if (!trimmed) {
|
|
14827
15929
|
return trimmed;
|
|
14828
15930
|
}
|
|
14829
|
-
if (
|
|
15931
|
+
if (path19.isAbsolute(trimmed)) {
|
|
14830
15932
|
if (isWithinRoot(sourceRoot, trimmed)) {
|
|
14831
|
-
return normalizePathSeparators(
|
|
15933
|
+
return normalizePathSeparators(path19.normalize(path19.relative(sourceRoot, trimmed) || "."));
|
|
14832
15934
|
}
|
|
14833
|
-
return
|
|
15935
|
+
return path19.normalize(trimmed);
|
|
14834
15936
|
}
|
|
14835
|
-
const resolvedFromSource =
|
|
15937
|
+
const resolvedFromSource = path19.resolve(sourceRoot, trimmed);
|
|
14836
15938
|
if (isWithinRoot(sourceRoot, resolvedFromSource)) {
|
|
14837
|
-
return normalizePathSeparators(
|
|
15939
|
+
return normalizePathSeparators(path19.normalize(trimmed));
|
|
14838
15940
|
}
|
|
14839
|
-
return normalizePathSeparators(
|
|
15941
|
+
return normalizePathSeparators(path19.normalize(path19.relative(targetRoot, resolvedFromSource)));
|
|
14840
15942
|
}).filter(Boolean);
|
|
14841
15943
|
}
|
|
14842
15944
|
|
|
@@ -14874,8 +15976,8 @@ function mergeUniqueStringArray(values) {
|
|
|
14874
15976
|
return [...new Set(values.map((value) => String(value).trim()))];
|
|
14875
15977
|
}
|
|
14876
15978
|
function normalizeKnowledgeBasePath2(value) {
|
|
14877
|
-
let normalized =
|
|
14878
|
-
const root =
|
|
15979
|
+
let normalized = path20.normalize(String(value).trim());
|
|
15980
|
+
const root = path20.parse(normalized).root;
|
|
14879
15981
|
while (normalized.length > root.length && /[\\/]$/.test(normalized)) {
|
|
14880
15982
|
normalized = normalized.slice(0, -1);
|
|
14881
15983
|
}
|
|
@@ -14909,11 +16011,11 @@ function validateConfigLayerShape(rawConfig, filePath) {
|
|
|
14909
16011
|
return rawConfig;
|
|
14910
16012
|
}
|
|
14911
16013
|
function loadJsonFile(filePath) {
|
|
14912
|
-
if (!
|
|
16014
|
+
if (!existsSync11(filePath)) {
|
|
14913
16015
|
return null;
|
|
14914
16016
|
}
|
|
14915
16017
|
try {
|
|
14916
|
-
const content =
|
|
16018
|
+
const content = readFileSync10(filePath, "utf-8");
|
|
14917
16019
|
return validateConfigLayerShape(JSON.parse(content), filePath);
|
|
14918
16020
|
} catch (error) {
|
|
14919
16021
|
if (error instanceof Error && error.message.startsWith("Config file ")) {
|
|
@@ -14933,7 +16035,7 @@ function loadProjectConfigLayer(projectRoot, host) {
|
|
|
14933
16035
|
return {};
|
|
14934
16036
|
}
|
|
14935
16037
|
const normalizedConfig = { ...projectConfig };
|
|
14936
|
-
const projectConfigBaseDir =
|
|
16038
|
+
const projectConfigBaseDir = path20.dirname(path20.dirname(projectConfigPath));
|
|
14937
16039
|
if (Array.isArray(normalizedConfig.knowledgeBases)) {
|
|
14938
16040
|
normalizedConfig.knowledgeBases = resolveInheritedKnowledgeBaseEntries(
|
|
14939
16041
|
normalizedConfig.knowledgeBases,
|
|
@@ -15023,10 +16125,10 @@ function loadEditableConfig(projectRoot, host) {
|
|
|
15023
16125
|
}
|
|
15024
16126
|
function saveConfig(projectRoot, config, host) {
|
|
15025
16127
|
const configPath = getConfigPath(projectRoot, host);
|
|
15026
|
-
const configDir =
|
|
15027
|
-
const configBaseDir =
|
|
15028
|
-
if (!
|
|
15029
|
-
|
|
16128
|
+
const configDir = path21.dirname(configPath);
|
|
16129
|
+
const configBaseDir = path21.dirname(configDir);
|
|
16130
|
+
if (!existsSync12(configDir)) {
|
|
16131
|
+
mkdirSync6(configDir, { recursive: true });
|
|
15030
16132
|
}
|
|
15031
16133
|
const serializableConfig = { ...config };
|
|
15032
16134
|
if (Array.isArray(serializableConfig.knowledgeBases)) {
|
|
@@ -15034,7 +16136,7 @@ function saveConfig(projectRoot, config, host) {
|
|
|
15034
16136
|
(kb) => serializeConfigPathValue(kb, configBaseDir)
|
|
15035
16137
|
);
|
|
15036
16138
|
}
|
|
15037
|
-
|
|
16139
|
+
writeFileSync5(configPath, JSON.stringify(serializableConfig, null, 2) + "\n", "utf-8");
|
|
15038
16140
|
}
|
|
15039
16141
|
|
|
15040
16142
|
// src/tools/operation-runtime.ts
|
|
@@ -15113,15 +16215,24 @@ function getOrCreateIndexer(projectRoot, host) {
|
|
|
15113
16215
|
}
|
|
15114
16216
|
const indexer = new Indexer(projectRoot, config, host);
|
|
15115
16217
|
indexerCache.set(key, indexer);
|
|
15116
|
-
configureAutoIndex(projectRoot, host, config, () => getOrCreateIndexer(projectRoot, host)
|
|
16218
|
+
configureAutoIndex(projectRoot, host, config, () => getOrCreateIndexer(projectRoot, host), {
|
|
16219
|
+
preserveManagedWorker: true,
|
|
16220
|
+
synchronizeBackgroundWorker: false
|
|
16221
|
+
});
|
|
15117
16222
|
return indexer;
|
|
15118
16223
|
}
|
|
15119
|
-
function initializeTools(projectRoot, config, host) {
|
|
16224
|
+
function initializeTools(projectRoot, config, host, options = {}) {
|
|
15120
16225
|
defaultProjectRoots.set(host, projectRoot);
|
|
15121
16226
|
const key = getIndexerCacheKey(projectRoot, host);
|
|
16227
|
+
if (options.preserveManagedWorker === true && isBackgroundWorkerManaged(projectRoot, host) && indexerCache.has(key)) {
|
|
16228
|
+
return;
|
|
16229
|
+
}
|
|
15122
16230
|
configCache.set(key, config);
|
|
15123
16231
|
indexerCache.set(key, new Indexer(projectRoot, config, host));
|
|
15124
|
-
configureAutoIndex(projectRoot, host, config, () => getOrCreateIndexer(projectRoot, host)
|
|
16232
|
+
configureAutoIndex(projectRoot, host, config, () => getOrCreateIndexer(projectRoot, host), {
|
|
16233
|
+
preserveManagedWorker: options.preserveManagedWorker,
|
|
16234
|
+
synchronizeBackgroundWorker: false
|
|
16235
|
+
});
|
|
15125
16236
|
}
|
|
15126
16237
|
function getIndexerForProject(projectRoot, host) {
|
|
15127
16238
|
const root = getProjectRoot(projectRoot, host);
|
|
@@ -15135,7 +16246,9 @@ function refreshIndexerForDirectory(projectRoot, host, config = parseConfig(load
|
|
|
15135
16246
|
const key = getIndexerCacheKey(projectRoot, host);
|
|
15136
16247
|
configCache.set(key, config);
|
|
15137
16248
|
indexerCache.set(key, new Indexer(projectRoot, config, host));
|
|
15138
|
-
configureAutoIndex(projectRoot, host, config, () => getOrCreateIndexer(projectRoot, host)
|
|
16249
|
+
configureAutoIndex(projectRoot, host, config, () => getOrCreateIndexer(projectRoot, host), {
|
|
16250
|
+
synchronizeBackgroundWorker: true
|
|
16251
|
+
});
|
|
15139
16252
|
return config;
|
|
15140
16253
|
}
|
|
15141
16254
|
var AutoIndexRetrievalUnavailableError = class extends Error {
|
|
@@ -15162,7 +16275,7 @@ function trimOrUndefined(value) {
|
|
|
15162
16275
|
return normalized || void 0;
|
|
15163
16276
|
}
|
|
15164
16277
|
function normalizeCallGraphPath(value) {
|
|
15165
|
-
let normalized =
|
|
16278
|
+
let normalized = path22.posix.normalize(value.trim().replaceAll("\\", "/"));
|
|
15166
16279
|
if (normalized.startsWith("./")) {
|
|
15167
16280
|
normalized = normalized.slice(2);
|
|
15168
16281
|
}
|
|
@@ -15355,12 +16468,12 @@ async function getCallGraphPath(projectRoot, host, from, to, maxDepth, fromFileP
|
|
|
15355
16468
|
if (fromResolution.status !== "resolved" || toResolution.status !== "resolved") {
|
|
15356
16469
|
return { from: fromResolution, to: toResolution, path: [] };
|
|
15357
16470
|
}
|
|
15358
|
-
const
|
|
16471
|
+
const path34 = await indexer.findCallPathBySymbolIds(
|
|
15359
16472
|
fromResolution.symbolId,
|
|
15360
16473
|
toResolution.symbolId,
|
|
15361
16474
|
maxDepth
|
|
15362
16475
|
);
|
|
15363
|
-
return { from: fromResolution, to: toResolution, path:
|
|
16476
|
+
return { from: fromResolution, to: toResolution, path: path34 };
|
|
15364
16477
|
}
|
|
15365
16478
|
async function runIndexCodebase(projectRoot, host, args, onProgress) {
|
|
15366
16479
|
const root = getProjectRoot(projectRoot, host);
|
|
@@ -15369,6 +16482,9 @@ async function runIndexCodebase(projectRoot, host, args, onProgress) {
|
|
|
15369
16482
|
if (args.estimateOnly) {
|
|
15370
16483
|
return { kind: "estimate", estimate: await indexer.estimateCost() };
|
|
15371
16484
|
}
|
|
16485
|
+
if (args.dryRun) {
|
|
16486
|
+
return { kind: "dryrun", dryrun: await indexer.dryRunCost() };
|
|
16487
|
+
}
|
|
15372
16488
|
const coordinated = runCoordinatedIndex(root, host, args.force ?? false, (progress) => {
|
|
15373
16489
|
if (onProgress) {
|
|
15374
16490
|
void onProgress(formatProgressTitle(progress), {
|
|
@@ -15555,15 +16671,15 @@ async function getIndexLogs(projectRoot, host, args) {
|
|
|
15555
16671
|
function addKnowledgeBase(projectRoot, host, knowledgeBasePath) {
|
|
15556
16672
|
const root = getProjectRoot(projectRoot, host);
|
|
15557
16673
|
const inputPath = knowledgeBasePath.trim();
|
|
15558
|
-
const normalizedPath3 =
|
|
15559
|
-
|
|
16674
|
+
const normalizedPath3 = path22.resolve(
|
|
16675
|
+
path22.isAbsolute(inputPath) ? inputPath : resolveKnowledgeBasePath(inputPath, root)
|
|
15560
16676
|
);
|
|
15561
|
-
if (!
|
|
16677
|
+
if (!existsSync13(normalizedPath3)) {
|
|
15562
16678
|
return `Error: Directory does not exist: ${normalizedPath3}`;
|
|
15563
16679
|
}
|
|
15564
16680
|
let realPath;
|
|
15565
16681
|
try {
|
|
15566
|
-
realPath =
|
|
16682
|
+
realPath = realpathSync6(normalizedPath3);
|
|
15567
16683
|
} catch {
|
|
15568
16684
|
return `Error: Cannot resolve path: ${normalizedPath3}`;
|
|
15569
16685
|
}
|
|
@@ -15592,7 +16708,7 @@ function addKnowledgeBase(projectRoot, host, knowledgeBasePath) {
|
|
|
15592
16708
|
}
|
|
15593
16709
|
}
|
|
15594
16710
|
for (const dotDir of sensitiveDotDirs) {
|
|
15595
|
-
const sensitiveDir =
|
|
16711
|
+
const sensitiveDir = path22.join(homeDir, dotDir);
|
|
15596
16712
|
if (sensitiveDir && (realPath === sensitiveDir || realPath.startsWith(`${sensitiveDir}/`))) {
|
|
15597
16713
|
return `Error: Adding sensitive directory as knowledge base is not allowed: ${normalizedPath3}`;
|
|
15598
16714
|
}
|
|
@@ -15638,7 +16754,7 @@ function listKnowledgeBases(projectRoot, host) {
|
|
|
15638
16754
|
for (let i = 0; i < knowledgeBases.length; i++) {
|
|
15639
16755
|
const kb = knowledgeBases[i];
|
|
15640
16756
|
const resolvedPath = resolveKnowledgeBasePath(kb, root);
|
|
15641
|
-
const exists =
|
|
16757
|
+
const exists = existsSync13(resolvedPath);
|
|
15642
16758
|
result += `[${i + 1}] ${kb}
|
|
15643
16759
|
`;
|
|
15644
16760
|
result += ` Resolved: ${resolvedPath}
|
|
@@ -15655,7 +16771,7 @@ function listKnowledgeBases(projectRoot, host) {
|
|
|
15655
16771
|
}
|
|
15656
16772
|
result += "\n";
|
|
15657
16773
|
}
|
|
15658
|
-
const hasHostConfig =
|
|
16774
|
+
const hasHostConfig = existsSync13(path22.join(root, getHostProjectConfigRelativePath(host)));
|
|
15659
16775
|
if (hasHostConfig) {
|
|
15660
16776
|
result += `
|
|
15661
16777
|
Config sources: 1 file(s).`;
|
|
@@ -16128,7 +17244,7 @@ async function resolveCodebaseContextUnmeasured(projectRoot, host, input) {
|
|
|
16128
17244
|
const directory = input.directory ?? void 0;
|
|
16129
17245
|
const tokenBudget = input.tokenBudget ?? void 0;
|
|
16130
17246
|
if (from && to) {
|
|
16131
|
-
const
|
|
17247
|
+
const path34 = await getCallGraphPath(
|
|
16132
17248
|
projectRoot,
|
|
16133
17249
|
host,
|
|
16134
17250
|
from,
|
|
@@ -16137,25 +17253,25 @@ async function resolveCodebaseContextUnmeasured(projectRoot, host, input) {
|
|
|
16137
17253
|
fromFilePath,
|
|
16138
17254
|
toFilePath
|
|
16139
17255
|
);
|
|
16140
|
-
const pathText = formatCallGraphPathResult(
|
|
16141
|
-
if (
|
|
17256
|
+
const pathText = formatCallGraphPathResult(path34);
|
|
17257
|
+
if (path34.path.length > 0) {
|
|
16142
17258
|
const fitted2 = fitTextToContextBudget(
|
|
16143
17259
|
pathText,
|
|
16144
17260
|
tokenBudget
|
|
16145
17261
|
);
|
|
16146
17262
|
return {
|
|
16147
17263
|
text: fitted2.text,
|
|
16148
|
-
details: fittedDetails("path", fitted2,
|
|
17264
|
+
details: fittedDetails("path", fitted2, path34.path.length)
|
|
16149
17265
|
};
|
|
16150
17266
|
}
|
|
16151
|
-
if (
|
|
17267
|
+
if (path34.from.status !== "resolved" || path34.to.status !== "resolved") {
|
|
16152
17268
|
const fitted2 = fitTextToContextBudget(pathText, tokenBudget);
|
|
16153
17269
|
return {
|
|
16154
17270
|
text: fitted2.text,
|
|
16155
17271
|
details: fittedDetails("path", fitted2, 0)
|
|
16156
17272
|
};
|
|
16157
17273
|
}
|
|
16158
|
-
const resolvedFrom =
|
|
17274
|
+
const resolvedFrom = path34.from;
|
|
16159
17275
|
const { callers } = await getCallGraphData(projectRoot, host, {
|
|
16160
17276
|
name: to,
|
|
16161
17277
|
direction: "callers",
|
|
@@ -16633,9 +17749,9 @@ function getRelevantEvidence(query) {
|
|
|
16633
17749
|
});
|
|
16634
17750
|
}
|
|
16635
17751
|
if (query.expected.acceptableFiles) {
|
|
16636
|
-
for (const
|
|
17752
|
+
for (const path34 of query.expected.acceptableFiles) {
|
|
16637
17753
|
legacyEvidence.push({
|
|
16638
|
-
path:
|
|
17754
|
+
path: path34,
|
|
16639
17755
|
...query.expected.symbol !== void 0 ? { symbol: query.expected.symbol } : {},
|
|
16640
17756
|
relevance: 1
|
|
16641
17757
|
});
|
|
@@ -16957,9 +18073,9 @@ function computeEvalMetrics(queries, perQuery, embeddingCallCount, embeddingToke
|
|
|
16957
18073
|
}
|
|
16958
18074
|
|
|
16959
18075
|
// src/eval/runner-config.ts
|
|
16960
|
-
import { existsSync as
|
|
16961
|
-
import * as
|
|
16962
|
-
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";
|
|
16963
18079
|
function isRecord2(value) {
|
|
16964
18080
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
16965
18081
|
}
|
|
@@ -16993,7 +18109,7 @@ function validateEvalConfigShape(rawConfig, filePath) {
|
|
|
16993
18109
|
}
|
|
16994
18110
|
function parseJsonConfigFile(filePath) {
|
|
16995
18111
|
try {
|
|
16996
|
-
return validateEvalConfigShape(JSON.parse(
|
|
18112
|
+
return validateEvalConfigShape(JSON.parse(readFileSync11(filePath, "utf-8")), filePath);
|
|
16997
18113
|
} catch (error) {
|
|
16998
18114
|
if (error instanceof Error && error.message.startsWith("Eval config at ")) {
|
|
16999
18115
|
throw error;
|
|
@@ -17003,20 +18119,20 @@ function parseJsonConfigFile(filePath) {
|
|
|
17003
18119
|
}
|
|
17004
18120
|
}
|
|
17005
18121
|
function toAbsolute(projectRoot, maybeRelative) {
|
|
17006
|
-
return
|
|
18122
|
+
return path23.isAbsolute(maybeRelative) ? maybeRelative : path23.join(projectRoot, maybeRelative);
|
|
17007
18123
|
}
|
|
17008
18124
|
function isProjectScopedConfigPath(configPath) {
|
|
17009
|
-
return
|
|
18125
|
+
return path23.basename(configPath) === "codebase-index.json" && path23.basename(path23.dirname(configPath)) === ".opencode";
|
|
17010
18126
|
}
|
|
17011
18127
|
function normalizeEvalConfigKnowledgeBases(rawConfig, projectRoot, resolvedConfigPath) {
|
|
17012
18128
|
const config = rawConfig && typeof rawConfig === "object" ? { ...rawConfig } : {};
|
|
17013
18129
|
const rebaseEntries = (values) => isProjectScopedConfigPath(resolvedConfigPath) ? resolveInheritedKnowledgeBaseEntries(
|
|
17014
18130
|
values,
|
|
17015
|
-
|
|
18131
|
+
path23.dirname(path23.dirname(resolvedConfigPath)),
|
|
17016
18132
|
projectRoot
|
|
17017
18133
|
) : rebasePathEntries(
|
|
17018
18134
|
values,
|
|
17019
|
-
|
|
18135
|
+
path23.dirname(resolvedConfigPath),
|
|
17020
18136
|
projectRoot
|
|
17021
18137
|
);
|
|
17022
18138
|
if (Array.isArray(config.knowledgeBases)) {
|
|
@@ -17029,7 +18145,7 @@ function normalizeEvalConfigKnowledgeBases(rawConfig, projectRoot, resolvedConfi
|
|
|
17029
18145
|
}
|
|
17030
18146
|
function loadRawConfig(projectRoot, configPath) {
|
|
17031
18147
|
const fromPath = configPath ? toAbsolute(projectRoot, configPath) : null;
|
|
17032
|
-
if (fromPath &&
|
|
18148
|
+
if (fromPath && existsSync14(fromPath)) {
|
|
17033
18149
|
return normalizeEvalConfigKnowledgeBases(
|
|
17034
18150
|
parseJsonConfigFile(fromPath),
|
|
17035
18151
|
projectRoot,
|
|
@@ -17037,15 +18153,15 @@ function loadRawConfig(projectRoot, configPath) {
|
|
|
17037
18153
|
);
|
|
17038
18154
|
}
|
|
17039
18155
|
const projectConfig = resolveProjectConfigPath(projectRoot, "opencode");
|
|
17040
|
-
if (
|
|
18156
|
+
if (existsSync14(projectConfig)) {
|
|
17041
18157
|
return normalizeEvalConfigKnowledgeBases(
|
|
17042
18158
|
parseJsonConfigFile(projectConfig),
|
|
17043
18159
|
projectRoot,
|
|
17044
18160
|
projectConfig
|
|
17045
18161
|
);
|
|
17046
18162
|
}
|
|
17047
|
-
const globalConfig =
|
|
17048
|
-
if (
|
|
18163
|
+
const globalConfig = path23.join(os8.homedir(), ".config", "opencode", "codebase-index.json");
|
|
18164
|
+
if (existsSync14(globalConfig)) {
|
|
17049
18165
|
return parseJsonConfigFile(globalConfig);
|
|
17050
18166
|
}
|
|
17051
18167
|
return {};
|
|
@@ -17054,24 +18170,24 @@ function getIndexRootPath(projectRoot, scope) {
|
|
|
17054
18170
|
return scope === "global" ? getGlobalIndexPath("opencode") : resolveProjectIndexPath(projectRoot, scope, "opencode");
|
|
17055
18171
|
}
|
|
17056
18172
|
function getLocalProjectIndexRoot(projectRoot) {
|
|
17057
|
-
return
|
|
18173
|
+
return path23.join(projectRoot, ".opencode", "index");
|
|
17058
18174
|
}
|
|
17059
18175
|
function getLocalProjectConfigPath(projectRoot) {
|
|
17060
|
-
return
|
|
18176
|
+
return path23.join(projectRoot, ".opencode", "codebase-index.json");
|
|
17061
18177
|
}
|
|
17062
18178
|
function clearIndexRoot(projectRoot, scope) {
|
|
17063
18179
|
const indexRoot = scope === "global" ? getIndexRootPath(projectRoot, scope) : getLocalProjectIndexRoot(projectRoot);
|
|
17064
|
-
if (
|
|
17065
|
-
|
|
18180
|
+
if (existsSync14(indexRoot)) {
|
|
18181
|
+
rmSync4(indexRoot, { recursive: true, force: true });
|
|
17066
18182
|
}
|
|
17067
18183
|
}
|
|
17068
18184
|
function ensureLocalEvalProjectConfig(projectRoot, configPath) {
|
|
17069
18185
|
const localConfigPath = getLocalProjectConfigPath(projectRoot);
|
|
17070
18186
|
const resolvedConfigPath = configPath ? toAbsolute(projectRoot, configPath) : resolveProjectConfigPath(projectRoot, "opencode");
|
|
17071
|
-
if (!configPath &&
|
|
18187
|
+
if (!configPath && existsSync14(localConfigPath)) {
|
|
17072
18188
|
return localConfigPath;
|
|
17073
18189
|
}
|
|
17074
|
-
if (!
|
|
18190
|
+
if (!existsSync14(resolvedConfigPath) || resolvedConfigPath === localConfigPath) {
|
|
17075
18191
|
return resolvedConfigPath;
|
|
17076
18192
|
}
|
|
17077
18193
|
const sourceConfig = normalizeEvalConfigKnowledgeBases(
|
|
@@ -17079,8 +18195,8 @@ function ensureLocalEvalProjectConfig(projectRoot, configPath) {
|
|
|
17079
18195
|
projectRoot,
|
|
17080
18196
|
resolvedConfigPath
|
|
17081
18197
|
);
|
|
17082
|
-
|
|
17083
|
-
|
|
18198
|
+
mkdirSync7(path23.dirname(localConfigPath), { recursive: true });
|
|
18199
|
+
writeFileSync6(localConfigPath, JSON.stringify(sourceConfig, null, 2), "utf-8");
|
|
17084
18200
|
return localConfigPath;
|
|
17085
18201
|
}
|
|
17086
18202
|
function loadParsedConfig(projectRoot, configPath) {
|
|
@@ -17113,9 +18229,9 @@ function getEmbeddingCostPer1MTokens(embeddingProvider) {
|
|
|
17113
18229
|
}
|
|
17114
18230
|
|
|
17115
18231
|
// src/eval/schema.ts
|
|
17116
|
-
import { readFileSync as
|
|
18232
|
+
import { readFileSync as readFileSync12 } from "fs";
|
|
17117
18233
|
function parseJsonFile(filePath) {
|
|
17118
|
-
const content =
|
|
18234
|
+
const content = readFileSync12(filePath, "utf-8");
|
|
17119
18235
|
try {
|
|
17120
18236
|
return JSON.parse(content);
|
|
17121
18237
|
} catch (error) {
|
|
@@ -17132,68 +18248,68 @@ function isStringArray4(value) {
|
|
|
17132
18248
|
function isNonEmptyString(value) {
|
|
17133
18249
|
return typeof value === "string" && value.trim().length > 0;
|
|
17134
18250
|
}
|
|
17135
|
-
function asPositiveNumber(value,
|
|
18251
|
+
function asPositiveNumber(value, path34) {
|
|
17136
18252
|
if (typeof value !== "number" || Number.isNaN(value) || value < 0) {
|
|
17137
|
-
throw new Error(`${
|
|
18253
|
+
throw new Error(`${path34} must be a non-negative number`);
|
|
17138
18254
|
}
|
|
17139
18255
|
return value;
|
|
17140
18256
|
}
|
|
17141
|
-
function parseQueryType(value,
|
|
18257
|
+
function parseQueryType(value, path34) {
|
|
17142
18258
|
if (value === "definition" || value === "implementation-intent" || value === "similarity" || value === "keyword-heavy" || value === "conceptual") {
|
|
17143
18259
|
return value;
|
|
17144
18260
|
}
|
|
17145
18261
|
throw new Error(
|
|
17146
|
-
`${
|
|
18262
|
+
`${path34} must be one of: definition, implementation-intent, similarity, keyword-heavy, conceptual`
|
|
17147
18263
|
);
|
|
17148
18264
|
}
|
|
17149
|
-
function parseExpectedRoute(value,
|
|
18265
|
+
function parseExpectedRoute(value, path34) {
|
|
17150
18266
|
if (value === void 0) return void 0;
|
|
17151
18267
|
if (value === "search" || value === "definition") return value;
|
|
17152
|
-
throw new Error(`${
|
|
18268
|
+
throw new Error(`${path34} must be one of: search, definition`);
|
|
17153
18269
|
}
|
|
17154
|
-
function parseExpectedOutcome(value,
|
|
18270
|
+
function parseExpectedOutcome(value, path34) {
|
|
17155
18271
|
if (value === void 0) return void 0;
|
|
17156
18272
|
if (value === "results" || value === "no-results") {
|
|
17157
18273
|
return value;
|
|
17158
18274
|
}
|
|
17159
|
-
throw new Error(`${
|
|
18275
|
+
throw new Error(`${path34} must be one of: results, no-results`);
|
|
17160
18276
|
}
|
|
17161
|
-
function parseRecoveryExpectation(value,
|
|
18277
|
+
function parseRecoveryExpectation(value, path34) {
|
|
17162
18278
|
if (value === void 0) return void 0;
|
|
17163
18279
|
if (value === "none" || value === "filter-relaxed") {
|
|
17164
18280
|
return value;
|
|
17165
18281
|
}
|
|
17166
|
-
throw new Error(`${
|
|
18282
|
+
throw new Error(`${path34} must be one of: none, filter-relaxed`);
|
|
17167
18283
|
}
|
|
17168
|
-
function parseQueryDifficulty(value,
|
|
18284
|
+
function parseQueryDifficulty(value, path34) {
|
|
17169
18285
|
if (value === void 0) return void 0;
|
|
17170
18286
|
if (value === "easy" || value === "medium" || value === "hard") {
|
|
17171
18287
|
return value;
|
|
17172
18288
|
}
|
|
17173
|
-
throw new Error(`${
|
|
18289
|
+
throw new Error(`${path34} must be one of: easy, medium, hard`);
|
|
17174
18290
|
}
|
|
17175
|
-
function parseQueryTags(value,
|
|
18291
|
+
function parseQueryTags(value, path34) {
|
|
17176
18292
|
if (value === void 0) return void 0;
|
|
17177
18293
|
if (!isStringArray4(value) || value.some((tag) => tag.trim().length === 0)) {
|
|
17178
|
-
throw new Error(`${
|
|
18294
|
+
throw new Error(`${path34} must be an array of non-empty strings`);
|
|
17179
18295
|
}
|
|
17180
18296
|
if (value.length > 16) {
|
|
17181
|
-
throw new Error(`${
|
|
18297
|
+
throw new Error(`${path34} must contain at most 16 tags`);
|
|
17182
18298
|
}
|
|
17183
18299
|
return value;
|
|
17184
18300
|
}
|
|
17185
|
-
function parseQueryArgs(value,
|
|
18301
|
+
function parseQueryArgs(value, path34) {
|
|
17186
18302
|
if (value === void 0) return void 0;
|
|
17187
18303
|
if (!isRecord3(value)) {
|
|
17188
|
-
throw new Error(`${
|
|
17189
|
-
}
|
|
17190
|
-
const symbol = parseStringOrUndefined(value.symbol, `${
|
|
17191
|
-
const filePath = parseStringOrUndefined(value.filePath, `${
|
|
17192
|
-
const fileType = parseStringOrUndefined(value.fileType, `${
|
|
17193
|
-
const directory = parseStringOrUndefined(value.directory, `${
|
|
17194
|
-
const callerLimit = parsePositiveIntegerOrUndefined(value.callerLimit, `${
|
|
17195
|
-
const calleeLimit = parsePositiveIntegerOrUndefined(value.calleeLimit, `${
|
|
17196
|
-
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`);
|
|
17197
18313
|
return {
|
|
17198
18314
|
...symbol !== void 0 ? { symbol } : {},
|
|
17199
18315
|
...filePath !== void 0 ? { filePath } : {},
|
|
@@ -17204,50 +18320,50 @@ function parseQueryArgs(value, path33) {
|
|
|
17204
18320
|
...tokenBudget !== void 0 ? { tokenBudget } : {}
|
|
17205
18321
|
};
|
|
17206
18322
|
}
|
|
17207
|
-
function parsePositiveIntegerOrUndefined(value,
|
|
18323
|
+
function parsePositiveIntegerOrUndefined(value, path34) {
|
|
17208
18324
|
if (value === void 0 || value === null) return void 0;
|
|
17209
18325
|
if (typeof value !== "number" || !Number.isInteger(value) || value <= 0) {
|
|
17210
|
-
throw new Error(`${
|
|
18326
|
+
throw new Error(`${path34} must be a positive integer`);
|
|
17211
18327
|
}
|
|
17212
18328
|
return value;
|
|
17213
18329
|
}
|
|
17214
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-]+)*)?$/;
|
|
17215
|
-
function parseSemanticVersion(value,
|
|
18331
|
+
function parseSemanticVersion(value, path34) {
|
|
17216
18332
|
if (!isNonEmptyString(value)) {
|
|
17217
|
-
throw new Error(`${
|
|
18333
|
+
throw new Error(`${path34} must be a non-empty string`);
|
|
17218
18334
|
}
|
|
17219
18335
|
if (!SEMVER_VERSION_PATTERN.test(value)) {
|
|
17220
|
-
throw new Error(`${
|
|
18336
|
+
throw new Error(`${path34} must be a valid semantic version (MAJOR.MINOR.PATCH)`);
|
|
17221
18337
|
}
|
|
17222
18338
|
return value;
|
|
17223
18339
|
}
|
|
17224
|
-
function parseRetrievalMode(value,
|
|
18340
|
+
function parseRetrievalMode(value, path34) {
|
|
17225
18341
|
if (value === void 0 || value === "search") return "search";
|
|
17226
18342
|
if (value === "context" || value === "edit-context") return value;
|
|
17227
|
-
throw new Error(`${
|
|
18343
|
+
throw new Error(`${path34} must be one of: search, context, edit-context`);
|
|
17228
18344
|
}
|
|
17229
|
-
function parseStringOrUndefined(value,
|
|
18345
|
+
function parseStringOrUndefined(value, path34) {
|
|
17230
18346
|
if (value === void 0 || value === null) return void 0;
|
|
17231
18347
|
if (!isNonEmptyString(value)) {
|
|
17232
|
-
throw new Error(`${
|
|
18348
|
+
throw new Error(`${path34} must be a non-empty string`);
|
|
17233
18349
|
}
|
|
17234
18350
|
return value;
|
|
17235
18351
|
}
|
|
17236
|
-
function parseGradedEvidence(value,
|
|
18352
|
+
function parseGradedEvidence(value, path34) {
|
|
17237
18353
|
if (value === void 0) return [];
|
|
17238
18354
|
if (!Array.isArray(value)) {
|
|
17239
|
-
throw new Error(`${
|
|
18355
|
+
throw new Error(`${path34} must be an array`);
|
|
17240
18356
|
}
|
|
17241
18357
|
return value.map((entry, index) => {
|
|
17242
18358
|
if (!isRecord3(entry)) {
|
|
17243
|
-
throw new Error(`${
|
|
18359
|
+
throw new Error(`${path34}[${index}] must be an object`);
|
|
17244
18360
|
}
|
|
17245
|
-
const evidencePath = parseStringOrUndefined(entry.path, `${
|
|
18361
|
+
const evidencePath = parseStringOrUndefined(entry.path, `${path34}[${index}].path`);
|
|
17246
18362
|
if (evidencePath === void 0) {
|
|
17247
|
-
throw new Error(`${
|
|
18363
|
+
throw new Error(`${path34}[${index}].path is required`);
|
|
17248
18364
|
}
|
|
17249
|
-
const symbol = parseStringOrUndefined(entry.symbol, `${
|
|
17250
|
-
const relevance = parseEvidenceRelevance(entry.relevance, `${
|
|
18365
|
+
const symbol = parseStringOrUndefined(entry.symbol, `${path34}[${index}].symbol`);
|
|
18366
|
+
const relevance = parseEvidenceRelevance(entry.relevance, `${path34}[${index}].relevance`);
|
|
17251
18367
|
return {
|
|
17252
18368
|
path: evidencePath,
|
|
17253
18369
|
...symbol !== void 0 ? { symbol } : {},
|
|
@@ -17255,27 +18371,27 @@ function parseGradedEvidence(value, path33) {
|
|
|
17255
18371
|
};
|
|
17256
18372
|
});
|
|
17257
18373
|
}
|
|
17258
|
-
function parseEvidenceRelevance(value,
|
|
18374
|
+
function parseEvidenceRelevance(value, path34) {
|
|
17259
18375
|
if (value === void 0) {
|
|
17260
|
-
throw new Error(`${
|
|
18376
|
+
throw new Error(`${path34} is required`);
|
|
17261
18377
|
}
|
|
17262
18378
|
if (value !== 1 && value !== 2 && value !== 3) {
|
|
17263
|
-
throw new Error(`${
|
|
18379
|
+
throw new Error(`${path34} must be 1, 2, or 3`);
|
|
17264
18380
|
}
|
|
17265
18381
|
return value;
|
|
17266
18382
|
}
|
|
17267
|
-
function parseExpectedGraphNeighbor(value,
|
|
18383
|
+
function parseExpectedGraphNeighbor(value, path34) {
|
|
17268
18384
|
if (value === void 0) return void 0;
|
|
17269
18385
|
if (!isRecord3(value)) {
|
|
17270
|
-
throw new Error(`${
|
|
18386
|
+
throw new Error(`${path34} must be an object`);
|
|
17271
18387
|
}
|
|
17272
18388
|
if (value.direction !== "caller" && value.direction !== "callee") {
|
|
17273
|
-
throw new Error(`${
|
|
18389
|
+
throw new Error(`${path34}.direction must be one of: caller, callee`);
|
|
17274
18390
|
}
|
|
17275
|
-
const filePath = parseStringOrUndefined(value.filePath, `${
|
|
17276
|
-
const symbol = parseStringOrUndefined(value.symbol, `${
|
|
18391
|
+
const filePath = parseStringOrUndefined(value.filePath, `${path34}.filePath`);
|
|
18392
|
+
const symbol = parseStringOrUndefined(value.symbol, `${path34}.symbol`);
|
|
17277
18393
|
if (filePath === void 0 && symbol === void 0) {
|
|
17278
|
-
throw new Error(`${
|
|
18394
|
+
throw new Error(`${path34} must include filePath or symbol`);
|
|
17279
18395
|
}
|
|
17280
18396
|
return {
|
|
17281
18397
|
direction: value.direction,
|
|
@@ -17283,9 +18399,9 @@ function parseExpectedGraphNeighbor(value, path33) {
|
|
|
17283
18399
|
...symbol !== void 0 ? { symbol } : {}
|
|
17284
18400
|
};
|
|
17285
18401
|
}
|
|
17286
|
-
function parseExpected(input,
|
|
18402
|
+
function parseExpected(input, path34) {
|
|
17287
18403
|
if (!isRecord3(input)) {
|
|
17288
|
-
throw new Error(`${
|
|
18404
|
+
throw new Error(`${path34} must be an object`);
|
|
17289
18405
|
}
|
|
17290
18406
|
const filePathRaw = input.filePath;
|
|
17291
18407
|
const acceptableFilesRaw = input.acceptableFiles;
|
|
@@ -17296,29 +18412,29 @@ function parseExpected(input, path33) {
|
|
|
17296
18412
|
const recoveryExpectationRaw = input.recoveryExpectation;
|
|
17297
18413
|
const gradedEvidenceRaw = input.gradedEvidence;
|
|
17298
18414
|
const graphNeighborRaw = input.graphNeighbor;
|
|
17299
|
-
const filePath = parseStringOrUndefined(filePathRaw, `${
|
|
18415
|
+
const filePath = parseStringOrUndefined(filePathRaw, `${path34}.filePath`);
|
|
17300
18416
|
const acceptableFiles = isStringArray4(acceptableFilesRaw) ? acceptableFilesRaw : void 0;
|
|
17301
|
-
const gradedEvidence = parseGradedEvidence(gradedEvidenceRaw, `${
|
|
17302
|
-
const graphNeighbor = parseExpectedGraphNeighbor(graphNeighborRaw, `${
|
|
17303
|
-
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`);
|
|
17304
18420
|
if (expectedOutcome !== "no-results" && !filePath && (!acceptableFiles || acceptableFiles.length === 0) && gradedEvidence.length === 0) {
|
|
17305
18421
|
throw new Error(
|
|
17306
|
-
`${
|
|
18422
|
+
`${path34} must include expected.filePath, expected.acceptableFiles, or expected.gradedEvidence`
|
|
17307
18423
|
);
|
|
17308
18424
|
}
|
|
17309
18425
|
if (acceptableFilesRaw !== void 0 && !isStringArray4(acceptableFilesRaw)) {
|
|
17310
|
-
throw new Error(`${
|
|
18426
|
+
throw new Error(`${path34}.acceptableFiles must be an array of strings`);
|
|
17311
18427
|
}
|
|
17312
18428
|
if (symbolRaw !== void 0 && typeof symbolRaw !== "string") {
|
|
17313
|
-
throw new Error(`${
|
|
18429
|
+
throw new Error(`${path34}.symbol must be a string when provided`);
|
|
17314
18430
|
}
|
|
17315
18431
|
if (branchRaw !== void 0 && typeof branchRaw !== "string") {
|
|
17316
|
-
throw new Error(`${
|
|
18432
|
+
throw new Error(`${path34}.branch must be a string when provided`);
|
|
17317
18433
|
}
|
|
17318
|
-
const expectedRoute = parseExpectedRoute(expectedRouteRaw, `${
|
|
18434
|
+
const expectedRoute = parseExpectedRoute(expectedRouteRaw, `${path34}.expectedRoute`);
|
|
17319
18435
|
const recoveryExpectation = parseRecoveryExpectation(
|
|
17320
18436
|
recoveryExpectationRaw,
|
|
17321
|
-
`${
|
|
18437
|
+
`${path34}.recoveryExpectation`
|
|
17322
18438
|
);
|
|
17323
18439
|
return {
|
|
17324
18440
|
filePath,
|
|
@@ -17332,13 +18448,13 @@ function parseExpected(input, path33) {
|
|
|
17332
18448
|
...graphNeighbor !== void 0 ? { graphNeighbor } : {}
|
|
17333
18449
|
};
|
|
17334
18450
|
}
|
|
17335
|
-
function parseQueryLanguage(value,
|
|
17336
|
-
return parseStringOrUndefined(value,
|
|
18451
|
+
function parseQueryLanguage(value, path34) {
|
|
18452
|
+
return parseStringOrUndefined(value, path34);
|
|
17337
18453
|
}
|
|
17338
18454
|
function parseQuery(input, index) {
|
|
17339
|
-
const
|
|
18455
|
+
const path34 = `queries[${index}]`;
|
|
17340
18456
|
if (!isRecord3(input)) {
|
|
17341
|
-
throw new Error(`${
|
|
18457
|
+
throw new Error(`${path34} must be an object`);
|
|
17342
18458
|
}
|
|
17343
18459
|
const id = input.id;
|
|
17344
18460
|
const query = input.query;
|
|
@@ -17350,21 +18466,21 @@ function parseQuery(input, index) {
|
|
|
17350
18466
|
const tags = input.tags;
|
|
17351
18467
|
const args = input.args;
|
|
17352
18468
|
if (typeof id !== "string" || id.trim().length === 0) {
|
|
17353
|
-
throw new Error(`${
|
|
18469
|
+
throw new Error(`${path34}.id must be a non-empty string`);
|
|
17354
18470
|
}
|
|
17355
18471
|
if (typeof query !== "string" || query.trim().length === 0) {
|
|
17356
|
-
throw new Error(`${
|
|
18472
|
+
throw new Error(`${path34}.query must be a non-empty string`);
|
|
17357
18473
|
}
|
|
17358
18474
|
return {
|
|
17359
18475
|
id,
|
|
17360
18476
|
query,
|
|
17361
|
-
queryType: parseQueryType(queryType, `${
|
|
17362
|
-
retrievalMode: parseRetrievalMode(retrievalMode, `${
|
|
17363
|
-
language: parseQueryLanguage(language, `${
|
|
17364
|
-
difficulty: parseQueryDifficulty(difficulty, `${
|
|
17365
|
-
args: parseQueryArgs(args, `${
|
|
17366
|
-
tags: parseQueryTags(tags, `${
|
|
17367
|
-
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`)
|
|
17368
18484
|
};
|
|
17369
18485
|
}
|
|
17370
18486
|
function parseGoldenDataset(raw, sourceLabel) {
|
|
@@ -17780,13 +18896,13 @@ async function runEvaluation(options) {
|
|
|
17780
18896
|
};
|
|
17781
18897
|
const outputDir = createRunDirectory(toAbsolute(options.projectRoot, options.outputRoot));
|
|
17782
18898
|
const perQueryArtifact = buildPerQueryArtifact(perQuery);
|
|
17783
|
-
writeJson(
|
|
17784
|
-
writeJson(
|
|
18899
|
+
writeJson(path24.join(outputDir, "summary.json"), summary);
|
|
18900
|
+
writeJson(path24.join(outputDir, "per-query.json"), perQueryArtifact);
|
|
17785
18901
|
let comparison;
|
|
17786
18902
|
if (againstPath) {
|
|
17787
18903
|
const baseline = loadSummary(againstPath);
|
|
17788
18904
|
comparison = compareSummaries(summary, baseline, againstPath);
|
|
17789
|
-
writeJson(
|
|
18905
|
+
writeJson(path24.join(outputDir, "compare.json"), comparison);
|
|
17790
18906
|
}
|
|
17791
18907
|
let gate;
|
|
17792
18908
|
if (options.ciMode) {
|
|
@@ -17796,10 +18912,10 @@ async function runEvaluation(options) {
|
|
|
17796
18912
|
const budget = loadBudget(budgetPath);
|
|
17797
18913
|
if (!comparison && budget.baselinePath) {
|
|
17798
18914
|
const resolvedBaseline = toAbsolute(options.projectRoot, budget.baselinePath);
|
|
17799
|
-
if (
|
|
18915
|
+
if (existsSync15(resolvedBaseline)) {
|
|
17800
18916
|
const baselineSummary = loadSummary(resolvedBaseline);
|
|
17801
18917
|
comparison = compareSummaries(summary, baselineSummary, resolvedBaseline);
|
|
17802
|
-
writeJson(
|
|
18918
|
+
writeJson(path24.join(outputDir, "compare.json"), comparison);
|
|
17803
18919
|
} else if (budget.failOnMissingBaseline) {
|
|
17804
18920
|
throw new Error(
|
|
17805
18921
|
`Budget baseline is missing: ${resolvedBaseline}. Set failOnMissingBaseline=false to allow CI run without baseline.`
|
|
@@ -17809,7 +18925,7 @@ async function runEvaluation(options) {
|
|
|
17809
18925
|
gate = evaluateBudgetGate(budget, summary, comparison);
|
|
17810
18926
|
}
|
|
17811
18927
|
const markdown = createSummaryMarkdown(summary, comparison, gate);
|
|
17812
|
-
writeText(
|
|
18928
|
+
writeText(path24.join(outputDir, "summary.md"), markdown);
|
|
17813
18929
|
return { outputDir, summary, perQuery, comparison, gate };
|
|
17814
18930
|
} finally {
|
|
17815
18931
|
await indexer.close();
|
|
@@ -17867,23 +18983,23 @@ async function runSweep(options, sweep) {
|
|
|
17867
18983
|
bestByMrrAt10,
|
|
17868
18984
|
bestByP95Latency
|
|
17869
18985
|
};
|
|
17870
|
-
writeJson(
|
|
18986
|
+
writeJson(path24.join(outputDir, "compare.json"), aggregate);
|
|
17871
18987
|
const md = createSummaryMarkdown(
|
|
17872
18988
|
bestByHitAt5?.summary ?? runs[0].summary,
|
|
17873
18989
|
bestByHitAt5?.comparison,
|
|
17874
18990
|
void 0,
|
|
17875
18991
|
aggregate
|
|
17876
18992
|
);
|
|
17877
|
-
writeText(
|
|
17878
|
-
writeJson(
|
|
18993
|
+
writeText(path24.join(outputDir, "summary.md"), md);
|
|
18994
|
+
writeJson(path24.join(outputDir, "summary.json"), bestByHitAt5?.summary ?? runs[0].summary);
|
|
17879
18995
|
return { outputDir, aggregate };
|
|
17880
18996
|
}
|
|
17881
18997
|
|
|
17882
18998
|
// src/eval/cli.ts
|
|
17883
|
-
import * as
|
|
18999
|
+
import * as path26 from "path";
|
|
17884
19000
|
|
|
17885
19001
|
// src/eval/cli-parser.ts
|
|
17886
|
-
import * as
|
|
19002
|
+
import * as path25 from "path";
|
|
17887
19003
|
function printUsage() {
|
|
17888
19004
|
console.log(`
|
|
17889
19005
|
Usage:
|
|
@@ -17955,12 +19071,12 @@ function parseEvalArgs(argv, cwd) {
|
|
|
17955
19071
|
const arg = argv[i];
|
|
17956
19072
|
const next = argv[i + 1];
|
|
17957
19073
|
if (arg === "--project" && next) {
|
|
17958
|
-
parsed.projectRoot =
|
|
19074
|
+
parsed.projectRoot = path25.resolve(cwd, next);
|
|
17959
19075
|
i += 1;
|
|
17960
19076
|
continue;
|
|
17961
19077
|
}
|
|
17962
19078
|
if (arg === "--config" && next) {
|
|
17963
|
-
parsed.configPath =
|
|
19079
|
+
parsed.configPath = path25.resolve(cwd, next);
|
|
17964
19080
|
i += 1;
|
|
17965
19081
|
continue;
|
|
17966
19082
|
}
|
|
@@ -18156,22 +19272,22 @@ async function handleEvalCommand(args, cwd) {
|
|
|
18156
19272
|
if (!parsed.againstPath.endsWith(".json")) {
|
|
18157
19273
|
throw new Error("eval diff --against must point to a summary JSON file");
|
|
18158
19274
|
}
|
|
18159
|
-
const currentSummary = loadSummary(
|
|
19275
|
+
const currentSummary = loadSummary(path26.resolve(parsed.projectRoot, currentPath), {
|
|
18160
19276
|
allowLegacyDiversityMetrics: true
|
|
18161
19277
|
});
|
|
18162
|
-
const baselineSummary = loadSummary(
|
|
19278
|
+
const baselineSummary = loadSummary(path26.resolve(parsed.projectRoot, parsed.againstPath), {
|
|
18163
19279
|
allowLegacyDiversityMetrics: true
|
|
18164
19280
|
});
|
|
18165
19281
|
const comparison = compareSummaries(
|
|
18166
19282
|
currentSummary,
|
|
18167
19283
|
baselineSummary,
|
|
18168
|
-
|
|
19284
|
+
path26.resolve(parsed.projectRoot, parsed.againstPath)
|
|
18169
19285
|
);
|
|
18170
|
-
const outputDir = createRunDirectory(
|
|
19286
|
+
const outputDir = createRunDirectory(path26.resolve(parsed.projectRoot, parsed.outputRoot));
|
|
18171
19287
|
const summaryMd = createSummaryMarkdown(currentSummary, comparison);
|
|
18172
|
-
writeJson(
|
|
18173
|
-
writeText(
|
|
18174
|
-
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);
|
|
18175
19291
|
console.log(`Eval diff complete. Artifacts: ${outputDir}`);
|
|
18176
19292
|
return 0;
|
|
18177
19293
|
}
|
|
@@ -18182,9 +19298,9 @@ async function handleEvalCommand(args, cwd) {
|
|
|
18182
19298
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
18183
19299
|
|
|
18184
19300
|
// src/package-metadata.ts
|
|
18185
|
-
import { readFileSync as
|
|
19301
|
+
import { readFileSync as readFileSync13 } from "fs";
|
|
18186
19302
|
function getPackageVersion() {
|
|
18187
|
-
const raw = JSON.parse(
|
|
19303
|
+
const raw = JSON.parse(readFileSync13(new URL("../package.json", import.meta.url), "utf-8"));
|
|
18188
19304
|
if (raw && typeof raw === "object" && "version" in raw && typeof raw.version === "string") {
|
|
18189
19305
|
return raw.version;
|
|
18190
19306
|
}
|
|
@@ -18295,6 +19411,7 @@ async function executeCodebaseEditContext(projectRoot, host, args) {
|
|
|
18295
19411
|
async function executeIndexCodebase(projectRoot, host, args, onProgress) {
|
|
18296
19412
|
const result = await runIndexCodebase(projectRoot, host, args, onProgress);
|
|
18297
19413
|
if (result.kind === "estimate") return { text: formatCostEstimate(result.estimate) };
|
|
19414
|
+
if (result.kind === "dryrun") return { text: formatDryRunEstimate(result.dryrun) };
|
|
18298
19415
|
if (result.kind === "busy") return { text: result.text, isError: true };
|
|
18299
19416
|
if (result.kind === "message") return { text: result.text };
|
|
18300
19417
|
return { text: formatIndexStats(result.stats, args.verbose ?? false) };
|
|
@@ -18331,7 +19448,7 @@ async function executeCallGraph(projectRoot, host, args) {
|
|
|
18331
19448
|
return { text: formatCallGraphResult(await getCallGraphData(projectRoot, host, args)) };
|
|
18332
19449
|
}
|
|
18333
19450
|
async function executeCallGraphPath(projectRoot, host, args) {
|
|
18334
|
-
const
|
|
19451
|
+
const path34 = await getCallGraphPath(
|
|
18335
19452
|
projectRoot,
|
|
18336
19453
|
host,
|
|
18337
19454
|
args.from,
|
|
@@ -18340,7 +19457,7 @@ async function executeCallGraphPath(projectRoot, host, args) {
|
|
|
18340
19457
|
args.fromFilePath,
|
|
18341
19458
|
args.toFilePath
|
|
18342
19459
|
);
|
|
18343
|
-
return { text: formatCallGraphPathResult(
|
|
19460
|
+
return { text: formatCallGraphPathResult(path34) };
|
|
18344
19461
|
}
|
|
18345
19462
|
async function executeCodeCommunities(projectRoot, host, args) {
|
|
18346
19463
|
const result = await getCodeCommunities(projectRoot, host, args);
|
|
@@ -18622,6 +19739,7 @@ ${formatCodebasePeek(results)}`;
|
|
|
18622
19739
|
{
|
|
18623
19740
|
force: allowNullAsUndefined(z2.boolean().optional().default(false)).describe("Force reindex even if already indexed"),
|
|
18624
19741
|
estimateOnly: allowNullAsUndefined(z2.boolean().optional().default(false)).describe("Only show cost estimate without indexing"),
|
|
19742
|
+
dryRun: allowNullAsUndefined(z2.boolean().optional().default(false)).describe("Parse the file set and report the exact embedding token total without indexing. Read-only; the index is not changed. The total is the value 'Tokens used' climbs to for a force index (and an upper bound for an incremental)."),
|
|
18625
19743
|
verbose: allowNullAsUndefined(z2.boolean().optional().default(false)).describe("Show detailed info about skipped files and parsing failures")
|
|
18626
19744
|
},
|
|
18627
19745
|
async (args) => {
|
|
@@ -18834,9 +19952,64 @@ ${formatSearchResults(results)}` }] };
|
|
|
18834
19952
|
}
|
|
18835
19953
|
|
|
18836
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
|
+
}
|
|
18837
19979
|
function getServerInstructions(host) {
|
|
18838
19980
|
const hostText = `host ${host}`;
|
|
18839
|
-
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. 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.`;
|
|
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.`;
|
|
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);
|
|
18840
20013
|
}
|
|
18841
20014
|
function createMcpServer(projectRoot, config, host) {
|
|
18842
20015
|
const server = new McpServer({
|
|
@@ -18845,11 +20018,14 @@ function createMcpServer(projectRoot, config, host) {
|
|
|
18845
20018
|
}, {
|
|
18846
20019
|
instructions: getServerInstructions(host)
|
|
18847
20020
|
});
|
|
18848
|
-
initializeTools(projectRoot, config, host);
|
|
18849
|
-
|
|
20021
|
+
initializeTools(projectRoot, config, host, { preserveManagedWorker: true });
|
|
20022
|
+
const backgroundWorker = configureMcpBackgroundWorker(projectRoot, config, host);
|
|
20023
|
+
if (backgroundWorker.managesWorker) {
|
|
20024
|
+
retainMcpBackgroundWorker(projectRoot, host);
|
|
20025
|
+
}
|
|
18850
20026
|
let stopCoordinationPromise = null;
|
|
18851
20027
|
const stopCoordination = () => {
|
|
18852
|
-
stopCoordinationPromise ??=
|
|
20028
|
+
stopCoordinationPromise ??= backgroundWorker.managesWorker ? releaseMcpBackgroundWorker(projectRoot, host) : Promise.resolve();
|
|
18853
20029
|
return stopCoordinationPromise;
|
|
18854
20030
|
};
|
|
18855
20031
|
const closeProtocol = server.server.close.bind(server.server);
|
|
@@ -18865,7 +20041,9 @@ function createMcpServer(projectRoot, config, host) {
|
|
|
18865
20041
|
const onServerClose = server.server.onclose;
|
|
18866
20042
|
server.server.onclose = () => {
|
|
18867
20043
|
onServerClose?.();
|
|
18868
|
-
void stopCoordination()
|
|
20044
|
+
void stopCoordination().catch((error) => {
|
|
20045
|
+
console.error("[codebase-index] Failed to stop MCP background worker after transport close:", error);
|
|
20046
|
+
});
|
|
18869
20047
|
};
|
|
18870
20048
|
registerMcpTools(server, {
|
|
18871
20049
|
projectRoot,
|
|
@@ -18876,7 +20054,7 @@ function createMcpServer(projectRoot, config, host) {
|
|
|
18876
20054
|
}
|
|
18877
20055
|
|
|
18878
20056
|
// src/watcher/file-watcher.ts
|
|
18879
|
-
import { existsSync as
|
|
20057
|
+
import { existsSync as existsSync16, statSync as statSync6 } from "fs";
|
|
18880
20058
|
|
|
18881
20059
|
// node_modules/chokidar/index.js
|
|
18882
20060
|
import { EventEmitter as EventEmitter2 } from "events";
|
|
@@ -18968,7 +20146,7 @@ var ReaddirpStream = class extends Readable {
|
|
|
18968
20146
|
this._directoryFilter = normalizeFilter(opts.directoryFilter);
|
|
18969
20147
|
const statMethod = opts.lstat ? lstat : stat;
|
|
18970
20148
|
if (wantBigintFsStats) {
|
|
18971
|
-
this._stat = (
|
|
20149
|
+
this._stat = (path34) => statMethod(path34, { bigint: true });
|
|
18972
20150
|
} else {
|
|
18973
20151
|
this._stat = statMethod;
|
|
18974
20152
|
}
|
|
@@ -18993,8 +20171,8 @@ var ReaddirpStream = class extends Readable {
|
|
|
18993
20171
|
const par = this.parent;
|
|
18994
20172
|
const fil = par && par.files;
|
|
18995
20173
|
if (fil && fil.length > 0) {
|
|
18996
|
-
const { path:
|
|
18997
|
-
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));
|
|
18998
20176
|
const awaited = await Promise.all(slice);
|
|
18999
20177
|
for (const entry of awaited) {
|
|
19000
20178
|
if (!entry)
|
|
@@ -19034,21 +20212,21 @@ var ReaddirpStream = class extends Readable {
|
|
|
19034
20212
|
this.reading = false;
|
|
19035
20213
|
}
|
|
19036
20214
|
}
|
|
19037
|
-
async _exploreDir(
|
|
20215
|
+
async _exploreDir(path34, depth) {
|
|
19038
20216
|
let files;
|
|
19039
20217
|
try {
|
|
19040
|
-
files = await readdir(
|
|
20218
|
+
files = await readdir(path34, this._rdOptions);
|
|
19041
20219
|
} catch (error) {
|
|
19042
20220
|
this._onError(error);
|
|
19043
20221
|
}
|
|
19044
|
-
return { files, depth, path:
|
|
20222
|
+
return { files, depth, path: path34 };
|
|
19045
20223
|
}
|
|
19046
|
-
async _formatEntry(dirent,
|
|
20224
|
+
async _formatEntry(dirent, path34) {
|
|
19047
20225
|
let entry;
|
|
19048
|
-
const
|
|
20226
|
+
const basename9 = this._isDirent ? dirent.name : dirent;
|
|
19049
20227
|
try {
|
|
19050
|
-
const fullPath = presolve(pjoin(
|
|
19051
|
-
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 };
|
|
19052
20230
|
entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
|
|
19053
20231
|
} catch (err) {
|
|
19054
20232
|
this._onError(err);
|
|
@@ -19447,16 +20625,16 @@ var delFromSet = (main, prop, item) => {
|
|
|
19447
20625
|
};
|
|
19448
20626
|
var isEmptySet = (val) => val instanceof Set ? val.size === 0 : !val;
|
|
19449
20627
|
var FsWatchInstances = /* @__PURE__ */ new Map();
|
|
19450
|
-
function createFsWatchInstance(
|
|
20628
|
+
function createFsWatchInstance(path34, options, listener, errHandler, emitRaw) {
|
|
19451
20629
|
const handleEvent = (rawEvent, evPath) => {
|
|
19452
|
-
listener(
|
|
19453
|
-
emitRaw(rawEvent, evPath, { watchedPath:
|
|
19454
|
-
if (evPath &&
|
|
19455
|
-
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));
|
|
19456
20634
|
}
|
|
19457
20635
|
};
|
|
19458
20636
|
try {
|
|
19459
|
-
return fs_watch(
|
|
20637
|
+
return fs_watch(path34, {
|
|
19460
20638
|
persistent: options.persistent
|
|
19461
20639
|
}, handleEvent);
|
|
19462
20640
|
} catch (error) {
|
|
@@ -19472,12 +20650,12 @@ var fsWatchBroadcast = (fullPath, listenerType, val1, val2, val3) => {
|
|
|
19472
20650
|
listener(val1, val2, val3);
|
|
19473
20651
|
});
|
|
19474
20652
|
};
|
|
19475
|
-
var setFsWatchListener = (
|
|
20653
|
+
var setFsWatchListener = (path34, fullPath, options, handlers) => {
|
|
19476
20654
|
const { listener, errHandler, rawEmitter } = handlers;
|
|
19477
20655
|
let cont = FsWatchInstances.get(fullPath);
|
|
19478
20656
|
let watcher;
|
|
19479
20657
|
if (!options.persistent) {
|
|
19480
|
-
watcher = createFsWatchInstance(
|
|
20658
|
+
watcher = createFsWatchInstance(path34, options, listener, errHandler, rawEmitter);
|
|
19481
20659
|
if (!watcher)
|
|
19482
20660
|
return;
|
|
19483
20661
|
return watcher.close.bind(watcher);
|
|
@@ -19488,7 +20666,7 @@ var setFsWatchListener = (path33, fullPath, options, handlers) => {
|
|
|
19488
20666
|
addAndConvert(cont, KEY_RAW, rawEmitter);
|
|
19489
20667
|
} else {
|
|
19490
20668
|
watcher = createFsWatchInstance(
|
|
19491
|
-
|
|
20669
|
+
path34,
|
|
19492
20670
|
options,
|
|
19493
20671
|
fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS),
|
|
19494
20672
|
errHandler,
|
|
@@ -19503,7 +20681,7 @@ var setFsWatchListener = (path33, fullPath, options, handlers) => {
|
|
|
19503
20681
|
cont.watcherUnusable = true;
|
|
19504
20682
|
if (isWindows && error.code === "EPERM") {
|
|
19505
20683
|
try {
|
|
19506
|
-
const fd = await open(
|
|
20684
|
+
const fd = await open(path34, "r");
|
|
19507
20685
|
await fd.close();
|
|
19508
20686
|
broadcastErr(error);
|
|
19509
20687
|
} catch (err) {
|
|
@@ -19534,7 +20712,7 @@ var setFsWatchListener = (path33, fullPath, options, handlers) => {
|
|
|
19534
20712
|
};
|
|
19535
20713
|
};
|
|
19536
20714
|
var FsWatchFileInstances = /* @__PURE__ */ new Map();
|
|
19537
|
-
var setFsWatchFileListener = (
|
|
20715
|
+
var setFsWatchFileListener = (path34, fullPath, options, handlers) => {
|
|
19538
20716
|
const { listener, rawEmitter } = handlers;
|
|
19539
20717
|
let cont = FsWatchFileInstances.get(fullPath);
|
|
19540
20718
|
const copts = cont && cont.options;
|
|
@@ -19556,7 +20734,7 @@ var setFsWatchFileListener = (path33, fullPath, options, handlers) => {
|
|
|
19556
20734
|
});
|
|
19557
20735
|
const currmtime = curr.mtimeMs;
|
|
19558
20736
|
if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {
|
|
19559
|
-
foreach(cont.listeners, (listener2) => listener2(
|
|
20737
|
+
foreach(cont.listeners, (listener2) => listener2(path34, curr));
|
|
19560
20738
|
}
|
|
19561
20739
|
})
|
|
19562
20740
|
};
|
|
@@ -19586,13 +20764,13 @@ var NodeFsHandler = class {
|
|
|
19586
20764
|
* @param listener on fs change
|
|
19587
20765
|
* @returns closer for the watcher instance
|
|
19588
20766
|
*/
|
|
19589
|
-
_watchWithNodeFs(
|
|
20767
|
+
_watchWithNodeFs(path34, listener) {
|
|
19590
20768
|
const opts = this.fsw.options;
|
|
19591
|
-
const directory = sp.dirname(
|
|
19592
|
-
const
|
|
20769
|
+
const directory = sp.dirname(path34);
|
|
20770
|
+
const basename9 = sp.basename(path34);
|
|
19593
20771
|
const parent = this.fsw._getWatchedDir(directory);
|
|
19594
|
-
parent.add(
|
|
19595
|
-
const absolutePath = sp.resolve(
|
|
20772
|
+
parent.add(basename9);
|
|
20773
|
+
const absolutePath = sp.resolve(path34);
|
|
19596
20774
|
const options = {
|
|
19597
20775
|
persistent: opts.persistent
|
|
19598
20776
|
};
|
|
@@ -19601,13 +20779,13 @@ var NodeFsHandler = class {
|
|
|
19601
20779
|
let closer;
|
|
19602
20780
|
if (opts.usePolling) {
|
|
19603
20781
|
const enableBin = opts.interval !== opts.binaryInterval;
|
|
19604
|
-
options.interval = enableBin && isBinaryPath(
|
|
19605
|
-
closer = setFsWatchFileListener(
|
|
20782
|
+
options.interval = enableBin && isBinaryPath(basename9) ? opts.binaryInterval : opts.interval;
|
|
20783
|
+
closer = setFsWatchFileListener(path34, absolutePath, options, {
|
|
19606
20784
|
listener,
|
|
19607
20785
|
rawEmitter: this.fsw._emitRaw
|
|
19608
20786
|
});
|
|
19609
20787
|
} else {
|
|
19610
|
-
closer = setFsWatchListener(
|
|
20788
|
+
closer = setFsWatchListener(path34, absolutePath, options, {
|
|
19611
20789
|
listener,
|
|
19612
20790
|
errHandler: this._boundHandleError,
|
|
19613
20791
|
rawEmitter: this.fsw._emitRaw
|
|
@@ -19623,13 +20801,13 @@ var NodeFsHandler = class {
|
|
|
19623
20801
|
if (this.fsw.closed) {
|
|
19624
20802
|
return;
|
|
19625
20803
|
}
|
|
19626
|
-
const
|
|
19627
|
-
const
|
|
19628
|
-
const parent = this.fsw._getWatchedDir(
|
|
20804
|
+
const dirname16 = sp.dirname(file);
|
|
20805
|
+
const basename9 = sp.basename(file);
|
|
20806
|
+
const parent = this.fsw._getWatchedDir(dirname16);
|
|
19629
20807
|
let prevStats = stats;
|
|
19630
|
-
if (parent.has(
|
|
20808
|
+
if (parent.has(basename9))
|
|
19631
20809
|
return;
|
|
19632
|
-
const listener = async (
|
|
20810
|
+
const listener = async (path34, newStats) => {
|
|
19633
20811
|
if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5))
|
|
19634
20812
|
return;
|
|
19635
20813
|
if (!newStats || newStats.mtimeMs === 0) {
|
|
@@ -19643,18 +20821,18 @@ var NodeFsHandler = class {
|
|
|
19643
20821
|
this.fsw._emit(EV.CHANGE, file, newStats2);
|
|
19644
20822
|
}
|
|
19645
20823
|
if ((isMacos || isLinux || isFreeBSD) && prevStats.ino !== newStats2.ino) {
|
|
19646
|
-
this.fsw._closeFile(
|
|
20824
|
+
this.fsw._closeFile(path34);
|
|
19647
20825
|
prevStats = newStats2;
|
|
19648
20826
|
const closer2 = this._watchWithNodeFs(file, listener);
|
|
19649
20827
|
if (closer2)
|
|
19650
|
-
this.fsw._addPathCloser(
|
|
20828
|
+
this.fsw._addPathCloser(path34, closer2);
|
|
19651
20829
|
} else {
|
|
19652
20830
|
prevStats = newStats2;
|
|
19653
20831
|
}
|
|
19654
20832
|
} catch (error) {
|
|
19655
|
-
this.fsw._remove(
|
|
20833
|
+
this.fsw._remove(dirname16, basename9);
|
|
19656
20834
|
}
|
|
19657
|
-
} else if (parent.has(
|
|
20835
|
+
} else if (parent.has(basename9)) {
|
|
19658
20836
|
const at = newStats.atimeMs;
|
|
19659
20837
|
const mt = newStats.mtimeMs;
|
|
19660
20838
|
if (!at || at <= mt || mt !== prevStats.mtimeMs) {
|
|
@@ -19679,7 +20857,7 @@ var NodeFsHandler = class {
|
|
|
19679
20857
|
* @param item basename of this item
|
|
19680
20858
|
* @returns true if no more processing is needed for this entry.
|
|
19681
20859
|
*/
|
|
19682
|
-
async _handleSymlink(entry, directory,
|
|
20860
|
+
async _handleSymlink(entry, directory, path34, item) {
|
|
19683
20861
|
if (this.fsw.closed) {
|
|
19684
20862
|
return;
|
|
19685
20863
|
}
|
|
@@ -19689,7 +20867,7 @@ var NodeFsHandler = class {
|
|
|
19689
20867
|
this.fsw._incrReadyCount();
|
|
19690
20868
|
let linkPath;
|
|
19691
20869
|
try {
|
|
19692
|
-
linkPath = await fsrealpath(
|
|
20870
|
+
linkPath = await fsrealpath(path34);
|
|
19693
20871
|
} catch (e) {
|
|
19694
20872
|
this.fsw._emitReady();
|
|
19695
20873
|
return true;
|
|
@@ -19699,12 +20877,12 @@ var NodeFsHandler = class {
|
|
|
19699
20877
|
if (dir.has(item)) {
|
|
19700
20878
|
if (this.fsw._symlinkPaths.get(full) !== linkPath) {
|
|
19701
20879
|
this.fsw._symlinkPaths.set(full, linkPath);
|
|
19702
|
-
this.fsw._emit(EV.CHANGE,
|
|
20880
|
+
this.fsw._emit(EV.CHANGE, path34, entry.stats);
|
|
19703
20881
|
}
|
|
19704
20882
|
} else {
|
|
19705
20883
|
dir.add(item);
|
|
19706
20884
|
this.fsw._symlinkPaths.set(full, linkPath);
|
|
19707
|
-
this.fsw._emit(EV.ADD,
|
|
20885
|
+
this.fsw._emit(EV.ADD, path34, entry.stats);
|
|
19708
20886
|
}
|
|
19709
20887
|
this.fsw._emitReady();
|
|
19710
20888
|
return true;
|
|
@@ -19734,9 +20912,9 @@ var NodeFsHandler = class {
|
|
|
19734
20912
|
return;
|
|
19735
20913
|
}
|
|
19736
20914
|
const item = entry.path;
|
|
19737
|
-
let
|
|
20915
|
+
let path34 = sp.join(directory, item);
|
|
19738
20916
|
current.add(item);
|
|
19739
|
-
if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory,
|
|
20917
|
+
if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path34, item)) {
|
|
19740
20918
|
return;
|
|
19741
20919
|
}
|
|
19742
20920
|
if (this.fsw.closed) {
|
|
@@ -19745,11 +20923,11 @@ var NodeFsHandler = class {
|
|
|
19745
20923
|
}
|
|
19746
20924
|
if (item === target || !target && !previous.has(item)) {
|
|
19747
20925
|
this.fsw._incrReadyCount();
|
|
19748
|
-
|
|
19749
|
-
this._addToNodeFs(
|
|
20926
|
+
path34 = sp.join(dir, sp.relative(dir, path34));
|
|
20927
|
+
this._addToNodeFs(path34, initialAdd, wh, depth + 1);
|
|
19750
20928
|
}
|
|
19751
20929
|
}).on(EV.ERROR, this._boundHandleError);
|
|
19752
|
-
return new Promise((
|
|
20930
|
+
return new Promise((resolve21, reject) => {
|
|
19753
20931
|
if (!stream)
|
|
19754
20932
|
return reject();
|
|
19755
20933
|
stream.once(STR_END, () => {
|
|
@@ -19758,7 +20936,7 @@ var NodeFsHandler = class {
|
|
|
19758
20936
|
return;
|
|
19759
20937
|
}
|
|
19760
20938
|
const wasThrottled = throttler ? throttler.clear() : false;
|
|
19761
|
-
|
|
20939
|
+
resolve21(void 0);
|
|
19762
20940
|
previous.getChildren().filter((item) => {
|
|
19763
20941
|
return item !== directory && !current.has(item);
|
|
19764
20942
|
}).forEach((item) => {
|
|
@@ -19815,13 +20993,13 @@ var NodeFsHandler = class {
|
|
|
19815
20993
|
* @param depth Child path actually targeted for watch
|
|
19816
20994
|
* @param target Child path actually targeted for watch
|
|
19817
20995
|
*/
|
|
19818
|
-
async _addToNodeFs(
|
|
20996
|
+
async _addToNodeFs(path34, initialAdd, priorWh, depth, target) {
|
|
19819
20997
|
const ready = this.fsw._emitReady;
|
|
19820
|
-
if (this.fsw._isIgnored(
|
|
20998
|
+
if (this.fsw._isIgnored(path34) || this.fsw.closed) {
|
|
19821
20999
|
ready();
|
|
19822
21000
|
return false;
|
|
19823
21001
|
}
|
|
19824
|
-
const wh = this.fsw._getWatchHelpers(
|
|
21002
|
+
const wh = this.fsw._getWatchHelpers(path34);
|
|
19825
21003
|
if (priorWh) {
|
|
19826
21004
|
wh.filterPath = (entry) => priorWh.filterPath(entry);
|
|
19827
21005
|
wh.filterDir = (entry) => priorWh.filterDir(entry);
|
|
@@ -19837,8 +21015,8 @@ var NodeFsHandler = class {
|
|
|
19837
21015
|
const follow = this.fsw.options.followSymlinks;
|
|
19838
21016
|
let closer;
|
|
19839
21017
|
if (stats.isDirectory()) {
|
|
19840
|
-
const absPath = sp.resolve(
|
|
19841
|
-
const targetPath = follow ? await fsrealpath(
|
|
21018
|
+
const absPath = sp.resolve(path34);
|
|
21019
|
+
const targetPath = follow ? await fsrealpath(path34) : path34;
|
|
19842
21020
|
if (this.fsw.closed)
|
|
19843
21021
|
return;
|
|
19844
21022
|
closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
|
|
@@ -19848,29 +21026,29 @@ var NodeFsHandler = class {
|
|
|
19848
21026
|
this.fsw._symlinkPaths.set(absPath, targetPath);
|
|
19849
21027
|
}
|
|
19850
21028
|
} else if (stats.isSymbolicLink()) {
|
|
19851
|
-
const targetPath = follow ? await fsrealpath(
|
|
21029
|
+
const targetPath = follow ? await fsrealpath(path34) : path34;
|
|
19852
21030
|
if (this.fsw.closed)
|
|
19853
21031
|
return;
|
|
19854
21032
|
const parent = sp.dirname(wh.watchPath);
|
|
19855
21033
|
this.fsw._getWatchedDir(parent).add(wh.watchPath);
|
|
19856
21034
|
this.fsw._emit(EV.ADD, wh.watchPath, stats);
|
|
19857
|
-
closer = await this._handleDir(parent, stats, initialAdd, depth,
|
|
21035
|
+
closer = await this._handleDir(parent, stats, initialAdd, depth, path34, wh, targetPath);
|
|
19858
21036
|
if (this.fsw.closed)
|
|
19859
21037
|
return;
|
|
19860
21038
|
if (targetPath !== void 0) {
|
|
19861
|
-
this.fsw._symlinkPaths.set(sp.resolve(
|
|
21039
|
+
this.fsw._symlinkPaths.set(sp.resolve(path34), targetPath);
|
|
19862
21040
|
}
|
|
19863
21041
|
} else {
|
|
19864
21042
|
closer = this._handleFile(wh.watchPath, stats, initialAdd);
|
|
19865
21043
|
}
|
|
19866
21044
|
ready();
|
|
19867
21045
|
if (closer)
|
|
19868
|
-
this.fsw._addPathCloser(
|
|
21046
|
+
this.fsw._addPathCloser(path34, closer);
|
|
19869
21047
|
return false;
|
|
19870
21048
|
} catch (error) {
|
|
19871
21049
|
if (this.fsw._handleError(error)) {
|
|
19872
21050
|
ready();
|
|
19873
|
-
return
|
|
21051
|
+
return path34;
|
|
19874
21052
|
}
|
|
19875
21053
|
}
|
|
19876
21054
|
}
|
|
@@ -19913,24 +21091,24 @@ function createPattern(matcher) {
|
|
|
19913
21091
|
}
|
|
19914
21092
|
return () => false;
|
|
19915
21093
|
}
|
|
19916
|
-
function normalizePath3(
|
|
19917
|
-
if (typeof
|
|
21094
|
+
function normalizePath3(path34) {
|
|
21095
|
+
if (typeof path34 !== "string")
|
|
19918
21096
|
throw new Error("string expected");
|
|
19919
|
-
|
|
19920
|
-
|
|
21097
|
+
path34 = sp2.normalize(path34);
|
|
21098
|
+
path34 = path34.replace(/\\/g, "/");
|
|
19921
21099
|
let prepend = false;
|
|
19922
|
-
if (
|
|
21100
|
+
if (path34.startsWith("//"))
|
|
19923
21101
|
prepend = true;
|
|
19924
|
-
|
|
21102
|
+
path34 = path34.replace(DOUBLE_SLASH_RE, "/");
|
|
19925
21103
|
if (prepend)
|
|
19926
|
-
|
|
19927
|
-
return
|
|
21104
|
+
path34 = "/" + path34;
|
|
21105
|
+
return path34;
|
|
19928
21106
|
}
|
|
19929
21107
|
function matchPatterns(patterns, testString, stats) {
|
|
19930
|
-
const
|
|
21108
|
+
const path34 = normalizePath3(testString);
|
|
19931
21109
|
for (let index = 0; index < patterns.length; index++) {
|
|
19932
21110
|
const pattern = patterns[index];
|
|
19933
|
-
if (pattern(
|
|
21111
|
+
if (pattern(path34, stats)) {
|
|
19934
21112
|
return true;
|
|
19935
21113
|
}
|
|
19936
21114
|
}
|
|
@@ -19968,19 +21146,19 @@ var toUnix = (string) => {
|
|
|
19968
21146
|
}
|
|
19969
21147
|
return str;
|
|
19970
21148
|
};
|
|
19971
|
-
var normalizePathToUnix = (
|
|
19972
|
-
var normalizeIgnored = (cwd = "") => (
|
|
19973
|
-
if (typeof
|
|
19974
|
-
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));
|
|
19975
21153
|
} else {
|
|
19976
|
-
return
|
|
21154
|
+
return path34;
|
|
19977
21155
|
}
|
|
19978
21156
|
};
|
|
19979
|
-
var getAbsolutePath = (
|
|
19980
|
-
if (sp2.isAbsolute(
|
|
19981
|
-
return
|
|
21157
|
+
var getAbsolutePath = (path34, cwd) => {
|
|
21158
|
+
if (sp2.isAbsolute(path34)) {
|
|
21159
|
+
return path34;
|
|
19982
21160
|
}
|
|
19983
|
-
return sp2.join(cwd,
|
|
21161
|
+
return sp2.join(cwd, path34);
|
|
19984
21162
|
};
|
|
19985
21163
|
var EMPTY_SET = Object.freeze(/* @__PURE__ */ new Set());
|
|
19986
21164
|
var DirEntry = class {
|
|
@@ -20045,10 +21223,10 @@ var WatchHelper = class {
|
|
|
20045
21223
|
dirParts;
|
|
20046
21224
|
followSymlinks;
|
|
20047
21225
|
statMethod;
|
|
20048
|
-
constructor(
|
|
21226
|
+
constructor(path34, follow, fsw) {
|
|
20049
21227
|
this.fsw = fsw;
|
|
20050
|
-
const watchPath =
|
|
20051
|
-
this.path =
|
|
21228
|
+
const watchPath = path34;
|
|
21229
|
+
this.path = path34 = path34.replace(REPLACER_RE, "");
|
|
20052
21230
|
this.watchPath = watchPath;
|
|
20053
21231
|
this.fullWatchPath = sp2.resolve(watchPath);
|
|
20054
21232
|
this.dirParts = [];
|
|
@@ -20188,20 +21366,20 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
20188
21366
|
this._closePromise = void 0;
|
|
20189
21367
|
let paths = unifyPaths(paths_);
|
|
20190
21368
|
if (cwd) {
|
|
20191
|
-
paths = paths.map((
|
|
20192
|
-
const absPath = getAbsolutePath(
|
|
21369
|
+
paths = paths.map((path34) => {
|
|
21370
|
+
const absPath = getAbsolutePath(path34, cwd);
|
|
20193
21371
|
return absPath;
|
|
20194
21372
|
});
|
|
20195
21373
|
}
|
|
20196
|
-
paths.forEach((
|
|
20197
|
-
this._removeIgnoredPath(
|
|
21374
|
+
paths.forEach((path34) => {
|
|
21375
|
+
this._removeIgnoredPath(path34);
|
|
20198
21376
|
});
|
|
20199
21377
|
this._userIgnored = void 0;
|
|
20200
21378
|
if (!this._readyCount)
|
|
20201
21379
|
this._readyCount = 0;
|
|
20202
21380
|
this._readyCount += paths.length;
|
|
20203
|
-
Promise.all(paths.map(async (
|
|
20204
|
-
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);
|
|
20205
21383
|
if (res)
|
|
20206
21384
|
this._emitReady();
|
|
20207
21385
|
return res;
|
|
@@ -20223,17 +21401,17 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
20223
21401
|
return this;
|
|
20224
21402
|
const paths = unifyPaths(paths_);
|
|
20225
21403
|
const { cwd } = this.options;
|
|
20226
|
-
paths.forEach((
|
|
20227
|
-
if (!sp2.isAbsolute(
|
|
21404
|
+
paths.forEach((path34) => {
|
|
21405
|
+
if (!sp2.isAbsolute(path34) && !this._closers.has(path34)) {
|
|
20228
21406
|
if (cwd)
|
|
20229
|
-
|
|
20230
|
-
|
|
21407
|
+
path34 = sp2.join(cwd, path34);
|
|
21408
|
+
path34 = sp2.resolve(path34);
|
|
20231
21409
|
}
|
|
20232
|
-
this._closePath(
|
|
20233
|
-
this._addIgnoredPath(
|
|
20234
|
-
if (this._watched.has(
|
|
21410
|
+
this._closePath(path34);
|
|
21411
|
+
this._addIgnoredPath(path34);
|
|
21412
|
+
if (this._watched.has(path34)) {
|
|
20235
21413
|
this._addIgnoredPath({
|
|
20236
|
-
path:
|
|
21414
|
+
path: path34,
|
|
20237
21415
|
recursive: true
|
|
20238
21416
|
});
|
|
20239
21417
|
}
|
|
@@ -20297,38 +21475,38 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
20297
21475
|
* @param stats arguments to be passed with event
|
|
20298
21476
|
* @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag
|
|
20299
21477
|
*/
|
|
20300
|
-
async _emit(event,
|
|
21478
|
+
async _emit(event, path34, stats) {
|
|
20301
21479
|
if (this.closed)
|
|
20302
21480
|
return;
|
|
20303
21481
|
const opts = this.options;
|
|
20304
21482
|
if (isWindows)
|
|
20305
|
-
|
|
21483
|
+
path34 = sp2.normalize(path34);
|
|
20306
21484
|
if (opts.cwd)
|
|
20307
|
-
|
|
20308
|
-
const args = [
|
|
21485
|
+
path34 = sp2.relative(opts.cwd, path34);
|
|
21486
|
+
const args = [path34];
|
|
20309
21487
|
if (stats != null)
|
|
20310
21488
|
args.push(stats);
|
|
20311
21489
|
const awf = opts.awaitWriteFinish;
|
|
20312
21490
|
let pw;
|
|
20313
|
-
if (awf && (pw = this._pendingWrites.get(
|
|
21491
|
+
if (awf && (pw = this._pendingWrites.get(path34))) {
|
|
20314
21492
|
pw.lastChange = /* @__PURE__ */ new Date();
|
|
20315
21493
|
return this;
|
|
20316
21494
|
}
|
|
20317
21495
|
if (opts.atomic) {
|
|
20318
21496
|
if (event === EVENTS.UNLINK) {
|
|
20319
|
-
this._pendingUnlinks.set(
|
|
21497
|
+
this._pendingUnlinks.set(path34, [event, ...args]);
|
|
20320
21498
|
setTimeout(() => {
|
|
20321
|
-
this._pendingUnlinks.forEach((entry,
|
|
21499
|
+
this._pendingUnlinks.forEach((entry, path35) => {
|
|
20322
21500
|
this.emit(...entry);
|
|
20323
21501
|
this.emit(EVENTS.ALL, ...entry);
|
|
20324
|
-
this._pendingUnlinks.delete(
|
|
21502
|
+
this._pendingUnlinks.delete(path35);
|
|
20325
21503
|
});
|
|
20326
21504
|
}, typeof opts.atomic === "number" ? opts.atomic : 100);
|
|
20327
21505
|
return this;
|
|
20328
21506
|
}
|
|
20329
|
-
if (event === EVENTS.ADD && this._pendingUnlinks.has(
|
|
21507
|
+
if (event === EVENTS.ADD && this._pendingUnlinks.has(path34)) {
|
|
20330
21508
|
event = EVENTS.CHANGE;
|
|
20331
|
-
this._pendingUnlinks.delete(
|
|
21509
|
+
this._pendingUnlinks.delete(path34);
|
|
20332
21510
|
}
|
|
20333
21511
|
}
|
|
20334
21512
|
if (awf && (event === EVENTS.ADD || event === EVENTS.CHANGE) && this._readyEmitted) {
|
|
@@ -20346,16 +21524,16 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
20346
21524
|
this.emitWithAll(event, args);
|
|
20347
21525
|
}
|
|
20348
21526
|
};
|
|
20349
|
-
this._awaitWriteFinish(
|
|
21527
|
+
this._awaitWriteFinish(path34, awf.stabilityThreshold, event, awfEmit);
|
|
20350
21528
|
return this;
|
|
20351
21529
|
}
|
|
20352
21530
|
if (event === EVENTS.CHANGE) {
|
|
20353
|
-
const isThrottled = !this._throttle(EVENTS.CHANGE,
|
|
21531
|
+
const isThrottled = !this._throttle(EVENTS.CHANGE, path34, 50);
|
|
20354
21532
|
if (isThrottled)
|
|
20355
21533
|
return this;
|
|
20356
21534
|
}
|
|
20357
21535
|
if (opts.alwaysStat && stats === void 0 && (event === EVENTS.ADD || event === EVENTS.ADD_DIR || event === EVENTS.CHANGE)) {
|
|
20358
|
-
const fullPath = opts.cwd ? sp2.join(opts.cwd,
|
|
21536
|
+
const fullPath = opts.cwd ? sp2.join(opts.cwd, path34) : path34;
|
|
20359
21537
|
let stats2;
|
|
20360
21538
|
try {
|
|
20361
21539
|
stats2 = await stat3(fullPath);
|
|
@@ -20386,23 +21564,23 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
20386
21564
|
* @param timeout duration of time to suppress duplicate actions
|
|
20387
21565
|
* @returns tracking object or false if action should be suppressed
|
|
20388
21566
|
*/
|
|
20389
|
-
_throttle(actionType,
|
|
21567
|
+
_throttle(actionType, path34, timeout) {
|
|
20390
21568
|
if (!this._throttled.has(actionType)) {
|
|
20391
21569
|
this._throttled.set(actionType, /* @__PURE__ */ new Map());
|
|
20392
21570
|
}
|
|
20393
21571
|
const action = this._throttled.get(actionType);
|
|
20394
21572
|
if (!action)
|
|
20395
21573
|
throw new Error("invalid throttle");
|
|
20396
|
-
const actionPath = action.get(
|
|
21574
|
+
const actionPath = action.get(path34);
|
|
20397
21575
|
if (actionPath) {
|
|
20398
21576
|
actionPath.count++;
|
|
20399
21577
|
return false;
|
|
20400
21578
|
}
|
|
20401
21579
|
let timeoutObject;
|
|
20402
21580
|
const clear = () => {
|
|
20403
|
-
const item = action.get(
|
|
21581
|
+
const item = action.get(path34);
|
|
20404
21582
|
const count = item ? item.count : 0;
|
|
20405
|
-
action.delete(
|
|
21583
|
+
action.delete(path34);
|
|
20406
21584
|
clearTimeout(timeoutObject);
|
|
20407
21585
|
if (item)
|
|
20408
21586
|
clearTimeout(item.timeoutObject);
|
|
@@ -20410,7 +21588,7 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
20410
21588
|
};
|
|
20411
21589
|
timeoutObject = setTimeout(clear, timeout);
|
|
20412
21590
|
const thr = { timeoutObject, clear, count: 0 };
|
|
20413
|
-
action.set(
|
|
21591
|
+
action.set(path34, thr);
|
|
20414
21592
|
return thr;
|
|
20415
21593
|
}
|
|
20416
21594
|
_incrReadyCount() {
|
|
@@ -20424,44 +21602,44 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
20424
21602
|
* @param event
|
|
20425
21603
|
* @param awfEmit Callback to be called when ready for event to be emitted.
|
|
20426
21604
|
*/
|
|
20427
|
-
_awaitWriteFinish(
|
|
21605
|
+
_awaitWriteFinish(path34, threshold, event, awfEmit) {
|
|
20428
21606
|
const awf = this.options.awaitWriteFinish;
|
|
20429
21607
|
if (typeof awf !== "object")
|
|
20430
21608
|
return;
|
|
20431
21609
|
const pollInterval = awf.pollInterval;
|
|
20432
21610
|
let timeoutHandler;
|
|
20433
|
-
let fullPath =
|
|
20434
|
-
if (this.options.cwd && !sp2.isAbsolute(
|
|
20435
|
-
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);
|
|
20436
21614
|
}
|
|
20437
21615
|
const now2 = /* @__PURE__ */ new Date();
|
|
20438
21616
|
const writes = this._pendingWrites;
|
|
20439
21617
|
function awaitWriteFinishFn(prevStat) {
|
|
20440
21618
|
statcb(fullPath, (err, curStat) => {
|
|
20441
|
-
if (err || !writes.has(
|
|
21619
|
+
if (err || !writes.has(path34)) {
|
|
20442
21620
|
if (err && err.code !== "ENOENT")
|
|
20443
21621
|
awfEmit(err);
|
|
20444
21622
|
return;
|
|
20445
21623
|
}
|
|
20446
21624
|
const now3 = Number(/* @__PURE__ */ new Date());
|
|
20447
21625
|
if (prevStat && curStat.size !== prevStat.size) {
|
|
20448
|
-
writes.get(
|
|
21626
|
+
writes.get(path34).lastChange = now3;
|
|
20449
21627
|
}
|
|
20450
|
-
const pw = writes.get(
|
|
21628
|
+
const pw = writes.get(path34);
|
|
20451
21629
|
const df = now3 - pw.lastChange;
|
|
20452
21630
|
if (df >= threshold) {
|
|
20453
|
-
writes.delete(
|
|
21631
|
+
writes.delete(path34);
|
|
20454
21632
|
awfEmit(void 0, curStat);
|
|
20455
21633
|
} else {
|
|
20456
21634
|
timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat);
|
|
20457
21635
|
}
|
|
20458
21636
|
});
|
|
20459
21637
|
}
|
|
20460
|
-
if (!writes.has(
|
|
20461
|
-
writes.set(
|
|
21638
|
+
if (!writes.has(path34)) {
|
|
21639
|
+
writes.set(path34, {
|
|
20462
21640
|
lastChange: now2,
|
|
20463
21641
|
cancelWait: () => {
|
|
20464
|
-
writes.delete(
|
|
21642
|
+
writes.delete(path34);
|
|
20465
21643
|
clearTimeout(timeoutHandler);
|
|
20466
21644
|
return event;
|
|
20467
21645
|
}
|
|
@@ -20472,8 +21650,8 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
20472
21650
|
/**
|
|
20473
21651
|
* Determines whether user has asked to ignore this path.
|
|
20474
21652
|
*/
|
|
20475
|
-
_isIgnored(
|
|
20476
|
-
if (this.options.atomic && DOT_RE.test(
|
|
21653
|
+
_isIgnored(path34, stats) {
|
|
21654
|
+
if (this.options.atomic && DOT_RE.test(path34))
|
|
20477
21655
|
return true;
|
|
20478
21656
|
if (!this._userIgnored) {
|
|
20479
21657
|
const { cwd } = this.options;
|
|
@@ -20483,17 +21661,17 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
20483
21661
|
const list = [...ignoredPaths.map(normalizeIgnored(cwd)), ...ignored];
|
|
20484
21662
|
this._userIgnored = anymatch(list, void 0);
|
|
20485
21663
|
}
|
|
20486
|
-
return this._userIgnored(
|
|
21664
|
+
return this._userIgnored(path34, stats);
|
|
20487
21665
|
}
|
|
20488
|
-
_isntIgnored(
|
|
20489
|
-
return !this._isIgnored(
|
|
21666
|
+
_isntIgnored(path34, stat5) {
|
|
21667
|
+
return !this._isIgnored(path34, stat5);
|
|
20490
21668
|
}
|
|
20491
21669
|
/**
|
|
20492
21670
|
* Provides a set of common helpers and properties relating to symlink handling.
|
|
20493
21671
|
* @param path file or directory pattern being watched
|
|
20494
21672
|
*/
|
|
20495
|
-
_getWatchHelpers(
|
|
20496
|
-
return new WatchHelper(
|
|
21673
|
+
_getWatchHelpers(path34) {
|
|
21674
|
+
return new WatchHelper(path34, this.options.followSymlinks, this);
|
|
20497
21675
|
}
|
|
20498
21676
|
// Directory helpers
|
|
20499
21677
|
// -----------------
|
|
@@ -20525,63 +21703,63 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
20525
21703
|
* @param item base path of item/directory
|
|
20526
21704
|
*/
|
|
20527
21705
|
_remove(directory, item, isDirectory) {
|
|
20528
|
-
const
|
|
20529
|
-
const fullPath = sp2.resolve(
|
|
20530
|
-
isDirectory = isDirectory != null ? isDirectory : this._watched.has(
|
|
20531
|
-
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))
|
|
20532
21710
|
return;
|
|
20533
21711
|
if (!isDirectory && this._watched.size === 1) {
|
|
20534
21712
|
this.add(directory, item, true);
|
|
20535
21713
|
}
|
|
20536
|
-
const wp = this._getWatchedDir(
|
|
21714
|
+
const wp = this._getWatchedDir(path34);
|
|
20537
21715
|
const nestedDirectoryChildren = wp.getChildren();
|
|
20538
|
-
nestedDirectoryChildren.forEach((nested) => this._remove(
|
|
21716
|
+
nestedDirectoryChildren.forEach((nested) => this._remove(path34, nested));
|
|
20539
21717
|
const parent = this._getWatchedDir(directory);
|
|
20540
21718
|
const wasTracked = parent.has(item);
|
|
20541
21719
|
parent.remove(item);
|
|
20542
21720
|
if (this._symlinkPaths.has(fullPath)) {
|
|
20543
21721
|
this._symlinkPaths.delete(fullPath);
|
|
20544
21722
|
}
|
|
20545
|
-
let relPath =
|
|
21723
|
+
let relPath = path34;
|
|
20546
21724
|
if (this.options.cwd)
|
|
20547
|
-
relPath = sp2.relative(this.options.cwd,
|
|
21725
|
+
relPath = sp2.relative(this.options.cwd, path34);
|
|
20548
21726
|
if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
|
|
20549
21727
|
const event = this._pendingWrites.get(relPath).cancelWait();
|
|
20550
21728
|
if (event === EVENTS.ADD)
|
|
20551
21729
|
return;
|
|
20552
21730
|
}
|
|
20553
|
-
this._watched.delete(
|
|
21731
|
+
this._watched.delete(path34);
|
|
20554
21732
|
this._watched.delete(fullPath);
|
|
20555
21733
|
const eventName = isDirectory ? EVENTS.UNLINK_DIR : EVENTS.UNLINK;
|
|
20556
|
-
if (wasTracked && !this._isIgnored(
|
|
20557
|
-
this._emit(eventName,
|
|
20558
|
-
this._closePath(
|
|
21734
|
+
if (wasTracked && !this._isIgnored(path34))
|
|
21735
|
+
this._emit(eventName, path34);
|
|
21736
|
+
this._closePath(path34);
|
|
20559
21737
|
}
|
|
20560
21738
|
/**
|
|
20561
21739
|
* Closes all watchers for a path
|
|
20562
21740
|
*/
|
|
20563
|
-
_closePath(
|
|
20564
|
-
this._closeFile(
|
|
20565
|
-
const dir = sp2.dirname(
|
|
20566
|
-
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));
|
|
20567
21745
|
}
|
|
20568
21746
|
/**
|
|
20569
21747
|
* Closes only file-specific watchers
|
|
20570
21748
|
*/
|
|
20571
|
-
_closeFile(
|
|
20572
|
-
const closers = this._closers.get(
|
|
21749
|
+
_closeFile(path34) {
|
|
21750
|
+
const closers = this._closers.get(path34);
|
|
20573
21751
|
if (!closers)
|
|
20574
21752
|
return;
|
|
20575
21753
|
closers.forEach((closer) => closer());
|
|
20576
|
-
this._closers.delete(
|
|
21754
|
+
this._closers.delete(path34);
|
|
20577
21755
|
}
|
|
20578
|
-
_addPathCloser(
|
|
21756
|
+
_addPathCloser(path34, closer) {
|
|
20579
21757
|
if (!closer)
|
|
20580
21758
|
return;
|
|
20581
|
-
let list = this._closers.get(
|
|
21759
|
+
let list = this._closers.get(path34);
|
|
20582
21760
|
if (!list) {
|
|
20583
21761
|
list = [];
|
|
20584
|
-
this._closers.set(
|
|
21762
|
+
this._closers.set(path34, list);
|
|
20585
21763
|
}
|
|
20586
21764
|
list.push(closer);
|
|
20587
21765
|
}
|
|
@@ -20611,11 +21789,11 @@ function watch(paths, options = {}) {
|
|
|
20611
21789
|
var chokidar_default = { watch, FSWatcher };
|
|
20612
21790
|
|
|
20613
21791
|
// src/watcher/file-watcher.ts
|
|
20614
|
-
import * as
|
|
21792
|
+
import * as path29 from "path";
|
|
20615
21793
|
|
|
20616
21794
|
// src/watcher/native-recursive-watcher.ts
|
|
20617
21795
|
import { watch as watch2 } from "fs";
|
|
20618
|
-
import * as
|
|
21796
|
+
import * as path27 from "path";
|
|
20619
21797
|
var NativeRecursiveWatcher = class {
|
|
20620
21798
|
constructor(root, onChange, options = {}) {
|
|
20621
21799
|
this.root = root;
|
|
@@ -20663,9 +21841,9 @@ var NativeRecursiveWatcher = class {
|
|
|
20663
21841
|
toAbsolutePath(filename) {
|
|
20664
21842
|
if (filename == null) return null;
|
|
20665
21843
|
const normalizedFilename = typeof filename === "string" ? filename : filename.toString();
|
|
20666
|
-
const absolutePath =
|
|
20667
|
-
const relativePath =
|
|
20668
|
-
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);
|
|
20669
21847
|
return outsideRoot ? null : absolutePath;
|
|
20670
21848
|
}
|
|
20671
21849
|
defaultWatchFactory = (root, listener, options) => watch2(root, options, listener);
|
|
@@ -20673,16 +21851,16 @@ var NativeRecursiveWatcher = class {
|
|
|
20673
21851
|
|
|
20674
21852
|
// src/watcher/snapshot.ts
|
|
20675
21853
|
import * as fsPromises4 from "fs/promises";
|
|
20676
|
-
import * as
|
|
21854
|
+
import * as path28 from "path";
|
|
20677
21855
|
async function buildFileSnapshotScan(projectRoot, config, configPaths = []) {
|
|
20678
|
-
const normalizedProjectRoot =
|
|
21856
|
+
const normalizedProjectRoot = path28.resolve(projectRoot);
|
|
20679
21857
|
const ignoreFilter = createIgnoreFilter(normalizedProjectRoot);
|
|
20680
21858
|
const includePatterns = [...config.include, ...config.additionalInclude ?? []];
|
|
20681
21859
|
const maxDepth = config.indexing?.maxDepth ?? -1;
|
|
20682
21860
|
const snapshot = /* @__PURE__ */ new Map();
|
|
20683
21861
|
const unreadablePrefixes = /* @__PURE__ */ new Set();
|
|
20684
21862
|
const includeFile = async (filePath) => {
|
|
20685
|
-
const normalizedPath3 =
|
|
21863
|
+
const normalizedPath3 = path28.resolve(filePath);
|
|
20686
21864
|
if (!shouldIncludeFile(normalizedPath3, normalizedProjectRoot, includePatterns, config.exclude, ignoreFilter)) return;
|
|
20687
21865
|
const stat5 = await readStatIfFile(normalizedPath3, unreadablePrefixes);
|
|
20688
21866
|
if (stat5) snapshot.set(normalizedPath3, { size: stat5.size, mtimeMs: stat5.mtimeMs });
|
|
@@ -20694,16 +21872,16 @@ async function buildFileSnapshotScan(projectRoot, config, configPaths = []) {
|
|
|
20694
21872
|
} catch (error) {
|
|
20695
21873
|
if (isMissingFsError(error)) return;
|
|
20696
21874
|
if (isPermissionFsError(error)) {
|
|
20697
|
-
unreadablePrefixes.add(
|
|
21875
|
+
unreadablePrefixes.add(path28.resolve(directoryPath));
|
|
20698
21876
|
return;
|
|
20699
21877
|
}
|
|
20700
21878
|
throw error;
|
|
20701
21879
|
}
|
|
20702
21880
|
for (const entry of entries) {
|
|
20703
|
-
const fullPath =
|
|
20704
|
-
const relativePath =
|
|
21881
|
+
const fullPath = path28.join(directoryPath, entry.name);
|
|
21882
|
+
const relativePath = path28.relative(normalizedProjectRoot, fullPath);
|
|
20705
21883
|
if (entry.isDirectory()) {
|
|
20706
|
-
if (hasFilteredPathSegment(relativePath,
|
|
21884
|
+
if (hasFilteredPathSegment(relativePath, path28.sep) || isRestrictedDirectory(relativePath, path28.sep)) continue;
|
|
20707
21885
|
if (ignoreFilter.ignores(relativePath)) continue;
|
|
20708
21886
|
if (maxDepth === -1 || depth < maxDepth) await walk(fullPath, depth + 1);
|
|
20709
21887
|
} else if (entry.isFile()) {
|
|
@@ -20716,19 +21894,19 @@ async function buildFileSnapshotScan(projectRoot, config, configPaths = []) {
|
|
|
20716
21894
|
return { entries: snapshot, unreadablePrefixes };
|
|
20717
21895
|
}
|
|
20718
21896
|
async function buildFileSnapshotForPathScan(projectRoot, config, configPaths, targetPath) {
|
|
20719
|
-
const normalizedProjectRoot =
|
|
20720
|
-
const normalizedTargetPath =
|
|
21897
|
+
const normalizedProjectRoot = path28.resolve(projectRoot);
|
|
21898
|
+
const normalizedTargetPath = path28.resolve(targetPath);
|
|
20721
21899
|
if (!isWithinPath(normalizedProjectRoot, normalizedTargetPath)) {
|
|
20722
21900
|
return { entries: /* @__PURE__ */ new Map(), unreadablePrefixes: /* @__PURE__ */ new Set() };
|
|
20723
21901
|
}
|
|
20724
21902
|
const ignoreFilter = createIgnoreFilter(normalizedProjectRoot);
|
|
20725
21903
|
const includePatterns = [...config.include, ...config.additionalInclude ?? []];
|
|
20726
21904
|
const maxDepth = config.indexing?.maxDepth ?? -1;
|
|
20727
|
-
const explicitConfigPaths = new Set(configPaths.map((configPath) =>
|
|
21905
|
+
const explicitConfigPaths = new Set(configPaths.map((configPath) => path28.resolve(configPath)));
|
|
20728
21906
|
const snapshot = /* @__PURE__ */ new Map();
|
|
20729
21907
|
const unreadablePrefixes = /* @__PURE__ */ new Set();
|
|
20730
21908
|
const includeFile = async (filePath) => {
|
|
20731
|
-
const normalizedPath3 =
|
|
21909
|
+
const normalizedPath3 = path28.resolve(filePath);
|
|
20732
21910
|
if (!explicitConfigPaths.has(normalizedPath3) && !shouldIncludeFile(
|
|
20733
21911
|
normalizedPath3,
|
|
20734
21912
|
normalizedProjectRoot,
|
|
@@ -20746,16 +21924,16 @@ async function buildFileSnapshotForPathScan(projectRoot, config, configPaths, ta
|
|
|
20746
21924
|
} catch (error) {
|
|
20747
21925
|
if (isMissingFsError(error)) return;
|
|
20748
21926
|
if (isPermissionFsError(error)) {
|
|
20749
|
-
unreadablePrefixes.add(
|
|
21927
|
+
unreadablePrefixes.add(path28.resolve(directoryPath));
|
|
20750
21928
|
return;
|
|
20751
21929
|
}
|
|
20752
21930
|
throw error;
|
|
20753
21931
|
}
|
|
20754
21932
|
for (const entry of entries) {
|
|
20755
|
-
const fullPath =
|
|
20756
|
-
const relativePath =
|
|
21933
|
+
const fullPath = path28.join(directoryPath, entry.name);
|
|
21934
|
+
const relativePath = path28.relative(normalizedProjectRoot, fullPath);
|
|
20757
21935
|
if (entry.isDirectory()) {
|
|
20758
|
-
if (hasFilteredPathSegment(relativePath,
|
|
21936
|
+
if (hasFilteredPathSegment(relativePath, path28.sep) || isRestrictedDirectory(relativePath, path28.sep)) continue;
|
|
20759
21937
|
if (ignoreFilter.ignores(relativePath)) continue;
|
|
20760
21938
|
if (maxDepth === -1 || depth < maxDepth) await walk(fullPath, depth + 1);
|
|
20761
21939
|
} else if (entry.isFile()) {
|
|
@@ -20779,7 +21957,7 @@ function completeFileSnapshot(previous, scan) {
|
|
|
20779
21957
|
return completed;
|
|
20780
21958
|
}
|
|
20781
21959
|
async function includeExplicitConfigPaths(snapshot, unreadablePrefixes, configPaths) {
|
|
20782
|
-
for (const configPath of [...new Set(configPaths.map((value) =>
|
|
21960
|
+
for (const configPath of [...new Set(configPaths.map((value) => path28.resolve(value)))]) {
|
|
20783
21961
|
if (snapshot.has(configPath)) continue;
|
|
20784
21962
|
const stat5 = await readStatIfFile(configPath, unreadablePrefixes);
|
|
20785
21963
|
if (stat5) snapshot.set(configPath, { size: stat5.size, mtimeMs: stat5.mtimeMs });
|
|
@@ -20789,12 +21967,12 @@ async function includeExplicitConfigPathsInPath(snapshot, unreadablePrefixes, co
|
|
|
20789
21967
|
await includeExplicitConfigPaths(
|
|
20790
21968
|
snapshot,
|
|
20791
21969
|
unreadablePrefixes,
|
|
20792
|
-
configPaths.filter((configPath) => isWithinPath(targetPath,
|
|
21970
|
+
configPaths.filter((configPath) => isWithinPath(targetPath, path28.resolve(configPath)))
|
|
20793
21971
|
);
|
|
20794
21972
|
}
|
|
20795
21973
|
function isWithinPath(parentPath, childPath) {
|
|
20796
|
-
const relativePath =
|
|
20797
|
-
return relativePath === "" || !relativePath.startsWith(`..${
|
|
21974
|
+
const relativePath = path28.relative(parentPath, childPath);
|
|
21975
|
+
return relativePath === "" || !relativePath.startsWith(`..${path28.sep}`) && relativePath !== ".." && !path28.isAbsolute(relativePath);
|
|
20798
21976
|
}
|
|
20799
21977
|
async function readStatIfFile(filePath, unreadablePrefixes) {
|
|
20800
21978
|
try {
|
|
@@ -20803,7 +21981,7 @@ async function readStatIfFile(filePath, unreadablePrefixes) {
|
|
|
20803
21981
|
} catch (error) {
|
|
20804
21982
|
if (isMissingFsError(error)) return null;
|
|
20805
21983
|
if (isPermissionFsError(error)) {
|
|
20806
|
-
unreadablePrefixes.add(
|
|
21984
|
+
unreadablePrefixes.add(path28.resolve(filePath));
|
|
20807
21985
|
return null;
|
|
20808
21986
|
}
|
|
20809
21987
|
throw error;
|
|
@@ -20940,8 +22118,8 @@ var FileWatcher = class {
|
|
|
20940
22118
|
this.createWatcher();
|
|
20941
22119
|
}
|
|
20942
22120
|
resetReady() {
|
|
20943
|
-
this.readyPromise = new Promise((
|
|
20944
|
-
this.resolveReady =
|
|
22121
|
+
this.readyPromise = new Promise((resolve21) => {
|
|
22122
|
+
this.resolveReady = resolve21;
|
|
20945
22123
|
});
|
|
20946
22124
|
this.startupReadySignals = 1;
|
|
20947
22125
|
}
|
|
@@ -20972,7 +22150,7 @@ var FileWatcher = class {
|
|
|
20972
22150
|
const resolvedWatchTargets = watchTargets ?? this.getFullChokidarWatchTargets();
|
|
20973
22151
|
const watcherOptions = {
|
|
20974
22152
|
ignored: (filePath) => {
|
|
20975
|
-
const relativePath =
|
|
22153
|
+
const relativePath = path29.relative(this.projectRoot, filePath);
|
|
20976
22154
|
if (!relativePath) return false;
|
|
20977
22155
|
if (this.isProjectConfigPathOrAncestor(relativePath)) {
|
|
20978
22156
|
return false;
|
|
@@ -20980,10 +22158,10 @@ var FileWatcher = class {
|
|
|
20980
22158
|
if (this.isOutsideProjectPath(relativePath)) {
|
|
20981
22159
|
return true;
|
|
20982
22160
|
}
|
|
20983
|
-
if (hasFilteredPathSegment(relativePath,
|
|
22161
|
+
if (hasFilteredPathSegment(relativePath, path29.sep)) {
|
|
20984
22162
|
return true;
|
|
20985
22163
|
}
|
|
20986
|
-
if (isRestrictedDirectory(relativePath,
|
|
22164
|
+
if (isRestrictedDirectory(relativePath, path29.sep)) {
|
|
20987
22165
|
return true;
|
|
20988
22166
|
}
|
|
20989
22167
|
if (ignoreFilter.ignores(relativePath)) {
|
|
@@ -21074,13 +22252,13 @@ var FileWatcher = class {
|
|
|
21074
22252
|
getExternalConfigWatchTargets() {
|
|
21075
22253
|
return [...new Set(
|
|
21076
22254
|
this.projectConfigPaths.filter((projectConfigPath) => {
|
|
21077
|
-
const relativeConfigPath =
|
|
22255
|
+
const relativeConfigPath = path29.relative(this.projectRoot, projectConfigPath);
|
|
21078
22256
|
return this.isOutsideProjectPath(relativeConfigPath);
|
|
21079
22257
|
}).map((projectConfigPath) => {
|
|
21080
|
-
if (
|
|
22258
|
+
if (existsSync16(projectConfigPath)) {
|
|
21081
22259
|
return projectConfigPath;
|
|
21082
22260
|
}
|
|
21083
|
-
return this.getNearestExistingDirectory(
|
|
22261
|
+
return this.getNearestExistingDirectory(path29.dirname(projectConfigPath));
|
|
21084
22262
|
})
|
|
21085
22263
|
)];
|
|
21086
22264
|
}
|
|
@@ -21142,7 +22320,7 @@ var FileWatcher = class {
|
|
|
21142
22320
|
}
|
|
21143
22321
|
scheduleNativeReconciliation(generation, filePath) {
|
|
21144
22322
|
if (!this.isCurrentNativeSetup(generation)) return;
|
|
21145
|
-
const requiresFullReconciliation = filePath ===
|
|
22323
|
+
const requiresFullReconciliation = filePath === path29.join(this.projectRoot, ".gitignore");
|
|
21146
22324
|
const invalidatedPath = requiresFullReconciliation ? null : filePath;
|
|
21147
22325
|
this.nativeInvalidatedPaths.set(invalidatedPath, invalidatedPath !== null);
|
|
21148
22326
|
if (this.nativeReconcileTimer) {
|
|
@@ -21237,23 +22415,23 @@ var FileWatcher = class {
|
|
|
21237
22415
|
this.scheduleFlush();
|
|
21238
22416
|
}
|
|
21239
22417
|
isProjectConfigPath(filePath) {
|
|
21240
|
-
const relativePath =
|
|
21241
|
-
const normalizedRelativePath =
|
|
22418
|
+
const relativePath = path29.relative(this.projectRoot, filePath);
|
|
22419
|
+
const normalizedRelativePath = path29.normalize(relativePath);
|
|
21242
22420
|
return this.getProjectConfigRelativePaths().some((configPath) => configPath === normalizedRelativePath);
|
|
21243
22421
|
}
|
|
21244
22422
|
isProjectConfigPathOrAncestor(relativePath) {
|
|
21245
|
-
const normalizedRelativePath =
|
|
22423
|
+
const normalizedRelativePath = path29.normalize(relativePath);
|
|
21246
22424
|
return this.getProjectConfigRelativePaths().some(
|
|
21247
|
-
(configPath) => configPath === normalizedRelativePath || configPath.startsWith(`${normalizedRelativePath}${
|
|
22425
|
+
(configPath) => configPath === normalizedRelativePath || configPath.startsWith(`${normalizedRelativePath}${path29.sep}`)
|
|
21248
22426
|
);
|
|
21249
22427
|
}
|
|
21250
22428
|
isOutsideProjectPath(relativePath) {
|
|
21251
|
-
return relativePath === ".." || relativePath.startsWith(`..${
|
|
22429
|
+
return relativePath === ".." || relativePath.startsWith(`..${path29.sep}`) || path29.isAbsolute(relativePath);
|
|
21252
22430
|
}
|
|
21253
22431
|
getNearestExistingDirectory(directoryPath) {
|
|
21254
22432
|
let candidate = directoryPath;
|
|
21255
|
-
while (!
|
|
21256
|
-
const parent =
|
|
22433
|
+
while (!existsSync16(candidate)) {
|
|
22434
|
+
const parent = path29.dirname(candidate);
|
|
21257
22435
|
if (parent === candidate) break;
|
|
21258
22436
|
candidate = parent;
|
|
21259
22437
|
}
|
|
@@ -21261,7 +22439,7 @@ var FileWatcher = class {
|
|
|
21261
22439
|
}
|
|
21262
22440
|
getProjectConfigRelativePaths() {
|
|
21263
22441
|
return this.projectConfigPaths.map(
|
|
21264
|
-
(configPath) =>
|
|
22442
|
+
(configPath) => path29.normalize(path29.relative(this.projectRoot, configPath))
|
|
21265
22443
|
);
|
|
21266
22444
|
}
|
|
21267
22445
|
getConfigPathStates() {
|
|
@@ -21319,7 +22497,7 @@ var FileWatcher = class {
|
|
|
21319
22497
|
return;
|
|
21320
22498
|
}
|
|
21321
22499
|
const changes = Array.from(this.pendingChanges.entries()).map(
|
|
21322
|
-
([
|
|
22500
|
+
([path34, type]) => ({ path: path34, type })
|
|
21323
22501
|
);
|
|
21324
22502
|
this.pendingChanges.clear();
|
|
21325
22503
|
try {
|
|
@@ -21365,7 +22543,7 @@ var FileWatcher = class {
|
|
|
21365
22543
|
};
|
|
21366
22544
|
|
|
21367
22545
|
// src/watcher/git-head-watcher.ts
|
|
21368
|
-
import * as
|
|
22546
|
+
import * as path30 from "path";
|
|
21369
22547
|
var GitHeadWatcher = class {
|
|
21370
22548
|
watcher = null;
|
|
21371
22549
|
projectRoot;
|
|
@@ -21387,13 +22565,13 @@ var GitHeadWatcher = class {
|
|
|
21387
22565
|
this.readyPromise = Promise.resolve();
|
|
21388
22566
|
return;
|
|
21389
22567
|
}
|
|
21390
|
-
this.readyPromise = new Promise((
|
|
21391
|
-
this.resolveReady =
|
|
22568
|
+
this.readyPromise = new Promise((resolve21) => {
|
|
22569
|
+
this.resolveReady = resolve21;
|
|
21392
22570
|
});
|
|
21393
22571
|
this.onBranchChange = handler;
|
|
21394
22572
|
this.currentBranch = getCurrentBranch(this.projectRoot);
|
|
21395
22573
|
const headPath = getHeadPath(this.projectRoot);
|
|
21396
|
-
const refsPath =
|
|
22574
|
+
const refsPath = path30.join(this.projectRoot, ".git", "refs", "heads");
|
|
21397
22575
|
this.watcher = chokidar_default.watch([headPath, refsPath], {
|
|
21398
22576
|
persistent: true,
|
|
21399
22577
|
ignoreInitial: true,
|
|
@@ -21461,7 +22639,9 @@ var GitHeadWatcher = class {
|
|
|
21461
22639
|
function createWatcherWithIndexer(getIndexer, projectRoot, config, host, options = {}) {
|
|
21462
22640
|
const fileWatcher = new FileWatcher(projectRoot, config, host, options);
|
|
21463
22641
|
const configPaths = getConfigPaths(projectRoot, host, options);
|
|
21464
|
-
configureAutoIndex(projectRoot, host, parseConfig(config), getIndexer
|
|
22642
|
+
configureAutoIndex(projectRoot, host, parseConfig(config), getIndexer, {
|
|
22643
|
+
synchronizeBackgroundWorker: false
|
|
22644
|
+
});
|
|
21465
22645
|
let stopped = false;
|
|
21466
22646
|
const requestReindex = () => {
|
|
21467
22647
|
if (stopped) return;
|
|
@@ -21481,7 +22661,9 @@ function createWatcherWithIndexer(getIndexer, projectRoot, config, host, options
|
|
|
21481
22661
|
const parsedConfig = options.configPath ? parseConfig(loadConfigFile(options.configPath)) : void 0;
|
|
21482
22662
|
const refreshedConfig = refreshIndexerForDirectory(projectRoot, host, parsedConfig);
|
|
21483
22663
|
if (refreshedConfig) {
|
|
21484
|
-
configureAutoIndex(projectRoot, host, refreshedConfig, getIndexer
|
|
22664
|
+
configureAutoIndex(projectRoot, host, refreshedConfig, getIndexer, {
|
|
22665
|
+
synchronizeBackgroundWorker: false
|
|
22666
|
+
});
|
|
21485
22667
|
}
|
|
21486
22668
|
}
|
|
21487
22669
|
requestReindex();
|
|
@@ -21529,7 +22711,7 @@ function getConfigPaths(projectRoot, host, options) {
|
|
|
21529
22711
|
|
|
21530
22712
|
// src/tools/visualize/activity.ts
|
|
21531
22713
|
import { execFileSync } from "child_process";
|
|
21532
|
-
import * as
|
|
22714
|
+
import * as path31 from "path";
|
|
21533
22715
|
function attachRecentActivity(data, projectRoot) {
|
|
21534
22716
|
const activity = readGitActivity(projectRoot);
|
|
21535
22717
|
const changes = activity.size > 0 ? buildGitChanges(data, activity, projectRoot) : buildGraphChanges(data);
|
|
@@ -21691,7 +22873,7 @@ function normalizePath4(filePath) {
|
|
|
21691
22873
|
return filePath.replace(/\\/g, "/");
|
|
21692
22874
|
}
|
|
21693
22875
|
function toGitRelativePath(projectRoot, filePath) {
|
|
21694
|
-
const relativePath =
|
|
22876
|
+
const relativePath = path31.isAbsolute(filePath) ? path31.relative(projectRoot, filePath) : filePath;
|
|
21695
22877
|
return normalizePath4(relativePath);
|
|
21696
22878
|
}
|
|
21697
22879
|
|
|
@@ -21949,7 +23131,7 @@ render();
|
|
|
21949
23131
|
}
|
|
21950
23132
|
|
|
21951
23133
|
// src/tools/visualize/transform.ts
|
|
21952
|
-
import * as
|
|
23134
|
+
import * as path32 from "path";
|
|
21953
23135
|
|
|
21954
23136
|
// src/tools/visualize/modules.ts
|
|
21955
23137
|
var MAX_MODULES = 18;
|
|
@@ -22209,7 +23391,7 @@ function transformForVisualization(symbols, edges, options = {}) {
|
|
|
22209
23391
|
filePath: s.filePath,
|
|
22210
23392
|
kind: s.kind,
|
|
22211
23393
|
line: s.startLine,
|
|
22212
|
-
directory:
|
|
23394
|
+
directory: path32.dirname(s.filePath),
|
|
22213
23395
|
moduleId: "",
|
|
22214
23396
|
moduleLabel: ""
|
|
22215
23397
|
}));
|
|
@@ -22237,9 +23419,9 @@ function parseArgs(argv) {
|
|
|
22237
23419
|
let host = "opencode";
|
|
22238
23420
|
for (let i = 2; i < argv.length; i++) {
|
|
22239
23421
|
if (argv[i] === "--project" && argv[i + 1]) {
|
|
22240
|
-
project =
|
|
23422
|
+
project = path33.resolve(argv[++i]);
|
|
22241
23423
|
} else if (argv[i] === "--config" && argv[i + 1]) {
|
|
22242
|
-
config =
|
|
23424
|
+
config = path33.resolve(argv[++i]);
|
|
22243
23425
|
} else if (argv[i] === "--host" && argv[i + 1]) {
|
|
22244
23426
|
host = parseHostMode(argv[++i]);
|
|
22245
23427
|
} else if (argv[i] === "--host") {
|
|
@@ -22254,6 +23436,7 @@ function parseIndexArgs(argv, cwd) {
|
|
|
22254
23436
|
let config;
|
|
22255
23437
|
let force = false;
|
|
22256
23438
|
let estimateOnly = false;
|
|
23439
|
+
let dryRun = false;
|
|
22257
23440
|
let verbose = false;
|
|
22258
23441
|
for (let i = 0; i < argv.length; i += 1) {
|
|
22259
23442
|
const arg = argv[i];
|
|
@@ -22266,7 +23449,7 @@ function parseIndexArgs(argv, cwd) {
|
|
|
22266
23449
|
if (!arg.startsWith("--project=")) {
|
|
22267
23450
|
i += 1;
|
|
22268
23451
|
}
|
|
22269
|
-
project =
|
|
23452
|
+
project = path33.resolve(cwd, value);
|
|
22270
23453
|
continue;
|
|
22271
23454
|
}
|
|
22272
23455
|
if (arg === "--config" || arg.startsWith("--config=")) {
|
|
@@ -22277,7 +23460,7 @@ function parseIndexArgs(argv, cwd) {
|
|
|
22277
23460
|
if (!arg.startsWith("--config=")) {
|
|
22278
23461
|
i += 1;
|
|
22279
23462
|
}
|
|
22280
|
-
config =
|
|
23463
|
+
config = path33.resolve(cwd, value);
|
|
22281
23464
|
continue;
|
|
22282
23465
|
}
|
|
22283
23466
|
if (arg === "--host" || arg.startsWith("--host=")) {
|
|
@@ -22291,13 +23474,16 @@ function parseIndexArgs(argv, cwd) {
|
|
|
22291
23474
|
host = parseHostMode(value);
|
|
22292
23475
|
continue;
|
|
22293
23476
|
}
|
|
22294
|
-
if (arg === "--force" || arg === "--estimate-only" || arg === "--verbose") {
|
|
23477
|
+
if (arg === "--force" || arg === "--estimate-only" || arg === "--dry-run" || arg === "--verbose") {
|
|
22295
23478
|
if (arg === "--force") {
|
|
22296
23479
|
force = true;
|
|
22297
23480
|
}
|
|
22298
23481
|
if (arg === "--estimate-only") {
|
|
22299
23482
|
estimateOnly = true;
|
|
22300
23483
|
}
|
|
23484
|
+
if (arg === "--dry-run") {
|
|
23485
|
+
dryRun = true;
|
|
23486
|
+
}
|
|
22301
23487
|
if (arg === "--verbose") {
|
|
22302
23488
|
verbose = true;
|
|
22303
23489
|
}
|
|
@@ -22308,7 +23494,7 @@ function parseIndexArgs(argv, cwd) {
|
|
|
22308
23494
|
}
|
|
22309
23495
|
throw new Error(`Unknown index option: ${arg}`);
|
|
22310
23496
|
}
|
|
22311
|
-
return { project, host, config, force, estimateOnly, verbose };
|
|
23497
|
+
return { project, host, config, force, estimateOnly, dryRun, verbose };
|
|
22312
23498
|
}
|
|
22313
23499
|
function loadCliRawConfig(args) {
|
|
22314
23500
|
return args.config ? loadConfigFile(args.config) : loadMergedConfig(args.project, args.host);
|
|
@@ -22325,6 +23511,7 @@ Options:
|
|
|
22325
23511
|
--config <path> Explicit JSON config path
|
|
22326
23512
|
--force Rebuild index even if already up to date
|
|
22327
23513
|
--estimate-only Estimate indexing cost only
|
|
23514
|
+
--dry-run Parse only; report the exact embedding token total without indexing
|
|
22328
23515
|
--verbose Include detailed final index statistics
|
|
22329
23516
|
--help Show this message
|
|
22330
23517
|
|
|
@@ -22333,7 +23520,7 @@ Progress and diagnostics are written to stderr. Final index output is written to
|
|
|
22333
23520
|
);
|
|
22334
23521
|
}
|
|
22335
23522
|
function isCliEntrypoint(moduleUrl, argvPath) {
|
|
22336
|
-
return argvPath !== void 0 &&
|
|
23523
|
+
return argvPath !== void 0 && realpathSync7(fileURLToPath2(moduleUrl)) === realpathSync7(argvPath);
|
|
22337
23524
|
}
|
|
22338
23525
|
function parseVisualizeArgs(argv, cwd) {
|
|
22339
23526
|
let project = cwd;
|
|
@@ -22343,7 +23530,7 @@ function parseVisualizeArgs(argv, cwd) {
|
|
|
22343
23530
|
for (let i = 0; i < argv.length; i++) {
|
|
22344
23531
|
const arg = argv[i];
|
|
22345
23532
|
if (arg === "--project" && argv[i + 1]) {
|
|
22346
|
-
project =
|
|
23533
|
+
project = path33.resolve(argv[++i]);
|
|
22347
23534
|
} else if (arg === "--max" && argv[i + 1]) {
|
|
22348
23535
|
maxNodes = Number(argv[++i]);
|
|
22349
23536
|
} else if (arg.startsWith("--max=") || arg.startsWith("max=")) {
|
|
@@ -22380,8 +23567,8 @@ async function handleVisualizeCommand(argv, cwd) {
|
|
|
22380
23567
|
console.error("No connected symbols found. Retry with: npm run visualize -- orphans");
|
|
22381
23568
|
return 1;
|
|
22382
23569
|
}
|
|
22383
|
-
const outputPath =
|
|
22384
|
-
|
|
23570
|
+
const outputPath = path33.join(os9.tmpdir(), `call-graph-${Date.now()}.html`);
|
|
23571
|
+
writeFileSync7(outputPath, generateVisualizationHtml(vizData), "utf-8");
|
|
22385
23572
|
console.log(`Temporal call graph visualization generated: ${outputPath}`);
|
|
22386
23573
|
console.log(`Nodes: ${vizData.nodes.length} | Edges: ${vizData.edges.length}`);
|
|
22387
23574
|
console.log(`Recent change lenses: ${vizData.changes?.length ?? 0}`);
|
|
@@ -22412,7 +23599,6 @@ async function runMcpCli(argv) {
|
|
|
22412
23599
|
const config = parseConfig(rawConfig);
|
|
22413
23600
|
const server = createMcpServer(args.project, config, args.host);
|
|
22414
23601
|
const transport = new StdioServerTransport();
|
|
22415
|
-
let watcher = null;
|
|
22416
23602
|
let shutdownPromise;
|
|
22417
23603
|
const onServerClose = server.server.onclose;
|
|
22418
23604
|
const shutdown = () => {
|
|
@@ -22426,16 +23612,19 @@ async function runMcpCli(argv) {
|
|
|
22426
23612
|
shutdownPromise = (async () => {
|
|
22427
23613
|
let exitCode = 0;
|
|
22428
23614
|
try {
|
|
22429
|
-
await
|
|
22430
|
-
} catch (error) {
|
|
22431
|
-
exitCode = 1;
|
|
22432
|
-
console.error("Failed to stop MCP file watcher cleanly:", error);
|
|
22433
|
-
}
|
|
22434
|
-
try {
|
|
22435
|
-
await stopAutoIndex(args.project, args.host);
|
|
23615
|
+
await stopBackgroundWorker(args.project, args.host);
|
|
22436
23616
|
} catch (error) {
|
|
22437
23617
|
exitCode = 1;
|
|
22438
|
-
|
|
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
|
+
}
|
|
22439
23628
|
}
|
|
22440
23629
|
try {
|
|
22441
23630
|
await server.close();
|
|
@@ -22464,19 +23653,25 @@ async function runMcpCli(argv) {
|
|
|
22464
23653
|
process.once("SIGHUP", requestShutdown);
|
|
22465
23654
|
process.once("SIGTERM", requestShutdown);
|
|
22466
23655
|
}
|
|
22467
|
-
await server.connect(transport);
|
|
22468
|
-
if (shutdownPromise) return;
|
|
22469
23656
|
const isHomeDir = isHomeDirectory(args.project);
|
|
22470
23657
|
const isValidProject = !isHomeDir && (!config.indexing.requireProjectMarker || hasProjectMarker(args.project));
|
|
22471
|
-
|
|
22472
|
-
|
|
22473
|
-
|
|
22474
|
-
|
|
22475
|
-
|
|
22476
|
-
|
|
22477
|
-
|
|
22478
|
-
|
|
22479
|
-
|
|
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;
|
|
22480
23675
|
}
|
|
22481
23676
|
function printIndexProgress(onProgress, title, metadata) {
|
|
22482
23677
|
const details = Object.entries(metadata).filter(([, value]) => value !== void 0 && value !== null).map(([key, value]) => `${key}=${isSensitiveKey(key) ? "[REDACTED]" : String(value)}`).join(" ");
|
|
@@ -22520,6 +23715,7 @@ async function handleIndexCommand(argv, cwd, deps = {}) {
|
|
|
22520
23715
|
const indexArgs = {
|
|
22521
23716
|
force: parsedArgs.force,
|
|
22522
23717
|
estimateOnly: parsedArgs.estimateOnly,
|
|
23718
|
+
dryRun: parsedArgs.dryRun,
|
|
22523
23719
|
verbose: parsedArgs.verbose
|
|
22524
23720
|
};
|
|
22525
23721
|
const result = await runIndex(parsedArgs.project, parsedArgs.host, indexArgs, (title, metadata) => {
|