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/pi-extension.js
CHANGED
|
@@ -328,7 +328,7 @@ var require_ignore = __commonJS({
|
|
|
328
328
|
// path matching.
|
|
329
329
|
// - check `string` either `MODE_IGNORE` or `MODE_CHECK_IGNORE`
|
|
330
330
|
// @returns {TestResult} true if a file is ignored
|
|
331
|
-
test(
|
|
331
|
+
test(path26, checkUnignored, mode) {
|
|
332
332
|
let ignored = false;
|
|
333
333
|
let unignored = false;
|
|
334
334
|
let matchedRule;
|
|
@@ -337,7 +337,7 @@ var require_ignore = __commonJS({
|
|
|
337
337
|
if (unignored === negative && ignored !== unignored || negative && !ignored && !unignored && !checkUnignored) {
|
|
338
338
|
return;
|
|
339
339
|
}
|
|
340
|
-
const matched = rule[mode].test(
|
|
340
|
+
const matched = rule[mode].test(path26);
|
|
341
341
|
if (!matched) {
|
|
342
342
|
return;
|
|
343
343
|
}
|
|
@@ -358,17 +358,17 @@ var require_ignore = __commonJS({
|
|
|
358
358
|
var throwError = (message, Ctor) => {
|
|
359
359
|
throw new Ctor(message);
|
|
360
360
|
};
|
|
361
|
-
var checkPath = (
|
|
362
|
-
if (!isString(
|
|
361
|
+
var checkPath = (path26, originalPath, doThrow) => {
|
|
362
|
+
if (!isString(path26)) {
|
|
363
363
|
return doThrow(
|
|
364
364
|
`path must be a string, but got \`${originalPath}\``,
|
|
365
365
|
TypeError
|
|
366
366
|
);
|
|
367
367
|
}
|
|
368
|
-
if (!
|
|
368
|
+
if (!path26) {
|
|
369
369
|
return doThrow(`path must not be empty`, TypeError);
|
|
370
370
|
}
|
|
371
|
-
if (checkPath.isNotRelative(
|
|
371
|
+
if (checkPath.isNotRelative(path26)) {
|
|
372
372
|
const r = "`path.relative()`d";
|
|
373
373
|
return doThrow(
|
|
374
374
|
`path should be a ${r} string, but got "${originalPath}"`,
|
|
@@ -377,7 +377,7 @@ var require_ignore = __commonJS({
|
|
|
377
377
|
}
|
|
378
378
|
return true;
|
|
379
379
|
};
|
|
380
|
-
var isNotRelative = (
|
|
380
|
+
var isNotRelative = (path26) => REGEX_TEST_INVALID_PATH.test(path26);
|
|
381
381
|
checkPath.isNotRelative = isNotRelative;
|
|
382
382
|
checkPath.convert = (p) => p;
|
|
383
383
|
var Ignore2 = class {
|
|
@@ -407,19 +407,19 @@ var require_ignore = __commonJS({
|
|
|
407
407
|
}
|
|
408
408
|
// @returns {TestResult}
|
|
409
409
|
_test(originalPath, cache, checkUnignored, slices) {
|
|
410
|
-
const
|
|
410
|
+
const path26 = originalPath && checkPath.convert(originalPath);
|
|
411
411
|
checkPath(
|
|
412
|
-
|
|
412
|
+
path26,
|
|
413
413
|
originalPath,
|
|
414
414
|
this._strictPathCheck ? throwError : RETURN_FALSE
|
|
415
415
|
);
|
|
416
|
-
return this._t(
|
|
416
|
+
return this._t(path26, cache, checkUnignored, slices);
|
|
417
417
|
}
|
|
418
|
-
checkIgnore(
|
|
419
|
-
if (!REGEX_TEST_TRAILING_SLASH.test(
|
|
420
|
-
return this.test(
|
|
418
|
+
checkIgnore(path26) {
|
|
419
|
+
if (!REGEX_TEST_TRAILING_SLASH.test(path26)) {
|
|
420
|
+
return this.test(path26);
|
|
421
421
|
}
|
|
422
|
-
const slices =
|
|
422
|
+
const slices = path26.split(SLASH2).filter(Boolean);
|
|
423
423
|
slices.pop();
|
|
424
424
|
if (slices.length) {
|
|
425
425
|
const parent = this._t(
|
|
@@ -432,18 +432,18 @@ var require_ignore = __commonJS({
|
|
|
432
432
|
return parent;
|
|
433
433
|
}
|
|
434
434
|
}
|
|
435
|
-
return this._rules.test(
|
|
435
|
+
return this._rules.test(path26, false, MODE_CHECK_IGNORE);
|
|
436
436
|
}
|
|
437
|
-
_t(
|
|
438
|
-
if (
|
|
439
|
-
return cache[
|
|
437
|
+
_t(path26, cache, checkUnignored, slices) {
|
|
438
|
+
if (path26 in cache) {
|
|
439
|
+
return cache[path26];
|
|
440
440
|
}
|
|
441
441
|
if (!slices) {
|
|
442
|
-
slices =
|
|
442
|
+
slices = path26.split(SLASH2).filter(Boolean);
|
|
443
443
|
}
|
|
444
444
|
slices.pop();
|
|
445
445
|
if (!slices.length) {
|
|
446
|
-
return cache[
|
|
446
|
+
return cache[path26] = this._rules.test(path26, checkUnignored, MODE_IGNORE);
|
|
447
447
|
}
|
|
448
448
|
const parent = this._t(
|
|
449
449
|
slices.join(SLASH2) + SLASH2,
|
|
@@ -451,29 +451,29 @@ var require_ignore = __commonJS({
|
|
|
451
451
|
checkUnignored,
|
|
452
452
|
slices
|
|
453
453
|
);
|
|
454
|
-
return cache[
|
|
454
|
+
return cache[path26] = parent.ignored ? parent : this._rules.test(path26, checkUnignored, MODE_IGNORE);
|
|
455
455
|
}
|
|
456
|
-
ignores(
|
|
457
|
-
return this._test(
|
|
456
|
+
ignores(path26) {
|
|
457
|
+
return this._test(path26, this._ignoreCache, false).ignored;
|
|
458
458
|
}
|
|
459
459
|
createFilter() {
|
|
460
|
-
return (
|
|
460
|
+
return (path26) => !this.ignores(path26);
|
|
461
461
|
}
|
|
462
462
|
filter(paths) {
|
|
463
463
|
return makeArray(paths).filter(this.createFilter());
|
|
464
464
|
}
|
|
465
465
|
// @returns {TestResult}
|
|
466
|
-
test(
|
|
467
|
-
return this._test(
|
|
466
|
+
test(path26) {
|
|
467
|
+
return this._test(path26, this._testCache, true);
|
|
468
468
|
}
|
|
469
469
|
};
|
|
470
470
|
var factory = (options) => new Ignore2(options);
|
|
471
|
-
var isPathValid = (
|
|
471
|
+
var isPathValid = (path26) => checkPath(path26 && checkPath.convert(path26), path26, RETURN_FALSE);
|
|
472
472
|
var setupWindows = () => {
|
|
473
473
|
const makePosix = (str) => /^\\\\\?\\/.test(str) || /["<>|\u0000-\u001F]+/u.test(str) ? str : str.replace(/\\/g, "/");
|
|
474
474
|
checkPath.convert = makePosix;
|
|
475
475
|
const REGEX_TEST_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i;
|
|
476
|
-
checkPath.isNotRelative = (
|
|
476
|
+
checkPath.isNotRelative = (path26) => REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path26) || isNotRelative(path26);
|
|
477
477
|
};
|
|
478
478
|
if (
|
|
479
479
|
// Detect `process` so that it can run in browsers.
|
|
@@ -2043,6 +2043,26 @@ function formatCostEstimate(estimate) {
|
|
|
2043
2043
|
\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
|
|
2044
2044
|
`;
|
|
2045
2045
|
}
|
|
2046
|
+
function formatDryRunEstimate(estimate) {
|
|
2047
|
+
return `Dry run: parsed the file set to measure the embedding workload. No embedding requests were made and the index was not changed.
|
|
2048
|
+
|
|
2049
|
+
Files to embed: ${estimate.filesCount.toLocaleString()}
|
|
2050
|
+
Chunks to embed: ${estimate.chunksCount.toLocaleString()}
|
|
2051
|
+
Tokens to embed: ${estimate.tokensToEmbed.toLocaleString()}
|
|
2052
|
+
|
|
2053
|
+
The "Tokens to embed" value uses the local estimateTokens(text) = ceil(len/4). It
|
|
2054
|
+
matches the live "Tokens used" counter only for providers that report usage on the
|
|
2055
|
+
same basis (ollama); for providers that report a server tokenizer count (OpenAI,
|
|
2056
|
+
Gemini, custom) it is only an estimate.
|
|
2057
|
+
|
|
2058
|
+
For a matching provider and a project-scoped force index, the force pass clears its
|
|
2059
|
+
own cached embeddings, so the live counter climbs to this number. A force index on a
|
|
2060
|
+
shared global index can reuse cached embeddings from other projects, and an
|
|
2061
|
+
incremental index counts cached chunks that are not re-embedded; in both cases this
|
|
2062
|
+
number is an upper bound on the live counter, so a progress percent against this
|
|
2063
|
+
total tops out below 100%.
|
|
2064
|
+
`;
|
|
2065
|
+
}
|
|
2046
2066
|
function formatBytes(bytes) {
|
|
2047
2067
|
if (bytes === 0) return "0 B";
|
|
2048
2068
|
const k = 1024;
|
|
@@ -2221,8 +2241,8 @@ function formatCodeCommunities(result) {
|
|
|
2221
2241
|
}
|
|
2222
2242
|
|
|
2223
2243
|
// src/tools/operations.ts
|
|
2224
|
-
import { existsSync as
|
|
2225
|
-
import * as
|
|
2244
|
+
import { existsSync as existsSync13, realpathSync as realpathSync6, statSync as statSync5 } from "fs";
|
|
2245
|
+
import * as path21 from "path";
|
|
2226
2246
|
|
|
2227
2247
|
// src/tools/knowledge-base-paths.ts
|
|
2228
2248
|
import * as path9 from "path";
|
|
@@ -2934,8 +2954,8 @@ function formatExactSearchHandoff(results) {
|
|
|
2934
2954
|
}
|
|
2935
2955
|
function formatContextEvidence(result, index) {
|
|
2936
2956
|
const symbol = result.name ? ` ${JSON.stringify(compactEvidenceValue(result.name, 80))}` : "";
|
|
2937
|
-
const
|
|
2938
|
-
return `[${index}] ${result.chunkType}${symbol} in ${
|
|
2957
|
+
const path26 = compactEvidenceValue(result.filePath, 120);
|
|
2958
|
+
return `[${index}] ${result.chunkType}${symbol} in ${path26}:${result.startLine}-${result.endLine} (score ${result.score.toFixed(2)})`;
|
|
2939
2959
|
}
|
|
2940
2960
|
function formatContextPack(heading, selected, candidateCount, duplicateCount, limitOmittedCount, budgetOmittedCount, includeExactSearchHandoff) {
|
|
2941
2961
|
const lines = selected.map((result, index) => formatContextEvidence(result, index + 1));
|
|
@@ -3577,9 +3597,9 @@ function formatEffectivenessMetrics(snapshot) {
|
|
|
3577
3597
|
}
|
|
3578
3598
|
|
|
3579
3599
|
// src/utils/auto-index.ts
|
|
3580
|
-
import { existsSync as
|
|
3581
|
-
import * as
|
|
3582
|
-
import * as
|
|
3600
|
+
import { existsSync as existsSync9, realpathSync as realpathSync4 } from "fs";
|
|
3601
|
+
import * as os5 from "os";
|
|
3602
|
+
import * as path13 from "path";
|
|
3583
3603
|
|
|
3584
3604
|
// src/indexer/index-lock.ts
|
|
3585
3605
|
import { randomUUID } from "crypto";
|
|
@@ -3836,7 +3856,7 @@ function removeDeadReclaimMarker(lockPath, expectedOwner) {
|
|
|
3836
3856
|
return true;
|
|
3837
3857
|
}
|
|
3838
3858
|
function reclaimDeadOwner(indexPath, lockPath, expectedOwner) {
|
|
3839
|
-
const
|
|
3859
|
+
const reclaimPath2 = path10.join(lockPath, RECLAIM_DIRECTORY_NAME);
|
|
3840
3860
|
const reclaimOwner = {
|
|
3841
3861
|
pid: process.pid,
|
|
3842
3862
|
hostname: os3.hostname(),
|
|
@@ -3845,19 +3865,19 @@ function reclaimDeadOwner(indexPath, lockPath, expectedOwner) {
|
|
|
3845
3865
|
expectedOwnerToken: expectedOwner.token
|
|
3846
3866
|
};
|
|
3847
3867
|
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
3848
|
-
if (publishJsonDirectory(
|
|
3868
|
+
if (publishJsonDirectory(reclaimPath2, reclaimOwner)) break;
|
|
3849
3869
|
if (attempt === 0 && removeDeadReclaimMarker(lockPath, expectedOwner)) continue;
|
|
3850
3870
|
return false;
|
|
3851
3871
|
}
|
|
3852
3872
|
try {
|
|
3853
|
-
const currentReclaimer = readReclaimOwner(
|
|
3873
|
+
const currentReclaimer = readReclaimOwner(reclaimPath2);
|
|
3854
3874
|
const currentOwner = readDirectoryOwner(lockPath);
|
|
3855
3875
|
if (!currentReclaimer || !sameReclaimOwner(currentReclaimer, reclaimOwner) || !currentOwner || !sameOwner(currentOwner, expectedOwner) || getOwnerLiveness(currentOwner) !== "dead") {
|
|
3856
3876
|
return false;
|
|
3857
3877
|
}
|
|
3858
3878
|
publishRecoveryMarker(indexPath, expectedOwner);
|
|
3859
3879
|
const ownerBeforeQuarantine = readDirectoryOwner(lockPath);
|
|
3860
|
-
const reclaimerBeforeQuarantine = readReclaimOwner(
|
|
3880
|
+
const reclaimerBeforeQuarantine = readReclaimOwner(reclaimPath2);
|
|
3861
3881
|
if (!ownerBeforeQuarantine || !sameOwner(ownerBeforeQuarantine, expectedOwner) || getOwnerLiveness(ownerBeforeQuarantine) !== "dead" || !reclaimerBeforeQuarantine || !sameReclaimOwner(reclaimerBeforeQuarantine, reclaimOwner)) {
|
|
3862
3882
|
return false;
|
|
3863
3883
|
}
|
|
@@ -4027,10 +4047,893 @@ function completeLeaseRecovery(lease) {
|
|
|
4027
4047
|
}
|
|
4028
4048
|
}
|
|
4029
4049
|
|
|
4050
|
+
// src/utils/background-worker.ts
|
|
4051
|
+
import { createHash, randomUUID as randomUUID2 } from "crypto";
|
|
4052
|
+
import {
|
|
4053
|
+
existsSync as existsSync7,
|
|
4054
|
+
lstatSync as lstatSync2,
|
|
4055
|
+
mkdirSync as mkdirSync2,
|
|
4056
|
+
readFileSync as readFileSync6,
|
|
4057
|
+
realpathSync as realpathSync3,
|
|
4058
|
+
renameSync as renameSync2,
|
|
4059
|
+
rmSync as rmSync2,
|
|
4060
|
+
writeFileSync as writeFileSync2
|
|
4061
|
+
} from "fs";
|
|
4062
|
+
import * as os4 from "os";
|
|
4063
|
+
import * as path11 from "path";
|
|
4064
|
+
var OWNER_FILE_NAME2 = "owner.json";
|
|
4065
|
+
var HEARTBEAT_FILE_PREFIX = "heartbeat.";
|
|
4066
|
+
var RECLAIM_DIRECTORY_NAME2 = "reclaim";
|
|
4067
|
+
var REFRESH_REQUEST_FILE_NAME = "refresh-request.json";
|
|
4068
|
+
var HEARTBEAT_INTERVAL_MS = 5e3;
|
|
4069
|
+
var STALE_LEASE_MS = 3e4;
|
|
4070
|
+
var RETRY_DELAY_MS = 5e3;
|
|
4071
|
+
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;
|
|
4072
|
+
var BackgroundWorkerStopError = class extends Error {
|
|
4073
|
+
constructor(watcherError, autoIndexError) {
|
|
4074
|
+
super("Failed to stop background worker");
|
|
4075
|
+
this.watcherError = watcherError;
|
|
4076
|
+
this.autoIndexError = autoIndexError;
|
|
4077
|
+
this.name = "BackgroundWorkerStopError";
|
|
4078
|
+
}
|
|
4079
|
+
watcherError;
|
|
4080
|
+
autoIndexError;
|
|
4081
|
+
};
|
|
4082
|
+
var workers = /* @__PURE__ */ new Map();
|
|
4083
|
+
var workerKeysByProject = /* @__PURE__ */ new Map();
|
|
4084
|
+
var workerReplacementBarriers = /* @__PURE__ */ new Map();
|
|
4085
|
+
function getErrorCode2(error) {
|
|
4086
|
+
return typeof error === "object" && error !== null && "code" in error ? String(error.code) : void 0;
|
|
4087
|
+
}
|
|
4088
|
+
function canonicalizePath(targetPath) {
|
|
4089
|
+
const resolved = path11.resolve(targetPath);
|
|
4090
|
+
if (existsSync7(resolved)) {
|
|
4091
|
+
try {
|
|
4092
|
+
return realpathSync3.native(resolved);
|
|
4093
|
+
} catch {
|
|
4094
|
+
return resolved;
|
|
4095
|
+
}
|
|
4096
|
+
}
|
|
4097
|
+
const parent = path11.dirname(resolved);
|
|
4098
|
+
if (parent === resolved) return resolved;
|
|
4099
|
+
return path11.join(canonicalizePath(parent), path11.basename(resolved));
|
|
4100
|
+
}
|
|
4101
|
+
function projectLookupKey(projectRoot3, host) {
|
|
4102
|
+
return `${host}::${canonicalizePath(projectRoot3)}`;
|
|
4103
|
+
}
|
|
4104
|
+
function resolveIdentity(projectRoot3, config, host) {
|
|
4105
|
+
const canonicalProjectRoot = canonicalizePath(projectRoot3);
|
|
4106
|
+
const canonicalIndexPath = canonicalizePath(resolveProjectIndexPath(projectRoot3, config.scope, host));
|
|
4107
|
+
return {
|
|
4108
|
+
canonicalIndexPath,
|
|
4109
|
+
canonicalProjectRoot,
|
|
4110
|
+
key: `${canonicalIndexPath}::${canonicalProjectRoot}`
|
|
4111
|
+
};
|
|
4112
|
+
}
|
|
4113
|
+
function controllerKey(identity, host) {
|
|
4114
|
+
return `${identity.key}::${host}`;
|
|
4115
|
+
}
|
|
4116
|
+
function leaseDirectoryName(identity) {
|
|
4117
|
+
const hash = createHash("sha256").update(identity.key).digest("hex").slice(0, 32);
|
|
4118
|
+
return `background-worker.${hash}.lease`;
|
|
4119
|
+
}
|
|
4120
|
+
function leasePathFor(identity) {
|
|
4121
|
+
return path11.join(identity.canonicalIndexPath, leaseDirectoryName(identity));
|
|
4122
|
+
}
|
|
4123
|
+
function parseOwner2(value) {
|
|
4124
|
+
if (typeof value !== "object" || value === null) return null;
|
|
4125
|
+
const candidate = value;
|
|
4126
|
+
if (candidate.version !== 1) return null;
|
|
4127
|
+
if (!Number.isInteger(candidate.pid) || (candidate.pid ?? 0) <= 0) return null;
|
|
4128
|
+
if (typeof candidate.hostname !== "string" || candidate.hostname.length === 0) return null;
|
|
4129
|
+
if (typeof candidate.startedAt !== "string" || Number.isNaN(Date.parse(candidate.startedAt))) return null;
|
|
4130
|
+
if (typeof candidate.heartbeatAt !== "string" || Number.isNaN(Date.parse(candidate.heartbeatAt))) return null;
|
|
4131
|
+
if (typeof candidate.projectRoot !== "string" || candidate.projectRoot.length === 0) return null;
|
|
4132
|
+
if (typeof candidate.indexPath !== "string" || candidate.indexPath.length === 0) return null;
|
|
4133
|
+
if (typeof candidate.token !== "string" || !UUID_PATTERN2.test(candidate.token)) return null;
|
|
4134
|
+
return candidate;
|
|
4135
|
+
}
|
|
4136
|
+
function parseHeartbeat(value, expectedToken) {
|
|
4137
|
+
if (typeof value !== "object" || value === null) return null;
|
|
4138
|
+
const candidate = value;
|
|
4139
|
+
if (candidate.version !== 1 || candidate.token !== expectedToken) return null;
|
|
4140
|
+
if (typeof candidate.heartbeatAt !== "string" || Number.isNaN(Date.parse(candidate.heartbeatAt))) return null;
|
|
4141
|
+
return candidate;
|
|
4142
|
+
}
|
|
4143
|
+
function parseReclaimOwner2(value) {
|
|
4144
|
+
if (typeof value !== "object" || value === null) return null;
|
|
4145
|
+
const candidate = value;
|
|
4146
|
+
if (candidate.version !== 1) return null;
|
|
4147
|
+
if (!Number.isInteger(candidate.pid) || (candidate.pid ?? 0) <= 0) return null;
|
|
4148
|
+
if (typeof candidate.hostname !== "string" || candidate.hostname.length === 0) return null;
|
|
4149
|
+
if (typeof candidate.startedAt !== "string" || Number.isNaN(Date.parse(candidate.startedAt))) return null;
|
|
4150
|
+
if (typeof candidate.token !== "string" || !UUID_PATTERN2.test(candidate.token)) return null;
|
|
4151
|
+
if (candidate.expectedOwnerToken !== null && (typeof candidate.expectedOwnerToken !== "string" || !UUID_PATTERN2.test(candidate.expectedOwnerToken))) return null;
|
|
4152
|
+
return candidate;
|
|
4153
|
+
}
|
|
4154
|
+
function heartbeatPath(leasePath, token) {
|
|
4155
|
+
return path11.join(leasePath, `${HEARTBEAT_FILE_PREFIX}${token}.json`);
|
|
4156
|
+
}
|
|
4157
|
+
function reclaimPath(leasePath) {
|
|
4158
|
+
return path11.join(leasePath, RECLAIM_DIRECTORY_NAME2);
|
|
4159
|
+
}
|
|
4160
|
+
function refreshRequestPath(leasePath) {
|
|
4161
|
+
return path11.join(leasePath, REFRESH_REQUEST_FILE_NAME);
|
|
4162
|
+
}
|
|
4163
|
+
function readLeaseOwner(leasePath) {
|
|
4164
|
+
try {
|
|
4165
|
+
return parseOwner2(JSON.parse(readFileSync6(path11.join(leasePath, OWNER_FILE_NAME2), "utf-8")));
|
|
4166
|
+
} catch {
|
|
4167
|
+
return null;
|
|
4168
|
+
}
|
|
4169
|
+
}
|
|
4170
|
+
function readOwner(leasePath) {
|
|
4171
|
+
const owner = readLeaseOwner(leasePath);
|
|
4172
|
+
if (!owner) return null;
|
|
4173
|
+
try {
|
|
4174
|
+
const heartbeat = parseHeartbeat(
|
|
4175
|
+
JSON.parse(readFileSync6(heartbeatPath(leasePath, owner.token), "utf-8")),
|
|
4176
|
+
owner.token
|
|
4177
|
+
);
|
|
4178
|
+
return heartbeat ? { ...owner, heartbeatAt: heartbeat.heartbeatAt } : owner;
|
|
4179
|
+
} catch {
|
|
4180
|
+
return owner;
|
|
4181
|
+
}
|
|
4182
|
+
}
|
|
4183
|
+
function readReclaimOwner2(leasePath) {
|
|
4184
|
+
try {
|
|
4185
|
+
return parseReclaimOwner2(JSON.parse(readFileSync6(path11.join(reclaimPath(leasePath), OWNER_FILE_NAME2), "utf-8")));
|
|
4186
|
+
} catch {
|
|
4187
|
+
return null;
|
|
4188
|
+
}
|
|
4189
|
+
}
|
|
4190
|
+
function ownerLiveness(owner) {
|
|
4191
|
+
if (owner.hostname !== os4.hostname()) return "unknown";
|
|
4192
|
+
try {
|
|
4193
|
+
process.kill(owner.pid, 0);
|
|
4194
|
+
return "alive";
|
|
4195
|
+
} catch (error) {
|
|
4196
|
+
const code = getErrorCode2(error);
|
|
4197
|
+
if (code === "ESRCH") return "dead";
|
|
4198
|
+
if (code === "EPERM") return "alive";
|
|
4199
|
+
return "unknown";
|
|
4200
|
+
}
|
|
4201
|
+
}
|
|
4202
|
+
function isHeartbeatExpired(owner) {
|
|
4203
|
+
return Date.now() - Date.parse(owner.heartbeatAt) >= STALE_LEASE_MS;
|
|
4204
|
+
}
|
|
4205
|
+
function sameOwner2(left, right) {
|
|
4206
|
+
return left.pid === right.pid && left.hostname === right.hostname && left.token === right.token;
|
|
4207
|
+
}
|
|
4208
|
+
function writeHeartbeat(leasePath, owner) {
|
|
4209
|
+
const targetPath = heartbeatPath(leasePath, owner.token);
|
|
4210
|
+
const temporaryPath = `${targetPath}.tmp.${process.pid}.${owner.token}.${randomUUID2()}`;
|
|
4211
|
+
const heartbeat = {
|
|
4212
|
+
version: 1,
|
|
4213
|
+
token: owner.token,
|
|
4214
|
+
heartbeatAt: owner.heartbeatAt
|
|
4215
|
+
};
|
|
4216
|
+
try {
|
|
4217
|
+
writeFileSync2(temporaryPath, JSON.stringify(heartbeat), {
|
|
4218
|
+
encoding: "utf-8",
|
|
4219
|
+
flag: "wx",
|
|
4220
|
+
mode: 384
|
|
4221
|
+
});
|
|
4222
|
+
renameSync2(temporaryPath, targetPath);
|
|
4223
|
+
const currentOwner = readLeaseOwner(leasePath);
|
|
4224
|
+
return currentOwner !== null && sameOwner2(currentOwner, owner);
|
|
4225
|
+
} finally {
|
|
4226
|
+
if (existsSync7(temporaryPath)) rmSync2(temporaryPath, { force: true });
|
|
4227
|
+
}
|
|
4228
|
+
}
|
|
4229
|
+
function requestRefreshFromLeader(leasePath, allowDisabledAutoIndex) {
|
|
4230
|
+
const requestPath = refreshRequestPath(leasePath);
|
|
4231
|
+
const temporaryPath = `${requestPath}.tmp.${process.pid}.${randomUUID2()}`;
|
|
4232
|
+
try {
|
|
4233
|
+
const request = {
|
|
4234
|
+
allowDisabledAutoIndex,
|
|
4235
|
+
requestedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4236
|
+
version: 1
|
|
4237
|
+
};
|
|
4238
|
+
writeFileSync2(temporaryPath, JSON.stringify(request), {
|
|
4239
|
+
encoding: "utf-8",
|
|
4240
|
+
flag: "wx",
|
|
4241
|
+
mode: 384
|
|
4242
|
+
});
|
|
4243
|
+
renameSync2(temporaryPath, requestPath);
|
|
4244
|
+
} catch (error) {
|
|
4245
|
+
if (getErrorCode2(error) !== "ENOENT") {
|
|
4246
|
+
console.error("[codebase-index] Failed to request background index refresh from the project worker:", error);
|
|
4247
|
+
}
|
|
4248
|
+
} finally {
|
|
4249
|
+
if (existsSync7(temporaryPath)) rmSync2(temporaryPath, { force: true });
|
|
4250
|
+
}
|
|
4251
|
+
}
|
|
4252
|
+
function consumeRefreshRequest(leasePath) {
|
|
4253
|
+
const requestPath = refreshRequestPath(leasePath);
|
|
4254
|
+
const claimedPath = `${requestPath}.handling.${process.pid}.${randomUUID2()}`;
|
|
4255
|
+
try {
|
|
4256
|
+
renameSync2(requestPath, claimedPath);
|
|
4257
|
+
} catch (error) {
|
|
4258
|
+
if (getErrorCode2(error) === "ENOENT") return null;
|
|
4259
|
+
throw error;
|
|
4260
|
+
}
|
|
4261
|
+
try {
|
|
4262
|
+
const value = JSON.parse(readFileSync6(claimedPath, "utf-8"));
|
|
4263
|
+
return {
|
|
4264
|
+
allowDisabledAutoIndex: value.version === 1 && value.allowDisabledAutoIndex === true,
|
|
4265
|
+
requestedAt: typeof value.requestedAt === "string" ? value.requestedAt : (/* @__PURE__ */ new Date()).toISOString(),
|
|
4266
|
+
version: 1
|
|
4267
|
+
};
|
|
4268
|
+
} catch {
|
|
4269
|
+
return { allowDisabledAutoIndex: false, requestedAt: (/* @__PURE__ */ new Date()).toISOString(), version: 1 };
|
|
4270
|
+
} finally {
|
|
4271
|
+
rmSync2(claimedPath, { force: true });
|
|
4272
|
+
}
|
|
4273
|
+
}
|
|
4274
|
+
function publishLease(leasePath, owner) {
|
|
4275
|
+
const candidatePath = `${leasePath}.candidate.${process.pid}.${owner.token}`;
|
|
4276
|
+
try {
|
|
4277
|
+
mkdirSync2(candidatePath, { mode: 448 });
|
|
4278
|
+
} catch (error) {
|
|
4279
|
+
if (getErrorCode2(error) === "ENOENT") return false;
|
|
4280
|
+
throw error;
|
|
4281
|
+
}
|
|
4282
|
+
try {
|
|
4283
|
+
writeFileSync2(path11.join(candidatePath, OWNER_FILE_NAME2), JSON.stringify(owner), {
|
|
4284
|
+
encoding: "utf-8",
|
|
4285
|
+
flag: "wx",
|
|
4286
|
+
mode: 384
|
|
4287
|
+
});
|
|
4288
|
+
if (existsSync7(leasePath)) return false;
|
|
4289
|
+
try {
|
|
4290
|
+
renameSync2(candidatePath, leasePath);
|
|
4291
|
+
return true;
|
|
4292
|
+
} catch (error) {
|
|
4293
|
+
if (existsSync7(leasePath) || getErrorCode2(error) === "ENOENT") return false;
|
|
4294
|
+
throw error;
|
|
4295
|
+
}
|
|
4296
|
+
} finally {
|
|
4297
|
+
if (existsSync7(candidatePath)) rmSync2(candidatePath, { recursive: true, force: true });
|
|
4298
|
+
}
|
|
4299
|
+
}
|
|
4300
|
+
function sameReclaimOwner2(left, right) {
|
|
4301
|
+
return left.pid === right.pid && left.hostname === right.hostname && left.token === right.token && left.expectedOwnerToken === right.expectedOwnerToken;
|
|
4302
|
+
}
|
|
4303
|
+
function reclaimerLiveness(owner) {
|
|
4304
|
+
return ownerLiveness(owner);
|
|
4305
|
+
}
|
|
4306
|
+
function isReclaimMarkerExpired(leasePath, owner) {
|
|
4307
|
+
const startedAt = owner ? Date.parse(owner.startedAt) : (() => {
|
|
4308
|
+
try {
|
|
4309
|
+
return lstatSync2(reclaimPath(leasePath)).mtimeMs;
|
|
4310
|
+
} catch {
|
|
4311
|
+
return Date.now();
|
|
4312
|
+
}
|
|
4313
|
+
})();
|
|
4314
|
+
return Date.now() - startedAt >= STALE_LEASE_MS;
|
|
4315
|
+
}
|
|
4316
|
+
function hasActiveReclaimMarker(leasePath, owner) {
|
|
4317
|
+
const marker = readReclaimOwner2(leasePath);
|
|
4318
|
+
return marker !== null && marker.expectedOwnerToken === owner.token && (marker.hostname !== os4.hostname() || ownerLiveness(owner) !== "alive");
|
|
4319
|
+
}
|
|
4320
|
+
function publishReclaimMarker(leasePath, expectedOwner) {
|
|
4321
|
+
const markerPath = reclaimPath(leasePath);
|
|
4322
|
+
const owner = {
|
|
4323
|
+
version: 1,
|
|
4324
|
+
pid: process.pid,
|
|
4325
|
+
hostname: os4.hostname(),
|
|
4326
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4327
|
+
token: randomUUID2(),
|
|
4328
|
+
expectedOwnerToken: expectedOwner?.token ?? null
|
|
4329
|
+
};
|
|
4330
|
+
try {
|
|
4331
|
+
mkdirSync2(markerPath, { mode: 448 });
|
|
4332
|
+
} catch (error) {
|
|
4333
|
+
if (getErrorCode2(error) === "EEXIST" || getErrorCode2(error) === "ENOENT") return null;
|
|
4334
|
+
throw error;
|
|
4335
|
+
}
|
|
4336
|
+
try {
|
|
4337
|
+
writeFileSync2(path11.join(markerPath, OWNER_FILE_NAME2), JSON.stringify(owner), {
|
|
4338
|
+
encoding: "utf-8",
|
|
4339
|
+
flag: "wx",
|
|
4340
|
+
mode: 384
|
|
4341
|
+
});
|
|
4342
|
+
return owner;
|
|
4343
|
+
} catch (error) {
|
|
4344
|
+
rmSync2(markerPath, { recursive: true, force: true });
|
|
4345
|
+
throw error;
|
|
4346
|
+
}
|
|
4347
|
+
}
|
|
4348
|
+
function removeExpiredReclaimMarker(leasePath, expectedOwner) {
|
|
4349
|
+
const marker = readReclaimOwner2(leasePath);
|
|
4350
|
+
const markerPath = reclaimPath(leasePath);
|
|
4351
|
+
if (!existsSync7(markerPath)) return false;
|
|
4352
|
+
if (marker && marker.expectedOwnerToken !== (expectedOwner?.token ?? null)) return false;
|
|
4353
|
+
if (marker && (reclaimerLiveness(marker) === "alive" || !isReclaimMarkerExpired(leasePath, marker))) return false;
|
|
4354
|
+
if (!marker && !isReclaimMarkerExpired(leasePath, null)) return false;
|
|
4355
|
+
const staleMarkerPath = `${markerPath}.stale.${marker?.pid ?? process.pid}.${marker?.token ?? randomUUID2()}.${randomUUID2()}`;
|
|
4356
|
+
try {
|
|
4357
|
+
renameSync2(markerPath, staleMarkerPath);
|
|
4358
|
+
} catch (error) {
|
|
4359
|
+
if (getErrorCode2(error) === "ENOENT") return false;
|
|
4360
|
+
throw error;
|
|
4361
|
+
}
|
|
4362
|
+
try {
|
|
4363
|
+
let claimedMarker = null;
|
|
4364
|
+
try {
|
|
4365
|
+
claimedMarker = parseReclaimOwner2(
|
|
4366
|
+
JSON.parse(readFileSync6(path11.join(staleMarkerPath, OWNER_FILE_NAME2), "utf-8"))
|
|
4367
|
+
);
|
|
4368
|
+
} catch {
|
|
4369
|
+
claimedMarker = null;
|
|
4370
|
+
}
|
|
4371
|
+
const markerMatches = marker ? claimedMarker !== null && sameReclaimOwner2(claimedMarker, marker) : claimedMarker === null;
|
|
4372
|
+
if (!markerMatches || !canReclaimLease(leasePath, expectedOwner)) {
|
|
4373
|
+
if (!existsSync7(markerPath) && existsSync7(staleMarkerPath)) renameSync2(staleMarkerPath, markerPath);
|
|
4374
|
+
return false;
|
|
4375
|
+
}
|
|
4376
|
+
rmSync2(staleMarkerPath, { recursive: true, force: true });
|
|
4377
|
+
return true;
|
|
4378
|
+
} catch (error) {
|
|
4379
|
+
if (getErrorCode2(error) === "ENOENT") return false;
|
|
4380
|
+
throw error;
|
|
4381
|
+
}
|
|
4382
|
+
}
|
|
4383
|
+
function canReclaimLease(leasePath, expectedOwner) {
|
|
4384
|
+
if (!existsSync7(leasePath)) return false;
|
|
4385
|
+
if (!expectedOwner) return false;
|
|
4386
|
+
const currentOwner = readOwner(leasePath);
|
|
4387
|
+
if (!currentOwner || !sameOwner2(currentOwner, expectedOwner)) return false;
|
|
4388
|
+
if (currentOwner.hostname === os4.hostname()) {
|
|
4389
|
+
return ownerLiveness(currentOwner) === "dead";
|
|
4390
|
+
}
|
|
4391
|
+
return isHeartbeatExpired(currentOwner);
|
|
4392
|
+
}
|
|
4393
|
+
function reclaimLease(leasePath, expectedOwner) {
|
|
4394
|
+
let marker = null;
|
|
4395
|
+
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
4396
|
+
marker = publishReclaimMarker(leasePath, expectedOwner);
|
|
4397
|
+
if (marker) break;
|
|
4398
|
+
if (attempt === 0 && removeExpiredReclaimMarker(leasePath, expectedOwner)) continue;
|
|
4399
|
+
return false;
|
|
4400
|
+
}
|
|
4401
|
+
if (!marker) return false;
|
|
4402
|
+
const markerPath = reclaimPath(leasePath);
|
|
4403
|
+
try {
|
|
4404
|
+
const currentMarker = readReclaimOwner2(leasePath);
|
|
4405
|
+
if (!currentMarker || !sameReclaimOwner2(currentMarker, marker) || !canReclaimLease(leasePath, expectedOwner)) {
|
|
4406
|
+
return false;
|
|
4407
|
+
}
|
|
4408
|
+
const stalePath = `${leasePath}.stale.${process.pid}.${marker.token}`;
|
|
4409
|
+
renameSync2(leasePath, stalePath);
|
|
4410
|
+
const quarantinedOwner = readOwner(stalePath);
|
|
4411
|
+
const quarantinedMarker = readReclaimOwner2(stalePath);
|
|
4412
|
+
if (!quarantinedMarker || !sameReclaimOwner2(quarantinedMarker, marker) || expectedOwner !== null && (!quarantinedOwner || !sameOwner2(quarantinedOwner, expectedOwner))) {
|
|
4413
|
+
if (!existsSync7(leasePath) && existsSync7(stalePath)) renameSync2(stalePath, leasePath);
|
|
4414
|
+
return false;
|
|
4415
|
+
}
|
|
4416
|
+
rmSync2(stalePath, { recursive: true, force: true });
|
|
4417
|
+
return true;
|
|
4418
|
+
} catch (error) {
|
|
4419
|
+
if (getErrorCode2(error) === "ENOENT") return false;
|
|
4420
|
+
throw error;
|
|
4421
|
+
} finally {
|
|
4422
|
+
const currentMarker = readReclaimOwner2(leasePath);
|
|
4423
|
+
if (currentMarker && sameReclaimOwner2(currentMarker, marker)) {
|
|
4424
|
+
rmSync2(markerPath, { recursive: true, force: true });
|
|
4425
|
+
}
|
|
4426
|
+
}
|
|
4427
|
+
}
|
|
4428
|
+
function acquireLease(identity) {
|
|
4429
|
+
mkdirSync2(identity.canonicalIndexPath, { recursive: true, mode: 448 });
|
|
4430
|
+
const canonicalIndexPath = realpathSync3.native(identity.canonicalIndexPath);
|
|
4431
|
+
const leasePath = path11.join(canonicalIndexPath, leaseDirectoryName({ ...identity, canonicalIndexPath }));
|
|
4432
|
+
for (let attempt = 0; attempt < 4; attempt += 1) {
|
|
4433
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
4434
|
+
const owner = {
|
|
4435
|
+
version: 1,
|
|
4436
|
+
pid: process.pid,
|
|
4437
|
+
hostname: os4.hostname(),
|
|
4438
|
+
startedAt: timestamp,
|
|
4439
|
+
heartbeatAt: timestamp,
|
|
4440
|
+
projectRoot: identity.canonicalProjectRoot,
|
|
4441
|
+
indexPath: canonicalIndexPath,
|
|
4442
|
+
token: randomUUID2()
|
|
4443
|
+
};
|
|
4444
|
+
if (publishLease(leasePath, owner)) {
|
|
4445
|
+
return { leasePath, owner };
|
|
4446
|
+
}
|
|
4447
|
+
const existingOwner = readOwner(leasePath);
|
|
4448
|
+
if (existingOwner) {
|
|
4449
|
+
if (canReclaimLease(leasePath, existingOwner) && reclaimLease(leasePath, existingOwner)) continue;
|
|
4450
|
+
return null;
|
|
4451
|
+
}
|
|
4452
|
+
return null;
|
|
4453
|
+
}
|
|
4454
|
+
return null;
|
|
4455
|
+
}
|
|
4456
|
+
function releaseLease(lease) {
|
|
4457
|
+
const currentOwner = readOwner(lease.leasePath);
|
|
4458
|
+
if (!currentOwner || !sameOwner2(currentOwner, lease.owner)) return false;
|
|
4459
|
+
const releasePath = `${lease.leasePath}.release.${lease.owner.pid}.${lease.owner.token}`;
|
|
4460
|
+
try {
|
|
4461
|
+
renameSync2(lease.leasePath, releasePath);
|
|
4462
|
+
} catch (error) {
|
|
4463
|
+
if (getErrorCode2(error) === "ENOENT") return false;
|
|
4464
|
+
throw error;
|
|
4465
|
+
}
|
|
4466
|
+
const claimedOwner = readOwner(releasePath);
|
|
4467
|
+
if (!claimedOwner || !sameOwner2(claimedOwner, lease.owner)) {
|
|
4468
|
+
if (!existsSync7(lease.leasePath) && existsSync7(releasePath)) {
|
|
4469
|
+
renameSync2(releasePath, lease.leasePath);
|
|
4470
|
+
}
|
|
4471
|
+
return false;
|
|
4472
|
+
}
|
|
4473
|
+
rmSync2(releasePath, { recursive: true, force: true });
|
|
4474
|
+
return true;
|
|
4475
|
+
}
|
|
4476
|
+
var BackgroundWorkerController = class {
|
|
4477
|
+
constructor(projectRoot3, host, config, hooks, identity) {
|
|
4478
|
+
this.projectRoot = projectRoot3;
|
|
4479
|
+
this.host = host;
|
|
4480
|
+
this.config = config;
|
|
4481
|
+
this.hooks = hooks;
|
|
4482
|
+
this.identity = identity;
|
|
4483
|
+
}
|
|
4484
|
+
projectRoot;
|
|
4485
|
+
host;
|
|
4486
|
+
config;
|
|
4487
|
+
hooks;
|
|
4488
|
+
identity;
|
|
4489
|
+
lease = null;
|
|
4490
|
+
watcher = null;
|
|
4491
|
+
leaderReady = Promise.resolve();
|
|
4492
|
+
heartbeatTimer = null;
|
|
4493
|
+
retryTimer = null;
|
|
4494
|
+
teardownRetryTimer = null;
|
|
4495
|
+
transition = Promise.resolve();
|
|
4496
|
+
stopPromise = null;
|
|
4497
|
+
stopped = false;
|
|
4498
|
+
stopping = false;
|
|
4499
|
+
losingLeadership = false;
|
|
4500
|
+
restartAfterStop = false;
|
|
4501
|
+
leaderWorkStopped = false;
|
|
4502
|
+
startingLeaderWork = false;
|
|
4503
|
+
stopAutoIndexOnTeardown = true;
|
|
4504
|
+
autoIndexStarted = false;
|
|
4505
|
+
reportedError = null;
|
|
4506
|
+
update(config, hooks, options) {
|
|
4507
|
+
const autoIndexWasEnabled = this.config.indexing.autoIndex;
|
|
4508
|
+
const shouldReplaceWatcher = this.watcher !== null && hooks.watcherFactory !== void 0 && (hooks.watcherFactory === null || hooks.replaceWatcher === true);
|
|
4509
|
+
this.config = config;
|
|
4510
|
+
this.hooks = {
|
|
4511
|
+
...this.hooks,
|
|
4512
|
+
...hooks,
|
|
4513
|
+
watcherFactory: hooks.watcherFactory === void 0 ? this.hooks.watcherFactory : hooks.watcherFactory,
|
|
4514
|
+
watcherFactoryForConfig: hooks.watcherFactoryForConfig === void 0 ? this.hooks.watcherFactoryForConfig : hooks.watcherFactoryForConfig
|
|
4515
|
+
};
|
|
4516
|
+
if (autoIndexWasEnabled && !config.indexing.autoIndex || options.restartAutoIndex === true && config.indexing.autoIndex && !this.startingLeaderWork) {
|
|
4517
|
+
this.autoIndexStarted = false;
|
|
4518
|
+
}
|
|
4519
|
+
if (!this.canRun()) {
|
|
4520
|
+
void this.stop().catch((error) => {
|
|
4521
|
+
console.error("[codebase-index] Failed to stop background worker after disabling automatic work:", error);
|
|
4522
|
+
});
|
|
4523
|
+
return;
|
|
4524
|
+
}
|
|
4525
|
+
if (shouldReplaceWatcher) {
|
|
4526
|
+
void this.enqueue(async () => {
|
|
4527
|
+
const watcher = this.watcher;
|
|
4528
|
+
if (watcher) {
|
|
4529
|
+
await watcher.stop();
|
|
4530
|
+
if (this.watcher === watcher) this.watcher = null;
|
|
4531
|
+
}
|
|
4532
|
+
if (this.lease && !this.stopped) this.startLeaderWork();
|
|
4533
|
+
}).catch((error) => {
|
|
4534
|
+
console.error("[codebase-index] Failed to replace background file watcher:", error);
|
|
4535
|
+
});
|
|
4536
|
+
}
|
|
4537
|
+
this.start();
|
|
4538
|
+
}
|
|
4539
|
+
startAfter(activation) {
|
|
4540
|
+
this.transition = activation.catch(() => void 0);
|
|
4541
|
+
this.start();
|
|
4542
|
+
}
|
|
4543
|
+
start() {
|
|
4544
|
+
if (!this.canRun() || this.losingLeadership) return;
|
|
4545
|
+
if (this.stopping) {
|
|
4546
|
+
this.restartAfterStop = true;
|
|
4547
|
+
return;
|
|
4548
|
+
}
|
|
4549
|
+
this.stopped = false;
|
|
4550
|
+
void this.enqueue(async () => {
|
|
4551
|
+
if (this.stopped || this.stopping || this.losingLeadership || !this.canRun()) return;
|
|
4552
|
+
if (!this.lease) {
|
|
4553
|
+
try {
|
|
4554
|
+
this.lease = acquireLease(this.identity);
|
|
4555
|
+
this.reportedError = null;
|
|
4556
|
+
} catch (error) {
|
|
4557
|
+
this.reportAcquireError(error);
|
|
4558
|
+
this.scheduleRetry();
|
|
4559
|
+
return;
|
|
4560
|
+
}
|
|
4561
|
+
}
|
|
4562
|
+
if (!this.lease) {
|
|
4563
|
+
this.scheduleRetry();
|
|
4564
|
+
return;
|
|
4565
|
+
}
|
|
4566
|
+
this.startHeartbeat();
|
|
4567
|
+
this.startLeaderWork();
|
|
4568
|
+
});
|
|
4569
|
+
}
|
|
4570
|
+
waitForStart() {
|
|
4571
|
+
return this.transition.catch(() => void 0).then(() => this.leaderReady);
|
|
4572
|
+
}
|
|
4573
|
+
requestRefresh(allowDisabledAutoIndex = false) {
|
|
4574
|
+
this.start();
|
|
4575
|
+
if (!this.isLeader()) {
|
|
4576
|
+
requestRefreshFromLeader(leasePathFor(this.identity), allowDisabledAutoIndex);
|
|
4577
|
+
return;
|
|
4578
|
+
}
|
|
4579
|
+
void this.enqueue(async () => {
|
|
4580
|
+
if (this.stopped || !this.lease) return;
|
|
4581
|
+
this.hooks.startAutoIndex("retrieval", allowDisabledAutoIndex);
|
|
4582
|
+
});
|
|
4583
|
+
}
|
|
4584
|
+
isLeader() {
|
|
4585
|
+
return this.lease !== null && !this.stopping && !this.losingLeadership;
|
|
4586
|
+
}
|
|
4587
|
+
isStopping() {
|
|
4588
|
+
return this.stopping;
|
|
4589
|
+
}
|
|
4590
|
+
getHooksForConfig(config) {
|
|
4591
|
+
const watcherFactoryForConfig = this.hooks.watcherFactoryForConfig;
|
|
4592
|
+
if (!watcherFactoryForConfig) return this.hooks;
|
|
4593
|
+
return {
|
|
4594
|
+
...this.hooks,
|
|
4595
|
+
watcherFactory: watcherFactoryForConfig(config),
|
|
4596
|
+
replaceWatcher: true
|
|
4597
|
+
};
|
|
4598
|
+
}
|
|
4599
|
+
attachWatcher(watcherFactory, watcherFactoryForConfig) {
|
|
4600
|
+
if (this.hooks.watcherFactory !== void 0) return;
|
|
4601
|
+
this.hooks = {
|
|
4602
|
+
...this.hooks,
|
|
4603
|
+
watcherFactory,
|
|
4604
|
+
watcherFactoryForConfig: watcherFactoryForConfig ?? this.hooks.watcherFactoryForConfig
|
|
4605
|
+
};
|
|
4606
|
+
this.start();
|
|
4607
|
+
}
|
|
4608
|
+
async stop(stopAutoIndex = true) {
|
|
4609
|
+
if (this.stopPromise) return this.stopPromise;
|
|
4610
|
+
this.stopped = true;
|
|
4611
|
+
this.stopping = true;
|
|
4612
|
+
this.stopAutoIndexOnTeardown &&= stopAutoIndex;
|
|
4613
|
+
this.clearRetryTimer();
|
|
4614
|
+
const attempt = this.enqueue(async () => {
|
|
4615
|
+
try {
|
|
4616
|
+
const lease = this.lease;
|
|
4617
|
+
if (this.leaderWorkStopped) {
|
|
4618
|
+
if (lease) {
|
|
4619
|
+
this.releaseStoppedLease(lease);
|
|
4620
|
+
} else {
|
|
4621
|
+
this.finishStoppedLease();
|
|
4622
|
+
}
|
|
4623
|
+
return;
|
|
4624
|
+
}
|
|
4625
|
+
const hadLeaderWork = lease !== null || this.watcher !== null || this.autoIndexStarted;
|
|
4626
|
+
const stopped = await this.stopLeaderWork(hadLeaderWork && this.stopAutoIndexOnTeardown);
|
|
4627
|
+
if (!lease) {
|
|
4628
|
+
this.finishStoppedLease();
|
|
4629
|
+
return;
|
|
4630
|
+
}
|
|
4631
|
+
if (!stopped.completed) {
|
|
4632
|
+
this.releaseLeaseWhenAutoIndexStops(lease, stopped.completion);
|
|
4633
|
+
return;
|
|
4634
|
+
}
|
|
4635
|
+
this.leaderWorkStopped = true;
|
|
4636
|
+
this.releaseStoppedLease(lease);
|
|
4637
|
+
} catch (error) {
|
|
4638
|
+
this.scheduleTeardownRetry();
|
|
4639
|
+
throw error;
|
|
4640
|
+
}
|
|
4641
|
+
});
|
|
4642
|
+
const completion = attempt.finally(() => {
|
|
4643
|
+
if (this.stopPromise === completion) this.stopPromise = null;
|
|
4644
|
+
});
|
|
4645
|
+
this.stopPromise = completion;
|
|
4646
|
+
return completion;
|
|
4647
|
+
}
|
|
4648
|
+
canRun() {
|
|
4649
|
+
return this.config.indexing.autoIndex || this.hooks.watcherFactory != null;
|
|
4650
|
+
}
|
|
4651
|
+
enqueue(operation) {
|
|
4652
|
+
const next = this.transition.catch(() => void 0).then(operation);
|
|
4653
|
+
this.transition = next;
|
|
4654
|
+
return next;
|
|
4655
|
+
}
|
|
4656
|
+
startLeaderWork() {
|
|
4657
|
+
if (this.stopped || this.stopping || this.losingLeadership) return;
|
|
4658
|
+
this.startingLeaderWork = true;
|
|
4659
|
+
try {
|
|
4660
|
+
if (this.config.indexing.autoIndex && !this.autoIndexStarted) {
|
|
4661
|
+
this.autoIndexStarted = true;
|
|
4662
|
+
this.hooks.startAutoIndex("startup");
|
|
4663
|
+
}
|
|
4664
|
+
if (!this.watcher && this.hooks.watcherFactory) {
|
|
4665
|
+
try {
|
|
4666
|
+
const watcher = this.hooks.watcherFactory();
|
|
4667
|
+
this.watcher = watcher;
|
|
4668
|
+
this.leaderReady = watcher.whenReady?.().catch((error) => {
|
|
4669
|
+
console.error("[codebase-index] Failed while waiting for background file watcher startup:", error);
|
|
4670
|
+
}) ?? Promise.resolve();
|
|
4671
|
+
} catch (error) {
|
|
4672
|
+
console.error("[codebase-index] Failed to start background file watcher:", error);
|
|
4673
|
+
this.leaderReady = Promise.resolve();
|
|
4674
|
+
}
|
|
4675
|
+
}
|
|
4676
|
+
} finally {
|
|
4677
|
+
this.startingLeaderWork = false;
|
|
4678
|
+
}
|
|
4679
|
+
}
|
|
4680
|
+
async stopLeaderWork(stopAutoIndex) {
|
|
4681
|
+
const watcher = this.watcher;
|
|
4682
|
+
let watcherError;
|
|
4683
|
+
if (watcher) {
|
|
4684
|
+
try {
|
|
4685
|
+
await watcher.stop();
|
|
4686
|
+
if (this.watcher === watcher) this.watcher = null;
|
|
4687
|
+
} catch (error) {
|
|
4688
|
+
watcherError = error;
|
|
4689
|
+
}
|
|
4690
|
+
}
|
|
4691
|
+
let autoIndexError;
|
|
4692
|
+
let autoIndexStop = {
|
|
4693
|
+
completed: true,
|
|
4694
|
+
completion: Promise.resolve()
|
|
4695
|
+
};
|
|
4696
|
+
if (stopAutoIndex) {
|
|
4697
|
+
try {
|
|
4698
|
+
autoIndexStop = await this.hooks.stopAutoIndex();
|
|
4699
|
+
this.autoIndexStarted = false;
|
|
4700
|
+
} catch (error) {
|
|
4701
|
+
autoIndexError = error;
|
|
4702
|
+
}
|
|
4703
|
+
}
|
|
4704
|
+
if (watcherError !== void 0 || autoIndexError !== void 0) {
|
|
4705
|
+
throw new BackgroundWorkerStopError(watcherError, autoIndexError);
|
|
4706
|
+
}
|
|
4707
|
+
return autoIndexStop;
|
|
4708
|
+
}
|
|
4709
|
+
releaseLeaseWhenAutoIndexStops(lease, completion) {
|
|
4710
|
+
void completion.then(
|
|
4711
|
+
() => {
|
|
4712
|
+
void this.enqueue(async () => {
|
|
4713
|
+
if (this.lease !== lease || !this.stopping) return;
|
|
4714
|
+
this.leaderWorkStopped = true;
|
|
4715
|
+
this.releaseStoppedLease(lease);
|
|
4716
|
+
}).catch((error) => {
|
|
4717
|
+
console.error("[codebase-index] Failed to release background worker lease after automatic indexing stopped:", error);
|
|
4718
|
+
this.scheduleTeardownRetry();
|
|
4719
|
+
});
|
|
4720
|
+
},
|
|
4721
|
+
(error) => {
|
|
4722
|
+
console.error("[codebase-index] Failed while waiting for automatic indexing to stop:", error);
|
|
4723
|
+
this.scheduleTeardownRetry();
|
|
4724
|
+
}
|
|
4725
|
+
);
|
|
4726
|
+
}
|
|
4727
|
+
releaseStoppedLease(lease) {
|
|
4728
|
+
if (this.lease !== lease) {
|
|
4729
|
+
this.finishStoppedLease();
|
|
4730
|
+
return;
|
|
4731
|
+
}
|
|
4732
|
+
releaseLease(lease);
|
|
4733
|
+
this.lease = null;
|
|
4734
|
+
this.finishStoppedLease();
|
|
4735
|
+
}
|
|
4736
|
+
finishStoppedLease() {
|
|
4737
|
+
this.leaderWorkStopped = false;
|
|
4738
|
+
this.stopAutoIndexOnTeardown = true;
|
|
4739
|
+
this.stopping = false;
|
|
4740
|
+
this.clearTimers();
|
|
4741
|
+
this.restartAfterTeardown();
|
|
4742
|
+
if (!this.stopped || this.stopping) return;
|
|
4743
|
+
const projectKey = projectLookupKey(this.projectRoot, this.host);
|
|
4744
|
+
const key = controllerKey(this.identity, this.host);
|
|
4745
|
+
if (workers.get(key) === this) workers.delete(key);
|
|
4746
|
+
if (workerKeysByProject.get(projectKey) === key) workerKeysByProject.delete(projectKey);
|
|
4747
|
+
}
|
|
4748
|
+
startHeartbeat() {
|
|
4749
|
+
if (this.heartbeatTimer) return;
|
|
4750
|
+
const heartbeat = () => {
|
|
4751
|
+
void this.heartbeat();
|
|
4752
|
+
};
|
|
4753
|
+
this.heartbeatTimer = setInterval(heartbeat, HEARTBEAT_INTERVAL_MS);
|
|
4754
|
+
this.heartbeatTimer.unref?.();
|
|
4755
|
+
}
|
|
4756
|
+
async heartbeat() {
|
|
4757
|
+
const lease = this.lease;
|
|
4758
|
+
if (!lease || this.losingLeadership || this.stopped && !this.stopping) return;
|
|
4759
|
+
if (hasActiveReclaimMarker(lease.leasePath, lease.owner)) {
|
|
4760
|
+
await this.loseLeadership();
|
|
4761
|
+
return;
|
|
4762
|
+
}
|
|
4763
|
+
const currentOwner = readOwner(lease.leasePath);
|
|
4764
|
+
if (!currentOwner || !sameOwner2(currentOwner, lease.owner)) {
|
|
4765
|
+
await this.loseLeadership();
|
|
4766
|
+
return;
|
|
4767
|
+
}
|
|
4768
|
+
try {
|
|
4769
|
+
const nextOwner = { ...lease.owner, heartbeatAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
4770
|
+
if (!writeHeartbeat(lease.leasePath, nextOwner)) {
|
|
4771
|
+
await this.loseLeadership();
|
|
4772
|
+
return;
|
|
4773
|
+
}
|
|
4774
|
+
lease.owner = nextOwner;
|
|
4775
|
+
const refreshRequest = !this.stopping ? consumeRefreshRequest(lease.leasePath) : null;
|
|
4776
|
+
if (refreshRequest) {
|
|
4777
|
+
this.hooks.startAutoIndex("retrieval", refreshRequest.allowDisabledAutoIndex);
|
|
4778
|
+
}
|
|
4779
|
+
} catch (error) {
|
|
4780
|
+
const ownerAfterError = readOwner(lease.leasePath);
|
|
4781
|
+
if (hasActiveReclaimMarker(lease.leasePath, lease.owner) || !ownerAfterError || !sameOwner2(ownerAfterError, lease.owner)) {
|
|
4782
|
+
await this.loseLeadership();
|
|
4783
|
+
return;
|
|
4784
|
+
}
|
|
4785
|
+
console.error("[codebase-index] Failed to renew background worker lease:", error);
|
|
4786
|
+
}
|
|
4787
|
+
}
|
|
4788
|
+
async loseLeadership() {
|
|
4789
|
+
if (this.losingLeadership) return;
|
|
4790
|
+
this.losingLeadership = true;
|
|
4791
|
+
this.clearHeartbeat();
|
|
4792
|
+
await this.enqueue(async () => this.stopAfterLeadershipLoss());
|
|
4793
|
+
}
|
|
4794
|
+
async stopAfterLeadershipLoss() {
|
|
4795
|
+
const lease = this.lease;
|
|
4796
|
+
if (!lease) {
|
|
4797
|
+
this.losingLeadership = false;
|
|
4798
|
+
return;
|
|
4799
|
+
}
|
|
4800
|
+
try {
|
|
4801
|
+
const stopped = await this.stopLeaderWork(true);
|
|
4802
|
+
this.lease = null;
|
|
4803
|
+
this.losingLeadership = false;
|
|
4804
|
+
if (stopped.completed) {
|
|
4805
|
+
this.scheduleRetry();
|
|
4806
|
+
} else {
|
|
4807
|
+
void stopped.completion.then(() => this.scheduleRetry());
|
|
4808
|
+
}
|
|
4809
|
+
} catch (error) {
|
|
4810
|
+
console.error("[codebase-index] Failed to stop background work after losing its lease:", error);
|
|
4811
|
+
this.scheduleLostLeadershipTeardownRetry();
|
|
4812
|
+
}
|
|
4813
|
+
}
|
|
4814
|
+
scheduleRetry() {
|
|
4815
|
+
if (this.stopped || !this.canRun() || this.retryTimer) return;
|
|
4816
|
+
this.retryTimer = setTimeout(() => {
|
|
4817
|
+
this.retryTimer = null;
|
|
4818
|
+
this.start();
|
|
4819
|
+
}, RETRY_DELAY_MS);
|
|
4820
|
+
this.retryTimer.unref?.();
|
|
4821
|
+
}
|
|
4822
|
+
scheduleTeardownRetry() {
|
|
4823
|
+
if (!this.stopping || this.teardownRetryTimer) return;
|
|
4824
|
+
this.teardownRetryTimer = setTimeout(() => {
|
|
4825
|
+
this.teardownRetryTimer = null;
|
|
4826
|
+
void this.stop(this.stopAutoIndexOnTeardown).catch((error) => {
|
|
4827
|
+
console.error("[codebase-index] Failed to retry background worker teardown:", error);
|
|
4828
|
+
});
|
|
4829
|
+
}, RETRY_DELAY_MS);
|
|
4830
|
+
this.teardownRetryTimer.unref?.();
|
|
4831
|
+
}
|
|
4832
|
+
restartAfterTeardown() {
|
|
4833
|
+
if (!this.restartAfterStop || !this.canRun() || this.losingLeadership) return;
|
|
4834
|
+
this.restartAfterStop = false;
|
|
4835
|
+
this.stopped = false;
|
|
4836
|
+
this.start();
|
|
4837
|
+
}
|
|
4838
|
+
scheduleLostLeadershipTeardownRetry() {
|
|
4839
|
+
if (this.stopped || !this.losingLeadership || this.retryTimer) return;
|
|
4840
|
+
this.retryTimer = setTimeout(() => {
|
|
4841
|
+
this.retryTimer = null;
|
|
4842
|
+
void this.enqueue(async () => this.stopAfterLeadershipLoss());
|
|
4843
|
+
}, RETRY_DELAY_MS);
|
|
4844
|
+
this.retryTimer.unref?.();
|
|
4845
|
+
}
|
|
4846
|
+
clearHeartbeat() {
|
|
4847
|
+
if (!this.heartbeatTimer) return;
|
|
4848
|
+
clearInterval(this.heartbeatTimer);
|
|
4849
|
+
this.heartbeatTimer = null;
|
|
4850
|
+
}
|
|
4851
|
+
clearTimers() {
|
|
4852
|
+
this.clearHeartbeat();
|
|
4853
|
+
this.clearRetryTimer();
|
|
4854
|
+
if (this.teardownRetryTimer) {
|
|
4855
|
+
clearTimeout(this.teardownRetryTimer);
|
|
4856
|
+
this.teardownRetryTimer = null;
|
|
4857
|
+
}
|
|
4858
|
+
}
|
|
4859
|
+
clearRetryTimer() {
|
|
4860
|
+
if (!this.retryTimer) return;
|
|
4861
|
+
clearTimeout(this.retryTimer);
|
|
4862
|
+
this.retryTimer = null;
|
|
4863
|
+
}
|
|
4864
|
+
reportAcquireError(error) {
|
|
4865
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
4866
|
+
if (this.reportedError === message) return;
|
|
4867
|
+
this.reportedError = message;
|
|
4868
|
+
console.error("[codebase-index] Failed to acquire background worker lease:", error);
|
|
4869
|
+
}
|
|
4870
|
+
};
|
|
4871
|
+
function configureBackgroundWorker(projectRoot3, host, config, hooks, options = {}) {
|
|
4872
|
+
const projectKey = projectLookupKey(projectRoot3, host);
|
|
4873
|
+
const identity = resolveIdentity(projectRoot3, config, host);
|
|
4874
|
+
const key = controllerKey(identity, host);
|
|
4875
|
+
const previousKey = workerKeysByProject.get(projectKey);
|
|
4876
|
+
if (previousKey && previousKey !== key) {
|
|
4877
|
+
const previous = workers.get(previousKey);
|
|
4878
|
+
const previousBarrier = workerReplacementBarriers.get(projectKey) ?? Promise.resolve();
|
|
4879
|
+
const stopPrevious = previous?.stop(options.stopPreviousAutoIndex ?? true) ?? Promise.resolve();
|
|
4880
|
+
const activation = Promise.all([previousBarrier, stopPrevious]).then(() => void 0);
|
|
4881
|
+
workerReplacementBarriers.set(projectKey, activation);
|
|
4882
|
+
workers.delete(previousKey);
|
|
4883
|
+
const worker2 = new BackgroundWorkerController(projectRoot3, host, config, hooks, identity);
|
|
4884
|
+
worker2.startAfter(activation);
|
|
4885
|
+
workers.set(key, worker2);
|
|
4886
|
+
workerKeysByProject.set(projectKey, key);
|
|
4887
|
+
return;
|
|
4888
|
+
}
|
|
4889
|
+
let worker = workers.get(key);
|
|
4890
|
+
if (!worker) {
|
|
4891
|
+
worker = new BackgroundWorkerController(projectRoot3, host, config, hooks, identity);
|
|
4892
|
+
workers.set(key, worker);
|
|
4893
|
+
} else {
|
|
4894
|
+
worker.update(config, hooks, options);
|
|
4895
|
+
}
|
|
4896
|
+
workerKeysByProject.set(projectKey, key);
|
|
4897
|
+
worker.start();
|
|
4898
|
+
}
|
|
4899
|
+
function updateBackgroundWorkerConfig(projectRoot3, host, config) {
|
|
4900
|
+
const projectKey = projectLookupKey(projectRoot3, host);
|
|
4901
|
+
const key = workerKeysByProject.get(projectKey);
|
|
4902
|
+
const worker = key ? workers.get(key) : void 0;
|
|
4903
|
+
if (!worker) return;
|
|
4904
|
+
configureBackgroundWorker(projectRoot3, host, config, worker.getHooksForConfig(config), {
|
|
4905
|
+
stopPreviousAutoIndex: false,
|
|
4906
|
+
restartAutoIndex: true
|
|
4907
|
+
});
|
|
4908
|
+
}
|
|
4909
|
+
function waitForBackgroundWorkerStart(projectRoot3, host) {
|
|
4910
|
+
const key = workerKeysByProject.get(projectLookupKey(projectRoot3, host));
|
|
4911
|
+
return workers.get(key ?? "")?.waitForStart() ?? Promise.resolve();
|
|
4912
|
+
}
|
|
4913
|
+
function requestBackgroundWorkerRefresh(projectRoot3, host, allowDisabledAutoIndex = false) {
|
|
4914
|
+
const key = workerKeysByProject.get(projectLookupKey(projectRoot3, host));
|
|
4915
|
+
workers.get(key ?? "")?.requestRefresh(allowDisabledAutoIndex);
|
|
4916
|
+
}
|
|
4917
|
+
function isBackgroundWorkerManaged(projectRoot3, host) {
|
|
4918
|
+
const key = workerKeysByProject.get(projectLookupKey(projectRoot3, host));
|
|
4919
|
+
return key !== void 0 && workers.has(key);
|
|
4920
|
+
}
|
|
4921
|
+
function isBackgroundWorkerLeader(projectRoot3, host) {
|
|
4922
|
+
const key = workerKeysByProject.get(projectLookupKey(projectRoot3, host));
|
|
4923
|
+
return key !== void 0 && workers.get(key)?.isLeader() === true;
|
|
4924
|
+
}
|
|
4925
|
+
async function stopBackgroundWorker(projectRoot3, host) {
|
|
4926
|
+
const projectKey = projectLookupKey(projectRoot3, host);
|
|
4927
|
+
const key = workerKeysByProject.get(projectKey);
|
|
4928
|
+
const worker = key ? workers.get(key) : void 0;
|
|
4929
|
+
if (!worker) return;
|
|
4930
|
+
await worker.stop();
|
|
4931
|
+
}
|
|
4932
|
+
|
|
4030
4933
|
// src/utils/files.ts
|
|
4031
4934
|
var import_ignore = __toESM(require_ignore(), 1);
|
|
4032
|
-
import { existsSync as
|
|
4033
|
-
import * as
|
|
4935
|
+
import { existsSync as existsSync8, readFileSync as readFileSync7, promises as fsPromises } from "fs";
|
|
4936
|
+
import * as path12 from "path";
|
|
4034
4937
|
var PROJECT_MARKERS = [
|
|
4035
4938
|
".git",
|
|
4036
4939
|
"package.json",
|
|
@@ -4048,7 +4951,7 @@ var PROJECT_MARKERS = [
|
|
|
4048
4951
|
];
|
|
4049
4952
|
function hasProjectMarker(projectRoot3) {
|
|
4050
4953
|
for (const marker of PROJECT_MARKERS) {
|
|
4051
|
-
if (
|
|
4954
|
+
if (existsSync8(path12.join(projectRoot3, marker))) {
|
|
4052
4955
|
return true;
|
|
4053
4956
|
}
|
|
4054
4957
|
}
|
|
@@ -4075,33 +4978,53 @@ function createIgnoreFilter(projectRoot3) {
|
|
|
4075
4978
|
"**/*build*/**"
|
|
4076
4979
|
];
|
|
4077
4980
|
ig.add(defaultIgnores);
|
|
4078
|
-
const gitignorePath =
|
|
4079
|
-
if (
|
|
4080
|
-
const gitignoreContent =
|
|
4981
|
+
const gitignorePath = path12.join(projectRoot3, ".gitignore");
|
|
4982
|
+
if (existsSync8(gitignorePath)) {
|
|
4983
|
+
const gitignoreContent = readFileSync7(gitignorePath, "utf-8");
|
|
4081
4984
|
ig.add(gitignoreContent);
|
|
4082
4985
|
}
|
|
4083
4986
|
return ig;
|
|
4084
4987
|
}
|
|
4085
|
-
function
|
|
4086
|
-
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
|
|
4091
|
-
|
|
4988
|
+
function toPosixRelativePath(relativePath) {
|
|
4989
|
+
return relativePath.split(path12.sep).join("/");
|
|
4990
|
+
}
|
|
4991
|
+
function matchesAnyGlob(filePath, patterns) {
|
|
4992
|
+
const normalized = toPosixRelativePath(filePath);
|
|
4993
|
+
return patterns.some((pattern) => matchGlob(normalized, pattern));
|
|
4994
|
+
}
|
|
4995
|
+
function isExcludedByPatterns(relativePath, excludePatterns) {
|
|
4996
|
+
return matchesAnyGlob(relativePath, excludePatterns);
|
|
4997
|
+
}
|
|
4998
|
+
function isExcludedDirectory(relativePath, excludePatterns) {
|
|
4999
|
+
const normalized = toPosixRelativePath(relativePath);
|
|
5000
|
+
if (matchesAnyGlob(normalized, excludePatterns)) {
|
|
5001
|
+
return true;
|
|
4092
5002
|
}
|
|
4093
5003
|
for (const pattern of excludePatterns) {
|
|
4094
|
-
|
|
4095
|
-
|
|
5004
|
+
const posixPattern = toPosixRelativePath(pattern).replace(/\/+$/, "");
|
|
5005
|
+
if (!posixPattern.endsWith("/**")) {
|
|
5006
|
+
continue;
|
|
4096
5007
|
}
|
|
4097
|
-
|
|
4098
|
-
|
|
4099
|
-
if (matchGlob(relativePath, pattern)) {
|
|
5008
|
+
const directoryPattern = posixPattern.slice(0, -3);
|
|
5009
|
+
if (directoryPattern && matchesAnyGlob(normalized, [directoryPattern])) {
|
|
4100
5010
|
return true;
|
|
4101
5011
|
}
|
|
4102
5012
|
}
|
|
4103
5013
|
return false;
|
|
4104
5014
|
}
|
|
5015
|
+
function shouldIncludeFile(filePath, projectRoot3, includePatterns, excludePatterns, ignoreFilter) {
|
|
5016
|
+
const relativePath = toPosixRelativePath(path12.relative(projectRoot3, filePath));
|
|
5017
|
+
if (hasFilteredPathSegment(relativePath, "/")) {
|
|
5018
|
+
return false;
|
|
5019
|
+
}
|
|
5020
|
+
if (ignoreFilter.ignores(relativePath)) {
|
|
5021
|
+
return false;
|
|
5022
|
+
}
|
|
5023
|
+
if (isExcludedByPatterns(relativePath, excludePatterns)) {
|
|
5024
|
+
return false;
|
|
5025
|
+
}
|
|
5026
|
+
return matchesAnyGlob(relativePath, includePatterns);
|
|
5027
|
+
}
|
|
4105
5028
|
function matchGlob(filePath, pattern) {
|
|
4106
5029
|
if (pattern.startsWith("**/")) {
|
|
4107
5030
|
const withoutPrefix = pattern.slice(3);
|
|
@@ -4122,8 +5045,8 @@ async function* walkDirectory(dir, projectRoot3, includePatterns, excludePattern
|
|
|
4122
5045
|
const filesInDir = [];
|
|
4123
5046
|
const subdirs = [];
|
|
4124
5047
|
for (const entry of entries) {
|
|
4125
|
-
const fullPath =
|
|
4126
|
-
const relativePath =
|
|
5048
|
+
const fullPath = path12.join(dir, entry.name);
|
|
5049
|
+
const relativePath = toPosixRelativePath(path12.relative(projectRoot3, fullPath));
|
|
4127
5050
|
if (isHiddenPathSegment(entry.name)) {
|
|
4128
5051
|
if (entry.isDirectory()) {
|
|
4129
5052
|
skipped.push({ path: relativePath, reason: "excluded" });
|
|
@@ -4141,6 +5064,10 @@ async function* walkDirectory(dir, projectRoot3, includePatterns, excludePattern
|
|
|
4141
5064
|
continue;
|
|
4142
5065
|
}
|
|
4143
5066
|
if (entry.isDirectory()) {
|
|
5067
|
+
if (isExcludedDirectory(relativePath, excludePatterns)) {
|
|
5068
|
+
skipped.push({ path: relativePath, reason: "excluded" });
|
|
5069
|
+
continue;
|
|
5070
|
+
}
|
|
4144
5071
|
subdirs.push({ fullPath, relativePath });
|
|
4145
5072
|
} else if (entry.isFile()) {
|
|
4146
5073
|
const stat5 = await fsPromises.stat(fullPath);
|
|
@@ -4148,20 +5075,11 @@ async function* walkDirectory(dir, projectRoot3, includePatterns, excludePattern
|
|
|
4148
5075
|
skipped.push({ path: relativePath, reason: "too_large" });
|
|
4149
5076
|
continue;
|
|
4150
5077
|
}
|
|
4151
|
-
|
|
4152
|
-
|
|
4153
|
-
|
|
4154
|
-
continue;
|
|
4155
|
-
}
|
|
4156
|
-
}
|
|
4157
|
-
let matched = false;
|
|
4158
|
-
for (const pattern of includePatterns) {
|
|
4159
|
-
if (matchGlob(relativePath, pattern)) {
|
|
4160
|
-
matched = true;
|
|
4161
|
-
break;
|
|
4162
|
-
}
|
|
5078
|
+
if (isExcludedByPatterns(relativePath, excludePatterns)) {
|
|
5079
|
+
skipped.push({ path: relativePath, reason: "excluded" });
|
|
5080
|
+
continue;
|
|
4163
5081
|
}
|
|
4164
|
-
if (
|
|
5082
|
+
if (matchesAnyGlob(relativePath, includePatterns)) {
|
|
4165
5083
|
filesInDir.push({ path: fullPath, size: stat5.size });
|
|
4166
5084
|
}
|
|
4167
5085
|
}
|
|
@@ -4172,7 +5090,7 @@ async function* walkDirectory(dir, projectRoot3, includePatterns, excludePattern
|
|
|
4172
5090
|
yield f;
|
|
4173
5091
|
}
|
|
4174
5092
|
for (let i = options.maxFilesPerDirectory; i < filesInDir.length; i++) {
|
|
4175
|
-
skipped.push({ path:
|
|
5093
|
+
skipped.push({ path: toPosixRelativePath(path12.relative(projectRoot3, filesInDir[i].path)), reason: "excluded" });
|
|
4176
5094
|
}
|
|
4177
5095
|
const canRecurse = options.maxDepth === -1 || currentDepth < options.maxDepth;
|
|
4178
5096
|
if (canRecurse) {
|
|
@@ -4212,8 +5130,8 @@ async function collectFiles(projectRoot3, includePatterns, excludePatterns, maxF
|
|
|
4212
5130
|
if (additionalRoots && additionalRoots.length > 0) {
|
|
4213
5131
|
const normalizedRoots = /* @__PURE__ */ new Set();
|
|
4214
5132
|
for (const kbRoot of additionalRoots) {
|
|
4215
|
-
const resolved =
|
|
4216
|
-
|
|
5133
|
+
const resolved = path12.normalize(
|
|
5134
|
+
path12.isAbsolute(kbRoot) ? kbRoot : path12.resolve(projectRoot3, kbRoot)
|
|
4217
5135
|
);
|
|
4218
5136
|
normalizedRoots.add(resolved);
|
|
4219
5137
|
}
|
|
@@ -4254,7 +5172,7 @@ function getErrorMessage(error) {
|
|
|
4254
5172
|
return error instanceof Error ? error.message : String(error);
|
|
4255
5173
|
}
|
|
4256
5174
|
function runCommand(file, args, options) {
|
|
4257
|
-
return new Promise((
|
|
5175
|
+
return new Promise((resolve18, reject) => {
|
|
4258
5176
|
childProcess.execFile(
|
|
4259
5177
|
file,
|
|
4260
5178
|
args,
|
|
@@ -4264,7 +5182,7 @@ function runCommand(file, args, options) {
|
|
|
4264
5182
|
reject(error);
|
|
4265
5183
|
return;
|
|
4266
5184
|
}
|
|
4267
|
-
|
|
5185
|
+
resolve18(stdout);
|
|
4268
5186
|
}
|
|
4269
5187
|
);
|
|
4270
5188
|
});
|
|
@@ -4356,29 +5274,29 @@ var AutoIndexCancelledError = class extends Error {
|
|
|
4356
5274
|
function now() {
|
|
4357
5275
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
4358
5276
|
}
|
|
4359
|
-
function
|
|
4360
|
-
const resolved =
|
|
4361
|
-
if (
|
|
5277
|
+
function canonicalizePath2(targetPath) {
|
|
5278
|
+
const resolved = path13.resolve(targetPath);
|
|
5279
|
+
if (existsSync9(resolved)) {
|
|
4362
5280
|
try {
|
|
4363
|
-
return
|
|
5281
|
+
return realpathSync4.native(resolved);
|
|
4364
5282
|
} catch {
|
|
4365
5283
|
return resolved;
|
|
4366
5284
|
}
|
|
4367
5285
|
}
|
|
4368
|
-
const parent =
|
|
5286
|
+
const parent = path13.dirname(resolved);
|
|
4369
5287
|
if (parent === resolved) return resolved;
|
|
4370
|
-
return
|
|
5288
|
+
return path13.join(canonicalizePath2(parent), path13.basename(resolved));
|
|
4371
5289
|
}
|
|
4372
5290
|
function isHomeDirectory(projectRoot3) {
|
|
4373
|
-
return
|
|
5291
|
+
return canonicalizePath2(projectRoot3) === canonicalizePath2(os5.homedir());
|
|
4374
5292
|
}
|
|
4375
|
-
function
|
|
4376
|
-
return `${host}::${
|
|
5293
|
+
function projectLookupKey2(projectRoot3, host) {
|
|
5294
|
+
return `${host}::${canonicalizePath2(projectRoot3)}`;
|
|
4377
5295
|
}
|
|
4378
5296
|
function coordinatorKey(projectRoot3, config, host) {
|
|
4379
|
-
const canonicalProjectRoot =
|
|
5297
|
+
const canonicalProjectRoot = canonicalizePath2(projectRoot3);
|
|
4380
5298
|
const indexPath = resolveProjectIndexPath(projectRoot3, config.scope, host);
|
|
4381
|
-
return `${
|
|
5299
|
+
return `${canonicalizePath2(indexPath)}::${canonicalProjectRoot}`;
|
|
4382
5300
|
}
|
|
4383
5301
|
function getProjectSafety(projectRoot3, config) {
|
|
4384
5302
|
if (isHomeDirectory(projectRoot3)) {
|
|
@@ -4409,10 +5327,10 @@ function safeFailureMessage(error) {
|
|
|
4409
5327
|
}
|
|
4410
5328
|
function cancellableDelay(delayMs, signal) {
|
|
4411
5329
|
if (signal.aborted) return Promise.reject(new AutoIndexCancelledError());
|
|
4412
|
-
return new Promise((
|
|
5330
|
+
return new Promise((resolve18, reject) => {
|
|
4413
5331
|
const timer = setTimeout(() => {
|
|
4414
5332
|
signal.removeEventListener("abort", onAbort);
|
|
4415
|
-
|
|
5333
|
+
resolve18();
|
|
4416
5334
|
}, delayMs);
|
|
4417
5335
|
timer.unref?.();
|
|
4418
5336
|
const onAbort = () => {
|
|
@@ -4424,18 +5342,44 @@ function cancellableDelay(delayMs, signal) {
|
|
|
4424
5342
|
}
|
|
4425
5343
|
function withTimeout(promise, timeoutMs) {
|
|
4426
5344
|
if (timeoutMs <= 0) return Promise.resolve(void 0);
|
|
4427
|
-
return new Promise((
|
|
4428
|
-
const timer = setTimeout(() =>
|
|
5345
|
+
return new Promise((resolve18) => {
|
|
5346
|
+
const timer = setTimeout(() => resolve18(void 0), timeoutMs);
|
|
4429
5347
|
timer.unref?.();
|
|
4430
5348
|
void promise.then((value) => {
|
|
4431
5349
|
clearTimeout(timer);
|
|
4432
|
-
|
|
5350
|
+
resolve18(value);
|
|
4433
5351
|
}, () => {
|
|
4434
5352
|
clearTimeout(timer);
|
|
4435
|
-
|
|
5353
|
+
resolve18(void 0);
|
|
4436
5354
|
});
|
|
4437
5355
|
});
|
|
4438
5356
|
}
|
|
5357
|
+
function settlesWithin(promise, timeoutMs) {
|
|
5358
|
+
if (timeoutMs <= 0) return Promise.resolve(false);
|
|
5359
|
+
return new Promise((resolve18) => {
|
|
5360
|
+
let settled = false;
|
|
5361
|
+
const timer = setTimeout(() => {
|
|
5362
|
+
if (settled) return;
|
|
5363
|
+
settled = true;
|
|
5364
|
+
resolve18(false);
|
|
5365
|
+
}, timeoutMs);
|
|
5366
|
+
timer.unref?.();
|
|
5367
|
+
void promise.then(
|
|
5368
|
+
() => {
|
|
5369
|
+
if (settled) return;
|
|
5370
|
+
settled = true;
|
|
5371
|
+
clearTimeout(timer);
|
|
5372
|
+
resolve18(true);
|
|
5373
|
+
},
|
|
5374
|
+
() => {
|
|
5375
|
+
if (settled) return;
|
|
5376
|
+
settled = true;
|
|
5377
|
+
clearTimeout(timer);
|
|
5378
|
+
resolve18(true);
|
|
5379
|
+
}
|
|
5380
|
+
);
|
|
5381
|
+
});
|
|
5382
|
+
}
|
|
4439
5383
|
function requestPriority(request) {
|
|
4440
5384
|
if (request.force) return 4;
|
|
4441
5385
|
if (request.source === "manual") return 3;
|
|
@@ -4446,6 +5390,7 @@ function mergeRequests(current, next) {
|
|
|
4446
5390
|
if (!current) return next;
|
|
4447
5391
|
const preferred = requestPriority(next) > requestPriority(current) ? next : current;
|
|
4448
5392
|
return {
|
|
5393
|
+
allowDisabledAutoIndex: current.allowDisabledAutoIndex || next.allowDisabledAutoIndex,
|
|
4449
5394
|
checkFreshness: current.checkFreshness && next.checkFreshness,
|
|
4450
5395
|
force: current.force || next.force,
|
|
4451
5396
|
onProgress: next.onProgress ?? current.onProgress,
|
|
@@ -4507,11 +5452,11 @@ var AutoIndexCoordinator = class {
|
|
|
4507
5452
|
progress: this.status.progress ? { ...this.status.progress } : void 0
|
|
4508
5453
|
};
|
|
4509
5454
|
}
|
|
4510
|
-
start(source) {
|
|
5455
|
+
start(source, allowDisabledAutoIndex = false) {
|
|
4511
5456
|
this.refreshSafety();
|
|
4512
|
-
if (!this.registration.config.indexing.autoIndex || !this.registration.safeToRun) return null;
|
|
5457
|
+
if (!this.registration.config.indexing.autoIndex && !allowDisabledAutoIndex || !this.registration.safeToRun) return null;
|
|
4513
5458
|
if (this.status.state === "failed") return this.inFlight;
|
|
4514
|
-
return this.request({ checkFreshness: true, force: false, source });
|
|
5459
|
+
return this.request({ allowDisabledAutoIndex, checkFreshness: true, force: false, source });
|
|
4515
5460
|
}
|
|
4516
5461
|
request(request) {
|
|
4517
5462
|
if (this.stopped) {
|
|
@@ -4586,13 +5531,15 @@ var AutoIndexCoordinator = class {
|
|
|
4586
5531
|
retryAttempt: void 0
|
|
4587
5532
|
});
|
|
4588
5533
|
const inFlight = this.inFlight;
|
|
4589
|
-
|
|
4590
|
-
|
|
4591
|
-
|
|
4592
|
-
} else {
|
|
4593
|
-
await withTimeout(inFlight, SHUTDOWN_WAIT_MS);
|
|
4594
|
-
}
|
|
5534
|
+
const completion = inFlight ? inFlight.then(() => void 0, () => void 0) : Promise.resolve();
|
|
5535
|
+
if (!inFlight) {
|
|
5536
|
+
return { completed: true, completion };
|
|
4595
5537
|
}
|
|
5538
|
+
if (waitForCompletion) {
|
|
5539
|
+
await completion;
|
|
5540
|
+
return { completed: true, completion };
|
|
5541
|
+
}
|
|
5542
|
+
return { completed: await settlesWithin(completion, SHUTDOWN_WAIT_MS), completion };
|
|
4596
5543
|
}
|
|
4597
5544
|
startRequest(request) {
|
|
4598
5545
|
if (this.stopped || !this.canRun(request)) {
|
|
@@ -4781,7 +5728,7 @@ var AutoIndexCoordinator = class {
|
|
|
4781
5728
|
if (request.source === "manual" || request.source === "watcher") {
|
|
4782
5729
|
return true;
|
|
4783
5730
|
}
|
|
4784
|
-
return this.registration.safeToRun && this.registration.config.indexing.autoIndex;
|
|
5731
|
+
return this.registration.safeToRun && (this.registration.config.indexing.autoIndex || request.allowDisabledAutoIndex === true);
|
|
4785
5732
|
}
|
|
4786
5733
|
shouldDeferForBattery(request) {
|
|
4787
5734
|
return this.registration.backgroundIndexingPolicy !== null && (request.source === "startup" || request.source === "watcher");
|
|
@@ -4814,17 +5761,17 @@ var AutoIndexCoordinator = class {
|
|
|
4814
5761
|
}
|
|
4815
5762
|
}
|
|
4816
5763
|
waitForBatteryRetry(delayMs) {
|
|
4817
|
-
return new Promise((
|
|
5764
|
+
return new Promise((resolve18) => {
|
|
4818
5765
|
const timer = setTimeout(() => {
|
|
4819
5766
|
if (this.batteryRetryTimer === timer) {
|
|
4820
5767
|
this.batteryRetryTimer = null;
|
|
4821
5768
|
this.resolveBatteryRetry = null;
|
|
4822
5769
|
}
|
|
4823
|
-
|
|
5770
|
+
resolve18();
|
|
4824
5771
|
}, delayMs);
|
|
4825
5772
|
timer.unref?.();
|
|
4826
5773
|
this.batteryRetryTimer = timer;
|
|
4827
|
-
this.resolveBatteryRetry =
|
|
5774
|
+
this.resolveBatteryRetry = resolve18;
|
|
4828
5775
|
});
|
|
4829
5776
|
}
|
|
4830
5777
|
cancelBatteryRetry() {
|
|
@@ -4832,9 +5779,9 @@ var AutoIndexCoordinator = class {
|
|
|
4832
5779
|
clearTimeout(this.batteryRetryTimer);
|
|
4833
5780
|
this.batteryRetryTimer = null;
|
|
4834
5781
|
}
|
|
4835
|
-
const
|
|
5782
|
+
const resolve18 = this.resolveBatteryRetry;
|
|
4836
5783
|
this.resolveBatteryRetry = null;
|
|
4837
|
-
|
|
5784
|
+
resolve18?.();
|
|
4838
5785
|
}
|
|
4839
5786
|
finishBatteryCheck(batteryCheck) {
|
|
4840
5787
|
if (this.batteryCheck !== batteryCheck) return;
|
|
@@ -4847,12 +5794,25 @@ var AutoIndexCoordinator = class {
|
|
|
4847
5794
|
}
|
|
4848
5795
|
};
|
|
4849
5796
|
function getCoordinator(projectRoot3, host) {
|
|
4850
|
-
const key = coordinatorKeysByProject.get(
|
|
5797
|
+
const key = coordinatorKeysByProject.get(projectLookupKey2(projectRoot3, host));
|
|
4851
5798
|
return key ? coordinators.get(key) ?? null : null;
|
|
4852
5799
|
}
|
|
4853
|
-
function
|
|
4854
|
-
|
|
5800
|
+
function synchronizeBackgroundWorker(projectRoot3, host, config, safeToRun) {
|
|
5801
|
+
if (safeToRun) {
|
|
5802
|
+
updateBackgroundWorkerConfig(projectRoot3, host, config);
|
|
5803
|
+
return;
|
|
5804
|
+
}
|
|
5805
|
+
void stopBackgroundWorker(projectRoot3, host).catch((error) => {
|
|
5806
|
+
console.error("[codebase-index] Failed to stop background worker after project safety changed:", error);
|
|
5807
|
+
});
|
|
5808
|
+
}
|
|
5809
|
+
function configureAutoIndex(projectRoot3, host, config, getIndexer, options = {}) {
|
|
5810
|
+
const projectKey = projectLookupKey2(projectRoot3, host);
|
|
4855
5811
|
const safety = getProjectSafety(projectRoot3, config);
|
|
5812
|
+
const synchronizeWorker = options.synchronizeBackgroundWorker ?? true;
|
|
5813
|
+
if (options.preserveManagedWorker === true && isBackgroundWorkerManaged(projectRoot3, host)) {
|
|
5814
|
+
return;
|
|
5815
|
+
}
|
|
4856
5816
|
const registration = {
|
|
4857
5817
|
backgroundIndexingPolicy: createBackgroundIndexingPolicy(
|
|
4858
5818
|
config.indexing.pauseBackgroundIndexingOnBattery
|
|
@@ -4870,6 +5830,9 @@ function configureAutoIndex(projectRoot3, host, config, getIndexer) {
|
|
|
4870
5830
|
const stopPrevious = previousCoordinator?.stop(true) ?? Promise.resolve();
|
|
4871
5831
|
const activation = Promise.all([previousBarrier, stopPrevious]).then(() => void 0);
|
|
4872
5832
|
coordinatorReplacementBarriers.set(projectKey, activation);
|
|
5833
|
+
if (synchronizeWorker) {
|
|
5834
|
+
synchronizeBackgroundWorker(projectRoot3, host, config, safety.safeToRun);
|
|
5835
|
+
}
|
|
4873
5836
|
coordinators.delete(previousKey);
|
|
4874
5837
|
const coordinator2 = new AutoIndexCoordinator(registration);
|
|
4875
5838
|
coordinator2.activateAfter(activation);
|
|
@@ -4885,8 +5848,17 @@ function configureAutoIndex(projectRoot3, host, config, getIndexer) {
|
|
|
4885
5848
|
coordinator.update(registration);
|
|
4886
5849
|
}
|
|
4887
5850
|
coordinatorKeysByProject.set(projectKey, key);
|
|
5851
|
+
if (synchronizeWorker) {
|
|
5852
|
+
synchronizeBackgroundWorker(projectRoot3, host, config, safety.safeToRun);
|
|
5853
|
+
}
|
|
5854
|
+
}
|
|
5855
|
+
function startAutoIndexForBackgroundWorker(projectRoot3, host, source = "startup", allowDisabledAutoIndex = false) {
|
|
5856
|
+
return getCoordinator(projectRoot3, host)?.start(source, allowDisabledAutoIndex) ?? null;
|
|
4888
5857
|
}
|
|
4889
5858
|
function requestBackgroundIndex(projectRoot3, host) {
|
|
5859
|
+
if (isBackgroundWorkerManaged(projectRoot3, host) && !isBackgroundWorkerLeader(projectRoot3, host)) {
|
|
5860
|
+
return null;
|
|
5861
|
+
}
|
|
4890
5862
|
return getCoordinator(projectRoot3, host)?.request({
|
|
4891
5863
|
checkFreshness: false,
|
|
4892
5864
|
force: false,
|
|
@@ -4926,15 +5898,23 @@ async function waitForAutoIndexForRetrieval(projectRoot3, host) {
|
|
|
4926
5898
|
};
|
|
4927
5899
|
}
|
|
4928
5900
|
try {
|
|
4929
|
-
|
|
5901
|
+
const readiness = await getSearchReadiness(coordinator);
|
|
5902
|
+
if (readiness.searchable) {
|
|
5903
|
+
return { ready: true };
|
|
5904
|
+
}
|
|
5905
|
+
if (readiness.blocked) return unavailableSnapshotResult(readiness.reason);
|
|
4930
5906
|
} catch {
|
|
4931
5907
|
}
|
|
4932
|
-
const job =
|
|
5908
|
+
const job = startRetrievalRefresh(projectRoot3, host, coordinator);
|
|
4933
5909
|
if (job) {
|
|
4934
5910
|
await withTimeout(job, coordinator.getWaitMs());
|
|
5911
|
+
} else if (isBackgroundWorkerManaged(projectRoot3, host)) {
|
|
5912
|
+
await waitForPublishedSnapshot(coordinator, coordinator.getWaitMs());
|
|
4935
5913
|
}
|
|
4936
5914
|
try {
|
|
4937
|
-
|
|
5915
|
+
const readiness = await getSearchReadiness(coordinator);
|
|
5916
|
+
if (readiness.searchable) return { ready: true };
|
|
5917
|
+
if (readiness.blocked) return unavailableSnapshotResult(readiness.reason);
|
|
4938
5918
|
} catch {
|
|
4939
5919
|
}
|
|
4940
5920
|
const status = coordinator.snapshot();
|
|
@@ -4955,21 +5935,52 @@ async function waitForAutoIndexForRetrieval(projectRoot3, host) {
|
|
|
4955
5935
|
text: `Automatic indexing is ${status.state}. Retry shortly or call index_status for progress. You can also run index_codebase explicitly.`
|
|
4956
5936
|
};
|
|
4957
5937
|
}
|
|
4958
|
-
async function
|
|
4959
|
-
|
|
5938
|
+
async function stopAutoIndexForBackgroundWorker(projectRoot3, host, waitForCompletion = false) {
|
|
5939
|
+
const coordinator = getCoordinator(projectRoot3, host);
|
|
5940
|
+
if (!coordinator) {
|
|
5941
|
+
return { completed: true, completion: Promise.resolve() };
|
|
5942
|
+
}
|
|
5943
|
+
return coordinator.stop(waitForCompletion);
|
|
4960
5944
|
}
|
|
4961
|
-
async function
|
|
5945
|
+
async function getSearchReadiness(coordinator) {
|
|
4962
5946
|
const indexer = coordinator.getIndexer();
|
|
4963
5947
|
if (indexer.getIndexFreshness) {
|
|
4964
5948
|
const freshness = await indexer.getIndexFreshness();
|
|
4965
|
-
|
|
5949
|
+
const searchable = freshness.readable && freshness.current && freshness.reason === "current";
|
|
5950
|
+
return {
|
|
5951
|
+
blocked: freshness.reason === "unreadable" || freshness.reason === "incompatible" || freshness.reason === "failed-batches" || freshness.reason === "migration-required",
|
|
5952
|
+
reason: freshness.reason,
|
|
5953
|
+
searchable
|
|
5954
|
+
};
|
|
5955
|
+
}
|
|
5956
|
+
const indexed = (await indexer.getStatus()).indexed;
|
|
5957
|
+
return { blocked: false, searchable: indexed };
|
|
5958
|
+
}
|
|
5959
|
+
function unavailableSnapshotResult(reason) {
|
|
5960
|
+
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.";
|
|
5961
|
+
return {
|
|
5962
|
+
ready: false,
|
|
5963
|
+
text: `${detail} Run index_codebase before retrying retrieval.`
|
|
5964
|
+
};
|
|
5965
|
+
}
|
|
5966
|
+
function startRetrievalRefresh(projectRoot3, host, coordinator) {
|
|
5967
|
+
if (isBackgroundWorkerManaged(projectRoot3, host)) {
|
|
5968
|
+
requestBackgroundWorkerRefresh(projectRoot3, host, true);
|
|
5969
|
+
return isBackgroundWorkerLeader(projectRoot3, host) ? coordinator.currentJob() : null;
|
|
5970
|
+
}
|
|
5971
|
+
return coordinator.start("retrieval") ?? coordinator.currentJob();
|
|
5972
|
+
}
|
|
5973
|
+
async function waitForPublishedSnapshot(coordinator, waitMs) {
|
|
5974
|
+
const deadline = Date.now() + waitMs;
|
|
5975
|
+
while (Date.now() < deadline) {
|
|
5976
|
+
if ((await getSearchReadiness(coordinator)).searchable) return;
|
|
5977
|
+
await new Promise((resolve18) => setTimeout(resolve18, Math.min(250, deadline - Date.now())));
|
|
4966
5978
|
}
|
|
4967
|
-
return (await indexer.getStatus()).indexed;
|
|
4968
5979
|
}
|
|
4969
5980
|
|
|
4970
5981
|
// src/tools/config-state.ts
|
|
4971
|
-
import { existsSync as
|
|
4972
|
-
import * as
|
|
5982
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
5983
|
+
import * as path14 from "path";
|
|
4973
5984
|
function normalizeKnowledgeBasePaths(config, projectRoot3) {
|
|
4974
5985
|
const normalized = { ...config };
|
|
4975
5986
|
if (Array.isArray(normalized.knowledgeBases)) {
|
|
@@ -4996,10 +6007,10 @@ function loadEditableConfig(projectRoot3, host) {
|
|
|
4996
6007
|
}
|
|
4997
6008
|
function saveConfig(projectRoot3, config, host) {
|
|
4998
6009
|
const configPath = getConfigPath(projectRoot3, host);
|
|
4999
|
-
const configDir =
|
|
5000
|
-
const configBaseDir =
|
|
5001
|
-
if (!
|
|
5002
|
-
|
|
6010
|
+
const configDir = path14.dirname(configPath);
|
|
6011
|
+
const configBaseDir = path14.dirname(configDir);
|
|
6012
|
+
if (!existsSync10(configDir)) {
|
|
6013
|
+
mkdirSync3(configDir, { recursive: true });
|
|
5003
6014
|
}
|
|
5004
6015
|
const serializableConfig = { ...config };
|
|
5005
6016
|
if (Array.isArray(serializableConfig.knowledgeBases)) {
|
|
@@ -5007,12 +6018,12 @@ function saveConfig(projectRoot3, config, host) {
|
|
|
5007
6018
|
(kb) => serializeConfigPathValue(kb, configBaseDir)
|
|
5008
6019
|
);
|
|
5009
6020
|
}
|
|
5010
|
-
|
|
6021
|
+
writeFileSync3(configPath, JSON.stringify(serializableConfig, null, 2) + "\n", "utf-8");
|
|
5011
6022
|
}
|
|
5012
6023
|
|
|
5013
6024
|
// src/indexer/index.ts
|
|
5014
|
-
import { existsSync as
|
|
5015
|
-
import * as
|
|
6025
|
+
import { existsSync as existsSync12, readFileSync as readFileSync9, statSync as statSync4, writeFileSync as writeFileSync4, renameSync as renameSync4, unlinkSync as unlinkSync2, mkdirSync as mkdirSync5, promises as fsPromises3 } from "fs";
|
|
6026
|
+
import * as path20 from "path";
|
|
5016
6027
|
import { performance as performance2 } from "perf_hooks";
|
|
5017
6028
|
import { execFile as execFile5 } from "child_process";
|
|
5018
6029
|
import { promisify as promisify4 } from "util";
|
|
@@ -5039,7 +6050,7 @@ function pTimeout(promise, options) {
|
|
|
5039
6050
|
} = options;
|
|
5040
6051
|
let timer;
|
|
5041
6052
|
let abortHandler;
|
|
5042
|
-
const wrappedPromise = new Promise((
|
|
6053
|
+
const wrappedPromise = new Promise((resolve18, reject) => {
|
|
5043
6054
|
if (typeof milliseconds !== "number" || Math.sign(milliseconds) !== 1) {
|
|
5044
6055
|
throw new TypeError(`Expected \`milliseconds\` to be a positive number, got \`${milliseconds}\``);
|
|
5045
6056
|
}
|
|
@@ -5053,7 +6064,7 @@ function pTimeout(promise, options) {
|
|
|
5053
6064
|
};
|
|
5054
6065
|
signal.addEventListener("abort", abortHandler, { once: true });
|
|
5055
6066
|
}
|
|
5056
|
-
promise.then(
|
|
6067
|
+
promise.then(resolve18, reject);
|
|
5057
6068
|
if (milliseconds === Number.POSITIVE_INFINITY) {
|
|
5058
6069
|
return;
|
|
5059
6070
|
}
|
|
@@ -5061,7 +6072,7 @@ function pTimeout(promise, options) {
|
|
|
5061
6072
|
timer = customTimers.setTimeout.call(void 0, () => {
|
|
5062
6073
|
if (fallback) {
|
|
5063
6074
|
try {
|
|
5064
|
-
|
|
6075
|
+
resolve18(fallback());
|
|
5065
6076
|
} catch (error) {
|
|
5066
6077
|
reject(error);
|
|
5067
6078
|
}
|
|
@@ -5071,7 +6082,7 @@ function pTimeout(promise, options) {
|
|
|
5071
6082
|
promise.cancel();
|
|
5072
6083
|
}
|
|
5073
6084
|
if (message === false) {
|
|
5074
|
-
|
|
6085
|
+
resolve18();
|
|
5075
6086
|
} else if (message instanceof Error) {
|
|
5076
6087
|
reject(message);
|
|
5077
6088
|
} else {
|
|
@@ -5473,7 +6484,7 @@ var PQueue = class extends import_index.default {
|
|
|
5473
6484
|
// Assign unique ID if not provided
|
|
5474
6485
|
id: options.id ?? (this.#idAssigner++).toString()
|
|
5475
6486
|
};
|
|
5476
|
-
return new Promise((
|
|
6487
|
+
return new Promise((resolve18, reject) => {
|
|
5477
6488
|
const taskSymbol = /* @__PURE__ */ Symbol(`task-${options.id}`);
|
|
5478
6489
|
let cleanupQueueAbortHandler = () => void 0;
|
|
5479
6490
|
const run = async () => {
|
|
@@ -5513,7 +6524,7 @@ var PQueue = class extends import_index.default {
|
|
|
5513
6524
|
})]);
|
|
5514
6525
|
}
|
|
5515
6526
|
const result = await operation;
|
|
5516
|
-
|
|
6527
|
+
resolve18(result);
|
|
5517
6528
|
this.emit("completed", result);
|
|
5518
6529
|
} catch (error) {
|
|
5519
6530
|
reject(error);
|
|
@@ -5701,13 +6712,13 @@ var PQueue = class extends import_index.default {
|
|
|
5701
6712
|
});
|
|
5702
6713
|
}
|
|
5703
6714
|
async #onEvent(event, filter) {
|
|
5704
|
-
return new Promise((
|
|
6715
|
+
return new Promise((resolve18) => {
|
|
5705
6716
|
const listener = () => {
|
|
5706
6717
|
if (filter && !filter()) {
|
|
5707
6718
|
return;
|
|
5708
6719
|
}
|
|
5709
6720
|
this.off(event, listener);
|
|
5710
|
-
|
|
6721
|
+
resolve18();
|
|
5711
6722
|
};
|
|
5712
6723
|
this.on(event, listener);
|
|
5713
6724
|
});
|
|
@@ -5993,7 +7004,7 @@ async function onAttemptFailure({ error, attemptNumber, retriesConsumed, startTi
|
|
|
5993
7004
|
const finalDelay = Math.min(delayTime, remainingTime);
|
|
5994
7005
|
options.signal?.throwIfAborted();
|
|
5995
7006
|
if (finalDelay > 0) {
|
|
5996
|
-
await new Promise((
|
|
7007
|
+
await new Promise((resolve18, reject) => {
|
|
5997
7008
|
const onAbort = () => {
|
|
5998
7009
|
clearTimeout(timeoutToken);
|
|
5999
7010
|
options.signal?.removeEventListener("abort", onAbort);
|
|
@@ -6001,7 +7012,7 @@ async function onAttemptFailure({ error, attemptNumber, retriesConsumed, startTi
|
|
|
6001
7012
|
};
|
|
6002
7013
|
const timeoutToken = setTimeout(() => {
|
|
6003
7014
|
options.signal?.removeEventListener("abort", onAbort);
|
|
6004
|
-
|
|
7015
|
+
resolve18();
|
|
6005
7016
|
}, finalDelay);
|
|
6006
7017
|
if (options.unref) {
|
|
6007
7018
|
timeoutToken.unref?.();
|
|
@@ -6119,17 +7130,17 @@ function validateExternalUrl(urlString) {
|
|
|
6119
7130
|
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
6120
7131
|
return { valid: false, reason: `Blocked protocol: ${parsed.protocol}` };
|
|
6121
7132
|
}
|
|
6122
|
-
const
|
|
6123
|
-
if (BLOCKED_HOSTNAMES.has(
|
|
6124
|
-
return { valid: false, reason: `Blocked: cloud metadata service (${
|
|
7133
|
+
const hostname3 = parsed.hostname.toLowerCase();
|
|
7134
|
+
if (BLOCKED_HOSTNAMES.has(hostname3)) {
|
|
7135
|
+
return { valid: false, reason: `Blocked: cloud metadata service (${hostname3})` };
|
|
6125
7136
|
}
|
|
6126
7137
|
for (const pattern of BLOCKED_METADATA_IPS) {
|
|
6127
|
-
if (pattern.test(
|
|
6128
|
-
return { valid: false, reason: `Blocked: cloud metadata IP (${
|
|
7138
|
+
if (pattern.test(hostname3)) {
|
|
7139
|
+
return { valid: false, reason: `Blocked: cloud metadata IP (${hostname3})` };
|
|
6129
7140
|
}
|
|
6130
7141
|
}
|
|
6131
|
-
if (/^169\.254\./.test(
|
|
6132
|
-
return { valid: false, reason: `Blocked: link-local address (${
|
|
7142
|
+
if (/^169\.254\./.test(hostname3)) {
|
|
7143
|
+
return { valid: false, reason: `Blocked: link-local address (${hostname3})` };
|
|
6133
7144
|
}
|
|
6134
7145
|
return { valid: true };
|
|
6135
7146
|
}
|
|
@@ -7141,8 +8152,8 @@ function extractParamNames(params) {
|
|
|
7141
8152
|
}
|
|
7142
8153
|
|
|
7143
8154
|
// src/native/binding.ts
|
|
7144
|
-
import * as
|
|
7145
|
-
import * as
|
|
8155
|
+
import * as os6 from "os";
|
|
8156
|
+
import * as path15 from "path";
|
|
7146
8157
|
import * as module from "module";
|
|
7147
8158
|
import { fileURLToPath } from "url";
|
|
7148
8159
|
|
|
@@ -7178,7 +8189,7 @@ var MCP_BINARY_CURRENT_NAME = CURRENT_PRODUCT.mcpBinary;
|
|
|
7178
8189
|
var STABLE_NATIVE_BINARY_NAME = IDENTITY_CATALOG.native.binaryName;
|
|
7179
8190
|
|
|
7180
8191
|
// src/native/binding.ts
|
|
7181
|
-
function getNativeBindingFilename(platform2 =
|
|
8192
|
+
function getNativeBindingFilename(platform2 = os6.platform(), arch2 = os6.arch()) {
|
|
7182
8193
|
if (platform2 === "darwin" && arch2 === "arm64") {
|
|
7183
8194
|
return `${STABLE_NATIVE_BINARY_NAME}.darwin-arm64.node`;
|
|
7184
8195
|
}
|
|
@@ -7196,25 +8207,25 @@ function getNativeBindingFilename(platform2 = os5.platform(), arch2 = os5.arch()
|
|
|
7196
8207
|
}
|
|
7197
8208
|
throw new Error(`Unsupported platform: ${platform2}-${arch2}`);
|
|
7198
8209
|
}
|
|
7199
|
-
function resolveNativeBindingPath(packageRoot, platform2 =
|
|
7200
|
-
return
|
|
8210
|
+
function resolveNativeBindingPath(packageRoot, platform2 = os6.platform(), arch2 = os6.arch()) {
|
|
8211
|
+
return path15.join(packageRoot, "native", getNativeBindingFilename(platform2, arch2));
|
|
7201
8212
|
}
|
|
7202
8213
|
function getNativeBinding() {
|
|
7203
8214
|
let currentDir;
|
|
7204
8215
|
let requireTarget;
|
|
7205
8216
|
if (typeof import.meta !== "undefined" && import.meta.url) {
|
|
7206
|
-
currentDir =
|
|
8217
|
+
currentDir = path15.dirname(fileURLToPath(import.meta.url));
|
|
7207
8218
|
requireTarget = import.meta.url;
|
|
7208
8219
|
} else if (typeof __dirname !== "undefined") {
|
|
7209
8220
|
currentDir = __dirname;
|
|
7210
8221
|
requireTarget = __filename;
|
|
7211
8222
|
} else {
|
|
7212
8223
|
currentDir = process.cwd();
|
|
7213
|
-
requireTarget =
|
|
8224
|
+
requireTarget = path15.join(currentDir, "index.js");
|
|
7214
8225
|
}
|
|
7215
8226
|
const normalizedDir = currentDir.replace(/\\/g, "/");
|
|
7216
|
-
const isDevMode = normalizedDir.includes("/src/native") || currentDir.includes(
|
|
7217
|
-
const packageRoot = isDevMode ?
|
|
8227
|
+
const isDevMode = normalizedDir.includes("/src/native") || currentDir.includes(path15.join("src", "native"));
|
|
8228
|
+
const packageRoot = isDevMode ? path15.resolve(currentDir, "../..") : path15.resolve(currentDir, "..");
|
|
7218
8229
|
const nativePath = resolveNativeBindingPath(packageRoot);
|
|
7219
8230
|
const require2 = module.createRequire(requireTarget);
|
|
7220
8231
|
return require2(nativePath);
|
|
@@ -7798,8 +8809,8 @@ var Database = class _Database {
|
|
|
7798
8809
|
|
|
7799
8810
|
// src/git/branch-materialization.ts
|
|
7800
8811
|
import { promises as fsPromises2 } from "fs";
|
|
7801
|
-
import * as
|
|
7802
|
-
import * as
|
|
8812
|
+
import * as os7 from "os";
|
|
8813
|
+
import * as path16 from "path";
|
|
7803
8814
|
|
|
7804
8815
|
// src/git/branch-resolution.ts
|
|
7805
8816
|
import { execFile as execFile2 } from "child_process";
|
|
@@ -8118,13 +9129,13 @@ async function isWorktreeRegistered(projectRoot3, worktreePath) {
|
|
|
8118
9129
|
return false;
|
|
8119
9130
|
}
|
|
8120
9131
|
function isPathWithinRoot(filePath, rootPath) {
|
|
8121
|
-
const relative13 =
|
|
8122
|
-
return relative13 === "" || !relative13.startsWith(`..${
|
|
9132
|
+
const relative13 = path16.relative(path16.resolve(rootPath), path16.resolve(filePath));
|
|
9133
|
+
return relative13 === "" || !relative13.startsWith(`..${path16.sep}`) && relative13 !== ".." && !path16.isAbsolute(relative13);
|
|
8123
9134
|
}
|
|
8124
9135
|
async function pruneExactMissingWorktreeRegistration(projectRoot3, worktreePath) {
|
|
8125
9136
|
if (await pathExists(worktreePath)) return false;
|
|
8126
9137
|
const commonDir = await runGit(projectRoot3, ["rev-parse", "--path-format=absolute", "--git-common-dir"]);
|
|
8127
|
-
const registrationsRoot =
|
|
9138
|
+
const registrationsRoot = path16.join(commonDir, "worktrees");
|
|
8128
9139
|
let entries;
|
|
8129
9140
|
try {
|
|
8130
9141
|
entries = await fsPromises2.readdir(registrationsRoot, { withFileTypes: true });
|
|
@@ -8135,16 +9146,16 @@ async function pruneExactMissingWorktreeRegistration(projectRoot3, worktreePath)
|
|
|
8135
9146
|
const target = canonicalizePathForComparison(worktreePath);
|
|
8136
9147
|
for (const entry of entries) {
|
|
8137
9148
|
if (!entry.isDirectory()) continue;
|
|
8138
|
-
const registrationPath =
|
|
9149
|
+
const registrationPath = path16.join(registrationsRoot, entry.name);
|
|
8139
9150
|
if (!isPathWithinRoot(registrationPath, registrationsRoot)) continue;
|
|
8140
9151
|
let gitdirPath;
|
|
8141
9152
|
try {
|
|
8142
|
-
gitdirPath = (await fsPromises2.readFile(
|
|
9153
|
+
gitdirPath = (await fsPromises2.readFile(path16.join(registrationPath, "gitdir"), "utf8")).trim();
|
|
8143
9154
|
} catch {
|
|
8144
9155
|
continue;
|
|
8145
9156
|
}
|
|
8146
|
-
const resolvedGitdirPath =
|
|
8147
|
-
if (canonicalizePathForComparison(
|
|
9157
|
+
const resolvedGitdirPath = path16.isAbsolute(gitdirPath) ? gitdirPath : path16.resolve(registrationPath, gitdirPath);
|
|
9158
|
+
if (canonicalizePathForComparison(path16.dirname(resolvedGitdirPath)) !== target) continue;
|
|
8148
9159
|
await fsPromises2.rm(registrationPath, { recursive: true, force: true });
|
|
8149
9160
|
return true;
|
|
8150
9161
|
}
|
|
@@ -8162,7 +9173,7 @@ async function removeWorktree(projectRoot3, worktreePath) {
|
|
|
8162
9173
|
registered = await isWorktreeRegistered(projectRoot3, worktreePath);
|
|
8163
9174
|
} catch (error) {
|
|
8164
9175
|
errors.push(asError(error));
|
|
8165
|
-
throw new AggregateError(errors, `Could not verify temporary worktree deregistration; preserved ${
|
|
9176
|
+
throw new AggregateError(errors, `Could not verify temporary worktree deregistration; preserved ${path16.dirname(worktreePath)}`);
|
|
8166
9177
|
}
|
|
8167
9178
|
if (registered) {
|
|
8168
9179
|
try {
|
|
@@ -8178,7 +9189,7 @@ async function removeWorktree(projectRoot3, worktreePath) {
|
|
|
8178
9189
|
registered = await isWorktreeRegistered(projectRoot3, worktreePath);
|
|
8179
9190
|
} catch (error) {
|
|
8180
9191
|
errors.push(asError(error));
|
|
8181
|
-
throw new AggregateError(errors, `Could not verify temporary worktree deregistration; preserved ${
|
|
9192
|
+
throw new AggregateError(errors, `Could not verify temporary worktree deregistration; preserved ${path16.dirname(worktreePath)}`);
|
|
8182
9193
|
}
|
|
8183
9194
|
}
|
|
8184
9195
|
if (registered && !await pathExists(worktreePath)) {
|
|
@@ -8191,13 +9202,13 @@ async function removeWorktree(projectRoot3, worktreePath) {
|
|
|
8191
9202
|
}
|
|
8192
9203
|
if (registered) {
|
|
8193
9204
|
errors.push(new Error(`Temporary worktree remains registered: ${worktreePath}`));
|
|
8194
|
-
throw new AggregateError(errors, `Failed to deregister temporary worktree; preserved ${
|
|
9205
|
+
throw new AggregateError(errors, `Failed to deregister temporary worktree; preserved ${path16.dirname(worktreePath)}`);
|
|
8195
9206
|
}
|
|
8196
9207
|
try {
|
|
8197
|
-
await fsPromises2.rm(
|
|
9208
|
+
await fsPromises2.rm(path16.dirname(worktreePath), { recursive: true, force: true });
|
|
8198
9209
|
} catch (error) {
|
|
8199
9210
|
errors.push(asError(error));
|
|
8200
|
-
throw new AggregateError(errors, `Deregistered the temporary worktree but could not remove ${
|
|
9211
|
+
throw new AggregateError(errors, `Deregistered the temporary worktree but could not remove ${path16.dirname(worktreePath)}`);
|
|
8201
9212
|
}
|
|
8202
9213
|
}
|
|
8203
9214
|
async function cleanupTemporaryWorktree(projectRoot3, worktreePath, temporaryRoot) {
|
|
@@ -8233,9 +9244,9 @@ async function withMaterializedBranch(request, callback) {
|
|
|
8233
9244
|
`Git ref ${JSON.stringify(request.ref ?? request.branch)} is not available locally. For an unfetched branch, pass a remote-qualified name such as origin/feature.`
|
|
8234
9245
|
);
|
|
8235
9246
|
}
|
|
8236
|
-
const temporaryRoot = await fsPromises2.mkdtemp(
|
|
8237
|
-
const worktreePath =
|
|
8238
|
-
const hooksPath =
|
|
9247
|
+
const temporaryRoot = await fsPromises2.mkdtemp(path16.join(os7.tmpdir(), "codebase-index-branch-"));
|
|
9248
|
+
const worktreePath = path16.join(temporaryRoot, "worktree");
|
|
9249
|
+
const hooksPath = path16.join(temporaryRoot, "hooks");
|
|
8239
9250
|
await fsPromises2.mkdir(hooksPath);
|
|
8240
9251
|
const info = {
|
|
8241
9252
|
branch: request.branch,
|
|
@@ -8286,8 +9297,8 @@ async function withMaterializedBranch(request, callback) {
|
|
|
8286
9297
|
|
|
8287
9298
|
// src/tools/changed-files.ts
|
|
8288
9299
|
import { execFile as execFile3 } from "child_process";
|
|
8289
|
-
import { realpathSync as
|
|
8290
|
-
import * as
|
|
9300
|
+
import { realpathSync as realpathSync5 } from "fs";
|
|
9301
|
+
import * as path17 from "path";
|
|
8291
9302
|
import { promisify as promisify2 } from "util";
|
|
8292
9303
|
var execFileAsync2 = promisify2(execFile3);
|
|
8293
9304
|
var GH_PR_VIEW_FIELDS = [
|
|
@@ -8429,9 +9440,9 @@ function getHeadRepositoryIdentity(data, host) {
|
|
|
8429
9440
|
return `${host}/${owner.toLowerCase()}/${repository.replace(/\.git$/i, "").toLowerCase()}`;
|
|
8430
9441
|
}
|
|
8431
9442
|
function getLocalRepositoryIdentity(projectRoot3) {
|
|
8432
|
-
let canonicalRoot =
|
|
9443
|
+
let canonicalRoot = path17.resolve(projectRoot3);
|
|
8433
9444
|
try {
|
|
8434
|
-
canonicalRoot =
|
|
9445
|
+
canonicalRoot = realpathSync5.native(canonicalRoot);
|
|
8435
9446
|
} catch {
|
|
8436
9447
|
}
|
|
8437
9448
|
return `local:${canonicalRoot}`;
|
|
@@ -8490,17 +9501,17 @@ async function getMergeBase(projectRoot3, baseCommit, headCommit) {
|
|
|
8490
9501
|
return commit;
|
|
8491
9502
|
}
|
|
8492
9503
|
function normalizeFiles(rawFiles, projectRoot3) {
|
|
8493
|
-
const root =
|
|
9504
|
+
const root = path17.resolve(projectRoot3);
|
|
8494
9505
|
const seen = /* @__PURE__ */ new Set();
|
|
8495
9506
|
const result = [];
|
|
8496
9507
|
for (const raw of rawFiles) {
|
|
8497
9508
|
if (raw.length === 0) continue;
|
|
8498
|
-
const absolute =
|
|
8499
|
-
const relative13 =
|
|
8500
|
-
if (
|
|
9509
|
+
const absolute = path17.resolve(root, raw);
|
|
9510
|
+
const relative13 = path17.relative(root, absolute);
|
|
9511
|
+
if (path17.isAbsolute(raw) || relative13 === ".." || relative13.startsWith(`..${path17.sep}`) || path17.isAbsolute(relative13)) {
|
|
8501
9512
|
throw new Error(`Changed file escapes the project root: ${JSON.stringify(raw)}`);
|
|
8502
9513
|
}
|
|
8503
|
-
const cleaned = relative13.startsWith(`.${
|
|
9514
|
+
const cleaned = relative13.startsWith(`.${path17.sep}`) ? relative13.slice(2) : relative13;
|
|
8504
9515
|
if (!seen.has(cleaned)) {
|
|
8505
9516
|
seen.add(cleaned);
|
|
8506
9517
|
result.push(cleaned);
|
|
@@ -8511,7 +9522,7 @@ function normalizeFiles(rawFiles, projectRoot3) {
|
|
|
8511
9522
|
|
|
8512
9523
|
// src/indexer/git-blame.ts
|
|
8513
9524
|
import { execFile as execFile4 } from "child_process";
|
|
8514
|
-
import * as
|
|
9525
|
+
import * as path18 from "path";
|
|
8515
9526
|
import { promisify as promisify3 } from "util";
|
|
8516
9527
|
var execFileAsync3 = promisify3(execFile4);
|
|
8517
9528
|
function parseGitBlamePorcelain(output) {
|
|
@@ -8549,7 +9560,7 @@ function parseGitBlamePorcelain(output) {
|
|
|
8549
9560
|
return Array.from(commits.values()).filter((commit) => commit.lines > 0).sort((a, b) => b.lines - a.lines || b.committedAt - a.committedAt)[0];
|
|
8550
9561
|
}
|
|
8551
9562
|
async function getChunkGitBlame(projectRoot3, filePath, startLine, endLine) {
|
|
8552
|
-
const relativePath =
|
|
9563
|
+
const relativePath = path18.relative(projectRoot3, filePath);
|
|
8553
9564
|
try {
|
|
8554
9565
|
const { stdout } = await execFileAsync3(
|
|
8555
9566
|
"git",
|
|
@@ -8881,6 +9892,9 @@ var CALL_GRAPH_SYMBOL_CHUNK_TYPES = /* @__PURE__ */ new Set([
|
|
|
8881
9892
|
"enum_declaration",
|
|
8882
9893
|
"function_definition",
|
|
8883
9894
|
"class_definition",
|
|
9895
|
+
// Ruby module/class symbols that are declaration-bearing and navigable.
|
|
9896
|
+
"class",
|
|
9897
|
+
"module",
|
|
8884
9898
|
"class_specifier",
|
|
8885
9899
|
"struct_specifier",
|
|
8886
9900
|
"namespace_definition",
|
|
@@ -9125,8 +10139,8 @@ function pathSegmentsForAffinityMatch(filePath) {
|
|
|
9125
10139
|
if (segments.length === 0) {
|
|
9126
10140
|
return [];
|
|
9127
10141
|
}
|
|
9128
|
-
const
|
|
9129
|
-
const basenameWithoutExt =
|
|
10142
|
+
const basename8 = segments[segments.length - 1] ?? "";
|
|
10143
|
+
const basenameWithoutExt = basename8.replace(/\.[^/.]+$/u, "");
|
|
9130
10144
|
const normalizedSegments = segments.map((segment) => segment.toLowerCase());
|
|
9131
10145
|
return Array.from(/* @__PURE__ */ new Set([
|
|
9132
10146
|
...normalizedSegments,
|
|
@@ -9435,8 +10449,8 @@ function hasAllEmbeddingParts(parts, expectedPartCount) {
|
|
|
9435
10449
|
|
|
9436
10450
|
// src/indexer/failed-state-persistence.ts
|
|
9437
10451
|
import * as fs2 from "fs";
|
|
9438
|
-
import { createHash, randomBytes as randomBytes3 } from "crypto";
|
|
9439
|
-
import * as
|
|
10452
|
+
import { createHash as createHash2, randomBytes as randomBytes3 } from "crypto";
|
|
10453
|
+
import * as path19 from "path";
|
|
9440
10454
|
import { StringDecoder } from "string_decoder";
|
|
9441
10455
|
var CURRENT_FAILED_BATCH_VERSION = 1;
|
|
9442
10456
|
var DEFAULT_MALFORMED_LINE_ACTION = "skip";
|
|
@@ -9454,7 +10468,7 @@ function* readFailedBatchRecords(filePath, options = {}) {
|
|
|
9454
10468
|
function createFailedBatchWriter(targetPath) {
|
|
9455
10469
|
const temporaryPath = createTemporaryPath(targetPath);
|
|
9456
10470
|
let finalized = false;
|
|
9457
|
-
fs2.mkdirSync(
|
|
10471
|
+
fs2.mkdirSync(path19.dirname(targetPath), { recursive: true });
|
|
9458
10472
|
fs2.closeSync(fs2.openSync(temporaryPath, "w"));
|
|
9459
10473
|
const write = (record) => {
|
|
9460
10474
|
if (finalized) {
|
|
@@ -9473,7 +10487,7 @@ function createFailedBatchWriter(targetPath) {
|
|
|
9473
10487
|
if (lines.length === 0) {
|
|
9474
10488
|
return;
|
|
9475
10489
|
}
|
|
9476
|
-
fs2.mkdirSync(
|
|
10490
|
+
fs2.mkdirSync(path19.dirname(targetPath), { recursive: true });
|
|
9477
10491
|
fs2.appendFileSync(temporaryPath, `${lines.join("\n")}
|
|
9478
10492
|
`, "utf-8");
|
|
9479
10493
|
};
|
|
@@ -9481,7 +10495,7 @@ function createFailedBatchWriter(targetPath) {
|
|
|
9481
10495
|
if (finalized) {
|
|
9482
10496
|
return;
|
|
9483
10497
|
}
|
|
9484
|
-
fs2.mkdirSync(
|
|
10498
|
+
fs2.mkdirSync(path19.dirname(targetPath), { recursive: true });
|
|
9485
10499
|
fs2.renameSync(temporaryPath, targetPath);
|
|
9486
10500
|
finalized = true;
|
|
9487
10501
|
};
|
|
@@ -9627,10 +10641,10 @@ function stripLeadingBomAndWhitespace(value) {
|
|
|
9627
10641
|
return result;
|
|
9628
10642
|
}
|
|
9629
10643
|
function createTemporaryPath(targetPath) {
|
|
9630
|
-
const randomId =
|
|
9631
|
-
const targetDir =
|
|
9632
|
-
const baseName =
|
|
9633
|
-
return
|
|
10644
|
+
const randomId = createHash2("sha1").update(`${Date.now()}:${randomBytes3(8).toString("hex")}`).digest("hex");
|
|
10645
|
+
const targetDir = path19.dirname(targetPath);
|
|
10646
|
+
const baseName = path19.basename(targetPath);
|
|
10647
|
+
return path19.join(targetDir, `.${baseName}.${randomId}.tmp`);
|
|
9634
10648
|
}
|
|
9635
10649
|
function handleMalformedLine(filePath, lineNumber, line, error, options) {
|
|
9636
10650
|
const action = options.malformedLineAction ?? DEFAULT_MALFORMED_LINE_ACTION;
|
|
@@ -9876,9 +10890,9 @@ var SWIFT_PARSER_VERSION = "1";
|
|
|
9876
10890
|
var METAL_PARSER_VERSION = "1";
|
|
9877
10891
|
var SYMBOL_EXTRACTOR_VERSION = "1";
|
|
9878
10892
|
function isPathWithinRoot2(filePath, rootPath) {
|
|
9879
|
-
const normalizedFilePath =
|
|
9880
|
-
const normalizedRoot =
|
|
9881
|
-
return normalizedFilePath === normalizedRoot || normalizedFilePath.startsWith(`${normalizedRoot}${
|
|
10893
|
+
const normalizedFilePath = path20.resolve(filePath);
|
|
10894
|
+
const normalizedRoot = path20.resolve(rootPath);
|
|
10895
|
+
return normalizedFilePath === normalizedRoot || normalizedFilePath.startsWith(`${normalizedRoot}${path20.sep}`);
|
|
9882
10896
|
}
|
|
9883
10897
|
function promoteIdentifierMatches(query, combined, semanticCandidates, keywordCandidates, database, branchChunkIds, prioritizeSourcePaths = classifyQueryIntentRaw(query) === "source") {
|
|
9884
10898
|
if (combined.length === 0) {
|
|
@@ -10209,10 +11223,10 @@ function matchesHardSearchFilters(candidate, options, projectRoot3) {
|
|
|
10209
11223
|
}
|
|
10210
11224
|
if (options?.directory) {
|
|
10211
11225
|
const candidatePath = canonicalizePathForComparison(
|
|
10212
|
-
|
|
11226
|
+
path20.resolve(projectRoot3, candidate.metadata.filePath.replace(/\\/g, path20.sep))
|
|
10213
11227
|
);
|
|
10214
11228
|
const directoryPath = canonicalizePathForComparison(
|
|
10215
|
-
|
|
11229
|
+
path20.resolve(projectRoot3, options.directory.trim().replace(/\\/g, path20.sep))
|
|
10216
11230
|
);
|
|
10217
11231
|
if (!isPathWithinRoot2(candidatePath, directoryPath)) return false;
|
|
10218
11232
|
}
|
|
@@ -10325,26 +11339,37 @@ var Indexer = class _Indexer {
|
|
|
10325
11339
|
return this.indexPathOverride ?? resolveProjectIndexPath(this.projectRoot, this.config.scope, this.host);
|
|
10326
11340
|
}
|
|
10327
11341
|
toCanonicalFilePath(filePath) {
|
|
10328
|
-
if (!
|
|
11342
|
+
if (!path20.isAbsolute(filePath)) {
|
|
10329
11343
|
return this.resolveStoredFilePath(filePath, this.projectRoot);
|
|
10330
11344
|
}
|
|
10331
|
-
if (
|
|
11345
|
+
if (path20.resolve(this.materializedProjectRoot) === path20.resolve(this.projectRoot) || !isPathWithinRoot2(filePath, this.materializedProjectRoot)) {
|
|
10332
11346
|
return filePath;
|
|
10333
11347
|
}
|
|
10334
|
-
return
|
|
11348
|
+
return path20.resolve(this.projectRoot, path20.relative(this.materializedProjectRoot, filePath));
|
|
10335
11349
|
}
|
|
10336
11350
|
toStoredFilePath(filePath) {
|
|
10337
11351
|
const canonicalFilePath = this.toCanonicalFilePath(filePath);
|
|
10338
11352
|
if (this.config.scope !== "project" || !isPathWithinRoot2(canonicalFilePath, this.projectRoot)) {
|
|
10339
11353
|
return canonicalFilePath;
|
|
10340
11354
|
}
|
|
10341
|
-
return
|
|
11355
|
+
return path20.relative(this.projectRoot, canonicalFilePath).split(path20.sep).join("/");
|
|
11356
|
+
}
|
|
11357
|
+
isStoredPathExcluded(storedPath) {
|
|
11358
|
+
let matchPath = storedPath.split(path20.sep).join("/");
|
|
11359
|
+
if (path20.isAbsolute(storedPath)) {
|
|
11360
|
+
const relativePath = path20.relative(this.projectRoot, storedPath).split(path20.sep).join("/");
|
|
11361
|
+
if (relativePath.startsWith("..") || path20.isAbsolute(relativePath)) {
|
|
11362
|
+
return false;
|
|
11363
|
+
}
|
|
11364
|
+
matchPath = relativePath;
|
|
11365
|
+
}
|
|
11366
|
+
return isExcludedByPatterns(matchPath, this.config.exclude);
|
|
10342
11367
|
}
|
|
10343
11368
|
resolveStoredFilePath(filePath, rootPath = this.projectRoot) {
|
|
10344
|
-
if (
|
|
11369
|
+
if (path20.isAbsolute(filePath)) {
|
|
10345
11370
|
return filePath;
|
|
10346
11371
|
}
|
|
10347
|
-
const resolvedPath =
|
|
11372
|
+
const resolvedPath = path20.resolve(rootPath, ...filePath.split("/"));
|
|
10348
11373
|
if (!isPathWithinRoot2(resolvedPath, rootPath)) {
|
|
10349
11374
|
throw new Error(`Stored project path escapes project root: ${JSON.stringify(filePath)}`);
|
|
10350
11375
|
}
|
|
@@ -10368,7 +11393,7 @@ var Indexer = class _Indexer {
|
|
|
10368
11393
|
}
|
|
10369
11394
|
toMaterializedFilePath(filePath) {
|
|
10370
11395
|
const storedFilePath = this.toStoredFilePath(filePath);
|
|
10371
|
-
if (
|
|
11396
|
+
if (path20.isAbsolute(storedFilePath)) {
|
|
10372
11397
|
return storedFilePath;
|
|
10373
11398
|
}
|
|
10374
11399
|
return this.resolveStoredFilePath(storedFilePath, this.materializedProjectRoot);
|
|
@@ -10385,10 +11410,10 @@ var Indexer = class _Indexer {
|
|
|
10385
11410
|
}
|
|
10386
11411
|
getRuntimeArtifactPath(fileName) {
|
|
10387
11412
|
const namespace = this.getRuntimeArtifactNamespace();
|
|
10388
|
-
if (!namespace) return
|
|
10389
|
-
const extension =
|
|
11413
|
+
if (!namespace) return path20.join(this.indexPath, fileName);
|
|
11414
|
+
const extension = path20.extname(fileName);
|
|
10390
11415
|
const baseName = fileName.slice(0, fileName.length - extension.length);
|
|
10391
|
-
return
|
|
11416
|
+
return path20.join(this.indexPath, `${baseName}.${namespace}${extension}`);
|
|
10392
11417
|
}
|
|
10393
11418
|
refreshRuntimeArtifactPaths() {
|
|
10394
11419
|
this.fileHashCachePath = this.getRuntimeArtifactPath("file-hashes.json");
|
|
@@ -10401,14 +11426,14 @@ var Indexer = class _Indexer {
|
|
|
10401
11426
|
getMaterializedKnowledgeBases() {
|
|
10402
11427
|
const canonicalProjectRoot = this.getCanonicalPath(this.projectRoot);
|
|
10403
11428
|
return this.config.knowledgeBases.map((knowledgeBase) => {
|
|
10404
|
-
const configuredPath =
|
|
11429
|
+
const configuredPath = path20.isAbsolute(knowledgeBase) ? knowledgeBase : path20.resolve(this.projectRoot, knowledgeBase);
|
|
10405
11430
|
const canonicalPath = this.getCanonicalPath(configuredPath);
|
|
10406
11431
|
if (!isPathWithinRoot2(canonicalPath, canonicalProjectRoot)) {
|
|
10407
11432
|
return canonicalPath;
|
|
10408
11433
|
}
|
|
10409
|
-
return
|
|
11434
|
+
return path20.resolve(
|
|
10410
11435
|
this.materializedProjectRoot,
|
|
10411
|
-
|
|
11436
|
+
path20.relative(canonicalProjectRoot, canonicalPath)
|
|
10412
11437
|
);
|
|
10413
11438
|
});
|
|
10414
11439
|
}
|
|
@@ -10416,7 +11441,7 @@ var Indexer = class _Indexer {
|
|
|
10416
11441
|
try {
|
|
10417
11442
|
return canonicalizePathForComparison(targetPath);
|
|
10418
11443
|
} catch {
|
|
10419
|
-
return
|
|
11444
|
+
return path20.resolve(targetPath);
|
|
10420
11445
|
}
|
|
10421
11446
|
}
|
|
10422
11447
|
getProjectIdentityHash(projectRoot3) {
|
|
@@ -10497,7 +11522,7 @@ var Indexer = class _Indexer {
|
|
|
10497
11522
|
} catch (error) {
|
|
10498
11523
|
releaseError = error;
|
|
10499
11524
|
this.writerArtifactFingerprint = null;
|
|
10500
|
-
if (!
|
|
11525
|
+
if (!existsSync12(lease.lockPath) && this.activeIndexLease?.owner.token === lease.owner.token) {
|
|
10501
11526
|
this.activeIndexLease = null;
|
|
10502
11527
|
}
|
|
10503
11528
|
}
|
|
@@ -10515,12 +11540,12 @@ var Indexer = class _Indexer {
|
|
|
10515
11540
|
return this.activeIndexLease;
|
|
10516
11541
|
}
|
|
10517
11542
|
loadFileHashCache() {
|
|
10518
|
-
if (!
|
|
11543
|
+
if (!existsSync12(this.fileHashCachePath)) {
|
|
10519
11544
|
this.fileHashCache = /* @__PURE__ */ new Map();
|
|
10520
11545
|
return;
|
|
10521
11546
|
}
|
|
10522
11547
|
try {
|
|
10523
|
-
const data =
|
|
11548
|
+
const data = readFileSync9(this.fileHashCachePath, "utf-8");
|
|
10524
11549
|
const parsed = JSON.parse(data);
|
|
10525
11550
|
this.fileHashCache = new Map(Object.entries(parsed));
|
|
10526
11551
|
} catch (error) {
|
|
@@ -10542,24 +11567,24 @@ var Indexer = class _Indexer {
|
|
|
10542
11567
|
atomicWriteSync(targetPath, data) {
|
|
10543
11568
|
const lease = this.requireActiveLease();
|
|
10544
11569
|
const tempPath = createLeaseTemporaryPath(targetPath, lease.owner, "tmp");
|
|
10545
|
-
|
|
11570
|
+
mkdirSync5(path20.dirname(targetPath), { recursive: true });
|
|
10546
11571
|
try {
|
|
10547
|
-
|
|
10548
|
-
|
|
11572
|
+
writeFileSync4(tempPath, data);
|
|
11573
|
+
renameSync4(tempPath, targetPath);
|
|
10549
11574
|
} finally {
|
|
10550
11575
|
removeLeaseTemporaryPath(tempPath);
|
|
10551
11576
|
}
|
|
10552
11577
|
}
|
|
10553
11578
|
saveInvertedIndex(invertedIndex) {
|
|
10554
11579
|
this.atomicWriteSync(
|
|
10555
|
-
|
|
11580
|
+
path20.join(this.indexPath, "inverted-index.json"),
|
|
10556
11581
|
invertedIndex.serialize()
|
|
10557
11582
|
);
|
|
10558
11583
|
}
|
|
10559
11584
|
getScopedRoots(projectRoot3 = this.projectRoot) {
|
|
10560
11585
|
const roots = /* @__PURE__ */ new Set([this.getCanonicalPath(projectRoot3)]);
|
|
10561
11586
|
for (const kbRoot of this.config.knowledgeBases) {
|
|
10562
|
-
roots.add(this.getCanonicalPath(
|
|
11587
|
+
roots.add(this.getCanonicalPath(path20.resolve(projectRoot3, kbRoot)));
|
|
10563
11588
|
}
|
|
10564
11589
|
return Array.from(roots);
|
|
10565
11590
|
}
|
|
@@ -10976,7 +12001,7 @@ var Indexer = class _Indexer {
|
|
|
10976
12001
|
return configuredProviderInfo !== null && recovery.embeddingProvider === configuredProviderInfo.provider && recovery.embeddingModel === configuredProviderInfo.modelInfo.model && recovery.embeddingDimensions === configuredProviderInfo.modelInfo.dimensions && recovery.embeddingStrategyVersion === EMBEDDING_STRATEGY_VERSION;
|
|
10977
12002
|
}
|
|
10978
12003
|
hasUnknownLegacyForceIndexClear(owner) {
|
|
10979
|
-
return owner.operation === "force-index" && owner.clearRecovery === void 0 && owner.recoveryProtocolVersion !== 1 &&
|
|
12004
|
+
return owner.operation === "force-index" && owner.clearRecovery === void 0 && owner.recoveryProtocolVersion !== 1 && existsSync12(path20.join(this.indexPath, "force-index-phase"));
|
|
10980
12005
|
}
|
|
10981
12006
|
async recoverFromInterruptedIndexingUnlocked(owners) {
|
|
10982
12007
|
for (const owner of owners) {
|
|
@@ -11162,7 +12187,7 @@ var Indexer = class _Indexer {
|
|
|
11162
12187
|
}
|
|
11163
12188
|
}
|
|
11164
12189
|
clearFailedBatchState() {
|
|
11165
|
-
if (
|
|
12190
|
+
if (existsSync12(this.failedBatchesPath)) {
|
|
11166
12191
|
try {
|
|
11167
12192
|
unlinkSync2(this.failedBatchesPath);
|
|
11168
12193
|
} catch {
|
|
@@ -11364,7 +12389,7 @@ var Indexer = class _Indexer {
|
|
|
11364
12389
|
await options.queue.onSizeLessThan(Math.max(1, options.providerRateLimits.concurrency));
|
|
11365
12390
|
const task = options.queue.add(async () => {
|
|
11366
12391
|
if (options.rateLimitState.backoffMs > 0) {
|
|
11367
|
-
await new Promise((
|
|
12392
|
+
await new Promise((resolve18) => setTimeout(resolve18, options.rateLimitState.backoffMs));
|
|
11368
12393
|
}
|
|
11369
12394
|
try {
|
|
11370
12395
|
const embeddingResult = await pRetry(
|
|
@@ -11783,12 +12808,12 @@ var Indexer = class _Indexer {
|
|
|
11783
12808
|
}
|
|
11784
12809
|
}
|
|
11785
12810
|
captureReaderArtifactFingerprint() {
|
|
11786
|
-
const storePath =
|
|
12811
|
+
const storePath = path20.join(this.indexPath, "vectors");
|
|
11787
12812
|
return {
|
|
11788
12813
|
vectors: `${this.getReaderFileFingerprint(storePath)}|${this.getReaderFileFingerprint(`${storePath}.meta.json`)}`,
|
|
11789
|
-
keyword: this.getReaderFileFingerprint(
|
|
11790
|
-
database: this.getReaderFileFingerprint(
|
|
11791
|
-
databaseIdentity: this.getReaderFileFingerprint(
|
|
12814
|
+
keyword: this.getReaderFileFingerprint(path20.join(this.indexPath, "inverted-index.json")),
|
|
12815
|
+
database: this.getReaderFileFingerprint(path20.join(this.indexPath, "codebase.db")),
|
|
12816
|
+
databaseIdentity: this.getReaderFileFingerprint(path20.join(this.indexPath, "codebase.db"), true)
|
|
11792
12817
|
};
|
|
11793
12818
|
}
|
|
11794
12819
|
refreshReaderArtifacts() {
|
|
@@ -11813,13 +12838,13 @@ var Indexer = class _Indexer {
|
|
|
11813
12838
|
issues.set(component, this.createReadIssue(component, message));
|
|
11814
12839
|
this.readerArtifactRetryAfter.set(component, Date.now() + READER_ARTIFACT_RETRY_INTERVAL_MS);
|
|
11815
12840
|
};
|
|
11816
|
-
const storePath =
|
|
12841
|
+
const storePath = path20.join(this.indexPath, "vectors");
|
|
11817
12842
|
const vectorMetadataPath = `${storePath}.meta.json`;
|
|
11818
|
-
const invertedIndexPath =
|
|
11819
|
-
const dbPath =
|
|
12843
|
+
const invertedIndexPath = path20.join(this.indexPath, "inverted-index.json");
|
|
12844
|
+
const dbPath = path20.join(this.indexPath, "codebase.db");
|
|
11820
12845
|
if (vectorsChanged || retryDue("vectors")) {
|
|
11821
|
-
const vectorStoreExists =
|
|
11822
|
-
const vectorMetadataExists =
|
|
12846
|
+
const vectorStoreExists = existsSync12(storePath);
|
|
12847
|
+
const vectorMetadataExists = existsSync12(vectorMetadataPath);
|
|
11823
12848
|
if (vectorStoreExists && vectorMetadataExists) {
|
|
11824
12849
|
try {
|
|
11825
12850
|
const store = new VectorStore(storePath, this.configuredProviderInfo.modelInfo.dimensions);
|
|
@@ -11834,8 +12859,8 @@ var Indexer = class _Indexer {
|
|
|
11834
12859
|
setIssue("vectors", this.getVectorReadIssueMessage());
|
|
11835
12860
|
}
|
|
11836
12861
|
}
|
|
11837
|
-
if (keywordChanged || retryDue("keyword") || !
|
|
11838
|
-
if (
|
|
12862
|
+
if (keywordChanged || retryDue("keyword") || !existsSync12(invertedIndexPath) && (this.store?.count() ?? 0) > 0) {
|
|
12863
|
+
if (existsSync12(invertedIndexPath)) {
|
|
11839
12864
|
try {
|
|
11840
12865
|
const invertedIndex = new InvertedIndex(invertedIndexPath);
|
|
11841
12866
|
invertedIndex.load();
|
|
@@ -11850,7 +12875,7 @@ var Indexer = class _Indexer {
|
|
|
11850
12875
|
}
|
|
11851
12876
|
}
|
|
11852
12877
|
if (databaseReplaced || databaseChanged && issues.has("database") || retryDue("database")) {
|
|
11853
|
-
if (
|
|
12878
|
+
if (existsSync12(dbPath)) {
|
|
11854
12879
|
try {
|
|
11855
12880
|
const database = Database.openReadOnly(dbPath);
|
|
11856
12881
|
if (this.database) {
|
|
@@ -11932,11 +12957,11 @@ var Indexer = class _Indexer {
|
|
|
11932
12957
|
});
|
|
11933
12958
|
this.provider = createEmbeddingProvider(this.configuredProviderInfo);
|
|
11934
12959
|
const dimensions = this.configuredProviderInfo.modelInfo.dimensions;
|
|
11935
|
-
const storePath =
|
|
12960
|
+
const storePath = path20.join(this.indexPath, "vectors");
|
|
11936
12961
|
const vectorMetadataPath = `${storePath}.meta.json`;
|
|
11937
|
-
const invertedIndexPath =
|
|
11938
|
-
const dbPath =
|
|
11939
|
-
let dbIsNew = !
|
|
12962
|
+
const invertedIndexPath = path20.join(this.indexPath, "inverted-index.json");
|
|
12963
|
+
const dbPath = path20.join(this.indexPath, "codebase.db");
|
|
12964
|
+
let dbIsNew = !existsSync12(dbPath);
|
|
11940
12965
|
const readerArtifactFingerprint = mode === "reader" ? this.captureReaderArtifactFingerprint() : null;
|
|
11941
12966
|
if (mode === "writer") {
|
|
11942
12967
|
await fsPromises3.mkdir(this.indexPath, { recursive: true });
|
|
@@ -11968,14 +12993,14 @@ var Indexer = class _Indexer {
|
|
|
11968
12993
|
}
|
|
11969
12994
|
}
|
|
11970
12995
|
this.store = new VectorStore(storePath, dimensions);
|
|
11971
|
-
if (
|
|
12996
|
+
if (existsSync12(storePath) || existsSync12(vectorMetadataPath)) {
|
|
11972
12997
|
this.store.load();
|
|
11973
12998
|
}
|
|
11974
12999
|
this.invertedIndex = new InvertedIndex(invertedIndexPath);
|
|
11975
13000
|
try {
|
|
11976
13001
|
this.invertedIndex.load();
|
|
11977
13002
|
} catch {
|
|
11978
|
-
if (
|
|
13003
|
+
if (existsSync12(invertedIndexPath)) {
|
|
11979
13004
|
await fsPromises3.unlink(invertedIndexPath);
|
|
11980
13005
|
}
|
|
11981
13006
|
this.invertedIndex = new InvertedIndex(invertedIndexPath);
|
|
@@ -11993,8 +13018,8 @@ var Indexer = class _Indexer {
|
|
|
11993
13018
|
}
|
|
11994
13019
|
} else {
|
|
11995
13020
|
this.store = new VectorStore(storePath, dimensions);
|
|
11996
|
-
const vectorStoreExists =
|
|
11997
|
-
const vectorMetadataExists =
|
|
13021
|
+
const vectorStoreExists = existsSync12(storePath);
|
|
13022
|
+
const vectorMetadataExists = existsSync12(vectorMetadataPath);
|
|
11998
13023
|
const vectorReadFailureMessage = this.getVectorReadIssueMessage();
|
|
11999
13024
|
if (vectorStoreExists !== vectorMetadataExists) {
|
|
12000
13025
|
this.recordReadIssue("vectors", vectorReadFailureMessage);
|
|
@@ -12007,7 +13032,7 @@ var Indexer = class _Indexer {
|
|
|
12007
13032
|
}
|
|
12008
13033
|
}
|
|
12009
13034
|
this.invertedIndex = new InvertedIndex(invertedIndexPath);
|
|
12010
|
-
if (
|
|
13035
|
+
if (existsSync12(invertedIndexPath)) {
|
|
12011
13036
|
try {
|
|
12012
13037
|
this.invertedIndex.load();
|
|
12013
13038
|
} catch (error) {
|
|
@@ -12021,7 +13046,7 @@ var Indexer = class _Indexer {
|
|
|
12021
13046
|
} else if (this.store.count() > 0) {
|
|
12022
13047
|
this.recordReadIssue("keyword", this.getKeywordReadIssueMessage());
|
|
12023
13048
|
}
|
|
12024
|
-
if (
|
|
13049
|
+
if (existsSync12(dbPath)) {
|
|
12025
13050
|
try {
|
|
12026
13051
|
this.database = Database.openReadOnly(dbPath);
|
|
12027
13052
|
} catch (error) {
|
|
@@ -12113,7 +13138,7 @@ var Indexer = class _Indexer {
|
|
|
12113
13138
|
if (await this.tryResetCorruptedIndex("running automatic orphan garbage collection", error)) {
|
|
12114
13139
|
return {
|
|
12115
13140
|
resetCorruptedIndex: true,
|
|
12116
|
-
warning: this.getCorruptedIndexWarning(
|
|
13141
|
+
warning: this.getCorruptedIndexWarning(path20.join(this.indexPath, "codebase.db"))
|
|
12117
13142
|
};
|
|
12118
13143
|
}
|
|
12119
13144
|
throw error;
|
|
@@ -12128,7 +13153,7 @@ var Indexer = class _Indexer {
|
|
|
12128
13153
|
return;
|
|
12129
13154
|
}
|
|
12130
13155
|
const retainedEntries = store.getAllMetadata().filter(({ key }) => !excludedSet.has(key));
|
|
12131
|
-
const storeBasePath =
|
|
13156
|
+
const storeBasePath = path20.join(this.indexPath, "vectors");
|
|
12132
13157
|
const storeIndexPath = storeBasePath;
|
|
12133
13158
|
const storeMetadataPath = `${storeBasePath}.meta.json`;
|
|
12134
13159
|
const lease = this.requireActiveLease();
|
|
@@ -12138,19 +13163,19 @@ var Indexer = class _Indexer {
|
|
|
12138
13163
|
let backedUpMetadata = false;
|
|
12139
13164
|
let rebuiltCount = 0;
|
|
12140
13165
|
let skippedCount = 0;
|
|
12141
|
-
if (
|
|
13166
|
+
if (existsSync12(backupIndexPath)) {
|
|
12142
13167
|
unlinkSync2(backupIndexPath);
|
|
12143
13168
|
}
|
|
12144
|
-
if (
|
|
13169
|
+
if (existsSync12(backupMetadataPath)) {
|
|
12145
13170
|
unlinkSync2(backupMetadataPath);
|
|
12146
13171
|
}
|
|
12147
13172
|
try {
|
|
12148
|
-
if (
|
|
12149
|
-
|
|
13173
|
+
if (existsSync12(storeIndexPath)) {
|
|
13174
|
+
renameSync4(storeIndexPath, backupIndexPath);
|
|
12150
13175
|
backedUpIndex = true;
|
|
12151
13176
|
}
|
|
12152
|
-
if (
|
|
12153
|
-
|
|
13177
|
+
if (existsSync12(storeMetadataPath)) {
|
|
13178
|
+
renameSync4(storeMetadataPath, backupMetadataPath);
|
|
12154
13179
|
backedUpMetadata = true;
|
|
12155
13180
|
}
|
|
12156
13181
|
store.clear();
|
|
@@ -12170,10 +13195,10 @@ var Indexer = class _Indexer {
|
|
|
12170
13195
|
rebuiltCount += 1;
|
|
12171
13196
|
}
|
|
12172
13197
|
store.save();
|
|
12173
|
-
if (backedUpIndex &&
|
|
13198
|
+
if (backedUpIndex && existsSync12(backupIndexPath)) {
|
|
12174
13199
|
unlinkSync2(backupIndexPath);
|
|
12175
13200
|
}
|
|
12176
|
-
if (backedUpMetadata &&
|
|
13201
|
+
if (backedUpMetadata && existsSync12(backupMetadataPath)) {
|
|
12177
13202
|
unlinkSync2(backupMetadataPath);
|
|
12178
13203
|
}
|
|
12179
13204
|
this.logger.gc("info", "Rebuilt vector store to avoid native remove", {
|
|
@@ -12186,17 +13211,17 @@ var Indexer = class _Indexer {
|
|
|
12186
13211
|
store.clear();
|
|
12187
13212
|
} catch {
|
|
12188
13213
|
}
|
|
12189
|
-
if (
|
|
13214
|
+
if (existsSync12(storeIndexPath)) {
|
|
12190
13215
|
unlinkSync2(storeIndexPath);
|
|
12191
13216
|
}
|
|
12192
|
-
if (
|
|
13217
|
+
if (existsSync12(storeMetadataPath)) {
|
|
12193
13218
|
unlinkSync2(storeMetadataPath);
|
|
12194
13219
|
}
|
|
12195
|
-
if (backedUpIndex &&
|
|
12196
|
-
|
|
13220
|
+
if (backedUpIndex && existsSync12(backupIndexPath)) {
|
|
13221
|
+
renameSync4(backupIndexPath, storeIndexPath);
|
|
12197
13222
|
}
|
|
12198
|
-
if (backedUpMetadata &&
|
|
12199
|
-
|
|
13223
|
+
if (backedUpMetadata && existsSync12(backupMetadataPath)) {
|
|
13224
|
+
renameSync4(backupMetadataPath, storeMetadataPath);
|
|
12200
13225
|
}
|
|
12201
13226
|
if (backedUpIndex || backedUpMetadata) {
|
|
12202
13227
|
store.load();
|
|
@@ -12211,11 +13236,11 @@ var Indexer = class _Indexer {
|
|
|
12211
13236
|
return `Detected a corrupted local SQLite index at ${dbPath} and reset the local index. Run index_codebase to rebuild search data.`;
|
|
12212
13237
|
}
|
|
12213
13238
|
async removeProjectRuntimeStateArtifacts() {
|
|
12214
|
-
if (!
|
|
13239
|
+
if (!existsSync12(this.indexPath)) return;
|
|
12215
13240
|
const names = await fsPromises3.readdir(this.indexPath);
|
|
12216
13241
|
const runtimeStatePattern = /^(?:file-hashes|failed-batches)(?:\.[a-f0-9]{16})?\.json$/;
|
|
12217
13242
|
await Promise.all(
|
|
12218
|
-
names.filter((name) => runtimeStatePattern.test(name)).map((name) => fsPromises3.rm(
|
|
13243
|
+
names.filter((name) => runtimeStatePattern.test(name)).map((name) => fsPromises3.rm(path20.join(this.indexPath, name), { force: true }))
|
|
12219
13244
|
);
|
|
12220
13245
|
}
|
|
12221
13246
|
async resetLocalIndexArtifacts() {
|
|
@@ -12231,13 +13256,13 @@ var Indexer = class _Indexer {
|
|
|
12231
13256
|
this.readerArtifactRetryAfter.clear();
|
|
12232
13257
|
this.fileHashCache.clear();
|
|
12233
13258
|
const resetPaths = [
|
|
12234
|
-
|
|
12235
|
-
|
|
12236
|
-
|
|
12237
|
-
|
|
12238
|
-
|
|
12239
|
-
|
|
12240
|
-
|
|
13259
|
+
path20.join(this.indexPath, "codebase.db"),
|
|
13260
|
+
path20.join(this.indexPath, "codebase.db-shm"),
|
|
13261
|
+
path20.join(this.indexPath, "codebase.db-wal"),
|
|
13262
|
+
path20.join(this.indexPath, "vectors"),
|
|
13263
|
+
path20.join(this.indexPath, "vectors.usearch"),
|
|
13264
|
+
path20.join(this.indexPath, "vectors.meta.json"),
|
|
13265
|
+
path20.join(this.indexPath, "inverted-index.json")
|
|
12241
13266
|
];
|
|
12242
13267
|
await Promise.all(resetPaths.map((targetPath) => fsPromises3.rm(targetPath, { recursive: true, force: true })));
|
|
12243
13268
|
await this.removeProjectRuntimeStateArtifacts();
|
|
@@ -12247,7 +13272,7 @@ var Indexer = class _Indexer {
|
|
|
12247
13272
|
if (!isSqliteCorruptionError(error)) {
|
|
12248
13273
|
return false;
|
|
12249
13274
|
}
|
|
12250
|
-
const dbPath =
|
|
13275
|
+
const dbPath = path20.join(this.indexPath, "codebase.db");
|
|
12251
13276
|
const warning = this.getCorruptedIndexWarning(dbPath);
|
|
12252
13277
|
const errorMessage = getErrorMessage4(error);
|
|
12253
13278
|
if (this.config.scope === "global") {
|
|
@@ -12481,6 +13506,70 @@ var Indexer = class _Indexer {
|
|
|
12481
13506
|
);
|
|
12482
13507
|
return createCostEstimate(files, configuredProviderInfo);
|
|
12483
13508
|
}
|
|
13509
|
+
// Dry-run counterpart to index()/forceIndex(): parse the real file set and sum
|
|
13510
|
+
// estimateTokens over the embedding text of every indexable chunk, without
|
|
13511
|
+
// calling the embedding provider or writing to the index. Read-only and
|
|
13512
|
+
// lock-free (mirrors estimateCost). The token sum is the exact value "Tokens
|
|
13513
|
+
// used" climbs to for a force index (cache bypassed); for an incremental it is
|
|
13514
|
+
// an upper bound because cached chunks are counted here but not re-embedded.
|
|
13515
|
+
// Used by index_codebase(dryRun:true) to give a stable, monotonic progress
|
|
13516
|
+
// denominator that matches the live "Tokens used" basis.
|
|
13517
|
+
async dryRunCost() {
|
|
13518
|
+
const { configuredProviderInfo } = await this.ensureInitialized();
|
|
13519
|
+
const maxChunkTokens = getSafeEmbeddingChunkTokenLimit(configuredProviderInfo);
|
|
13520
|
+
const includePatterns = [...this.config.include, ...this.config.additionalInclude];
|
|
13521
|
+
const { files } = await collectFiles(
|
|
13522
|
+
this.materializedProjectRoot,
|
|
13523
|
+
includePatterns,
|
|
13524
|
+
this.config.exclude,
|
|
13525
|
+
this.config.indexing.maxFileSize,
|
|
13526
|
+
this.getMaterializedKnowledgeBases(),
|
|
13527
|
+
{ maxDepth: this.config.indexing.maxDepth, maxFilesPerDirectory: this.config.indexing.maxFilesPerDirectory }
|
|
13528
|
+
);
|
|
13529
|
+
let filesCount = 0;
|
|
13530
|
+
let chunksCount = 0;
|
|
13531
|
+
let tokensToEmbed = 0;
|
|
13532
|
+
for (const batch of iterateOrderedFileBatches(files, (f) => f.size, this.fileBatchLimits)) {
|
|
13533
|
+
const loadedFiles = await Promise.all(batch.map(async (f) => {
|
|
13534
|
+
try {
|
|
13535
|
+
return {
|
|
13536
|
+
path: this.toStoredFilePath(f.path),
|
|
13537
|
+
content: await fsPromises3.readFile(f.path, "utf-8")
|
|
13538
|
+
};
|
|
13539
|
+
} catch {
|
|
13540
|
+
return null;
|
|
13541
|
+
}
|
|
13542
|
+
}));
|
|
13543
|
+
const readable = loadedFiles.filter(
|
|
13544
|
+
(f) => f !== null
|
|
13545
|
+
);
|
|
13546
|
+
filesCount += readable.length;
|
|
13547
|
+
const contentByPath = new Map(readable.map((f) => [f.path, f.content]));
|
|
13548
|
+
const parsedFiles = parseFiles(readable, this.config.indexing.linesPerChunk);
|
|
13549
|
+
for (const parsed of parsedFiles) {
|
|
13550
|
+
let chunksToProcess = parsed.chunks;
|
|
13551
|
+
if (this.config.indexing.fallbackToTextOnMaxChunks && chunksToProcess.length > this.config.indexing.maxChunksPerFile) {
|
|
13552
|
+
const content = contentByPath.get(parsed.path);
|
|
13553
|
+
if (content !== void 0) {
|
|
13554
|
+
chunksToProcess = parseFileAsText(parsed.path, content, this.config.indexing.linesPerChunk);
|
|
13555
|
+
}
|
|
13556
|
+
}
|
|
13557
|
+
chunksToProcess = selectIndexableChunks(
|
|
13558
|
+
chunksToProcess,
|
|
13559
|
+
this.config.indexing.maxChunksPerFile,
|
|
13560
|
+
this.config.indexing.semanticOnly
|
|
13561
|
+
);
|
|
13562
|
+
for (const chunk of chunksToProcess) {
|
|
13563
|
+
const texts = createEmbeddingTexts(chunk, parsed.path, maxChunkTokens);
|
|
13564
|
+
chunksCount += 1;
|
|
13565
|
+
for (const text3 of texts) {
|
|
13566
|
+
tokensToEmbed += estimateTokens(text3);
|
|
13567
|
+
}
|
|
13568
|
+
}
|
|
13569
|
+
}
|
|
13570
|
+
}
|
|
13571
|
+
return { filesCount, chunksCount, tokensToEmbed };
|
|
13572
|
+
}
|
|
12484
13573
|
async index(onProgress) {
|
|
12485
13574
|
return this.withIndexMutationLease("index", async (recoveredOwners) => {
|
|
12486
13575
|
return this.indexUnlocked(onProgress, recoveredOwners);
|
|
@@ -12570,10 +13659,10 @@ var Indexer = class _Indexer {
|
|
|
12570
13659
|
const reparseCachedMetalFiles = database.getMetadata(metalParserMetadataKey) !== METAL_PARSER_VERSION;
|
|
12571
13660
|
const symbolExtractorMetadataKey = this.getSymbolExtractorVersionMetadataKey();
|
|
12572
13661
|
const refreshCachedSymbols = database.getMetadata(symbolExtractorMetadataKey) !== SYMBOL_EXTRACTOR_VERSION;
|
|
12573
|
-
if (reparseCachedSwiftFiles && Array.from(this.fileHashCache.keys()).some((filePath) =>
|
|
13662
|
+
if (reparseCachedSwiftFiles && Array.from(this.fileHashCache.keys()).some((filePath) => path20.extname(filePath).toLowerCase() === ".swift")) {
|
|
12574
13663
|
this.logger.info("Reindexing cached Swift files for parser support");
|
|
12575
13664
|
}
|
|
12576
|
-
if (reparseCachedMetalFiles && Array.from(this.fileHashCache.keys()).some((filePath) =>
|
|
13665
|
+
if (reparseCachedMetalFiles && Array.from(this.fileHashCache.keys()).some((filePath) => path20.extname(filePath).toLowerCase() === ".metal")) {
|
|
12577
13666
|
this.logger.info("Reindexing cached Metal files for parser support");
|
|
12578
13667
|
}
|
|
12579
13668
|
const includePatterns = [...this.config.include, ...this.config.additionalInclude];
|
|
@@ -12617,8 +13706,8 @@ var Indexer = class _Indexer {
|
|
|
12617
13706
|
const needsCallGraphRefresh = cachedHashMatches && needsCallGraphResolutionMigration && database.getChunksByFile(storedPath).some(
|
|
12618
13707
|
(chunk) => chunk.language === "php" || chunk.language === "c" || chunk.language === "cpp"
|
|
12619
13708
|
);
|
|
12620
|
-
const requiresSwiftParserUpgrade = reparseCachedSwiftFiles &&
|
|
12621
|
-
const requiresMetalParserUpgrade = reparseCachedMetalFiles &&
|
|
13709
|
+
const requiresSwiftParserUpgrade = reparseCachedSwiftFiles && path20.extname(storedPath).toLowerCase() === ".swift";
|
|
13710
|
+
const requiresMetalParserUpgrade = reparseCachedMetalFiles && path20.extname(storedPath).toLowerCase() === ".metal";
|
|
12622
13711
|
const inMigrationScope = forceScopedReembed && scopedRoots !== null && this.isFileInCurrentScope(storedPath, scopedRoots);
|
|
12623
13712
|
if (cachedHashMatches && !inMigrationScope && !needsCallGraphRefresh && !requiresSwiftParserUpgrade && !requiresMetalParserUpgrade && !refreshCachedSymbols) {
|
|
12624
13713
|
unchangedFilePaths.add(storedPath);
|
|
@@ -12677,7 +13766,7 @@ var Indexer = class _Indexer {
|
|
|
12677
13766
|
}
|
|
12678
13767
|
}
|
|
12679
13768
|
}
|
|
12680
|
-
const shouldRetryFailedPath = (filePath) => filePath !== null && currentFileHashes.has(filePath) && unchangedFilePaths.has(filePath);
|
|
13769
|
+
const shouldRetryFailedPath = (filePath) => filePath !== null && !this.isStoredPathExcluded(filePath) && currentFileHashes.has(filePath) && unchangedFilePaths.has(filePath);
|
|
12681
13770
|
const failedProcessing = this.prepareFailedBatchProcessing(scopedRoots, shouldRetryFailedPath);
|
|
12682
13771
|
const maxChunkTokens = getSafeEmbeddingChunkTokenLimit(configuredProviderInfo);
|
|
12683
13772
|
const providerRateLimits = this.getProviderRateLimits(configuredProviderInfo.provider);
|
|
@@ -12781,7 +13870,7 @@ var Indexer = class _Indexer {
|
|
|
12781
13870
|
throw new Error(`Parsed file was not present in its source batch: ${parsed.path}`);
|
|
12782
13871
|
}
|
|
12783
13872
|
if (parsed.chunks.length === 0) {
|
|
12784
|
-
stats.parseFailures.push(
|
|
13873
|
+
stats.parseFailures.push(path20.isAbsolute(parsed.path) ? path20.relative(this.projectRoot, parsed.path) : parsed.path);
|
|
12785
13874
|
}
|
|
12786
13875
|
let chunksToProcess = parsed.chunks;
|
|
12787
13876
|
if (this.config.indexing.fallbackToTextOnMaxChunks && chunksToProcess.length > this.config.indexing.maxChunksPerFile) {
|
|
@@ -13116,8 +14205,8 @@ var Indexer = class _Indexer {
|
|
|
13116
14205
|
previousBranchSymbolIds,
|
|
13117
14206
|
Array.from(allSymbolIds)
|
|
13118
14207
|
);
|
|
13119
|
-
const vectorPath =
|
|
13120
|
-
const shouldFingerprintLegacyPair = !store.hasFingerprint() &&
|
|
14208
|
+
const vectorPath = path20.join(this.indexPath, "vectors");
|
|
14209
|
+
const shouldFingerprintLegacyPair = !store.hasFingerprint() && existsSync12(vectorPath) && existsSync12(`${vectorPath}.meta.json`);
|
|
13121
14210
|
if (backfilledBlameMetadata || shouldFingerprintLegacyPair || removedStoredChunks) {
|
|
13122
14211
|
store.save();
|
|
13123
14212
|
}
|
|
@@ -13912,7 +15001,7 @@ var Indexer = class _Indexer {
|
|
|
13912
15001
|
const missingChunkKeys = [];
|
|
13913
15002
|
const chunkKeysByRemovedFile = /* @__PURE__ */ new Map();
|
|
13914
15003
|
for (const [filePath, chunkKeys] of filePathsToChunkKeys) {
|
|
13915
|
-
if (!
|
|
15004
|
+
if (!existsSync12(this.toMaterializedFilePath(filePath))) {
|
|
13916
15005
|
chunkKeysByRemovedFile.set(filePath, chunkKeys);
|
|
13917
15006
|
for (const key of chunkKeys) {
|
|
13918
15007
|
missingChunkKeys.push(key);
|
|
@@ -13975,7 +15064,7 @@ var Indexer = class _Indexer {
|
|
|
13975
15064
|
gcOrphanSymbols: 0,
|
|
13976
15065
|
gcOrphanCallEdges: 0,
|
|
13977
15066
|
resetCorruptedIndex: true,
|
|
13978
|
-
warning: this.getCorruptedIndexWarning(
|
|
15067
|
+
warning: this.getCorruptedIndexWarning(path20.join(this.indexPath, "codebase.db"))
|
|
13979
15068
|
};
|
|
13980
15069
|
}
|
|
13981
15070
|
this.logger.recordGc(removedCount, gcOrphanChunks, gcOrphanEmbeddings);
|
|
@@ -14005,7 +15094,8 @@ var Indexer = class _Indexer {
|
|
|
14005
15094
|
const maxChunkTokens = getSafeEmbeddingChunkTokenLimit(configuredProviderInfo);
|
|
14006
15095
|
const providerRateLimits = this.getProviderRateLimits(configuredProviderInfo.provider);
|
|
14007
15096
|
const roots = this.config.scope === "global" ? this.getScopedRoots() : null;
|
|
14008
|
-
const
|
|
15097
|
+
const shouldProcessFailedPath = (filePath) => filePath === null || !this.isStoredPathExcluded(filePath);
|
|
15098
|
+
const failedProcessing = this.prepareFailedBatchProcessing(roots, shouldProcessFailedPath);
|
|
14009
15099
|
if (failedProcessing.latestById.size === 0) {
|
|
14010
15100
|
this.finalizeFailedBatchWriteState(failedProcessing.state);
|
|
14011
15101
|
return { succeeded: 0, failed: 0, remaining: 0 };
|
|
@@ -14018,7 +15108,7 @@ var Indexer = class _Indexer {
|
|
|
14018
15108
|
const retryableChunks = this.iterateLatestFailedChunks(
|
|
14019
15109
|
failedProcessing.latestById,
|
|
14020
15110
|
roots,
|
|
14021
|
-
|
|
15111
|
+
shouldProcessFailedPath,
|
|
14022
15112
|
maxChunkTokens
|
|
14023
15113
|
);
|
|
14024
15114
|
for (const retryBatch of iterateOrderedFileBatches(
|
|
@@ -14288,9 +15378,9 @@ var Indexer = class _Indexer {
|
|
|
14288
15378
|
this.requireReadableComponents(readIssues, "database");
|
|
14289
15379
|
let shortest = [];
|
|
14290
15380
|
for (const branchKey of this.getBranchCatalogKeys()) {
|
|
14291
|
-
const
|
|
14292
|
-
if (
|
|
14293
|
-
shortest =
|
|
15381
|
+
const path26 = database.findShortestPath(fromName, toName, branchKey, maxDepth);
|
|
15382
|
+
if (path26.length > 0 && (shortest.length === 0 || path26.length < shortest.length)) {
|
|
15383
|
+
shortest = path26;
|
|
14294
15384
|
}
|
|
14295
15385
|
}
|
|
14296
15386
|
return shortest.map((hop) => this.resolveFilePathRecord(hop));
|
|
@@ -14338,13 +15428,13 @@ var Indexer = class _Indexer {
|
|
|
14338
15428
|
}
|
|
14339
15429
|
}
|
|
14340
15430
|
if (!found) continue;
|
|
14341
|
-
const
|
|
15431
|
+
const path26 = [];
|
|
14342
15432
|
let currentSymbolId = toSymbolId;
|
|
14343
15433
|
while (true) {
|
|
14344
15434
|
const symbol = symbolsById.get(currentSymbolId);
|
|
14345
15435
|
if (!symbol) break;
|
|
14346
15436
|
const parent = parentBySymbolId.get(currentSymbolId);
|
|
14347
|
-
|
|
15437
|
+
path26.push({
|
|
14348
15438
|
symbolId: symbol.id,
|
|
14349
15439
|
symbolName: symbol.name,
|
|
14350
15440
|
filePath: symbol.filePath,
|
|
@@ -14354,9 +15444,9 @@ var Indexer = class _Indexer {
|
|
|
14354
15444
|
if (!parent) break;
|
|
14355
15445
|
currentSymbolId = parent.parentId;
|
|
14356
15446
|
}
|
|
14357
|
-
|
|
14358
|
-
if (
|
|
14359
|
-
shortest =
|
|
15447
|
+
path26.reverse();
|
|
15448
|
+
if (path26.length > 0 && (shortest.length === 0 || path26.length < shortest.length)) {
|
|
15449
|
+
shortest = path26;
|
|
14360
15450
|
}
|
|
14361
15451
|
}
|
|
14362
15452
|
return shortest.map((hop) => this.resolveFilePathRecord(hop));
|
|
@@ -14507,7 +15597,7 @@ var Indexer = class _Indexer {
|
|
|
14507
15597
|
);
|
|
14508
15598
|
}
|
|
14509
15599
|
}
|
|
14510
|
-
const toStoredChangedFiles = (filePaths) => filePaths.map((filePath) => this.toStoredFilePath(
|
|
15600
|
+
const toStoredChangedFiles = (filePaths) => filePaths.map((filePath) => this.toStoredFilePath(path20.resolve(this.projectRoot, filePath)));
|
|
14511
15601
|
const storedChangedFiles = toStoredChangedFiles(changedFiles);
|
|
14512
15602
|
const directSymbols = database.getSymbolsForFiles(storedChangedFiles, branchKey);
|
|
14513
15603
|
const directIds = directSymbols.map((s) => s.id);
|
|
@@ -14656,12 +15746,12 @@ var Indexer = class _Indexer {
|
|
|
14656
15746
|
if (meta.filePath) filePaths.add(meta.filePath);
|
|
14657
15747
|
}
|
|
14658
15748
|
const directory = options?.directory?.replace(/\/$/, "");
|
|
14659
|
-
const absoluteDirectoryFilter = directory ?
|
|
15749
|
+
const absoluteDirectoryFilter = directory ? path20.resolve(this.projectRoot, directory) : void 0;
|
|
14660
15750
|
for (const filePath of filePaths) {
|
|
14661
15751
|
if (directory) {
|
|
14662
15752
|
const absoluteFilePath = this.resolveStoredFilePath(filePath);
|
|
14663
15753
|
const matchesRelative = filePath === directory || filePath.startsWith(directory + "/");
|
|
14664
|
-
const matchesProjectRelative = absoluteDirectoryFilter !== void 0 && (absoluteFilePath === absoluteDirectoryFilter || absoluteFilePath.startsWith(absoluteDirectoryFilter +
|
|
15754
|
+
const matchesProjectRelative = absoluteDirectoryFilter !== void 0 && (absoluteFilePath === absoluteDirectoryFilter || absoluteFilePath.startsWith(absoluteDirectoryFilter + path20.sep));
|
|
14665
15755
|
if (!matchesRelative && !matchesProjectRelative) {
|
|
14666
15756
|
continue;
|
|
14667
15757
|
}
|
|
@@ -14778,7 +15868,10 @@ function getOrCreateIndexer(projectRoot3, host) {
|
|
|
14778
15868
|
}
|
|
14779
15869
|
const indexer = new Indexer(projectRoot3, config, host);
|
|
14780
15870
|
indexerCache.set(key, indexer);
|
|
14781
|
-
configureAutoIndex(projectRoot3, host, config, () => getOrCreateIndexer(projectRoot3, host)
|
|
15871
|
+
configureAutoIndex(projectRoot3, host, config, () => getOrCreateIndexer(projectRoot3, host), {
|
|
15872
|
+
preserveManagedWorker: true,
|
|
15873
|
+
synchronizeBackgroundWorker: false
|
|
15874
|
+
});
|
|
14782
15875
|
return indexer;
|
|
14783
15876
|
}
|
|
14784
15877
|
function getIndexerForProject(projectRoot3, host) {
|
|
@@ -14793,7 +15886,9 @@ function refreshIndexerForDirectory(projectRoot3, host, config = parseConfig(loa
|
|
|
14793
15886
|
const key = getIndexerCacheKey(projectRoot3, host);
|
|
14794
15887
|
configCache.set(key, config);
|
|
14795
15888
|
indexerCache.set(key, new Indexer(projectRoot3, config, host));
|
|
14796
|
-
configureAutoIndex(projectRoot3, host, config, () => getOrCreateIndexer(projectRoot3, host)
|
|
15889
|
+
configureAutoIndex(projectRoot3, host, config, () => getOrCreateIndexer(projectRoot3, host), {
|
|
15890
|
+
synchronizeBackgroundWorker: true
|
|
15891
|
+
});
|
|
14797
15892
|
return config;
|
|
14798
15893
|
}
|
|
14799
15894
|
var AutoIndexRetrievalUnavailableError = class extends Error {
|
|
@@ -14820,7 +15915,7 @@ function trimOrUndefined(value) {
|
|
|
14820
15915
|
return normalized || void 0;
|
|
14821
15916
|
}
|
|
14822
15917
|
function normalizeCallGraphPath(value) {
|
|
14823
|
-
let normalized =
|
|
15918
|
+
let normalized = path21.posix.normalize(value.trim().replaceAll("\\", "/"));
|
|
14824
15919
|
if (normalized.startsWith("./")) {
|
|
14825
15920
|
normalized = normalized.slice(2);
|
|
14826
15921
|
}
|
|
@@ -15013,12 +16108,12 @@ async function getCallGraphPath(projectRoot3, host, from, to, maxDepth, fromFile
|
|
|
15013
16108
|
if (fromResolution.status !== "resolved" || toResolution.status !== "resolved") {
|
|
15014
16109
|
return { from: fromResolution, to: toResolution, path: [] };
|
|
15015
16110
|
}
|
|
15016
|
-
const
|
|
16111
|
+
const path26 = await indexer.findCallPathBySymbolIds(
|
|
15017
16112
|
fromResolution.symbolId,
|
|
15018
16113
|
toResolution.symbolId,
|
|
15019
16114
|
maxDepth
|
|
15020
16115
|
);
|
|
15021
|
-
return { from: fromResolution, to: toResolution, path:
|
|
16116
|
+
return { from: fromResolution, to: toResolution, path: path26 };
|
|
15022
16117
|
}
|
|
15023
16118
|
async function runIndexCodebase(projectRoot3, host, args, onProgress) {
|
|
15024
16119
|
const root = getProjectRoot(projectRoot3, host);
|
|
@@ -15027,6 +16122,9 @@ async function runIndexCodebase(projectRoot3, host, args, onProgress) {
|
|
|
15027
16122
|
if (args.estimateOnly) {
|
|
15028
16123
|
return { kind: "estimate", estimate: await indexer.estimateCost() };
|
|
15029
16124
|
}
|
|
16125
|
+
if (args.dryRun) {
|
|
16126
|
+
return { kind: "dryrun", dryrun: await indexer.dryRunCost() };
|
|
16127
|
+
}
|
|
15030
16128
|
const coordinated = runCoordinatedIndex(root, host, args.force ?? false, (progress) => {
|
|
15031
16129
|
if (onProgress) {
|
|
15032
16130
|
void onProgress(formatProgressTitle(progress), {
|
|
@@ -15213,15 +16311,15 @@ async function getIndexLogs(projectRoot3, host, args) {
|
|
|
15213
16311
|
function addKnowledgeBase(projectRoot3, host, knowledgeBasePath) {
|
|
15214
16312
|
const root = getProjectRoot(projectRoot3, host);
|
|
15215
16313
|
const inputPath = knowledgeBasePath.trim();
|
|
15216
|
-
const normalizedPath2 =
|
|
15217
|
-
|
|
16314
|
+
const normalizedPath2 = path21.resolve(
|
|
16315
|
+
path21.isAbsolute(inputPath) ? inputPath : resolveKnowledgeBasePath(inputPath, root)
|
|
15218
16316
|
);
|
|
15219
|
-
if (!
|
|
16317
|
+
if (!existsSync13(normalizedPath2)) {
|
|
15220
16318
|
return `Error: Directory does not exist: ${normalizedPath2}`;
|
|
15221
16319
|
}
|
|
15222
16320
|
let realPath;
|
|
15223
16321
|
try {
|
|
15224
|
-
realPath =
|
|
16322
|
+
realPath = realpathSync6(normalizedPath2);
|
|
15225
16323
|
} catch {
|
|
15226
16324
|
return `Error: Cannot resolve path: ${normalizedPath2}`;
|
|
15227
16325
|
}
|
|
@@ -15250,7 +16348,7 @@ function addKnowledgeBase(projectRoot3, host, knowledgeBasePath) {
|
|
|
15250
16348
|
}
|
|
15251
16349
|
}
|
|
15252
16350
|
for (const dotDir of sensitiveDotDirs) {
|
|
15253
|
-
const sensitiveDir =
|
|
16351
|
+
const sensitiveDir = path21.join(homeDir, dotDir);
|
|
15254
16352
|
if (sensitiveDir && (realPath === sensitiveDir || realPath.startsWith(`${sensitiveDir}/`))) {
|
|
15255
16353
|
return `Error: Adding sensitive directory as knowledge base is not allowed: ${normalizedPath2}`;
|
|
15256
16354
|
}
|
|
@@ -15296,7 +16394,7 @@ function listKnowledgeBases(projectRoot3, host) {
|
|
|
15296
16394
|
for (let i = 0; i < knowledgeBases.length; i++) {
|
|
15297
16395
|
const kb = knowledgeBases[i];
|
|
15298
16396
|
const resolvedPath = resolveKnowledgeBasePath(kb, root);
|
|
15299
|
-
const exists =
|
|
16397
|
+
const exists = existsSync13(resolvedPath);
|
|
15300
16398
|
result += `[${i + 1}] ${kb}
|
|
15301
16399
|
`;
|
|
15302
16400
|
result += ` Resolved: ${resolvedPath}
|
|
@@ -15313,7 +16411,7 @@ function listKnowledgeBases(projectRoot3, host) {
|
|
|
15313
16411
|
}
|
|
15314
16412
|
result += "\n";
|
|
15315
16413
|
}
|
|
15316
|
-
const hasHostConfig =
|
|
16414
|
+
const hasHostConfig = existsSync13(path21.join(root, getHostProjectConfigRelativePath(host)));
|
|
15317
16415
|
if (hasHostConfig) {
|
|
15318
16416
|
result += `
|
|
15319
16417
|
Config sources: 1 file(s).`;
|
|
@@ -15786,7 +16884,7 @@ async function resolveCodebaseContextUnmeasured(projectRoot3, host, input) {
|
|
|
15786
16884
|
const directory = input.directory ?? void 0;
|
|
15787
16885
|
const tokenBudget = input.tokenBudget ?? void 0;
|
|
15788
16886
|
if (from && to) {
|
|
15789
|
-
const
|
|
16887
|
+
const path26 = await getCallGraphPath(
|
|
15790
16888
|
projectRoot3,
|
|
15791
16889
|
host,
|
|
15792
16890
|
from,
|
|
@@ -15795,25 +16893,25 @@ async function resolveCodebaseContextUnmeasured(projectRoot3, host, input) {
|
|
|
15795
16893
|
fromFilePath,
|
|
15796
16894
|
toFilePath
|
|
15797
16895
|
);
|
|
15798
|
-
const pathText = formatCallGraphPathResult(
|
|
15799
|
-
if (
|
|
16896
|
+
const pathText = formatCallGraphPathResult(path26);
|
|
16897
|
+
if (path26.path.length > 0) {
|
|
15800
16898
|
const fitted2 = fitTextToContextBudget(
|
|
15801
16899
|
pathText,
|
|
15802
16900
|
tokenBudget
|
|
15803
16901
|
);
|
|
15804
16902
|
return {
|
|
15805
16903
|
text: fitted2.text,
|
|
15806
|
-
details: fittedDetails("path", fitted2,
|
|
16904
|
+
details: fittedDetails("path", fitted2, path26.path.length)
|
|
15807
16905
|
};
|
|
15808
16906
|
}
|
|
15809
|
-
if (
|
|
16907
|
+
if (path26.from.status !== "resolved" || path26.to.status !== "resolved") {
|
|
15810
16908
|
const fitted2 = fitTextToContextBudget(pathText, tokenBudget);
|
|
15811
16909
|
return {
|
|
15812
16910
|
text: fitted2.text,
|
|
15813
16911
|
details: fittedDetails("path", fitted2, 0)
|
|
15814
16912
|
};
|
|
15815
16913
|
}
|
|
15816
|
-
const resolvedFrom =
|
|
16914
|
+
const resolvedFrom = path26.from;
|
|
15817
16915
|
const { callers } = await getCallGraphData(projectRoot3, host, {
|
|
15818
16916
|
name: to,
|
|
15819
16917
|
direction: "callers",
|
|
@@ -16254,7 +17352,7 @@ function registerPiCallGraphTools(pi) {
|
|
|
16254
17352
|
}
|
|
16255
17353
|
|
|
16256
17354
|
// src/watcher/file-watcher.ts
|
|
16257
|
-
import { existsSync as
|
|
17355
|
+
import { existsSync as existsSync14, statSync as statSync6 } from "fs";
|
|
16258
17356
|
|
|
16259
17357
|
// node_modules/chokidar/index.js
|
|
16260
17358
|
import { EventEmitter as EventEmitter2 } from "events";
|
|
@@ -16346,7 +17444,7 @@ var ReaddirpStream = class extends Readable {
|
|
|
16346
17444
|
this._directoryFilter = normalizeFilter(opts.directoryFilter);
|
|
16347
17445
|
const statMethod = opts.lstat ? lstat : stat;
|
|
16348
17446
|
if (wantBigintFsStats) {
|
|
16349
|
-
this._stat = (
|
|
17447
|
+
this._stat = (path26) => statMethod(path26, { bigint: true });
|
|
16350
17448
|
} else {
|
|
16351
17449
|
this._stat = statMethod;
|
|
16352
17450
|
}
|
|
@@ -16371,8 +17469,8 @@ var ReaddirpStream = class extends Readable {
|
|
|
16371
17469
|
const par = this.parent;
|
|
16372
17470
|
const fil = par && par.files;
|
|
16373
17471
|
if (fil && fil.length > 0) {
|
|
16374
|
-
const { path:
|
|
16375
|
-
const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent,
|
|
17472
|
+
const { path: path26, depth } = par;
|
|
17473
|
+
const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path26));
|
|
16376
17474
|
const awaited = await Promise.all(slice);
|
|
16377
17475
|
for (const entry of awaited) {
|
|
16378
17476
|
if (!entry)
|
|
@@ -16412,21 +17510,21 @@ var ReaddirpStream = class extends Readable {
|
|
|
16412
17510
|
this.reading = false;
|
|
16413
17511
|
}
|
|
16414
17512
|
}
|
|
16415
|
-
async _exploreDir(
|
|
17513
|
+
async _exploreDir(path26, depth) {
|
|
16416
17514
|
let files;
|
|
16417
17515
|
try {
|
|
16418
|
-
files = await readdir(
|
|
17516
|
+
files = await readdir(path26, this._rdOptions);
|
|
16419
17517
|
} catch (error) {
|
|
16420
17518
|
this._onError(error);
|
|
16421
17519
|
}
|
|
16422
|
-
return { files, depth, path:
|
|
17520
|
+
return { files, depth, path: path26 };
|
|
16423
17521
|
}
|
|
16424
|
-
async _formatEntry(dirent,
|
|
17522
|
+
async _formatEntry(dirent, path26) {
|
|
16425
17523
|
let entry;
|
|
16426
|
-
const
|
|
17524
|
+
const basename8 = this._isDirent ? dirent.name : dirent;
|
|
16427
17525
|
try {
|
|
16428
|
-
const fullPath = presolve(pjoin(
|
|
16429
|
-
entry = { path: prelative(this._root, fullPath), fullPath, basename:
|
|
17526
|
+
const fullPath = presolve(pjoin(path26, basename8));
|
|
17527
|
+
entry = { path: prelative(this._root, fullPath), fullPath, basename: basename8 };
|
|
16430
17528
|
entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
|
|
16431
17529
|
} catch (err) {
|
|
16432
17530
|
this._onError(err);
|
|
@@ -16825,16 +17923,16 @@ var delFromSet = (main, prop, item) => {
|
|
|
16825
17923
|
};
|
|
16826
17924
|
var isEmptySet = (val) => val instanceof Set ? val.size === 0 : !val;
|
|
16827
17925
|
var FsWatchInstances = /* @__PURE__ */ new Map();
|
|
16828
|
-
function createFsWatchInstance(
|
|
17926
|
+
function createFsWatchInstance(path26, options, listener, errHandler, emitRaw) {
|
|
16829
17927
|
const handleEvent = (rawEvent, evPath) => {
|
|
16830
|
-
listener(
|
|
16831
|
-
emitRaw(rawEvent, evPath, { watchedPath:
|
|
16832
|
-
if (evPath &&
|
|
16833
|
-
fsWatchBroadcast(sp.resolve(
|
|
17928
|
+
listener(path26);
|
|
17929
|
+
emitRaw(rawEvent, evPath, { watchedPath: path26 });
|
|
17930
|
+
if (evPath && path26 !== evPath) {
|
|
17931
|
+
fsWatchBroadcast(sp.resolve(path26, evPath), KEY_LISTENERS, sp.join(path26, evPath));
|
|
16834
17932
|
}
|
|
16835
17933
|
};
|
|
16836
17934
|
try {
|
|
16837
|
-
return fs_watch(
|
|
17935
|
+
return fs_watch(path26, {
|
|
16838
17936
|
persistent: options.persistent
|
|
16839
17937
|
}, handleEvent);
|
|
16840
17938
|
} catch (error) {
|
|
@@ -16850,12 +17948,12 @@ var fsWatchBroadcast = (fullPath, listenerType, val1, val2, val3) => {
|
|
|
16850
17948
|
listener(val1, val2, val3);
|
|
16851
17949
|
});
|
|
16852
17950
|
};
|
|
16853
|
-
var setFsWatchListener = (
|
|
17951
|
+
var setFsWatchListener = (path26, fullPath, options, handlers) => {
|
|
16854
17952
|
const { listener, errHandler, rawEmitter } = handlers;
|
|
16855
17953
|
let cont = FsWatchInstances.get(fullPath);
|
|
16856
17954
|
let watcher;
|
|
16857
17955
|
if (!options.persistent) {
|
|
16858
|
-
watcher = createFsWatchInstance(
|
|
17956
|
+
watcher = createFsWatchInstance(path26, options, listener, errHandler, rawEmitter);
|
|
16859
17957
|
if (!watcher)
|
|
16860
17958
|
return;
|
|
16861
17959
|
return watcher.close.bind(watcher);
|
|
@@ -16866,7 +17964,7 @@ var setFsWatchListener = (path25, fullPath, options, handlers) => {
|
|
|
16866
17964
|
addAndConvert(cont, KEY_RAW, rawEmitter);
|
|
16867
17965
|
} else {
|
|
16868
17966
|
watcher = createFsWatchInstance(
|
|
16869
|
-
|
|
17967
|
+
path26,
|
|
16870
17968
|
options,
|
|
16871
17969
|
fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS),
|
|
16872
17970
|
errHandler,
|
|
@@ -16881,7 +17979,7 @@ var setFsWatchListener = (path25, fullPath, options, handlers) => {
|
|
|
16881
17979
|
cont.watcherUnusable = true;
|
|
16882
17980
|
if (isWindows && error.code === "EPERM") {
|
|
16883
17981
|
try {
|
|
16884
|
-
const fd = await open(
|
|
17982
|
+
const fd = await open(path26, "r");
|
|
16885
17983
|
await fd.close();
|
|
16886
17984
|
broadcastErr(error);
|
|
16887
17985
|
} catch (err) {
|
|
@@ -16912,7 +18010,7 @@ var setFsWatchListener = (path25, fullPath, options, handlers) => {
|
|
|
16912
18010
|
};
|
|
16913
18011
|
};
|
|
16914
18012
|
var FsWatchFileInstances = /* @__PURE__ */ new Map();
|
|
16915
|
-
var setFsWatchFileListener = (
|
|
18013
|
+
var setFsWatchFileListener = (path26, fullPath, options, handlers) => {
|
|
16916
18014
|
const { listener, rawEmitter } = handlers;
|
|
16917
18015
|
let cont = FsWatchFileInstances.get(fullPath);
|
|
16918
18016
|
const copts = cont && cont.options;
|
|
@@ -16934,7 +18032,7 @@ var setFsWatchFileListener = (path25, fullPath, options, handlers) => {
|
|
|
16934
18032
|
});
|
|
16935
18033
|
const currmtime = curr.mtimeMs;
|
|
16936
18034
|
if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {
|
|
16937
|
-
foreach(cont.listeners, (listener2) => listener2(
|
|
18035
|
+
foreach(cont.listeners, (listener2) => listener2(path26, curr));
|
|
16938
18036
|
}
|
|
16939
18037
|
})
|
|
16940
18038
|
};
|
|
@@ -16964,13 +18062,13 @@ var NodeFsHandler = class {
|
|
|
16964
18062
|
* @param listener on fs change
|
|
16965
18063
|
* @returns closer for the watcher instance
|
|
16966
18064
|
*/
|
|
16967
|
-
_watchWithNodeFs(
|
|
18065
|
+
_watchWithNodeFs(path26, listener) {
|
|
16968
18066
|
const opts = this.fsw.options;
|
|
16969
|
-
const directory = sp.dirname(
|
|
16970
|
-
const
|
|
18067
|
+
const directory = sp.dirname(path26);
|
|
18068
|
+
const basename8 = sp.basename(path26);
|
|
16971
18069
|
const parent = this.fsw._getWatchedDir(directory);
|
|
16972
|
-
parent.add(
|
|
16973
|
-
const absolutePath = sp.resolve(
|
|
18070
|
+
parent.add(basename8);
|
|
18071
|
+
const absolutePath = sp.resolve(path26);
|
|
16974
18072
|
const options = {
|
|
16975
18073
|
persistent: opts.persistent
|
|
16976
18074
|
};
|
|
@@ -16979,13 +18077,13 @@ var NodeFsHandler = class {
|
|
|
16979
18077
|
let closer;
|
|
16980
18078
|
if (opts.usePolling) {
|
|
16981
18079
|
const enableBin = opts.interval !== opts.binaryInterval;
|
|
16982
|
-
options.interval = enableBin && isBinaryPath(
|
|
16983
|
-
closer = setFsWatchFileListener(
|
|
18080
|
+
options.interval = enableBin && isBinaryPath(basename8) ? opts.binaryInterval : opts.interval;
|
|
18081
|
+
closer = setFsWatchFileListener(path26, absolutePath, options, {
|
|
16984
18082
|
listener,
|
|
16985
18083
|
rawEmitter: this.fsw._emitRaw
|
|
16986
18084
|
});
|
|
16987
18085
|
} else {
|
|
16988
|
-
closer = setFsWatchListener(
|
|
18086
|
+
closer = setFsWatchListener(path26, absolutePath, options, {
|
|
16989
18087
|
listener,
|
|
16990
18088
|
errHandler: this._boundHandleError,
|
|
16991
18089
|
rawEmitter: this.fsw._emitRaw
|
|
@@ -17001,13 +18099,13 @@ var NodeFsHandler = class {
|
|
|
17001
18099
|
if (this.fsw.closed) {
|
|
17002
18100
|
return;
|
|
17003
18101
|
}
|
|
17004
|
-
const
|
|
17005
|
-
const
|
|
17006
|
-
const parent = this.fsw._getWatchedDir(
|
|
18102
|
+
const dirname14 = sp.dirname(file);
|
|
18103
|
+
const basename8 = sp.basename(file);
|
|
18104
|
+
const parent = this.fsw._getWatchedDir(dirname14);
|
|
17007
18105
|
let prevStats = stats;
|
|
17008
|
-
if (parent.has(
|
|
18106
|
+
if (parent.has(basename8))
|
|
17009
18107
|
return;
|
|
17010
|
-
const listener = async (
|
|
18108
|
+
const listener = async (path26, newStats) => {
|
|
17011
18109
|
if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5))
|
|
17012
18110
|
return;
|
|
17013
18111
|
if (!newStats || newStats.mtimeMs === 0) {
|
|
@@ -17021,18 +18119,18 @@ var NodeFsHandler = class {
|
|
|
17021
18119
|
this.fsw._emit(EV.CHANGE, file, newStats2);
|
|
17022
18120
|
}
|
|
17023
18121
|
if ((isMacos || isLinux || isFreeBSD) && prevStats.ino !== newStats2.ino) {
|
|
17024
|
-
this.fsw._closeFile(
|
|
18122
|
+
this.fsw._closeFile(path26);
|
|
17025
18123
|
prevStats = newStats2;
|
|
17026
18124
|
const closer2 = this._watchWithNodeFs(file, listener);
|
|
17027
18125
|
if (closer2)
|
|
17028
|
-
this.fsw._addPathCloser(
|
|
18126
|
+
this.fsw._addPathCloser(path26, closer2);
|
|
17029
18127
|
} else {
|
|
17030
18128
|
prevStats = newStats2;
|
|
17031
18129
|
}
|
|
17032
18130
|
} catch (error) {
|
|
17033
|
-
this.fsw._remove(
|
|
18131
|
+
this.fsw._remove(dirname14, basename8);
|
|
17034
18132
|
}
|
|
17035
|
-
} else if (parent.has(
|
|
18133
|
+
} else if (parent.has(basename8)) {
|
|
17036
18134
|
const at = newStats.atimeMs;
|
|
17037
18135
|
const mt = newStats.mtimeMs;
|
|
17038
18136
|
if (!at || at <= mt || mt !== prevStats.mtimeMs) {
|
|
@@ -17057,7 +18155,7 @@ var NodeFsHandler = class {
|
|
|
17057
18155
|
* @param item basename of this item
|
|
17058
18156
|
* @returns true if no more processing is needed for this entry.
|
|
17059
18157
|
*/
|
|
17060
|
-
async _handleSymlink(entry, directory,
|
|
18158
|
+
async _handleSymlink(entry, directory, path26, item) {
|
|
17061
18159
|
if (this.fsw.closed) {
|
|
17062
18160
|
return;
|
|
17063
18161
|
}
|
|
@@ -17067,7 +18165,7 @@ var NodeFsHandler = class {
|
|
|
17067
18165
|
this.fsw._incrReadyCount();
|
|
17068
18166
|
let linkPath;
|
|
17069
18167
|
try {
|
|
17070
|
-
linkPath = await fsrealpath(
|
|
18168
|
+
linkPath = await fsrealpath(path26);
|
|
17071
18169
|
} catch (e) {
|
|
17072
18170
|
this.fsw._emitReady();
|
|
17073
18171
|
return true;
|
|
@@ -17077,12 +18175,12 @@ var NodeFsHandler = class {
|
|
|
17077
18175
|
if (dir.has(item)) {
|
|
17078
18176
|
if (this.fsw._symlinkPaths.get(full) !== linkPath) {
|
|
17079
18177
|
this.fsw._symlinkPaths.set(full, linkPath);
|
|
17080
|
-
this.fsw._emit(EV.CHANGE,
|
|
18178
|
+
this.fsw._emit(EV.CHANGE, path26, entry.stats);
|
|
17081
18179
|
}
|
|
17082
18180
|
} else {
|
|
17083
18181
|
dir.add(item);
|
|
17084
18182
|
this.fsw._symlinkPaths.set(full, linkPath);
|
|
17085
|
-
this.fsw._emit(EV.ADD,
|
|
18183
|
+
this.fsw._emit(EV.ADD, path26, entry.stats);
|
|
17086
18184
|
}
|
|
17087
18185
|
this.fsw._emitReady();
|
|
17088
18186
|
return true;
|
|
@@ -17112,9 +18210,9 @@ var NodeFsHandler = class {
|
|
|
17112
18210
|
return;
|
|
17113
18211
|
}
|
|
17114
18212
|
const item = entry.path;
|
|
17115
|
-
let
|
|
18213
|
+
let path26 = sp.join(directory, item);
|
|
17116
18214
|
current.add(item);
|
|
17117
|
-
if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory,
|
|
18215
|
+
if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path26, item)) {
|
|
17118
18216
|
return;
|
|
17119
18217
|
}
|
|
17120
18218
|
if (this.fsw.closed) {
|
|
@@ -17123,11 +18221,11 @@ var NodeFsHandler = class {
|
|
|
17123
18221
|
}
|
|
17124
18222
|
if (item === target || !target && !previous.has(item)) {
|
|
17125
18223
|
this.fsw._incrReadyCount();
|
|
17126
|
-
|
|
17127
|
-
this._addToNodeFs(
|
|
18224
|
+
path26 = sp.join(dir, sp.relative(dir, path26));
|
|
18225
|
+
this._addToNodeFs(path26, initialAdd, wh, depth + 1);
|
|
17128
18226
|
}
|
|
17129
18227
|
}).on(EV.ERROR, this._boundHandleError);
|
|
17130
|
-
return new Promise((
|
|
18228
|
+
return new Promise((resolve18, reject) => {
|
|
17131
18229
|
if (!stream)
|
|
17132
18230
|
return reject();
|
|
17133
18231
|
stream.once(STR_END, () => {
|
|
@@ -17136,7 +18234,7 @@ var NodeFsHandler = class {
|
|
|
17136
18234
|
return;
|
|
17137
18235
|
}
|
|
17138
18236
|
const wasThrottled = throttler ? throttler.clear() : false;
|
|
17139
|
-
|
|
18237
|
+
resolve18(void 0);
|
|
17140
18238
|
previous.getChildren().filter((item) => {
|
|
17141
18239
|
return item !== directory && !current.has(item);
|
|
17142
18240
|
}).forEach((item) => {
|
|
@@ -17193,13 +18291,13 @@ var NodeFsHandler = class {
|
|
|
17193
18291
|
* @param depth Child path actually targeted for watch
|
|
17194
18292
|
* @param target Child path actually targeted for watch
|
|
17195
18293
|
*/
|
|
17196
|
-
async _addToNodeFs(
|
|
18294
|
+
async _addToNodeFs(path26, initialAdd, priorWh, depth, target) {
|
|
17197
18295
|
const ready = this.fsw._emitReady;
|
|
17198
|
-
if (this.fsw._isIgnored(
|
|
18296
|
+
if (this.fsw._isIgnored(path26) || this.fsw.closed) {
|
|
17199
18297
|
ready();
|
|
17200
18298
|
return false;
|
|
17201
18299
|
}
|
|
17202
|
-
const wh = this.fsw._getWatchHelpers(
|
|
18300
|
+
const wh = this.fsw._getWatchHelpers(path26);
|
|
17203
18301
|
if (priorWh) {
|
|
17204
18302
|
wh.filterPath = (entry) => priorWh.filterPath(entry);
|
|
17205
18303
|
wh.filterDir = (entry) => priorWh.filterDir(entry);
|
|
@@ -17215,8 +18313,8 @@ var NodeFsHandler = class {
|
|
|
17215
18313
|
const follow = this.fsw.options.followSymlinks;
|
|
17216
18314
|
let closer;
|
|
17217
18315
|
if (stats.isDirectory()) {
|
|
17218
|
-
const absPath = sp.resolve(
|
|
17219
|
-
const targetPath = follow ? await fsrealpath(
|
|
18316
|
+
const absPath = sp.resolve(path26);
|
|
18317
|
+
const targetPath = follow ? await fsrealpath(path26) : path26;
|
|
17220
18318
|
if (this.fsw.closed)
|
|
17221
18319
|
return;
|
|
17222
18320
|
closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
|
|
@@ -17226,29 +18324,29 @@ var NodeFsHandler = class {
|
|
|
17226
18324
|
this.fsw._symlinkPaths.set(absPath, targetPath);
|
|
17227
18325
|
}
|
|
17228
18326
|
} else if (stats.isSymbolicLink()) {
|
|
17229
|
-
const targetPath = follow ? await fsrealpath(
|
|
18327
|
+
const targetPath = follow ? await fsrealpath(path26) : path26;
|
|
17230
18328
|
if (this.fsw.closed)
|
|
17231
18329
|
return;
|
|
17232
18330
|
const parent = sp.dirname(wh.watchPath);
|
|
17233
18331
|
this.fsw._getWatchedDir(parent).add(wh.watchPath);
|
|
17234
18332
|
this.fsw._emit(EV.ADD, wh.watchPath, stats);
|
|
17235
|
-
closer = await this._handleDir(parent, stats, initialAdd, depth,
|
|
18333
|
+
closer = await this._handleDir(parent, stats, initialAdd, depth, path26, wh, targetPath);
|
|
17236
18334
|
if (this.fsw.closed)
|
|
17237
18335
|
return;
|
|
17238
18336
|
if (targetPath !== void 0) {
|
|
17239
|
-
this.fsw._symlinkPaths.set(sp.resolve(
|
|
18337
|
+
this.fsw._symlinkPaths.set(sp.resolve(path26), targetPath);
|
|
17240
18338
|
}
|
|
17241
18339
|
} else {
|
|
17242
18340
|
closer = this._handleFile(wh.watchPath, stats, initialAdd);
|
|
17243
18341
|
}
|
|
17244
18342
|
ready();
|
|
17245
18343
|
if (closer)
|
|
17246
|
-
this.fsw._addPathCloser(
|
|
18344
|
+
this.fsw._addPathCloser(path26, closer);
|
|
17247
18345
|
return false;
|
|
17248
18346
|
} catch (error) {
|
|
17249
18347
|
if (this.fsw._handleError(error)) {
|
|
17250
18348
|
ready();
|
|
17251
|
-
return
|
|
18349
|
+
return path26;
|
|
17252
18350
|
}
|
|
17253
18351
|
}
|
|
17254
18352
|
}
|
|
@@ -17291,24 +18389,24 @@ function createPattern(matcher) {
|
|
|
17291
18389
|
}
|
|
17292
18390
|
return () => false;
|
|
17293
18391
|
}
|
|
17294
|
-
function normalizePath2(
|
|
17295
|
-
if (typeof
|
|
18392
|
+
function normalizePath2(path26) {
|
|
18393
|
+
if (typeof path26 !== "string")
|
|
17296
18394
|
throw new Error("string expected");
|
|
17297
|
-
|
|
17298
|
-
|
|
18395
|
+
path26 = sp2.normalize(path26);
|
|
18396
|
+
path26 = path26.replace(/\\/g, "/");
|
|
17299
18397
|
let prepend = false;
|
|
17300
|
-
if (
|
|
18398
|
+
if (path26.startsWith("//"))
|
|
17301
18399
|
prepend = true;
|
|
17302
|
-
|
|
18400
|
+
path26 = path26.replace(DOUBLE_SLASH_RE, "/");
|
|
17303
18401
|
if (prepend)
|
|
17304
|
-
|
|
17305
|
-
return
|
|
18402
|
+
path26 = "/" + path26;
|
|
18403
|
+
return path26;
|
|
17306
18404
|
}
|
|
17307
18405
|
function matchPatterns(patterns, testString, stats) {
|
|
17308
|
-
const
|
|
18406
|
+
const path26 = normalizePath2(testString);
|
|
17309
18407
|
for (let index = 0; index < patterns.length; index++) {
|
|
17310
18408
|
const pattern = patterns[index];
|
|
17311
|
-
if (pattern(
|
|
18409
|
+
if (pattern(path26, stats)) {
|
|
17312
18410
|
return true;
|
|
17313
18411
|
}
|
|
17314
18412
|
}
|
|
@@ -17346,19 +18444,19 @@ var toUnix = (string) => {
|
|
|
17346
18444
|
}
|
|
17347
18445
|
return str;
|
|
17348
18446
|
};
|
|
17349
|
-
var normalizePathToUnix = (
|
|
17350
|
-
var normalizeIgnored = (cwd = "") => (
|
|
17351
|
-
if (typeof
|
|
17352
|
-
return normalizePathToUnix(sp2.isAbsolute(
|
|
18447
|
+
var normalizePathToUnix = (path26) => toUnix(sp2.normalize(toUnix(path26)));
|
|
18448
|
+
var normalizeIgnored = (cwd = "") => (path26) => {
|
|
18449
|
+
if (typeof path26 === "string") {
|
|
18450
|
+
return normalizePathToUnix(sp2.isAbsolute(path26) ? path26 : sp2.join(cwd, path26));
|
|
17353
18451
|
} else {
|
|
17354
|
-
return
|
|
18452
|
+
return path26;
|
|
17355
18453
|
}
|
|
17356
18454
|
};
|
|
17357
|
-
var getAbsolutePath = (
|
|
17358
|
-
if (sp2.isAbsolute(
|
|
17359
|
-
return
|
|
18455
|
+
var getAbsolutePath = (path26, cwd) => {
|
|
18456
|
+
if (sp2.isAbsolute(path26)) {
|
|
18457
|
+
return path26;
|
|
17360
18458
|
}
|
|
17361
|
-
return sp2.join(cwd,
|
|
18459
|
+
return sp2.join(cwd, path26);
|
|
17362
18460
|
};
|
|
17363
18461
|
var EMPTY_SET = Object.freeze(/* @__PURE__ */ new Set());
|
|
17364
18462
|
var DirEntry = class {
|
|
@@ -17423,10 +18521,10 @@ var WatchHelper = class {
|
|
|
17423
18521
|
dirParts;
|
|
17424
18522
|
followSymlinks;
|
|
17425
18523
|
statMethod;
|
|
17426
|
-
constructor(
|
|
18524
|
+
constructor(path26, follow, fsw) {
|
|
17427
18525
|
this.fsw = fsw;
|
|
17428
|
-
const watchPath =
|
|
17429
|
-
this.path =
|
|
18526
|
+
const watchPath = path26;
|
|
18527
|
+
this.path = path26 = path26.replace(REPLACER_RE, "");
|
|
17430
18528
|
this.watchPath = watchPath;
|
|
17431
18529
|
this.fullWatchPath = sp2.resolve(watchPath);
|
|
17432
18530
|
this.dirParts = [];
|
|
@@ -17566,20 +18664,20 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
17566
18664
|
this._closePromise = void 0;
|
|
17567
18665
|
let paths = unifyPaths(paths_);
|
|
17568
18666
|
if (cwd) {
|
|
17569
|
-
paths = paths.map((
|
|
17570
|
-
const absPath = getAbsolutePath(
|
|
18667
|
+
paths = paths.map((path26) => {
|
|
18668
|
+
const absPath = getAbsolutePath(path26, cwd);
|
|
17571
18669
|
return absPath;
|
|
17572
18670
|
});
|
|
17573
18671
|
}
|
|
17574
|
-
paths.forEach((
|
|
17575
|
-
this._removeIgnoredPath(
|
|
18672
|
+
paths.forEach((path26) => {
|
|
18673
|
+
this._removeIgnoredPath(path26);
|
|
17576
18674
|
});
|
|
17577
18675
|
this._userIgnored = void 0;
|
|
17578
18676
|
if (!this._readyCount)
|
|
17579
18677
|
this._readyCount = 0;
|
|
17580
18678
|
this._readyCount += paths.length;
|
|
17581
|
-
Promise.all(paths.map(async (
|
|
17582
|
-
const res = await this._nodeFsHandler._addToNodeFs(
|
|
18679
|
+
Promise.all(paths.map(async (path26) => {
|
|
18680
|
+
const res = await this._nodeFsHandler._addToNodeFs(path26, !_internal, void 0, 0, _origAdd);
|
|
17583
18681
|
if (res)
|
|
17584
18682
|
this._emitReady();
|
|
17585
18683
|
return res;
|
|
@@ -17601,17 +18699,17 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
17601
18699
|
return this;
|
|
17602
18700
|
const paths = unifyPaths(paths_);
|
|
17603
18701
|
const { cwd } = this.options;
|
|
17604
|
-
paths.forEach((
|
|
17605
|
-
if (!sp2.isAbsolute(
|
|
18702
|
+
paths.forEach((path26) => {
|
|
18703
|
+
if (!sp2.isAbsolute(path26) && !this._closers.has(path26)) {
|
|
17606
18704
|
if (cwd)
|
|
17607
|
-
|
|
17608
|
-
|
|
18705
|
+
path26 = sp2.join(cwd, path26);
|
|
18706
|
+
path26 = sp2.resolve(path26);
|
|
17609
18707
|
}
|
|
17610
|
-
this._closePath(
|
|
17611
|
-
this._addIgnoredPath(
|
|
17612
|
-
if (this._watched.has(
|
|
18708
|
+
this._closePath(path26);
|
|
18709
|
+
this._addIgnoredPath(path26);
|
|
18710
|
+
if (this._watched.has(path26)) {
|
|
17613
18711
|
this._addIgnoredPath({
|
|
17614
|
-
path:
|
|
18712
|
+
path: path26,
|
|
17615
18713
|
recursive: true
|
|
17616
18714
|
});
|
|
17617
18715
|
}
|
|
@@ -17675,38 +18773,38 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
17675
18773
|
* @param stats arguments to be passed with event
|
|
17676
18774
|
* @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag
|
|
17677
18775
|
*/
|
|
17678
|
-
async _emit(event,
|
|
18776
|
+
async _emit(event, path26, stats) {
|
|
17679
18777
|
if (this.closed)
|
|
17680
18778
|
return;
|
|
17681
18779
|
const opts = this.options;
|
|
17682
18780
|
if (isWindows)
|
|
17683
|
-
|
|
18781
|
+
path26 = sp2.normalize(path26);
|
|
17684
18782
|
if (opts.cwd)
|
|
17685
|
-
|
|
17686
|
-
const args = [
|
|
18783
|
+
path26 = sp2.relative(opts.cwd, path26);
|
|
18784
|
+
const args = [path26];
|
|
17687
18785
|
if (stats != null)
|
|
17688
18786
|
args.push(stats);
|
|
17689
18787
|
const awf = opts.awaitWriteFinish;
|
|
17690
18788
|
let pw;
|
|
17691
|
-
if (awf && (pw = this._pendingWrites.get(
|
|
18789
|
+
if (awf && (pw = this._pendingWrites.get(path26))) {
|
|
17692
18790
|
pw.lastChange = /* @__PURE__ */ new Date();
|
|
17693
18791
|
return this;
|
|
17694
18792
|
}
|
|
17695
18793
|
if (opts.atomic) {
|
|
17696
18794
|
if (event === EVENTS.UNLINK) {
|
|
17697
|
-
this._pendingUnlinks.set(
|
|
18795
|
+
this._pendingUnlinks.set(path26, [event, ...args]);
|
|
17698
18796
|
setTimeout(() => {
|
|
17699
|
-
this._pendingUnlinks.forEach((entry,
|
|
18797
|
+
this._pendingUnlinks.forEach((entry, path27) => {
|
|
17700
18798
|
this.emit(...entry);
|
|
17701
18799
|
this.emit(EVENTS.ALL, ...entry);
|
|
17702
|
-
this._pendingUnlinks.delete(
|
|
18800
|
+
this._pendingUnlinks.delete(path27);
|
|
17703
18801
|
});
|
|
17704
18802
|
}, typeof opts.atomic === "number" ? opts.atomic : 100);
|
|
17705
18803
|
return this;
|
|
17706
18804
|
}
|
|
17707
|
-
if (event === EVENTS.ADD && this._pendingUnlinks.has(
|
|
18805
|
+
if (event === EVENTS.ADD && this._pendingUnlinks.has(path26)) {
|
|
17708
18806
|
event = EVENTS.CHANGE;
|
|
17709
|
-
this._pendingUnlinks.delete(
|
|
18807
|
+
this._pendingUnlinks.delete(path26);
|
|
17710
18808
|
}
|
|
17711
18809
|
}
|
|
17712
18810
|
if (awf && (event === EVENTS.ADD || event === EVENTS.CHANGE) && this._readyEmitted) {
|
|
@@ -17724,16 +18822,16 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
17724
18822
|
this.emitWithAll(event, args);
|
|
17725
18823
|
}
|
|
17726
18824
|
};
|
|
17727
|
-
this._awaitWriteFinish(
|
|
18825
|
+
this._awaitWriteFinish(path26, awf.stabilityThreshold, event, awfEmit);
|
|
17728
18826
|
return this;
|
|
17729
18827
|
}
|
|
17730
18828
|
if (event === EVENTS.CHANGE) {
|
|
17731
|
-
const isThrottled = !this._throttle(EVENTS.CHANGE,
|
|
18829
|
+
const isThrottled = !this._throttle(EVENTS.CHANGE, path26, 50);
|
|
17732
18830
|
if (isThrottled)
|
|
17733
18831
|
return this;
|
|
17734
18832
|
}
|
|
17735
18833
|
if (opts.alwaysStat && stats === void 0 && (event === EVENTS.ADD || event === EVENTS.ADD_DIR || event === EVENTS.CHANGE)) {
|
|
17736
|
-
const fullPath = opts.cwd ? sp2.join(opts.cwd,
|
|
18834
|
+
const fullPath = opts.cwd ? sp2.join(opts.cwd, path26) : path26;
|
|
17737
18835
|
let stats2;
|
|
17738
18836
|
try {
|
|
17739
18837
|
stats2 = await stat3(fullPath);
|
|
@@ -17764,23 +18862,23 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
17764
18862
|
* @param timeout duration of time to suppress duplicate actions
|
|
17765
18863
|
* @returns tracking object or false if action should be suppressed
|
|
17766
18864
|
*/
|
|
17767
|
-
_throttle(actionType,
|
|
18865
|
+
_throttle(actionType, path26, timeout) {
|
|
17768
18866
|
if (!this._throttled.has(actionType)) {
|
|
17769
18867
|
this._throttled.set(actionType, /* @__PURE__ */ new Map());
|
|
17770
18868
|
}
|
|
17771
18869
|
const action = this._throttled.get(actionType);
|
|
17772
18870
|
if (!action)
|
|
17773
18871
|
throw new Error("invalid throttle");
|
|
17774
|
-
const actionPath = action.get(
|
|
18872
|
+
const actionPath = action.get(path26);
|
|
17775
18873
|
if (actionPath) {
|
|
17776
18874
|
actionPath.count++;
|
|
17777
18875
|
return false;
|
|
17778
18876
|
}
|
|
17779
18877
|
let timeoutObject;
|
|
17780
18878
|
const clear = () => {
|
|
17781
|
-
const item = action.get(
|
|
18879
|
+
const item = action.get(path26);
|
|
17782
18880
|
const count = item ? item.count : 0;
|
|
17783
|
-
action.delete(
|
|
18881
|
+
action.delete(path26);
|
|
17784
18882
|
clearTimeout(timeoutObject);
|
|
17785
18883
|
if (item)
|
|
17786
18884
|
clearTimeout(item.timeoutObject);
|
|
@@ -17788,7 +18886,7 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
17788
18886
|
};
|
|
17789
18887
|
timeoutObject = setTimeout(clear, timeout);
|
|
17790
18888
|
const thr = { timeoutObject, clear, count: 0 };
|
|
17791
|
-
action.set(
|
|
18889
|
+
action.set(path26, thr);
|
|
17792
18890
|
return thr;
|
|
17793
18891
|
}
|
|
17794
18892
|
_incrReadyCount() {
|
|
@@ -17802,44 +18900,44 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
17802
18900
|
* @param event
|
|
17803
18901
|
* @param awfEmit Callback to be called when ready for event to be emitted.
|
|
17804
18902
|
*/
|
|
17805
|
-
_awaitWriteFinish(
|
|
18903
|
+
_awaitWriteFinish(path26, threshold, event, awfEmit) {
|
|
17806
18904
|
const awf = this.options.awaitWriteFinish;
|
|
17807
18905
|
if (typeof awf !== "object")
|
|
17808
18906
|
return;
|
|
17809
18907
|
const pollInterval = awf.pollInterval;
|
|
17810
18908
|
let timeoutHandler;
|
|
17811
|
-
let fullPath =
|
|
17812
|
-
if (this.options.cwd && !sp2.isAbsolute(
|
|
17813
|
-
fullPath = sp2.join(this.options.cwd,
|
|
18909
|
+
let fullPath = path26;
|
|
18910
|
+
if (this.options.cwd && !sp2.isAbsolute(path26)) {
|
|
18911
|
+
fullPath = sp2.join(this.options.cwd, path26);
|
|
17814
18912
|
}
|
|
17815
18913
|
const now2 = /* @__PURE__ */ new Date();
|
|
17816
18914
|
const writes = this._pendingWrites;
|
|
17817
18915
|
function awaitWriteFinishFn(prevStat) {
|
|
17818
18916
|
statcb(fullPath, (err, curStat) => {
|
|
17819
|
-
if (err || !writes.has(
|
|
18917
|
+
if (err || !writes.has(path26)) {
|
|
17820
18918
|
if (err && err.code !== "ENOENT")
|
|
17821
18919
|
awfEmit(err);
|
|
17822
18920
|
return;
|
|
17823
18921
|
}
|
|
17824
18922
|
const now3 = Number(/* @__PURE__ */ new Date());
|
|
17825
18923
|
if (prevStat && curStat.size !== prevStat.size) {
|
|
17826
|
-
writes.get(
|
|
18924
|
+
writes.get(path26).lastChange = now3;
|
|
17827
18925
|
}
|
|
17828
|
-
const pw = writes.get(
|
|
18926
|
+
const pw = writes.get(path26);
|
|
17829
18927
|
const df = now3 - pw.lastChange;
|
|
17830
18928
|
if (df >= threshold) {
|
|
17831
|
-
writes.delete(
|
|
18929
|
+
writes.delete(path26);
|
|
17832
18930
|
awfEmit(void 0, curStat);
|
|
17833
18931
|
} else {
|
|
17834
18932
|
timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat);
|
|
17835
18933
|
}
|
|
17836
18934
|
});
|
|
17837
18935
|
}
|
|
17838
|
-
if (!writes.has(
|
|
17839
|
-
writes.set(
|
|
18936
|
+
if (!writes.has(path26)) {
|
|
18937
|
+
writes.set(path26, {
|
|
17840
18938
|
lastChange: now2,
|
|
17841
18939
|
cancelWait: () => {
|
|
17842
|
-
writes.delete(
|
|
18940
|
+
writes.delete(path26);
|
|
17843
18941
|
clearTimeout(timeoutHandler);
|
|
17844
18942
|
return event;
|
|
17845
18943
|
}
|
|
@@ -17850,8 +18948,8 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
17850
18948
|
/**
|
|
17851
18949
|
* Determines whether user has asked to ignore this path.
|
|
17852
18950
|
*/
|
|
17853
|
-
_isIgnored(
|
|
17854
|
-
if (this.options.atomic && DOT_RE.test(
|
|
18951
|
+
_isIgnored(path26, stats) {
|
|
18952
|
+
if (this.options.atomic && DOT_RE.test(path26))
|
|
17855
18953
|
return true;
|
|
17856
18954
|
if (!this._userIgnored) {
|
|
17857
18955
|
const { cwd } = this.options;
|
|
@@ -17861,17 +18959,17 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
17861
18959
|
const list = [...ignoredPaths.map(normalizeIgnored(cwd)), ...ignored];
|
|
17862
18960
|
this._userIgnored = anymatch(list, void 0);
|
|
17863
18961
|
}
|
|
17864
|
-
return this._userIgnored(
|
|
18962
|
+
return this._userIgnored(path26, stats);
|
|
17865
18963
|
}
|
|
17866
|
-
_isntIgnored(
|
|
17867
|
-
return !this._isIgnored(
|
|
18964
|
+
_isntIgnored(path26, stat5) {
|
|
18965
|
+
return !this._isIgnored(path26, stat5);
|
|
17868
18966
|
}
|
|
17869
18967
|
/**
|
|
17870
18968
|
* Provides a set of common helpers and properties relating to symlink handling.
|
|
17871
18969
|
* @param path file or directory pattern being watched
|
|
17872
18970
|
*/
|
|
17873
|
-
_getWatchHelpers(
|
|
17874
|
-
return new WatchHelper(
|
|
18971
|
+
_getWatchHelpers(path26) {
|
|
18972
|
+
return new WatchHelper(path26, this.options.followSymlinks, this);
|
|
17875
18973
|
}
|
|
17876
18974
|
// Directory helpers
|
|
17877
18975
|
// -----------------
|
|
@@ -17903,63 +19001,63 @@ var FSWatcher = class extends EventEmitter2 {
|
|
|
17903
19001
|
* @param item base path of item/directory
|
|
17904
19002
|
*/
|
|
17905
19003
|
_remove(directory, item, isDirectory) {
|
|
17906
|
-
const
|
|
17907
|
-
const fullPath = sp2.resolve(
|
|
17908
|
-
isDirectory = isDirectory != null ? isDirectory : this._watched.has(
|
|
17909
|
-
if (!this._throttle("remove",
|
|
19004
|
+
const path26 = sp2.join(directory, item);
|
|
19005
|
+
const fullPath = sp2.resolve(path26);
|
|
19006
|
+
isDirectory = isDirectory != null ? isDirectory : this._watched.has(path26) || this._watched.has(fullPath);
|
|
19007
|
+
if (!this._throttle("remove", path26, 100))
|
|
17910
19008
|
return;
|
|
17911
19009
|
if (!isDirectory && this._watched.size === 1) {
|
|
17912
19010
|
this.add(directory, item, true);
|
|
17913
19011
|
}
|
|
17914
|
-
const wp = this._getWatchedDir(
|
|
19012
|
+
const wp = this._getWatchedDir(path26);
|
|
17915
19013
|
const nestedDirectoryChildren = wp.getChildren();
|
|
17916
|
-
nestedDirectoryChildren.forEach((nested) => this._remove(
|
|
19014
|
+
nestedDirectoryChildren.forEach((nested) => this._remove(path26, nested));
|
|
17917
19015
|
const parent = this._getWatchedDir(directory);
|
|
17918
19016
|
const wasTracked = parent.has(item);
|
|
17919
19017
|
parent.remove(item);
|
|
17920
19018
|
if (this._symlinkPaths.has(fullPath)) {
|
|
17921
19019
|
this._symlinkPaths.delete(fullPath);
|
|
17922
19020
|
}
|
|
17923
|
-
let relPath =
|
|
19021
|
+
let relPath = path26;
|
|
17924
19022
|
if (this.options.cwd)
|
|
17925
|
-
relPath = sp2.relative(this.options.cwd,
|
|
19023
|
+
relPath = sp2.relative(this.options.cwd, path26);
|
|
17926
19024
|
if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
|
|
17927
19025
|
const event = this._pendingWrites.get(relPath).cancelWait();
|
|
17928
19026
|
if (event === EVENTS.ADD)
|
|
17929
19027
|
return;
|
|
17930
19028
|
}
|
|
17931
|
-
this._watched.delete(
|
|
19029
|
+
this._watched.delete(path26);
|
|
17932
19030
|
this._watched.delete(fullPath);
|
|
17933
19031
|
const eventName = isDirectory ? EVENTS.UNLINK_DIR : EVENTS.UNLINK;
|
|
17934
|
-
if (wasTracked && !this._isIgnored(
|
|
17935
|
-
this._emit(eventName,
|
|
17936
|
-
this._closePath(
|
|
19032
|
+
if (wasTracked && !this._isIgnored(path26))
|
|
19033
|
+
this._emit(eventName, path26);
|
|
19034
|
+
this._closePath(path26);
|
|
17937
19035
|
}
|
|
17938
19036
|
/**
|
|
17939
19037
|
* Closes all watchers for a path
|
|
17940
19038
|
*/
|
|
17941
|
-
_closePath(
|
|
17942
|
-
this._closeFile(
|
|
17943
|
-
const dir = sp2.dirname(
|
|
17944
|
-
this._getWatchedDir(dir).remove(sp2.basename(
|
|
19039
|
+
_closePath(path26) {
|
|
19040
|
+
this._closeFile(path26);
|
|
19041
|
+
const dir = sp2.dirname(path26);
|
|
19042
|
+
this._getWatchedDir(dir).remove(sp2.basename(path26));
|
|
17945
19043
|
}
|
|
17946
19044
|
/**
|
|
17947
19045
|
* Closes only file-specific watchers
|
|
17948
19046
|
*/
|
|
17949
|
-
_closeFile(
|
|
17950
|
-
const closers = this._closers.get(
|
|
19047
|
+
_closeFile(path26) {
|
|
19048
|
+
const closers = this._closers.get(path26);
|
|
17951
19049
|
if (!closers)
|
|
17952
19050
|
return;
|
|
17953
19051
|
closers.forEach((closer) => closer());
|
|
17954
|
-
this._closers.delete(
|
|
19052
|
+
this._closers.delete(path26);
|
|
17955
19053
|
}
|
|
17956
|
-
_addPathCloser(
|
|
19054
|
+
_addPathCloser(path26, closer) {
|
|
17957
19055
|
if (!closer)
|
|
17958
19056
|
return;
|
|
17959
|
-
let list = this._closers.get(
|
|
19057
|
+
let list = this._closers.get(path26);
|
|
17960
19058
|
if (!list) {
|
|
17961
19059
|
list = [];
|
|
17962
|
-
this._closers.set(
|
|
19060
|
+
this._closers.set(path26, list);
|
|
17963
19061
|
}
|
|
17964
19062
|
list.push(closer);
|
|
17965
19063
|
}
|
|
@@ -17989,11 +19087,11 @@ function watch(paths, options = {}) {
|
|
|
17989
19087
|
var chokidar_default = { watch, FSWatcher };
|
|
17990
19088
|
|
|
17991
19089
|
// src/watcher/file-watcher.ts
|
|
17992
|
-
import * as
|
|
19090
|
+
import * as path24 from "path";
|
|
17993
19091
|
|
|
17994
19092
|
// src/watcher/native-recursive-watcher.ts
|
|
17995
19093
|
import { watch as watch2 } from "fs";
|
|
17996
|
-
import * as
|
|
19094
|
+
import * as path22 from "path";
|
|
17997
19095
|
var NativeRecursiveWatcher = class {
|
|
17998
19096
|
constructor(root, onChange, options = {}) {
|
|
17999
19097
|
this.root = root;
|
|
@@ -18041,9 +19139,9 @@ var NativeRecursiveWatcher = class {
|
|
|
18041
19139
|
toAbsolutePath(filename) {
|
|
18042
19140
|
if (filename == null) return null;
|
|
18043
19141
|
const normalizedFilename = typeof filename === "string" ? filename : filename.toString();
|
|
18044
|
-
const absolutePath =
|
|
18045
|
-
const relativePath =
|
|
18046
|
-
const outsideRoot = relativePath === ".." || relativePath.startsWith(`..${
|
|
19142
|
+
const absolutePath = path22.resolve(this.root, normalizedFilename);
|
|
19143
|
+
const relativePath = path22.relative(this.root, absolutePath);
|
|
19144
|
+
const outsideRoot = relativePath === ".." || relativePath.startsWith(`..${path22.sep}`) || path22.isAbsolute(relativePath);
|
|
18047
19145
|
return outsideRoot ? null : absolutePath;
|
|
18048
19146
|
}
|
|
18049
19147
|
defaultWatchFactory = (root, listener, options) => watch2(root, options, listener);
|
|
@@ -18051,16 +19149,16 @@ var NativeRecursiveWatcher = class {
|
|
|
18051
19149
|
|
|
18052
19150
|
// src/watcher/snapshot.ts
|
|
18053
19151
|
import * as fsPromises4 from "fs/promises";
|
|
18054
|
-
import * as
|
|
19152
|
+
import * as path23 from "path";
|
|
18055
19153
|
async function buildFileSnapshotScan(projectRoot3, config, configPaths = []) {
|
|
18056
|
-
const normalizedProjectRoot =
|
|
19154
|
+
const normalizedProjectRoot = path23.resolve(projectRoot3);
|
|
18057
19155
|
const ignoreFilter = createIgnoreFilter(normalizedProjectRoot);
|
|
18058
19156
|
const includePatterns = [...config.include, ...config.additionalInclude ?? []];
|
|
18059
19157
|
const maxDepth = config.indexing?.maxDepth ?? -1;
|
|
18060
19158
|
const snapshot = /* @__PURE__ */ new Map();
|
|
18061
19159
|
const unreadablePrefixes = /* @__PURE__ */ new Set();
|
|
18062
19160
|
const includeFile = async (filePath) => {
|
|
18063
|
-
const normalizedPath2 =
|
|
19161
|
+
const normalizedPath2 = path23.resolve(filePath);
|
|
18064
19162
|
if (!shouldIncludeFile(normalizedPath2, normalizedProjectRoot, includePatterns, config.exclude, ignoreFilter)) return;
|
|
18065
19163
|
const stat5 = await readStatIfFile(normalizedPath2, unreadablePrefixes);
|
|
18066
19164
|
if (stat5) snapshot.set(normalizedPath2, { size: stat5.size, mtimeMs: stat5.mtimeMs });
|
|
@@ -18072,16 +19170,16 @@ async function buildFileSnapshotScan(projectRoot3, config, configPaths = []) {
|
|
|
18072
19170
|
} catch (error) {
|
|
18073
19171
|
if (isMissingFsError(error)) return;
|
|
18074
19172
|
if (isPermissionFsError(error)) {
|
|
18075
|
-
unreadablePrefixes.add(
|
|
19173
|
+
unreadablePrefixes.add(path23.resolve(directoryPath));
|
|
18076
19174
|
return;
|
|
18077
19175
|
}
|
|
18078
19176
|
throw error;
|
|
18079
19177
|
}
|
|
18080
19178
|
for (const entry of entries) {
|
|
18081
|
-
const fullPath =
|
|
18082
|
-
const relativePath =
|
|
19179
|
+
const fullPath = path23.join(directoryPath, entry.name);
|
|
19180
|
+
const relativePath = path23.relative(normalizedProjectRoot, fullPath);
|
|
18083
19181
|
if (entry.isDirectory()) {
|
|
18084
|
-
if (hasFilteredPathSegment(relativePath,
|
|
19182
|
+
if (hasFilteredPathSegment(relativePath, path23.sep) || isRestrictedDirectory(relativePath, path23.sep)) continue;
|
|
18085
19183
|
if (ignoreFilter.ignores(relativePath)) continue;
|
|
18086
19184
|
if (maxDepth === -1 || depth < maxDepth) await walk(fullPath, depth + 1);
|
|
18087
19185
|
} else if (entry.isFile()) {
|
|
@@ -18094,19 +19192,19 @@ async function buildFileSnapshotScan(projectRoot3, config, configPaths = []) {
|
|
|
18094
19192
|
return { entries: snapshot, unreadablePrefixes };
|
|
18095
19193
|
}
|
|
18096
19194
|
async function buildFileSnapshotForPathScan(projectRoot3, config, configPaths, targetPath) {
|
|
18097
|
-
const normalizedProjectRoot =
|
|
18098
|
-
const normalizedTargetPath =
|
|
19195
|
+
const normalizedProjectRoot = path23.resolve(projectRoot3);
|
|
19196
|
+
const normalizedTargetPath = path23.resolve(targetPath);
|
|
18099
19197
|
if (!isWithinPath(normalizedProjectRoot, normalizedTargetPath)) {
|
|
18100
19198
|
return { entries: /* @__PURE__ */ new Map(), unreadablePrefixes: /* @__PURE__ */ new Set() };
|
|
18101
19199
|
}
|
|
18102
19200
|
const ignoreFilter = createIgnoreFilter(normalizedProjectRoot);
|
|
18103
19201
|
const includePatterns = [...config.include, ...config.additionalInclude ?? []];
|
|
18104
19202
|
const maxDepth = config.indexing?.maxDepth ?? -1;
|
|
18105
|
-
const explicitConfigPaths = new Set(configPaths.map((configPath) =>
|
|
19203
|
+
const explicitConfigPaths = new Set(configPaths.map((configPath) => path23.resolve(configPath)));
|
|
18106
19204
|
const snapshot = /* @__PURE__ */ new Map();
|
|
18107
19205
|
const unreadablePrefixes = /* @__PURE__ */ new Set();
|
|
18108
19206
|
const includeFile = async (filePath) => {
|
|
18109
|
-
const normalizedPath2 =
|
|
19207
|
+
const normalizedPath2 = path23.resolve(filePath);
|
|
18110
19208
|
if (!explicitConfigPaths.has(normalizedPath2) && !shouldIncludeFile(
|
|
18111
19209
|
normalizedPath2,
|
|
18112
19210
|
normalizedProjectRoot,
|
|
@@ -18124,16 +19222,16 @@ async function buildFileSnapshotForPathScan(projectRoot3, config, configPaths, t
|
|
|
18124
19222
|
} catch (error) {
|
|
18125
19223
|
if (isMissingFsError(error)) return;
|
|
18126
19224
|
if (isPermissionFsError(error)) {
|
|
18127
|
-
unreadablePrefixes.add(
|
|
19225
|
+
unreadablePrefixes.add(path23.resolve(directoryPath));
|
|
18128
19226
|
return;
|
|
18129
19227
|
}
|
|
18130
19228
|
throw error;
|
|
18131
19229
|
}
|
|
18132
19230
|
for (const entry of entries) {
|
|
18133
|
-
const fullPath =
|
|
18134
|
-
const relativePath =
|
|
19231
|
+
const fullPath = path23.join(directoryPath, entry.name);
|
|
19232
|
+
const relativePath = path23.relative(normalizedProjectRoot, fullPath);
|
|
18135
19233
|
if (entry.isDirectory()) {
|
|
18136
|
-
if (hasFilteredPathSegment(relativePath,
|
|
19234
|
+
if (hasFilteredPathSegment(relativePath, path23.sep) || isRestrictedDirectory(relativePath, path23.sep)) continue;
|
|
18137
19235
|
if (ignoreFilter.ignores(relativePath)) continue;
|
|
18138
19236
|
if (maxDepth === -1 || depth < maxDepth) await walk(fullPath, depth + 1);
|
|
18139
19237
|
} else if (entry.isFile()) {
|
|
@@ -18157,7 +19255,7 @@ function completeFileSnapshot(previous, scan) {
|
|
|
18157
19255
|
return completed;
|
|
18158
19256
|
}
|
|
18159
19257
|
async function includeExplicitConfigPaths(snapshot, unreadablePrefixes, configPaths) {
|
|
18160
|
-
for (const configPath of [...new Set(configPaths.map((value) =>
|
|
19258
|
+
for (const configPath of [...new Set(configPaths.map((value) => path23.resolve(value)))]) {
|
|
18161
19259
|
if (snapshot.has(configPath)) continue;
|
|
18162
19260
|
const stat5 = await readStatIfFile(configPath, unreadablePrefixes);
|
|
18163
19261
|
if (stat5) snapshot.set(configPath, { size: stat5.size, mtimeMs: stat5.mtimeMs });
|
|
@@ -18167,12 +19265,12 @@ async function includeExplicitConfigPathsInPath(snapshot, unreadablePrefixes, co
|
|
|
18167
19265
|
await includeExplicitConfigPaths(
|
|
18168
19266
|
snapshot,
|
|
18169
19267
|
unreadablePrefixes,
|
|
18170
|
-
configPaths.filter((configPath) => isWithinPath(targetPath,
|
|
19268
|
+
configPaths.filter((configPath) => isWithinPath(targetPath, path23.resolve(configPath)))
|
|
18171
19269
|
);
|
|
18172
19270
|
}
|
|
18173
19271
|
function isWithinPath(parentPath, childPath) {
|
|
18174
|
-
const relativePath =
|
|
18175
|
-
return relativePath === "" || !relativePath.startsWith(`..${
|
|
19272
|
+
const relativePath = path23.relative(parentPath, childPath);
|
|
19273
|
+
return relativePath === "" || !relativePath.startsWith(`..${path23.sep}`) && relativePath !== ".." && !path23.isAbsolute(relativePath);
|
|
18176
19274
|
}
|
|
18177
19275
|
async function readStatIfFile(filePath, unreadablePrefixes) {
|
|
18178
19276
|
try {
|
|
@@ -18181,7 +19279,7 @@ async function readStatIfFile(filePath, unreadablePrefixes) {
|
|
|
18181
19279
|
} catch (error) {
|
|
18182
19280
|
if (isMissingFsError(error)) return null;
|
|
18183
19281
|
if (isPermissionFsError(error)) {
|
|
18184
|
-
unreadablePrefixes.add(
|
|
19282
|
+
unreadablePrefixes.add(path23.resolve(filePath));
|
|
18185
19283
|
return null;
|
|
18186
19284
|
}
|
|
18187
19285
|
throw error;
|
|
@@ -18318,8 +19416,8 @@ var FileWatcher = class {
|
|
|
18318
19416
|
this.createWatcher();
|
|
18319
19417
|
}
|
|
18320
19418
|
resetReady() {
|
|
18321
|
-
this.readyPromise = new Promise((
|
|
18322
|
-
this.resolveReady =
|
|
19419
|
+
this.readyPromise = new Promise((resolve18) => {
|
|
19420
|
+
this.resolveReady = resolve18;
|
|
18323
19421
|
});
|
|
18324
19422
|
this.startupReadySignals = 1;
|
|
18325
19423
|
}
|
|
@@ -18350,7 +19448,7 @@ var FileWatcher = class {
|
|
|
18350
19448
|
const resolvedWatchTargets = watchTargets ?? this.getFullChokidarWatchTargets();
|
|
18351
19449
|
const watcherOptions = {
|
|
18352
19450
|
ignored: (filePath) => {
|
|
18353
|
-
const relativePath =
|
|
19451
|
+
const relativePath = path24.relative(this.projectRoot, filePath);
|
|
18354
19452
|
if (!relativePath) return false;
|
|
18355
19453
|
if (this.isProjectConfigPathOrAncestor(relativePath)) {
|
|
18356
19454
|
return false;
|
|
@@ -18358,10 +19456,10 @@ var FileWatcher = class {
|
|
|
18358
19456
|
if (this.isOutsideProjectPath(relativePath)) {
|
|
18359
19457
|
return true;
|
|
18360
19458
|
}
|
|
18361
|
-
if (hasFilteredPathSegment(relativePath,
|
|
19459
|
+
if (hasFilteredPathSegment(relativePath, path24.sep)) {
|
|
18362
19460
|
return true;
|
|
18363
19461
|
}
|
|
18364
|
-
if (isRestrictedDirectory(relativePath,
|
|
19462
|
+
if (isRestrictedDirectory(relativePath, path24.sep)) {
|
|
18365
19463
|
return true;
|
|
18366
19464
|
}
|
|
18367
19465
|
if (ignoreFilter.ignores(relativePath)) {
|
|
@@ -18452,13 +19550,13 @@ var FileWatcher = class {
|
|
|
18452
19550
|
getExternalConfigWatchTargets() {
|
|
18453
19551
|
return [...new Set(
|
|
18454
19552
|
this.projectConfigPaths.filter((projectConfigPath) => {
|
|
18455
|
-
const relativeConfigPath =
|
|
19553
|
+
const relativeConfigPath = path24.relative(this.projectRoot, projectConfigPath);
|
|
18456
19554
|
return this.isOutsideProjectPath(relativeConfigPath);
|
|
18457
19555
|
}).map((projectConfigPath) => {
|
|
18458
|
-
if (
|
|
19556
|
+
if (existsSync14(projectConfigPath)) {
|
|
18459
19557
|
return projectConfigPath;
|
|
18460
19558
|
}
|
|
18461
|
-
return this.getNearestExistingDirectory(
|
|
19559
|
+
return this.getNearestExistingDirectory(path24.dirname(projectConfigPath));
|
|
18462
19560
|
})
|
|
18463
19561
|
)];
|
|
18464
19562
|
}
|
|
@@ -18520,7 +19618,7 @@ var FileWatcher = class {
|
|
|
18520
19618
|
}
|
|
18521
19619
|
scheduleNativeReconciliation(generation, filePath) {
|
|
18522
19620
|
if (!this.isCurrentNativeSetup(generation)) return;
|
|
18523
|
-
const requiresFullReconciliation = filePath ===
|
|
19621
|
+
const requiresFullReconciliation = filePath === path24.join(this.projectRoot, ".gitignore");
|
|
18524
19622
|
const invalidatedPath = requiresFullReconciliation ? null : filePath;
|
|
18525
19623
|
this.nativeInvalidatedPaths.set(invalidatedPath, invalidatedPath !== null);
|
|
18526
19624
|
if (this.nativeReconcileTimer) {
|
|
@@ -18615,23 +19713,23 @@ var FileWatcher = class {
|
|
|
18615
19713
|
this.scheduleFlush();
|
|
18616
19714
|
}
|
|
18617
19715
|
isProjectConfigPath(filePath) {
|
|
18618
|
-
const relativePath =
|
|
18619
|
-
const normalizedRelativePath =
|
|
19716
|
+
const relativePath = path24.relative(this.projectRoot, filePath);
|
|
19717
|
+
const normalizedRelativePath = path24.normalize(relativePath);
|
|
18620
19718
|
return this.getProjectConfigRelativePaths().some((configPath) => configPath === normalizedRelativePath);
|
|
18621
19719
|
}
|
|
18622
19720
|
isProjectConfigPathOrAncestor(relativePath) {
|
|
18623
|
-
const normalizedRelativePath =
|
|
19721
|
+
const normalizedRelativePath = path24.normalize(relativePath);
|
|
18624
19722
|
return this.getProjectConfigRelativePaths().some(
|
|
18625
|
-
(configPath) => configPath === normalizedRelativePath || configPath.startsWith(`${normalizedRelativePath}${
|
|
19723
|
+
(configPath) => configPath === normalizedRelativePath || configPath.startsWith(`${normalizedRelativePath}${path24.sep}`)
|
|
18626
19724
|
);
|
|
18627
19725
|
}
|
|
18628
19726
|
isOutsideProjectPath(relativePath) {
|
|
18629
|
-
return relativePath === ".." || relativePath.startsWith(`..${
|
|
19727
|
+
return relativePath === ".." || relativePath.startsWith(`..${path24.sep}`) || path24.isAbsolute(relativePath);
|
|
18630
19728
|
}
|
|
18631
19729
|
getNearestExistingDirectory(directoryPath) {
|
|
18632
19730
|
let candidate = directoryPath;
|
|
18633
|
-
while (!
|
|
18634
|
-
const parent =
|
|
19731
|
+
while (!existsSync14(candidate)) {
|
|
19732
|
+
const parent = path24.dirname(candidate);
|
|
18635
19733
|
if (parent === candidate) break;
|
|
18636
19734
|
candidate = parent;
|
|
18637
19735
|
}
|
|
@@ -18639,7 +19737,7 @@ var FileWatcher = class {
|
|
|
18639
19737
|
}
|
|
18640
19738
|
getProjectConfigRelativePaths() {
|
|
18641
19739
|
return this.projectConfigPaths.map(
|
|
18642
|
-
(configPath) =>
|
|
19740
|
+
(configPath) => path24.normalize(path24.relative(this.projectRoot, configPath))
|
|
18643
19741
|
);
|
|
18644
19742
|
}
|
|
18645
19743
|
getConfigPathStates() {
|
|
@@ -18697,7 +19795,7 @@ var FileWatcher = class {
|
|
|
18697
19795
|
return;
|
|
18698
19796
|
}
|
|
18699
19797
|
const changes = Array.from(this.pendingChanges.entries()).map(
|
|
18700
|
-
([
|
|
19798
|
+
([path26, type]) => ({ path: path26, type })
|
|
18701
19799
|
);
|
|
18702
19800
|
this.pendingChanges.clear();
|
|
18703
19801
|
try {
|
|
@@ -18743,7 +19841,7 @@ var FileWatcher = class {
|
|
|
18743
19841
|
};
|
|
18744
19842
|
|
|
18745
19843
|
// src/watcher/git-head-watcher.ts
|
|
18746
|
-
import * as
|
|
19844
|
+
import * as path25 from "path";
|
|
18747
19845
|
var GitHeadWatcher = class {
|
|
18748
19846
|
watcher = null;
|
|
18749
19847
|
projectRoot;
|
|
@@ -18765,13 +19863,13 @@ var GitHeadWatcher = class {
|
|
|
18765
19863
|
this.readyPromise = Promise.resolve();
|
|
18766
19864
|
return;
|
|
18767
19865
|
}
|
|
18768
|
-
this.readyPromise = new Promise((
|
|
18769
|
-
this.resolveReady =
|
|
19866
|
+
this.readyPromise = new Promise((resolve18) => {
|
|
19867
|
+
this.resolveReady = resolve18;
|
|
18770
19868
|
});
|
|
18771
19869
|
this.onBranchChange = handler;
|
|
18772
19870
|
this.currentBranch = getCurrentBranch(this.projectRoot);
|
|
18773
19871
|
const headPath = getHeadPath(this.projectRoot);
|
|
18774
|
-
const refsPath =
|
|
19872
|
+
const refsPath = path25.join(this.projectRoot, ".git", "refs", "heads");
|
|
18775
19873
|
this.watcher = chokidar_default.watch([headPath, refsPath], {
|
|
18776
19874
|
persistent: true,
|
|
18777
19875
|
ignoreInitial: true,
|
|
@@ -18839,7 +19937,9 @@ var GitHeadWatcher = class {
|
|
|
18839
19937
|
function createWatcherWithIndexer(getIndexer, projectRoot3, config, host, options = {}) {
|
|
18840
19938
|
const fileWatcher = new FileWatcher(projectRoot3, config, host, options);
|
|
18841
19939
|
const configPaths = getConfigPaths(projectRoot3, host, options);
|
|
18842
|
-
configureAutoIndex(projectRoot3, host, parseConfig(config), getIndexer
|
|
19940
|
+
configureAutoIndex(projectRoot3, host, parseConfig(config), getIndexer, {
|
|
19941
|
+
synchronizeBackgroundWorker: false
|
|
19942
|
+
});
|
|
18843
19943
|
let stopped = false;
|
|
18844
19944
|
const requestReindex = () => {
|
|
18845
19945
|
if (stopped) return;
|
|
@@ -18859,7 +19959,9 @@ function createWatcherWithIndexer(getIndexer, projectRoot3, config, host, option
|
|
|
18859
19959
|
const parsedConfig = options.configPath ? parseConfig(loadConfigFile(options.configPath)) : void 0;
|
|
18860
19960
|
const refreshedConfig = refreshIndexerForDirectory(projectRoot3, host, parsedConfig);
|
|
18861
19961
|
if (refreshedConfig) {
|
|
18862
|
-
configureAutoIndex(projectRoot3, host, refreshedConfig, getIndexer
|
|
19962
|
+
configureAutoIndex(projectRoot3, host, refreshedConfig, getIndexer, {
|
|
19963
|
+
synchronizeBackgroundWorker: false
|
|
19964
|
+
});
|
|
18863
19965
|
}
|
|
18864
19966
|
}
|
|
18865
19967
|
requestReindex();
|
|
@@ -18907,7 +20009,6 @@ function getConfigPaths(projectRoot3, host, options) {
|
|
|
18907
20009
|
|
|
18908
20010
|
// src/adapters/pi/extension.ts
|
|
18909
20011
|
var HOST2 = "pi";
|
|
18910
|
-
var activeWatchers = /* @__PURE__ */ new Map();
|
|
18911
20012
|
var ChunkType = Type2.Union([
|
|
18912
20013
|
Type2.Literal("function"),
|
|
18913
20014
|
Type2.Literal("class"),
|
|
@@ -18926,24 +20027,30 @@ function projectRoot2(ctx) {
|
|
|
18926
20027
|
function isValidProject(projectRoot3, requireProjectMarker) {
|
|
18927
20028
|
return !isHomeDirectory(projectRoot3) && (!requireProjectMarker || hasProjectMarker(projectRoot3));
|
|
18928
20029
|
}
|
|
18929
|
-
function ensureWatcher(projectRoot3) {
|
|
18930
|
-
if (activeWatchers.has(projectRoot3)) return;
|
|
20030
|
+
async function ensureWatcher(projectRoot3) {
|
|
18931
20031
|
const config = parseConfig(loadMergedConfig(projectRoot3, HOST2));
|
|
18932
|
-
if (!
|
|
20032
|
+
if (!isValidProject(projectRoot3, config.indexing.requireProjectMarker)) {
|
|
20033
|
+
await stopBackgroundWorker(projectRoot3, HOST2).catch((error) => {
|
|
20034
|
+
console.error("[codebase-index] Failed to stop Pi background worker:", error);
|
|
20035
|
+
});
|
|
18933
20036
|
return;
|
|
18934
20037
|
}
|
|
18935
|
-
|
|
20038
|
+
getIndexerForProject(projectRoot3, HOST2);
|
|
20039
|
+
const watcherFactoryForConfig = (refreshedConfig) => refreshedConfig.indexing.watchFiles ? () => createWatcherWithIndexer(
|
|
18936
20040
|
() => getIndexerForProject(projectRoot3, HOST2),
|
|
18937
20041
|
projectRoot3,
|
|
18938
|
-
|
|
20042
|
+
refreshedConfig,
|
|
18939
20043
|
HOST2
|
|
18940
|
-
)
|
|
18941
|
-
|
|
18942
|
-
|
|
18943
|
-
|
|
18944
|
-
|
|
18945
|
-
|
|
18946
|
-
|
|
20044
|
+
) : null;
|
|
20045
|
+
configureBackgroundWorker(projectRoot3, HOST2, config, {
|
|
20046
|
+
startAutoIndex: (source, allowDisabledAutoIndex) => {
|
|
20047
|
+
startAutoIndexForBackgroundWorker(projectRoot3, HOST2, source, allowDisabledAutoIndex);
|
|
20048
|
+
},
|
|
20049
|
+
stopAutoIndex: () => stopAutoIndexForBackgroundWorker(projectRoot3, HOST2),
|
|
20050
|
+
watcherFactory: watcherFactoryForConfig(config),
|
|
20051
|
+
watcherFactoryForConfig
|
|
20052
|
+
});
|
|
20053
|
+
await waitForBackgroundWorkerStart(projectRoot3, HOST2);
|
|
18947
20054
|
}
|
|
18948
20055
|
function codebaseIndexPiExtension(pi) {
|
|
18949
20056
|
pi.registerTool({
|
|
@@ -19103,12 +20210,14 @@ function codebaseIndexPiExtension(pi) {
|
|
|
19103
20210
|
parameters: Type2.Object({
|
|
19104
20211
|
force: Type2.Optional(Type2.Boolean({ default: false })),
|
|
19105
20212
|
estimateOnly: Type2.Optional(Type2.Boolean({ default: false })),
|
|
20213
|
+
dryRun: Type2.Optional(Type2.Boolean({ default: false })),
|
|
19106
20214
|
verbose: Type2.Optional(Type2.Boolean({ default: false }))
|
|
19107
20215
|
}),
|
|
19108
20216
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
19109
20217
|
try {
|
|
19110
20218
|
const result = await runIndexCodebase(projectRoot2(ctx), HOST2, params);
|
|
19111
20219
|
if (result.kind === "estimate") return text2(formatCostEstimate(result.estimate), result.estimate);
|
|
20220
|
+
if (result.kind === "dryrun") return text2(formatDryRunEstimate(result.dryrun), result.dryrun);
|
|
19112
20221
|
if (result.kind === "busy") return text2(result.text, { code: "INDEX_BUSY" });
|
|
19113
20222
|
if (result.kind === "message") return text2(result.text);
|
|
19114
20223
|
return text2(formatIndexStats(result.stats, params.verbose ?? false), result.stats);
|
|
@@ -19174,16 +20283,16 @@ function codebaseIndexPiExtension(pi) {
|
|
|
19174
20283
|
});
|
|
19175
20284
|
registerPiCallGraphTools(pi);
|
|
19176
20285
|
pi.on("before_agent_start", async (event, ctx) => {
|
|
19177
|
-
ensureWatcher(projectRoot2(ctx));
|
|
20286
|
+
await ensureWatcher(projectRoot2(ctx));
|
|
19178
20287
|
return {
|
|
19179
20288
|
systemPrompt: `${event.systemPrompt}
|
|
19180
20289
|
|
|
19181
|
-
Check index_status first when index readiness is unknown. Use codebase_context only when repository orientation is needed (for layout, key symbols, or cross-file dependency intent), not mechanically for every task. When using codebase_context for orientation, request a compact first pass (for example: tokenBudget: 600, limit: 5) and inspect returned evidence before broad search/grep/bash/read-style reads. Avoid repeating broad reads when the compact evidence already answers the question. Use implementation_lookup for known symbols and call_graph/call_graph_path after endpoints are identified for dependency flow.`
|
|
20290
|
+
Check index_status first when index readiness is unknown. Use codebase_context only when repository orientation is needed (for layout, key symbols, or cross-file dependency intent), not mechanically for every task. When using codebase_context for orientation, request a compact first pass (for example: tokenBudget: 600, limit: 5) and inspect returned evidence before broad search/grep/bash/read-style reads. For change requests with a known or strongly suspected target symbol, optionally use codebase_edit_context as a compact, bounded pre-edit context for source plus direct callers and callees. Avoid repeating broad reads when the compact evidence already answers the question. Use implementation_lookup for known symbols and call_graph/call_graph_path after endpoints are identified for dependency flow.`
|
|
19182
20291
|
};
|
|
19183
20292
|
});
|
|
19184
20293
|
pi.on("session_shutdown", async (_event, ctx) => {
|
|
19185
20294
|
const root = projectRoot2(ctx);
|
|
19186
|
-
await
|
|
20295
|
+
await stopBackgroundWorker(root, HOST2);
|
|
19187
20296
|
});
|
|
19188
20297
|
pi.registerTool({
|
|
19189
20298
|
name: TOOL_NAME.PR_IMPACT,
|