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.cjs
CHANGED
|
@@ -333,7 +333,7 @@ var require_ignore = __commonJS({
|
|
|
333
333
|
// path matching.
|
|
334
334
|
// - check `string` either `MODE_IGNORE` or `MODE_CHECK_IGNORE`
|
|
335
335
|
// @returns {TestResult} true if a file is ignored
|
|
336
|
-
test(
|
|
336
|
+
test(path26, checkUnignored, mode) {
|
|
337
337
|
let ignored = false;
|
|
338
338
|
let unignored = false;
|
|
339
339
|
let matchedRule;
|
|
@@ -342,7 +342,7 @@ var require_ignore = __commonJS({
|
|
|
342
342
|
if (unignored === negative && ignored !== unignored || negative && !ignored && !unignored && !checkUnignored) {
|
|
343
343
|
return;
|
|
344
344
|
}
|
|
345
|
-
const matched = rule[mode].test(
|
|
345
|
+
const matched = rule[mode].test(path26);
|
|
346
346
|
if (!matched) {
|
|
347
347
|
return;
|
|
348
348
|
}
|
|
@@ -363,17 +363,17 @@ var require_ignore = __commonJS({
|
|
|
363
363
|
var throwError = (message, Ctor) => {
|
|
364
364
|
throw new Ctor(message);
|
|
365
365
|
};
|
|
366
|
-
var checkPath = (
|
|
367
|
-
if (!isString(
|
|
366
|
+
var checkPath = (path26, originalPath, doThrow) => {
|
|
367
|
+
if (!isString(path26)) {
|
|
368
368
|
return doThrow(
|
|
369
369
|
`path must be a string, but got \`${originalPath}\``,
|
|
370
370
|
TypeError
|
|
371
371
|
);
|
|
372
372
|
}
|
|
373
|
-
if (!
|
|
373
|
+
if (!path26) {
|
|
374
374
|
return doThrow(`path must not be empty`, TypeError);
|
|
375
375
|
}
|
|
376
|
-
if (checkPath.isNotRelative(
|
|
376
|
+
if (checkPath.isNotRelative(path26)) {
|
|
377
377
|
const r = "`path.relative()`d";
|
|
378
378
|
return doThrow(
|
|
379
379
|
`path should be a ${r} string, but got "${originalPath}"`,
|
|
@@ -382,7 +382,7 @@ var require_ignore = __commonJS({
|
|
|
382
382
|
}
|
|
383
383
|
return true;
|
|
384
384
|
};
|
|
385
|
-
var isNotRelative = (
|
|
385
|
+
var isNotRelative = (path26) => REGEX_TEST_INVALID_PATH.test(path26);
|
|
386
386
|
checkPath.isNotRelative = isNotRelative;
|
|
387
387
|
checkPath.convert = (p) => p;
|
|
388
388
|
var Ignore2 = class {
|
|
@@ -412,19 +412,19 @@ var require_ignore = __commonJS({
|
|
|
412
412
|
}
|
|
413
413
|
// @returns {TestResult}
|
|
414
414
|
_test(originalPath, cache, checkUnignored, slices) {
|
|
415
|
-
const
|
|
415
|
+
const path26 = originalPath && checkPath.convert(originalPath);
|
|
416
416
|
checkPath(
|
|
417
|
-
|
|
417
|
+
path26,
|
|
418
418
|
originalPath,
|
|
419
419
|
this._strictPathCheck ? throwError : RETURN_FALSE
|
|
420
420
|
);
|
|
421
|
-
return this._t(
|
|
421
|
+
return this._t(path26, cache, checkUnignored, slices);
|
|
422
422
|
}
|
|
423
|
-
checkIgnore(
|
|
424
|
-
if (!REGEX_TEST_TRAILING_SLASH.test(
|
|
425
|
-
return this.test(
|
|
423
|
+
checkIgnore(path26) {
|
|
424
|
+
if (!REGEX_TEST_TRAILING_SLASH.test(path26)) {
|
|
425
|
+
return this.test(path26);
|
|
426
426
|
}
|
|
427
|
-
const slices =
|
|
427
|
+
const slices = path26.split(SLASH2).filter(Boolean);
|
|
428
428
|
slices.pop();
|
|
429
429
|
if (slices.length) {
|
|
430
430
|
const parent = this._t(
|
|
@@ -437,18 +437,18 @@ var require_ignore = __commonJS({
|
|
|
437
437
|
return parent;
|
|
438
438
|
}
|
|
439
439
|
}
|
|
440
|
-
return this._rules.test(
|
|
440
|
+
return this._rules.test(path26, false, MODE_CHECK_IGNORE);
|
|
441
441
|
}
|
|
442
|
-
_t(
|
|
443
|
-
if (
|
|
444
|
-
return cache[
|
|
442
|
+
_t(path26, cache, checkUnignored, slices) {
|
|
443
|
+
if (path26 in cache) {
|
|
444
|
+
return cache[path26];
|
|
445
445
|
}
|
|
446
446
|
if (!slices) {
|
|
447
|
-
slices =
|
|
447
|
+
slices = path26.split(SLASH2).filter(Boolean);
|
|
448
448
|
}
|
|
449
449
|
slices.pop();
|
|
450
450
|
if (!slices.length) {
|
|
451
|
-
return cache[
|
|
451
|
+
return cache[path26] = this._rules.test(path26, checkUnignored, MODE_IGNORE);
|
|
452
452
|
}
|
|
453
453
|
const parent = this._t(
|
|
454
454
|
slices.join(SLASH2) + SLASH2,
|
|
@@ -456,29 +456,29 @@ var require_ignore = __commonJS({
|
|
|
456
456
|
checkUnignored,
|
|
457
457
|
slices
|
|
458
458
|
);
|
|
459
|
-
return cache[
|
|
459
|
+
return cache[path26] = parent.ignored ? parent : this._rules.test(path26, checkUnignored, MODE_IGNORE);
|
|
460
460
|
}
|
|
461
|
-
ignores(
|
|
462
|
-
return this._test(
|
|
461
|
+
ignores(path26) {
|
|
462
|
+
return this._test(path26, this._ignoreCache, false).ignored;
|
|
463
463
|
}
|
|
464
464
|
createFilter() {
|
|
465
|
-
return (
|
|
465
|
+
return (path26) => !this.ignores(path26);
|
|
466
466
|
}
|
|
467
467
|
filter(paths) {
|
|
468
468
|
return makeArray(paths).filter(this.createFilter());
|
|
469
469
|
}
|
|
470
470
|
// @returns {TestResult}
|
|
471
|
-
test(
|
|
472
|
-
return this._test(
|
|
471
|
+
test(path26) {
|
|
472
|
+
return this._test(path26, this._testCache, true);
|
|
473
473
|
}
|
|
474
474
|
};
|
|
475
475
|
var factory = (options) => new Ignore2(options);
|
|
476
|
-
var isPathValid = (
|
|
476
|
+
var isPathValid = (path26) => checkPath(path26 && checkPath.convert(path26), path26, RETURN_FALSE);
|
|
477
477
|
var setupWindows = () => {
|
|
478
478
|
const makePosix = (str) => /^\\\\\?\\/.test(str) || /["<>|\u0000-\u001F]+/u.test(str) ? str : str.replace(/\\/g, "/");
|
|
479
479
|
checkPath.convert = makePosix;
|
|
480
480
|
const REGEX_TEST_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i;
|
|
481
|
-
checkPath.isNotRelative = (
|
|
481
|
+
checkPath.isNotRelative = (path26) => REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path26) || isNotRelative(path26);
|
|
482
482
|
};
|
|
483
483
|
if (
|
|
484
484
|
// Detect `process` so that it can run in browsers.
|
|
@@ -2055,6 +2055,26 @@ function formatCostEstimate(estimate) {
|
|
|
2055
2055
|
\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
|
|
2056
2056
|
`;
|
|
2057
2057
|
}
|
|
2058
|
+
function formatDryRunEstimate(estimate) {
|
|
2059
|
+
return `Dry run: parsed the file set to measure the embedding workload. No embedding requests were made and the index was not changed.
|
|
2060
|
+
|
|
2061
|
+
Files to embed: ${estimate.filesCount.toLocaleString()}
|
|
2062
|
+
Chunks to embed: ${estimate.chunksCount.toLocaleString()}
|
|
2063
|
+
Tokens to embed: ${estimate.tokensToEmbed.toLocaleString()}
|
|
2064
|
+
|
|
2065
|
+
The "Tokens to embed" value uses the local estimateTokens(text) = ceil(len/4). It
|
|
2066
|
+
matches the live "Tokens used" counter only for providers that report usage on the
|
|
2067
|
+
same basis (ollama); for providers that report a server tokenizer count (OpenAI,
|
|
2068
|
+
Gemini, custom) it is only an estimate.
|
|
2069
|
+
|
|
2070
|
+
For a matching provider and a project-scoped force index, the force pass clears its
|
|
2071
|
+
own cached embeddings, so the live counter climbs to this number. A force index on a
|
|
2072
|
+
shared global index can reuse cached embeddings from other projects, and an
|
|
2073
|
+
incremental index counts cached chunks that are not re-embedded; in both cases this
|
|
2074
|
+
number is an upper bound on the live counter, so a progress percent against this
|
|
2075
|
+
total tops out below 100%.
|
|
2076
|
+
`;
|
|
2077
|
+
}
|
|
2058
2078
|
function formatBytes(bytes) {
|
|
2059
2079
|
if (bytes === 0) return "0 B";
|
|
2060
2080
|
const k = 1024;
|
|
@@ -2234,7 +2254,7 @@ function formatCodeCommunities(result) {
|
|
|
2234
2254
|
|
|
2235
2255
|
// src/tools/operations.ts
|
|
2236
2256
|
var import_fs13 = require("fs");
|
|
2237
|
-
var
|
|
2257
|
+
var path21 = __toESM(require("path"), 1);
|
|
2238
2258
|
|
|
2239
2259
|
// src/tools/knowledge-base-paths.ts
|
|
2240
2260
|
var path9 = __toESM(require("path"), 1);
|
|
@@ -2946,8 +2966,8 @@ function formatExactSearchHandoff(results) {
|
|
|
2946
2966
|
}
|
|
2947
2967
|
function formatContextEvidence(result, index) {
|
|
2948
2968
|
const symbol = result.name ? ` ${JSON.stringify(compactEvidenceValue(result.name, 80))}` : "";
|
|
2949
|
-
const
|
|
2950
|
-
return `[${index}] ${result.chunkType}${symbol} in ${
|
|
2969
|
+
const path26 = compactEvidenceValue(result.filePath, 120);
|
|
2970
|
+
return `[${index}] ${result.chunkType}${symbol} in ${path26}:${result.startLine}-${result.endLine} (score ${result.score.toFixed(2)})`;
|
|
2951
2971
|
}
|
|
2952
2972
|
function formatContextPack(heading, selected, candidateCount, duplicateCount, limitOmittedCount, budgetOmittedCount, includeExactSearchHandoff) {
|
|
2953
2973
|
const lines = selected.map((result, index) => formatContextEvidence(result, index + 1));
|
|
@@ -3590,8 +3610,8 @@ function formatEffectivenessMetrics(snapshot) {
|
|
|
3590
3610
|
|
|
3591
3611
|
// src/utils/auto-index.ts
|
|
3592
3612
|
var import_fs8 = require("fs");
|
|
3593
|
-
var
|
|
3594
|
-
var
|
|
3613
|
+
var os5 = __toESM(require("os"), 1);
|
|
3614
|
+
var path13 = __toESM(require("path"), 1);
|
|
3595
3615
|
|
|
3596
3616
|
// src/indexer/index-lock.ts
|
|
3597
3617
|
var import_crypto = require("crypto");
|
|
@@ -3838,7 +3858,7 @@ function removeDeadReclaimMarker(lockPath, expectedOwner) {
|
|
|
3838
3858
|
return true;
|
|
3839
3859
|
}
|
|
3840
3860
|
function reclaimDeadOwner(indexPath, lockPath, expectedOwner) {
|
|
3841
|
-
const
|
|
3861
|
+
const reclaimPath2 = path10.join(lockPath, RECLAIM_DIRECTORY_NAME);
|
|
3842
3862
|
const reclaimOwner = {
|
|
3843
3863
|
pid: process.pid,
|
|
3844
3864
|
hostname: os3.hostname(),
|
|
@@ -3847,19 +3867,19 @@ function reclaimDeadOwner(indexPath, lockPath, expectedOwner) {
|
|
|
3847
3867
|
expectedOwnerToken: expectedOwner.token
|
|
3848
3868
|
};
|
|
3849
3869
|
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
3850
|
-
if (publishJsonDirectory(
|
|
3870
|
+
if (publishJsonDirectory(reclaimPath2, reclaimOwner)) break;
|
|
3851
3871
|
if (attempt === 0 && removeDeadReclaimMarker(lockPath, expectedOwner)) continue;
|
|
3852
3872
|
return false;
|
|
3853
3873
|
}
|
|
3854
3874
|
try {
|
|
3855
|
-
const currentReclaimer = readReclaimOwner(
|
|
3875
|
+
const currentReclaimer = readReclaimOwner(reclaimPath2);
|
|
3856
3876
|
const currentOwner = readDirectoryOwner(lockPath);
|
|
3857
3877
|
if (!currentReclaimer || !sameReclaimOwner(currentReclaimer, reclaimOwner) || !currentOwner || !sameOwner(currentOwner, expectedOwner) || getOwnerLiveness(currentOwner) !== "dead") {
|
|
3858
3878
|
return false;
|
|
3859
3879
|
}
|
|
3860
3880
|
publishRecoveryMarker(indexPath, expectedOwner);
|
|
3861
3881
|
const ownerBeforeQuarantine = readDirectoryOwner(lockPath);
|
|
3862
|
-
const reclaimerBeforeQuarantine = readReclaimOwner(
|
|
3882
|
+
const reclaimerBeforeQuarantine = readReclaimOwner(reclaimPath2);
|
|
3863
3883
|
if (!ownerBeforeQuarantine || !sameOwner(ownerBeforeQuarantine, expectedOwner) || getOwnerLiveness(ownerBeforeQuarantine) !== "dead" || !reclaimerBeforeQuarantine || !sameReclaimOwner(reclaimerBeforeQuarantine, reclaimOwner)) {
|
|
3864
3884
|
return false;
|
|
3865
3885
|
}
|
|
@@ -4029,10 +4049,884 @@ function completeLeaseRecovery(lease) {
|
|
|
4029
4049
|
}
|
|
4030
4050
|
}
|
|
4031
4051
|
|
|
4052
|
+
// src/utils/background-worker.ts
|
|
4053
|
+
var import_node_crypto = require("crypto");
|
|
4054
|
+
var import_node_fs = require("fs");
|
|
4055
|
+
var os4 = __toESM(require("os"), 1);
|
|
4056
|
+
var path11 = __toESM(require("path"), 1);
|
|
4057
|
+
var OWNER_FILE_NAME2 = "owner.json";
|
|
4058
|
+
var HEARTBEAT_FILE_PREFIX = "heartbeat.";
|
|
4059
|
+
var RECLAIM_DIRECTORY_NAME2 = "reclaim";
|
|
4060
|
+
var REFRESH_REQUEST_FILE_NAME = "refresh-request.json";
|
|
4061
|
+
var HEARTBEAT_INTERVAL_MS = 5e3;
|
|
4062
|
+
var STALE_LEASE_MS = 3e4;
|
|
4063
|
+
var RETRY_DELAY_MS = 5e3;
|
|
4064
|
+
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;
|
|
4065
|
+
var BackgroundWorkerStopError = class extends Error {
|
|
4066
|
+
constructor(watcherError, autoIndexError) {
|
|
4067
|
+
super("Failed to stop background worker");
|
|
4068
|
+
this.watcherError = watcherError;
|
|
4069
|
+
this.autoIndexError = autoIndexError;
|
|
4070
|
+
this.name = "BackgroundWorkerStopError";
|
|
4071
|
+
}
|
|
4072
|
+
watcherError;
|
|
4073
|
+
autoIndexError;
|
|
4074
|
+
};
|
|
4075
|
+
var workers = /* @__PURE__ */ new Map();
|
|
4076
|
+
var workerKeysByProject = /* @__PURE__ */ new Map();
|
|
4077
|
+
var workerReplacementBarriers = /* @__PURE__ */ new Map();
|
|
4078
|
+
function getErrorCode2(error) {
|
|
4079
|
+
return typeof error === "object" && error !== null && "code" in error ? String(error.code) : void 0;
|
|
4080
|
+
}
|
|
4081
|
+
function canonicalizePath(targetPath) {
|
|
4082
|
+
const resolved = path11.resolve(targetPath);
|
|
4083
|
+
if ((0, import_node_fs.existsSync)(resolved)) {
|
|
4084
|
+
try {
|
|
4085
|
+
return import_node_fs.realpathSync.native(resolved);
|
|
4086
|
+
} catch {
|
|
4087
|
+
return resolved;
|
|
4088
|
+
}
|
|
4089
|
+
}
|
|
4090
|
+
const parent = path11.dirname(resolved);
|
|
4091
|
+
if (parent === resolved) return resolved;
|
|
4092
|
+
return path11.join(canonicalizePath(parent), path11.basename(resolved));
|
|
4093
|
+
}
|
|
4094
|
+
function projectLookupKey(projectRoot3, host) {
|
|
4095
|
+
return `${host}::${canonicalizePath(projectRoot3)}`;
|
|
4096
|
+
}
|
|
4097
|
+
function resolveIdentity(projectRoot3, config, host) {
|
|
4098
|
+
const canonicalProjectRoot = canonicalizePath(projectRoot3);
|
|
4099
|
+
const canonicalIndexPath = canonicalizePath(resolveProjectIndexPath(projectRoot3, config.scope, host));
|
|
4100
|
+
return {
|
|
4101
|
+
canonicalIndexPath,
|
|
4102
|
+
canonicalProjectRoot,
|
|
4103
|
+
key: `${canonicalIndexPath}::${canonicalProjectRoot}`
|
|
4104
|
+
};
|
|
4105
|
+
}
|
|
4106
|
+
function controllerKey(identity, host) {
|
|
4107
|
+
return `${identity.key}::${host}`;
|
|
4108
|
+
}
|
|
4109
|
+
function leaseDirectoryName(identity) {
|
|
4110
|
+
const hash = (0, import_node_crypto.createHash)("sha256").update(identity.key).digest("hex").slice(0, 32);
|
|
4111
|
+
return `background-worker.${hash}.lease`;
|
|
4112
|
+
}
|
|
4113
|
+
function leasePathFor(identity) {
|
|
4114
|
+
return path11.join(identity.canonicalIndexPath, leaseDirectoryName(identity));
|
|
4115
|
+
}
|
|
4116
|
+
function parseOwner2(value) {
|
|
4117
|
+
if (typeof value !== "object" || value === null) return null;
|
|
4118
|
+
const candidate = value;
|
|
4119
|
+
if (candidate.version !== 1) return null;
|
|
4120
|
+
if (!Number.isInteger(candidate.pid) || (candidate.pid ?? 0) <= 0) return null;
|
|
4121
|
+
if (typeof candidate.hostname !== "string" || candidate.hostname.length === 0) return null;
|
|
4122
|
+
if (typeof candidate.startedAt !== "string" || Number.isNaN(Date.parse(candidate.startedAt))) return null;
|
|
4123
|
+
if (typeof candidate.heartbeatAt !== "string" || Number.isNaN(Date.parse(candidate.heartbeatAt))) return null;
|
|
4124
|
+
if (typeof candidate.projectRoot !== "string" || candidate.projectRoot.length === 0) return null;
|
|
4125
|
+
if (typeof candidate.indexPath !== "string" || candidate.indexPath.length === 0) return null;
|
|
4126
|
+
if (typeof candidate.token !== "string" || !UUID_PATTERN2.test(candidate.token)) return null;
|
|
4127
|
+
return candidate;
|
|
4128
|
+
}
|
|
4129
|
+
function parseHeartbeat(value, expectedToken) {
|
|
4130
|
+
if (typeof value !== "object" || value === null) return null;
|
|
4131
|
+
const candidate = value;
|
|
4132
|
+
if (candidate.version !== 1 || candidate.token !== expectedToken) return null;
|
|
4133
|
+
if (typeof candidate.heartbeatAt !== "string" || Number.isNaN(Date.parse(candidate.heartbeatAt))) return null;
|
|
4134
|
+
return candidate;
|
|
4135
|
+
}
|
|
4136
|
+
function parseReclaimOwner2(value) {
|
|
4137
|
+
if (typeof value !== "object" || value === null) return null;
|
|
4138
|
+
const candidate = value;
|
|
4139
|
+
if (candidate.version !== 1) return null;
|
|
4140
|
+
if (!Number.isInteger(candidate.pid) || (candidate.pid ?? 0) <= 0) return null;
|
|
4141
|
+
if (typeof candidate.hostname !== "string" || candidate.hostname.length === 0) return null;
|
|
4142
|
+
if (typeof candidate.startedAt !== "string" || Number.isNaN(Date.parse(candidate.startedAt))) return null;
|
|
4143
|
+
if (typeof candidate.token !== "string" || !UUID_PATTERN2.test(candidate.token)) return null;
|
|
4144
|
+
if (candidate.expectedOwnerToken !== null && (typeof candidate.expectedOwnerToken !== "string" || !UUID_PATTERN2.test(candidate.expectedOwnerToken))) return null;
|
|
4145
|
+
return candidate;
|
|
4146
|
+
}
|
|
4147
|
+
function heartbeatPath(leasePath, token) {
|
|
4148
|
+
return path11.join(leasePath, `${HEARTBEAT_FILE_PREFIX}${token}.json`);
|
|
4149
|
+
}
|
|
4150
|
+
function reclaimPath(leasePath) {
|
|
4151
|
+
return path11.join(leasePath, RECLAIM_DIRECTORY_NAME2);
|
|
4152
|
+
}
|
|
4153
|
+
function refreshRequestPath(leasePath) {
|
|
4154
|
+
return path11.join(leasePath, REFRESH_REQUEST_FILE_NAME);
|
|
4155
|
+
}
|
|
4156
|
+
function readLeaseOwner(leasePath) {
|
|
4157
|
+
try {
|
|
4158
|
+
return parseOwner2(JSON.parse((0, import_node_fs.readFileSync)(path11.join(leasePath, OWNER_FILE_NAME2), "utf-8")));
|
|
4159
|
+
} catch {
|
|
4160
|
+
return null;
|
|
4161
|
+
}
|
|
4162
|
+
}
|
|
4163
|
+
function readOwner(leasePath) {
|
|
4164
|
+
const owner = readLeaseOwner(leasePath);
|
|
4165
|
+
if (!owner) return null;
|
|
4166
|
+
try {
|
|
4167
|
+
const heartbeat = parseHeartbeat(
|
|
4168
|
+
JSON.parse((0, import_node_fs.readFileSync)(heartbeatPath(leasePath, owner.token), "utf-8")),
|
|
4169
|
+
owner.token
|
|
4170
|
+
);
|
|
4171
|
+
return heartbeat ? { ...owner, heartbeatAt: heartbeat.heartbeatAt } : owner;
|
|
4172
|
+
} catch {
|
|
4173
|
+
return owner;
|
|
4174
|
+
}
|
|
4175
|
+
}
|
|
4176
|
+
function readReclaimOwner2(leasePath) {
|
|
4177
|
+
try {
|
|
4178
|
+
return parseReclaimOwner2(JSON.parse((0, import_node_fs.readFileSync)(path11.join(reclaimPath(leasePath), OWNER_FILE_NAME2), "utf-8")));
|
|
4179
|
+
} catch {
|
|
4180
|
+
return null;
|
|
4181
|
+
}
|
|
4182
|
+
}
|
|
4183
|
+
function ownerLiveness(owner) {
|
|
4184
|
+
if (owner.hostname !== os4.hostname()) return "unknown";
|
|
4185
|
+
try {
|
|
4186
|
+
process.kill(owner.pid, 0);
|
|
4187
|
+
return "alive";
|
|
4188
|
+
} catch (error) {
|
|
4189
|
+
const code = getErrorCode2(error);
|
|
4190
|
+
if (code === "ESRCH") return "dead";
|
|
4191
|
+
if (code === "EPERM") return "alive";
|
|
4192
|
+
return "unknown";
|
|
4193
|
+
}
|
|
4194
|
+
}
|
|
4195
|
+
function isHeartbeatExpired(owner) {
|
|
4196
|
+
return Date.now() - Date.parse(owner.heartbeatAt) >= STALE_LEASE_MS;
|
|
4197
|
+
}
|
|
4198
|
+
function sameOwner2(left, right) {
|
|
4199
|
+
return left.pid === right.pid && left.hostname === right.hostname && left.token === right.token;
|
|
4200
|
+
}
|
|
4201
|
+
function writeHeartbeat(leasePath, owner) {
|
|
4202
|
+
const targetPath = heartbeatPath(leasePath, owner.token);
|
|
4203
|
+
const temporaryPath = `${targetPath}.tmp.${process.pid}.${owner.token}.${(0, import_node_crypto.randomUUID)()}`;
|
|
4204
|
+
const heartbeat = {
|
|
4205
|
+
version: 1,
|
|
4206
|
+
token: owner.token,
|
|
4207
|
+
heartbeatAt: owner.heartbeatAt
|
|
4208
|
+
};
|
|
4209
|
+
try {
|
|
4210
|
+
(0, import_node_fs.writeFileSync)(temporaryPath, JSON.stringify(heartbeat), {
|
|
4211
|
+
encoding: "utf-8",
|
|
4212
|
+
flag: "wx",
|
|
4213
|
+
mode: 384
|
|
4214
|
+
});
|
|
4215
|
+
(0, import_node_fs.renameSync)(temporaryPath, targetPath);
|
|
4216
|
+
const currentOwner = readLeaseOwner(leasePath);
|
|
4217
|
+
return currentOwner !== null && sameOwner2(currentOwner, owner);
|
|
4218
|
+
} finally {
|
|
4219
|
+
if ((0, import_node_fs.existsSync)(temporaryPath)) (0, import_node_fs.rmSync)(temporaryPath, { force: true });
|
|
4220
|
+
}
|
|
4221
|
+
}
|
|
4222
|
+
function requestRefreshFromLeader(leasePath, allowDisabledAutoIndex) {
|
|
4223
|
+
const requestPath = refreshRequestPath(leasePath);
|
|
4224
|
+
const temporaryPath = `${requestPath}.tmp.${process.pid}.${(0, import_node_crypto.randomUUID)()}`;
|
|
4225
|
+
try {
|
|
4226
|
+
const request = {
|
|
4227
|
+
allowDisabledAutoIndex,
|
|
4228
|
+
requestedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4229
|
+
version: 1
|
|
4230
|
+
};
|
|
4231
|
+
(0, import_node_fs.writeFileSync)(temporaryPath, JSON.stringify(request), {
|
|
4232
|
+
encoding: "utf-8",
|
|
4233
|
+
flag: "wx",
|
|
4234
|
+
mode: 384
|
|
4235
|
+
});
|
|
4236
|
+
(0, import_node_fs.renameSync)(temporaryPath, requestPath);
|
|
4237
|
+
} catch (error) {
|
|
4238
|
+
if (getErrorCode2(error) !== "ENOENT") {
|
|
4239
|
+
console.error("[codebase-index] Failed to request background index refresh from the project worker:", error);
|
|
4240
|
+
}
|
|
4241
|
+
} finally {
|
|
4242
|
+
if ((0, import_node_fs.existsSync)(temporaryPath)) (0, import_node_fs.rmSync)(temporaryPath, { force: true });
|
|
4243
|
+
}
|
|
4244
|
+
}
|
|
4245
|
+
function consumeRefreshRequest(leasePath) {
|
|
4246
|
+
const requestPath = refreshRequestPath(leasePath);
|
|
4247
|
+
const claimedPath = `${requestPath}.handling.${process.pid}.${(0, import_node_crypto.randomUUID)()}`;
|
|
4248
|
+
try {
|
|
4249
|
+
(0, import_node_fs.renameSync)(requestPath, claimedPath);
|
|
4250
|
+
} catch (error) {
|
|
4251
|
+
if (getErrorCode2(error) === "ENOENT") return null;
|
|
4252
|
+
throw error;
|
|
4253
|
+
}
|
|
4254
|
+
try {
|
|
4255
|
+
const value = JSON.parse((0, import_node_fs.readFileSync)(claimedPath, "utf-8"));
|
|
4256
|
+
return {
|
|
4257
|
+
allowDisabledAutoIndex: value.version === 1 && value.allowDisabledAutoIndex === true,
|
|
4258
|
+
requestedAt: typeof value.requestedAt === "string" ? value.requestedAt : (/* @__PURE__ */ new Date()).toISOString(),
|
|
4259
|
+
version: 1
|
|
4260
|
+
};
|
|
4261
|
+
} catch {
|
|
4262
|
+
return { allowDisabledAutoIndex: false, requestedAt: (/* @__PURE__ */ new Date()).toISOString(), version: 1 };
|
|
4263
|
+
} finally {
|
|
4264
|
+
(0, import_node_fs.rmSync)(claimedPath, { force: true });
|
|
4265
|
+
}
|
|
4266
|
+
}
|
|
4267
|
+
function publishLease(leasePath, owner) {
|
|
4268
|
+
const candidatePath = `${leasePath}.candidate.${process.pid}.${owner.token}`;
|
|
4269
|
+
try {
|
|
4270
|
+
(0, import_node_fs.mkdirSync)(candidatePath, { mode: 448 });
|
|
4271
|
+
} catch (error) {
|
|
4272
|
+
if (getErrorCode2(error) === "ENOENT") return false;
|
|
4273
|
+
throw error;
|
|
4274
|
+
}
|
|
4275
|
+
try {
|
|
4276
|
+
(0, import_node_fs.writeFileSync)(path11.join(candidatePath, OWNER_FILE_NAME2), JSON.stringify(owner), {
|
|
4277
|
+
encoding: "utf-8",
|
|
4278
|
+
flag: "wx",
|
|
4279
|
+
mode: 384
|
|
4280
|
+
});
|
|
4281
|
+
if ((0, import_node_fs.existsSync)(leasePath)) return false;
|
|
4282
|
+
try {
|
|
4283
|
+
(0, import_node_fs.renameSync)(candidatePath, leasePath);
|
|
4284
|
+
return true;
|
|
4285
|
+
} catch (error) {
|
|
4286
|
+
if ((0, import_node_fs.existsSync)(leasePath) || getErrorCode2(error) === "ENOENT") return false;
|
|
4287
|
+
throw error;
|
|
4288
|
+
}
|
|
4289
|
+
} finally {
|
|
4290
|
+
if ((0, import_node_fs.existsSync)(candidatePath)) (0, import_node_fs.rmSync)(candidatePath, { recursive: true, force: true });
|
|
4291
|
+
}
|
|
4292
|
+
}
|
|
4293
|
+
function sameReclaimOwner2(left, right) {
|
|
4294
|
+
return left.pid === right.pid && left.hostname === right.hostname && left.token === right.token && left.expectedOwnerToken === right.expectedOwnerToken;
|
|
4295
|
+
}
|
|
4296
|
+
function reclaimerLiveness(owner) {
|
|
4297
|
+
return ownerLiveness(owner);
|
|
4298
|
+
}
|
|
4299
|
+
function isReclaimMarkerExpired(leasePath, owner) {
|
|
4300
|
+
const startedAt = owner ? Date.parse(owner.startedAt) : (() => {
|
|
4301
|
+
try {
|
|
4302
|
+
return (0, import_node_fs.lstatSync)(reclaimPath(leasePath)).mtimeMs;
|
|
4303
|
+
} catch {
|
|
4304
|
+
return Date.now();
|
|
4305
|
+
}
|
|
4306
|
+
})();
|
|
4307
|
+
return Date.now() - startedAt >= STALE_LEASE_MS;
|
|
4308
|
+
}
|
|
4309
|
+
function hasActiveReclaimMarker(leasePath, owner) {
|
|
4310
|
+
const marker = readReclaimOwner2(leasePath);
|
|
4311
|
+
return marker !== null && marker.expectedOwnerToken === owner.token && (marker.hostname !== os4.hostname() || ownerLiveness(owner) !== "alive");
|
|
4312
|
+
}
|
|
4313
|
+
function publishReclaimMarker(leasePath, expectedOwner) {
|
|
4314
|
+
const markerPath = reclaimPath(leasePath);
|
|
4315
|
+
const owner = {
|
|
4316
|
+
version: 1,
|
|
4317
|
+
pid: process.pid,
|
|
4318
|
+
hostname: os4.hostname(),
|
|
4319
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4320
|
+
token: (0, import_node_crypto.randomUUID)(),
|
|
4321
|
+
expectedOwnerToken: expectedOwner?.token ?? null
|
|
4322
|
+
};
|
|
4323
|
+
try {
|
|
4324
|
+
(0, import_node_fs.mkdirSync)(markerPath, { mode: 448 });
|
|
4325
|
+
} catch (error) {
|
|
4326
|
+
if (getErrorCode2(error) === "EEXIST" || getErrorCode2(error) === "ENOENT") return null;
|
|
4327
|
+
throw error;
|
|
4328
|
+
}
|
|
4329
|
+
try {
|
|
4330
|
+
(0, import_node_fs.writeFileSync)(path11.join(markerPath, OWNER_FILE_NAME2), JSON.stringify(owner), {
|
|
4331
|
+
encoding: "utf-8",
|
|
4332
|
+
flag: "wx",
|
|
4333
|
+
mode: 384
|
|
4334
|
+
});
|
|
4335
|
+
return owner;
|
|
4336
|
+
} catch (error) {
|
|
4337
|
+
(0, import_node_fs.rmSync)(markerPath, { recursive: true, force: true });
|
|
4338
|
+
throw error;
|
|
4339
|
+
}
|
|
4340
|
+
}
|
|
4341
|
+
function removeExpiredReclaimMarker(leasePath, expectedOwner) {
|
|
4342
|
+
const marker = readReclaimOwner2(leasePath);
|
|
4343
|
+
const markerPath = reclaimPath(leasePath);
|
|
4344
|
+
if (!(0, import_node_fs.existsSync)(markerPath)) return false;
|
|
4345
|
+
if (marker && marker.expectedOwnerToken !== (expectedOwner?.token ?? null)) return false;
|
|
4346
|
+
if (marker && (reclaimerLiveness(marker) === "alive" || !isReclaimMarkerExpired(leasePath, marker))) return false;
|
|
4347
|
+
if (!marker && !isReclaimMarkerExpired(leasePath, null)) return false;
|
|
4348
|
+
const staleMarkerPath = `${markerPath}.stale.${marker?.pid ?? process.pid}.${marker?.token ?? (0, import_node_crypto.randomUUID)()}.${(0, import_node_crypto.randomUUID)()}`;
|
|
4349
|
+
try {
|
|
4350
|
+
(0, import_node_fs.renameSync)(markerPath, staleMarkerPath);
|
|
4351
|
+
} catch (error) {
|
|
4352
|
+
if (getErrorCode2(error) === "ENOENT") return false;
|
|
4353
|
+
throw error;
|
|
4354
|
+
}
|
|
4355
|
+
try {
|
|
4356
|
+
let claimedMarker = null;
|
|
4357
|
+
try {
|
|
4358
|
+
claimedMarker = parseReclaimOwner2(
|
|
4359
|
+
JSON.parse((0, import_node_fs.readFileSync)(path11.join(staleMarkerPath, OWNER_FILE_NAME2), "utf-8"))
|
|
4360
|
+
);
|
|
4361
|
+
} catch {
|
|
4362
|
+
claimedMarker = null;
|
|
4363
|
+
}
|
|
4364
|
+
const markerMatches = marker ? claimedMarker !== null && sameReclaimOwner2(claimedMarker, marker) : claimedMarker === null;
|
|
4365
|
+
if (!markerMatches || !canReclaimLease(leasePath, expectedOwner)) {
|
|
4366
|
+
if (!(0, import_node_fs.existsSync)(markerPath) && (0, import_node_fs.existsSync)(staleMarkerPath)) (0, import_node_fs.renameSync)(staleMarkerPath, markerPath);
|
|
4367
|
+
return false;
|
|
4368
|
+
}
|
|
4369
|
+
(0, import_node_fs.rmSync)(staleMarkerPath, { recursive: true, force: true });
|
|
4370
|
+
return true;
|
|
4371
|
+
} catch (error) {
|
|
4372
|
+
if (getErrorCode2(error) === "ENOENT") return false;
|
|
4373
|
+
throw error;
|
|
4374
|
+
}
|
|
4375
|
+
}
|
|
4376
|
+
function canReclaimLease(leasePath, expectedOwner) {
|
|
4377
|
+
if (!(0, import_node_fs.existsSync)(leasePath)) return false;
|
|
4378
|
+
if (!expectedOwner) return false;
|
|
4379
|
+
const currentOwner = readOwner(leasePath);
|
|
4380
|
+
if (!currentOwner || !sameOwner2(currentOwner, expectedOwner)) return false;
|
|
4381
|
+
if (currentOwner.hostname === os4.hostname()) {
|
|
4382
|
+
return ownerLiveness(currentOwner) === "dead";
|
|
4383
|
+
}
|
|
4384
|
+
return isHeartbeatExpired(currentOwner);
|
|
4385
|
+
}
|
|
4386
|
+
function reclaimLease(leasePath, expectedOwner) {
|
|
4387
|
+
let marker = null;
|
|
4388
|
+
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
4389
|
+
marker = publishReclaimMarker(leasePath, expectedOwner);
|
|
4390
|
+
if (marker) break;
|
|
4391
|
+
if (attempt === 0 && removeExpiredReclaimMarker(leasePath, expectedOwner)) continue;
|
|
4392
|
+
return false;
|
|
4393
|
+
}
|
|
4394
|
+
if (!marker) return false;
|
|
4395
|
+
const markerPath = reclaimPath(leasePath);
|
|
4396
|
+
try {
|
|
4397
|
+
const currentMarker = readReclaimOwner2(leasePath);
|
|
4398
|
+
if (!currentMarker || !sameReclaimOwner2(currentMarker, marker) || !canReclaimLease(leasePath, expectedOwner)) {
|
|
4399
|
+
return false;
|
|
4400
|
+
}
|
|
4401
|
+
const stalePath = `${leasePath}.stale.${process.pid}.${marker.token}`;
|
|
4402
|
+
(0, import_node_fs.renameSync)(leasePath, stalePath);
|
|
4403
|
+
const quarantinedOwner = readOwner(stalePath);
|
|
4404
|
+
const quarantinedMarker = readReclaimOwner2(stalePath);
|
|
4405
|
+
if (!quarantinedMarker || !sameReclaimOwner2(quarantinedMarker, marker) || expectedOwner !== null && (!quarantinedOwner || !sameOwner2(quarantinedOwner, expectedOwner))) {
|
|
4406
|
+
if (!(0, import_node_fs.existsSync)(leasePath) && (0, import_node_fs.existsSync)(stalePath)) (0, import_node_fs.renameSync)(stalePath, leasePath);
|
|
4407
|
+
return false;
|
|
4408
|
+
}
|
|
4409
|
+
(0, import_node_fs.rmSync)(stalePath, { recursive: true, force: true });
|
|
4410
|
+
return true;
|
|
4411
|
+
} catch (error) {
|
|
4412
|
+
if (getErrorCode2(error) === "ENOENT") return false;
|
|
4413
|
+
throw error;
|
|
4414
|
+
} finally {
|
|
4415
|
+
const currentMarker = readReclaimOwner2(leasePath);
|
|
4416
|
+
if (currentMarker && sameReclaimOwner2(currentMarker, marker)) {
|
|
4417
|
+
(0, import_node_fs.rmSync)(markerPath, { recursive: true, force: true });
|
|
4418
|
+
}
|
|
4419
|
+
}
|
|
4420
|
+
}
|
|
4421
|
+
function acquireLease(identity) {
|
|
4422
|
+
(0, import_node_fs.mkdirSync)(identity.canonicalIndexPath, { recursive: true, mode: 448 });
|
|
4423
|
+
const canonicalIndexPath = import_node_fs.realpathSync.native(identity.canonicalIndexPath);
|
|
4424
|
+
const leasePath = path11.join(canonicalIndexPath, leaseDirectoryName({ ...identity, canonicalIndexPath }));
|
|
4425
|
+
for (let attempt = 0; attempt < 4; attempt += 1) {
|
|
4426
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
4427
|
+
const owner = {
|
|
4428
|
+
version: 1,
|
|
4429
|
+
pid: process.pid,
|
|
4430
|
+
hostname: os4.hostname(),
|
|
4431
|
+
startedAt: timestamp,
|
|
4432
|
+
heartbeatAt: timestamp,
|
|
4433
|
+
projectRoot: identity.canonicalProjectRoot,
|
|
4434
|
+
indexPath: canonicalIndexPath,
|
|
4435
|
+
token: (0, import_node_crypto.randomUUID)()
|
|
4436
|
+
};
|
|
4437
|
+
if (publishLease(leasePath, owner)) {
|
|
4438
|
+
return { leasePath, owner };
|
|
4439
|
+
}
|
|
4440
|
+
const existingOwner = readOwner(leasePath);
|
|
4441
|
+
if (existingOwner) {
|
|
4442
|
+
if (canReclaimLease(leasePath, existingOwner) && reclaimLease(leasePath, existingOwner)) continue;
|
|
4443
|
+
return null;
|
|
4444
|
+
}
|
|
4445
|
+
return null;
|
|
4446
|
+
}
|
|
4447
|
+
return null;
|
|
4448
|
+
}
|
|
4449
|
+
function releaseLease(lease) {
|
|
4450
|
+
const currentOwner = readOwner(lease.leasePath);
|
|
4451
|
+
if (!currentOwner || !sameOwner2(currentOwner, lease.owner)) return false;
|
|
4452
|
+
const releasePath = `${lease.leasePath}.release.${lease.owner.pid}.${lease.owner.token}`;
|
|
4453
|
+
try {
|
|
4454
|
+
(0, import_node_fs.renameSync)(lease.leasePath, releasePath);
|
|
4455
|
+
} catch (error) {
|
|
4456
|
+
if (getErrorCode2(error) === "ENOENT") return false;
|
|
4457
|
+
throw error;
|
|
4458
|
+
}
|
|
4459
|
+
const claimedOwner = readOwner(releasePath);
|
|
4460
|
+
if (!claimedOwner || !sameOwner2(claimedOwner, lease.owner)) {
|
|
4461
|
+
if (!(0, import_node_fs.existsSync)(lease.leasePath) && (0, import_node_fs.existsSync)(releasePath)) {
|
|
4462
|
+
(0, import_node_fs.renameSync)(releasePath, lease.leasePath);
|
|
4463
|
+
}
|
|
4464
|
+
return false;
|
|
4465
|
+
}
|
|
4466
|
+
(0, import_node_fs.rmSync)(releasePath, { recursive: true, force: true });
|
|
4467
|
+
return true;
|
|
4468
|
+
}
|
|
4469
|
+
var BackgroundWorkerController = class {
|
|
4470
|
+
constructor(projectRoot3, host, config, hooks, identity) {
|
|
4471
|
+
this.projectRoot = projectRoot3;
|
|
4472
|
+
this.host = host;
|
|
4473
|
+
this.config = config;
|
|
4474
|
+
this.hooks = hooks;
|
|
4475
|
+
this.identity = identity;
|
|
4476
|
+
}
|
|
4477
|
+
projectRoot;
|
|
4478
|
+
host;
|
|
4479
|
+
config;
|
|
4480
|
+
hooks;
|
|
4481
|
+
identity;
|
|
4482
|
+
lease = null;
|
|
4483
|
+
watcher = null;
|
|
4484
|
+
leaderReady = Promise.resolve();
|
|
4485
|
+
heartbeatTimer = null;
|
|
4486
|
+
retryTimer = null;
|
|
4487
|
+
teardownRetryTimer = null;
|
|
4488
|
+
transition = Promise.resolve();
|
|
4489
|
+
stopPromise = null;
|
|
4490
|
+
stopped = false;
|
|
4491
|
+
stopping = false;
|
|
4492
|
+
losingLeadership = false;
|
|
4493
|
+
restartAfterStop = false;
|
|
4494
|
+
leaderWorkStopped = false;
|
|
4495
|
+
startingLeaderWork = false;
|
|
4496
|
+
stopAutoIndexOnTeardown = true;
|
|
4497
|
+
autoIndexStarted = false;
|
|
4498
|
+
reportedError = null;
|
|
4499
|
+
update(config, hooks, options) {
|
|
4500
|
+
const autoIndexWasEnabled = this.config.indexing.autoIndex;
|
|
4501
|
+
const shouldReplaceWatcher = this.watcher !== null && hooks.watcherFactory !== void 0 && (hooks.watcherFactory === null || hooks.replaceWatcher === true);
|
|
4502
|
+
this.config = config;
|
|
4503
|
+
this.hooks = {
|
|
4504
|
+
...this.hooks,
|
|
4505
|
+
...hooks,
|
|
4506
|
+
watcherFactory: hooks.watcherFactory === void 0 ? this.hooks.watcherFactory : hooks.watcherFactory,
|
|
4507
|
+
watcherFactoryForConfig: hooks.watcherFactoryForConfig === void 0 ? this.hooks.watcherFactoryForConfig : hooks.watcherFactoryForConfig
|
|
4508
|
+
};
|
|
4509
|
+
if (autoIndexWasEnabled && !config.indexing.autoIndex || options.restartAutoIndex === true && config.indexing.autoIndex && !this.startingLeaderWork) {
|
|
4510
|
+
this.autoIndexStarted = false;
|
|
4511
|
+
}
|
|
4512
|
+
if (!this.canRun()) {
|
|
4513
|
+
void this.stop().catch((error) => {
|
|
4514
|
+
console.error("[codebase-index] Failed to stop background worker after disabling automatic work:", error);
|
|
4515
|
+
});
|
|
4516
|
+
return;
|
|
4517
|
+
}
|
|
4518
|
+
if (shouldReplaceWatcher) {
|
|
4519
|
+
void this.enqueue(async () => {
|
|
4520
|
+
const watcher = this.watcher;
|
|
4521
|
+
if (watcher) {
|
|
4522
|
+
await watcher.stop();
|
|
4523
|
+
if (this.watcher === watcher) this.watcher = null;
|
|
4524
|
+
}
|
|
4525
|
+
if (this.lease && !this.stopped) this.startLeaderWork();
|
|
4526
|
+
}).catch((error) => {
|
|
4527
|
+
console.error("[codebase-index] Failed to replace background file watcher:", error);
|
|
4528
|
+
});
|
|
4529
|
+
}
|
|
4530
|
+
this.start();
|
|
4531
|
+
}
|
|
4532
|
+
startAfter(activation) {
|
|
4533
|
+
this.transition = activation.catch(() => void 0);
|
|
4534
|
+
this.start();
|
|
4535
|
+
}
|
|
4536
|
+
start() {
|
|
4537
|
+
if (!this.canRun() || this.losingLeadership) return;
|
|
4538
|
+
if (this.stopping) {
|
|
4539
|
+
this.restartAfterStop = true;
|
|
4540
|
+
return;
|
|
4541
|
+
}
|
|
4542
|
+
this.stopped = false;
|
|
4543
|
+
void this.enqueue(async () => {
|
|
4544
|
+
if (this.stopped || this.stopping || this.losingLeadership || !this.canRun()) return;
|
|
4545
|
+
if (!this.lease) {
|
|
4546
|
+
try {
|
|
4547
|
+
this.lease = acquireLease(this.identity);
|
|
4548
|
+
this.reportedError = null;
|
|
4549
|
+
} catch (error) {
|
|
4550
|
+
this.reportAcquireError(error);
|
|
4551
|
+
this.scheduleRetry();
|
|
4552
|
+
return;
|
|
4553
|
+
}
|
|
4554
|
+
}
|
|
4555
|
+
if (!this.lease) {
|
|
4556
|
+
this.scheduleRetry();
|
|
4557
|
+
return;
|
|
4558
|
+
}
|
|
4559
|
+
this.startHeartbeat();
|
|
4560
|
+
this.startLeaderWork();
|
|
4561
|
+
});
|
|
4562
|
+
}
|
|
4563
|
+
waitForStart() {
|
|
4564
|
+
return this.transition.catch(() => void 0).then(() => this.leaderReady);
|
|
4565
|
+
}
|
|
4566
|
+
requestRefresh(allowDisabledAutoIndex = false) {
|
|
4567
|
+
this.start();
|
|
4568
|
+
if (!this.isLeader()) {
|
|
4569
|
+
requestRefreshFromLeader(leasePathFor(this.identity), allowDisabledAutoIndex);
|
|
4570
|
+
return;
|
|
4571
|
+
}
|
|
4572
|
+
void this.enqueue(async () => {
|
|
4573
|
+
if (this.stopped || !this.lease) return;
|
|
4574
|
+
this.hooks.startAutoIndex("retrieval", allowDisabledAutoIndex);
|
|
4575
|
+
});
|
|
4576
|
+
}
|
|
4577
|
+
isLeader() {
|
|
4578
|
+
return this.lease !== null && !this.stopping && !this.losingLeadership;
|
|
4579
|
+
}
|
|
4580
|
+
isStopping() {
|
|
4581
|
+
return this.stopping;
|
|
4582
|
+
}
|
|
4583
|
+
getHooksForConfig(config) {
|
|
4584
|
+
const watcherFactoryForConfig = this.hooks.watcherFactoryForConfig;
|
|
4585
|
+
if (!watcherFactoryForConfig) return this.hooks;
|
|
4586
|
+
return {
|
|
4587
|
+
...this.hooks,
|
|
4588
|
+
watcherFactory: watcherFactoryForConfig(config),
|
|
4589
|
+
replaceWatcher: true
|
|
4590
|
+
};
|
|
4591
|
+
}
|
|
4592
|
+
attachWatcher(watcherFactory, watcherFactoryForConfig) {
|
|
4593
|
+
if (this.hooks.watcherFactory !== void 0) return;
|
|
4594
|
+
this.hooks = {
|
|
4595
|
+
...this.hooks,
|
|
4596
|
+
watcherFactory,
|
|
4597
|
+
watcherFactoryForConfig: watcherFactoryForConfig ?? this.hooks.watcherFactoryForConfig
|
|
4598
|
+
};
|
|
4599
|
+
this.start();
|
|
4600
|
+
}
|
|
4601
|
+
async stop(stopAutoIndex = true) {
|
|
4602
|
+
if (this.stopPromise) return this.stopPromise;
|
|
4603
|
+
this.stopped = true;
|
|
4604
|
+
this.stopping = true;
|
|
4605
|
+
this.stopAutoIndexOnTeardown &&= stopAutoIndex;
|
|
4606
|
+
this.clearRetryTimer();
|
|
4607
|
+
const attempt = this.enqueue(async () => {
|
|
4608
|
+
try {
|
|
4609
|
+
const lease = this.lease;
|
|
4610
|
+
if (this.leaderWorkStopped) {
|
|
4611
|
+
if (lease) {
|
|
4612
|
+
this.releaseStoppedLease(lease);
|
|
4613
|
+
} else {
|
|
4614
|
+
this.finishStoppedLease();
|
|
4615
|
+
}
|
|
4616
|
+
return;
|
|
4617
|
+
}
|
|
4618
|
+
const hadLeaderWork = lease !== null || this.watcher !== null || this.autoIndexStarted;
|
|
4619
|
+
const stopped = await this.stopLeaderWork(hadLeaderWork && this.stopAutoIndexOnTeardown);
|
|
4620
|
+
if (!lease) {
|
|
4621
|
+
this.finishStoppedLease();
|
|
4622
|
+
return;
|
|
4623
|
+
}
|
|
4624
|
+
if (!stopped.completed) {
|
|
4625
|
+
this.releaseLeaseWhenAutoIndexStops(lease, stopped.completion);
|
|
4626
|
+
return;
|
|
4627
|
+
}
|
|
4628
|
+
this.leaderWorkStopped = true;
|
|
4629
|
+
this.releaseStoppedLease(lease);
|
|
4630
|
+
} catch (error) {
|
|
4631
|
+
this.scheduleTeardownRetry();
|
|
4632
|
+
throw error;
|
|
4633
|
+
}
|
|
4634
|
+
});
|
|
4635
|
+
const completion = attempt.finally(() => {
|
|
4636
|
+
if (this.stopPromise === completion) this.stopPromise = null;
|
|
4637
|
+
});
|
|
4638
|
+
this.stopPromise = completion;
|
|
4639
|
+
return completion;
|
|
4640
|
+
}
|
|
4641
|
+
canRun() {
|
|
4642
|
+
return this.config.indexing.autoIndex || this.hooks.watcherFactory != null;
|
|
4643
|
+
}
|
|
4644
|
+
enqueue(operation) {
|
|
4645
|
+
const next = this.transition.catch(() => void 0).then(operation);
|
|
4646
|
+
this.transition = next;
|
|
4647
|
+
return next;
|
|
4648
|
+
}
|
|
4649
|
+
startLeaderWork() {
|
|
4650
|
+
if (this.stopped || this.stopping || this.losingLeadership) return;
|
|
4651
|
+
this.startingLeaderWork = true;
|
|
4652
|
+
try {
|
|
4653
|
+
if (this.config.indexing.autoIndex && !this.autoIndexStarted) {
|
|
4654
|
+
this.autoIndexStarted = true;
|
|
4655
|
+
this.hooks.startAutoIndex("startup");
|
|
4656
|
+
}
|
|
4657
|
+
if (!this.watcher && this.hooks.watcherFactory) {
|
|
4658
|
+
try {
|
|
4659
|
+
const watcher = this.hooks.watcherFactory();
|
|
4660
|
+
this.watcher = watcher;
|
|
4661
|
+
this.leaderReady = watcher.whenReady?.().catch((error) => {
|
|
4662
|
+
console.error("[codebase-index] Failed while waiting for background file watcher startup:", error);
|
|
4663
|
+
}) ?? Promise.resolve();
|
|
4664
|
+
} catch (error) {
|
|
4665
|
+
console.error("[codebase-index] Failed to start background file watcher:", error);
|
|
4666
|
+
this.leaderReady = Promise.resolve();
|
|
4667
|
+
}
|
|
4668
|
+
}
|
|
4669
|
+
} finally {
|
|
4670
|
+
this.startingLeaderWork = false;
|
|
4671
|
+
}
|
|
4672
|
+
}
|
|
4673
|
+
async stopLeaderWork(stopAutoIndex) {
|
|
4674
|
+
const watcher = this.watcher;
|
|
4675
|
+
let watcherError;
|
|
4676
|
+
if (watcher) {
|
|
4677
|
+
try {
|
|
4678
|
+
await watcher.stop();
|
|
4679
|
+
if (this.watcher === watcher) this.watcher = null;
|
|
4680
|
+
} catch (error) {
|
|
4681
|
+
watcherError = error;
|
|
4682
|
+
}
|
|
4683
|
+
}
|
|
4684
|
+
let autoIndexError;
|
|
4685
|
+
let autoIndexStop = {
|
|
4686
|
+
completed: true,
|
|
4687
|
+
completion: Promise.resolve()
|
|
4688
|
+
};
|
|
4689
|
+
if (stopAutoIndex) {
|
|
4690
|
+
try {
|
|
4691
|
+
autoIndexStop = await this.hooks.stopAutoIndex();
|
|
4692
|
+
this.autoIndexStarted = false;
|
|
4693
|
+
} catch (error) {
|
|
4694
|
+
autoIndexError = error;
|
|
4695
|
+
}
|
|
4696
|
+
}
|
|
4697
|
+
if (watcherError !== void 0 || autoIndexError !== void 0) {
|
|
4698
|
+
throw new BackgroundWorkerStopError(watcherError, autoIndexError);
|
|
4699
|
+
}
|
|
4700
|
+
return autoIndexStop;
|
|
4701
|
+
}
|
|
4702
|
+
releaseLeaseWhenAutoIndexStops(lease, completion) {
|
|
4703
|
+
void completion.then(
|
|
4704
|
+
() => {
|
|
4705
|
+
void this.enqueue(async () => {
|
|
4706
|
+
if (this.lease !== lease || !this.stopping) return;
|
|
4707
|
+
this.leaderWorkStopped = true;
|
|
4708
|
+
this.releaseStoppedLease(lease);
|
|
4709
|
+
}).catch((error) => {
|
|
4710
|
+
console.error("[codebase-index] Failed to release background worker lease after automatic indexing stopped:", error);
|
|
4711
|
+
this.scheduleTeardownRetry();
|
|
4712
|
+
});
|
|
4713
|
+
},
|
|
4714
|
+
(error) => {
|
|
4715
|
+
console.error("[codebase-index] Failed while waiting for automatic indexing to stop:", error);
|
|
4716
|
+
this.scheduleTeardownRetry();
|
|
4717
|
+
}
|
|
4718
|
+
);
|
|
4719
|
+
}
|
|
4720
|
+
releaseStoppedLease(lease) {
|
|
4721
|
+
if (this.lease !== lease) {
|
|
4722
|
+
this.finishStoppedLease();
|
|
4723
|
+
return;
|
|
4724
|
+
}
|
|
4725
|
+
releaseLease(lease);
|
|
4726
|
+
this.lease = null;
|
|
4727
|
+
this.finishStoppedLease();
|
|
4728
|
+
}
|
|
4729
|
+
finishStoppedLease() {
|
|
4730
|
+
this.leaderWorkStopped = false;
|
|
4731
|
+
this.stopAutoIndexOnTeardown = true;
|
|
4732
|
+
this.stopping = false;
|
|
4733
|
+
this.clearTimers();
|
|
4734
|
+
this.restartAfterTeardown();
|
|
4735
|
+
if (!this.stopped || this.stopping) return;
|
|
4736
|
+
const projectKey = projectLookupKey(this.projectRoot, this.host);
|
|
4737
|
+
const key = controllerKey(this.identity, this.host);
|
|
4738
|
+
if (workers.get(key) === this) workers.delete(key);
|
|
4739
|
+
if (workerKeysByProject.get(projectKey) === key) workerKeysByProject.delete(projectKey);
|
|
4740
|
+
}
|
|
4741
|
+
startHeartbeat() {
|
|
4742
|
+
if (this.heartbeatTimer) return;
|
|
4743
|
+
const heartbeat = () => {
|
|
4744
|
+
void this.heartbeat();
|
|
4745
|
+
};
|
|
4746
|
+
this.heartbeatTimer = setInterval(heartbeat, HEARTBEAT_INTERVAL_MS);
|
|
4747
|
+
this.heartbeatTimer.unref?.();
|
|
4748
|
+
}
|
|
4749
|
+
async heartbeat() {
|
|
4750
|
+
const lease = this.lease;
|
|
4751
|
+
if (!lease || this.losingLeadership || this.stopped && !this.stopping) return;
|
|
4752
|
+
if (hasActiveReclaimMarker(lease.leasePath, lease.owner)) {
|
|
4753
|
+
await this.loseLeadership();
|
|
4754
|
+
return;
|
|
4755
|
+
}
|
|
4756
|
+
const currentOwner = readOwner(lease.leasePath);
|
|
4757
|
+
if (!currentOwner || !sameOwner2(currentOwner, lease.owner)) {
|
|
4758
|
+
await this.loseLeadership();
|
|
4759
|
+
return;
|
|
4760
|
+
}
|
|
4761
|
+
try {
|
|
4762
|
+
const nextOwner = { ...lease.owner, heartbeatAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
4763
|
+
if (!writeHeartbeat(lease.leasePath, nextOwner)) {
|
|
4764
|
+
await this.loseLeadership();
|
|
4765
|
+
return;
|
|
4766
|
+
}
|
|
4767
|
+
lease.owner = nextOwner;
|
|
4768
|
+
const refreshRequest = !this.stopping ? consumeRefreshRequest(lease.leasePath) : null;
|
|
4769
|
+
if (refreshRequest) {
|
|
4770
|
+
this.hooks.startAutoIndex("retrieval", refreshRequest.allowDisabledAutoIndex);
|
|
4771
|
+
}
|
|
4772
|
+
} catch (error) {
|
|
4773
|
+
const ownerAfterError = readOwner(lease.leasePath);
|
|
4774
|
+
if (hasActiveReclaimMarker(lease.leasePath, lease.owner) || !ownerAfterError || !sameOwner2(ownerAfterError, lease.owner)) {
|
|
4775
|
+
await this.loseLeadership();
|
|
4776
|
+
return;
|
|
4777
|
+
}
|
|
4778
|
+
console.error("[codebase-index] Failed to renew background worker lease:", error);
|
|
4779
|
+
}
|
|
4780
|
+
}
|
|
4781
|
+
async loseLeadership() {
|
|
4782
|
+
if (this.losingLeadership) return;
|
|
4783
|
+
this.losingLeadership = true;
|
|
4784
|
+
this.clearHeartbeat();
|
|
4785
|
+
await this.enqueue(async () => this.stopAfterLeadershipLoss());
|
|
4786
|
+
}
|
|
4787
|
+
async stopAfterLeadershipLoss() {
|
|
4788
|
+
const lease = this.lease;
|
|
4789
|
+
if (!lease) {
|
|
4790
|
+
this.losingLeadership = false;
|
|
4791
|
+
return;
|
|
4792
|
+
}
|
|
4793
|
+
try {
|
|
4794
|
+
const stopped = await this.stopLeaderWork(true);
|
|
4795
|
+
this.lease = null;
|
|
4796
|
+
this.losingLeadership = false;
|
|
4797
|
+
if (stopped.completed) {
|
|
4798
|
+
this.scheduleRetry();
|
|
4799
|
+
} else {
|
|
4800
|
+
void stopped.completion.then(() => this.scheduleRetry());
|
|
4801
|
+
}
|
|
4802
|
+
} catch (error) {
|
|
4803
|
+
console.error("[codebase-index] Failed to stop background work after losing its lease:", error);
|
|
4804
|
+
this.scheduleLostLeadershipTeardownRetry();
|
|
4805
|
+
}
|
|
4806
|
+
}
|
|
4807
|
+
scheduleRetry() {
|
|
4808
|
+
if (this.stopped || !this.canRun() || this.retryTimer) return;
|
|
4809
|
+
this.retryTimer = setTimeout(() => {
|
|
4810
|
+
this.retryTimer = null;
|
|
4811
|
+
this.start();
|
|
4812
|
+
}, RETRY_DELAY_MS);
|
|
4813
|
+
this.retryTimer.unref?.();
|
|
4814
|
+
}
|
|
4815
|
+
scheduleTeardownRetry() {
|
|
4816
|
+
if (!this.stopping || this.teardownRetryTimer) return;
|
|
4817
|
+
this.teardownRetryTimer = setTimeout(() => {
|
|
4818
|
+
this.teardownRetryTimer = null;
|
|
4819
|
+
void this.stop(this.stopAutoIndexOnTeardown).catch((error) => {
|
|
4820
|
+
console.error("[codebase-index] Failed to retry background worker teardown:", error);
|
|
4821
|
+
});
|
|
4822
|
+
}, RETRY_DELAY_MS);
|
|
4823
|
+
this.teardownRetryTimer.unref?.();
|
|
4824
|
+
}
|
|
4825
|
+
restartAfterTeardown() {
|
|
4826
|
+
if (!this.restartAfterStop || !this.canRun() || this.losingLeadership) return;
|
|
4827
|
+
this.restartAfterStop = false;
|
|
4828
|
+
this.stopped = false;
|
|
4829
|
+
this.start();
|
|
4830
|
+
}
|
|
4831
|
+
scheduleLostLeadershipTeardownRetry() {
|
|
4832
|
+
if (this.stopped || !this.losingLeadership || this.retryTimer) return;
|
|
4833
|
+
this.retryTimer = setTimeout(() => {
|
|
4834
|
+
this.retryTimer = null;
|
|
4835
|
+
void this.enqueue(async () => this.stopAfterLeadershipLoss());
|
|
4836
|
+
}, RETRY_DELAY_MS);
|
|
4837
|
+
this.retryTimer.unref?.();
|
|
4838
|
+
}
|
|
4839
|
+
clearHeartbeat() {
|
|
4840
|
+
if (!this.heartbeatTimer) return;
|
|
4841
|
+
clearInterval(this.heartbeatTimer);
|
|
4842
|
+
this.heartbeatTimer = null;
|
|
4843
|
+
}
|
|
4844
|
+
clearTimers() {
|
|
4845
|
+
this.clearHeartbeat();
|
|
4846
|
+
this.clearRetryTimer();
|
|
4847
|
+
if (this.teardownRetryTimer) {
|
|
4848
|
+
clearTimeout(this.teardownRetryTimer);
|
|
4849
|
+
this.teardownRetryTimer = null;
|
|
4850
|
+
}
|
|
4851
|
+
}
|
|
4852
|
+
clearRetryTimer() {
|
|
4853
|
+
if (!this.retryTimer) return;
|
|
4854
|
+
clearTimeout(this.retryTimer);
|
|
4855
|
+
this.retryTimer = null;
|
|
4856
|
+
}
|
|
4857
|
+
reportAcquireError(error) {
|
|
4858
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
4859
|
+
if (this.reportedError === message) return;
|
|
4860
|
+
this.reportedError = message;
|
|
4861
|
+
console.error("[codebase-index] Failed to acquire background worker lease:", error);
|
|
4862
|
+
}
|
|
4863
|
+
};
|
|
4864
|
+
function configureBackgroundWorker(projectRoot3, host, config, hooks, options = {}) {
|
|
4865
|
+
const projectKey = projectLookupKey(projectRoot3, host);
|
|
4866
|
+
const identity = resolveIdentity(projectRoot3, config, host);
|
|
4867
|
+
const key = controllerKey(identity, host);
|
|
4868
|
+
const previousKey = workerKeysByProject.get(projectKey);
|
|
4869
|
+
if (previousKey && previousKey !== key) {
|
|
4870
|
+
const previous = workers.get(previousKey);
|
|
4871
|
+
const previousBarrier = workerReplacementBarriers.get(projectKey) ?? Promise.resolve();
|
|
4872
|
+
const stopPrevious = previous?.stop(options.stopPreviousAutoIndex ?? true) ?? Promise.resolve();
|
|
4873
|
+
const activation = Promise.all([previousBarrier, stopPrevious]).then(() => void 0);
|
|
4874
|
+
workerReplacementBarriers.set(projectKey, activation);
|
|
4875
|
+
workers.delete(previousKey);
|
|
4876
|
+
const worker2 = new BackgroundWorkerController(projectRoot3, host, config, hooks, identity);
|
|
4877
|
+
worker2.startAfter(activation);
|
|
4878
|
+
workers.set(key, worker2);
|
|
4879
|
+
workerKeysByProject.set(projectKey, key);
|
|
4880
|
+
return;
|
|
4881
|
+
}
|
|
4882
|
+
let worker = workers.get(key);
|
|
4883
|
+
if (!worker) {
|
|
4884
|
+
worker = new BackgroundWorkerController(projectRoot3, host, config, hooks, identity);
|
|
4885
|
+
workers.set(key, worker);
|
|
4886
|
+
} else {
|
|
4887
|
+
worker.update(config, hooks, options);
|
|
4888
|
+
}
|
|
4889
|
+
workerKeysByProject.set(projectKey, key);
|
|
4890
|
+
worker.start();
|
|
4891
|
+
}
|
|
4892
|
+
function updateBackgroundWorkerConfig(projectRoot3, host, config) {
|
|
4893
|
+
const projectKey = projectLookupKey(projectRoot3, host);
|
|
4894
|
+
const key = workerKeysByProject.get(projectKey);
|
|
4895
|
+
const worker = key ? workers.get(key) : void 0;
|
|
4896
|
+
if (!worker) return;
|
|
4897
|
+
configureBackgroundWorker(projectRoot3, host, config, worker.getHooksForConfig(config), {
|
|
4898
|
+
stopPreviousAutoIndex: false,
|
|
4899
|
+
restartAutoIndex: true
|
|
4900
|
+
});
|
|
4901
|
+
}
|
|
4902
|
+
function waitForBackgroundWorkerStart(projectRoot3, host) {
|
|
4903
|
+
const key = workerKeysByProject.get(projectLookupKey(projectRoot3, host));
|
|
4904
|
+
return workers.get(key ?? "")?.waitForStart() ?? Promise.resolve();
|
|
4905
|
+
}
|
|
4906
|
+
function requestBackgroundWorkerRefresh(projectRoot3, host, allowDisabledAutoIndex = false) {
|
|
4907
|
+
const key = workerKeysByProject.get(projectLookupKey(projectRoot3, host));
|
|
4908
|
+
workers.get(key ?? "")?.requestRefresh(allowDisabledAutoIndex);
|
|
4909
|
+
}
|
|
4910
|
+
function isBackgroundWorkerManaged(projectRoot3, host) {
|
|
4911
|
+
const key = workerKeysByProject.get(projectLookupKey(projectRoot3, host));
|
|
4912
|
+
return key !== void 0 && workers.has(key);
|
|
4913
|
+
}
|
|
4914
|
+
function isBackgroundWorkerLeader(projectRoot3, host) {
|
|
4915
|
+
const key = workerKeysByProject.get(projectLookupKey(projectRoot3, host));
|
|
4916
|
+
return key !== void 0 && workers.get(key)?.isLeader() === true;
|
|
4917
|
+
}
|
|
4918
|
+
async function stopBackgroundWorker(projectRoot3, host) {
|
|
4919
|
+
const projectKey = projectLookupKey(projectRoot3, host);
|
|
4920
|
+
const key = workerKeysByProject.get(projectKey);
|
|
4921
|
+
const worker = key ? workers.get(key) : void 0;
|
|
4922
|
+
if (!worker) return;
|
|
4923
|
+
await worker.stop();
|
|
4924
|
+
}
|
|
4925
|
+
|
|
4032
4926
|
// src/utils/files.ts
|
|
4033
4927
|
var import_ignore = __toESM(require_ignore(), 1);
|
|
4034
4928
|
var import_fs7 = require("fs");
|
|
4035
|
-
var
|
|
4929
|
+
var path12 = __toESM(require("path"), 1);
|
|
4036
4930
|
var PROJECT_MARKERS = [
|
|
4037
4931
|
".git",
|
|
4038
4932
|
"package.json",
|
|
@@ -4050,7 +4944,7 @@ var PROJECT_MARKERS = [
|
|
|
4050
4944
|
];
|
|
4051
4945
|
function hasProjectMarker(projectRoot3) {
|
|
4052
4946
|
for (const marker of PROJECT_MARKERS) {
|
|
4053
|
-
if ((0, import_fs7.existsSync)(
|
|
4947
|
+
if ((0, import_fs7.existsSync)(path12.join(projectRoot3, marker))) {
|
|
4054
4948
|
return true;
|
|
4055
4949
|
}
|
|
4056
4950
|
}
|
|
@@ -4077,33 +4971,53 @@ function createIgnoreFilter(projectRoot3) {
|
|
|
4077
4971
|
"**/*build*/**"
|
|
4078
4972
|
];
|
|
4079
4973
|
ig.add(defaultIgnores);
|
|
4080
|
-
const gitignorePath =
|
|
4974
|
+
const gitignorePath = path12.join(projectRoot3, ".gitignore");
|
|
4081
4975
|
if ((0, import_fs7.existsSync)(gitignorePath)) {
|
|
4082
4976
|
const gitignoreContent = (0, import_fs7.readFileSync)(gitignorePath, "utf-8");
|
|
4083
4977
|
ig.add(gitignoreContent);
|
|
4084
4978
|
}
|
|
4085
4979
|
return ig;
|
|
4086
4980
|
}
|
|
4087
|
-
function
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
|
|
4981
|
+
function toPosixRelativePath(relativePath) {
|
|
4982
|
+
return relativePath.split(path12.sep).join("/");
|
|
4983
|
+
}
|
|
4984
|
+
function matchesAnyGlob(filePath, patterns) {
|
|
4985
|
+
const normalized = toPosixRelativePath(filePath);
|
|
4986
|
+
return patterns.some((pattern) => matchGlob(normalized, pattern));
|
|
4987
|
+
}
|
|
4988
|
+
function isExcludedByPatterns(relativePath, excludePatterns) {
|
|
4989
|
+
return matchesAnyGlob(relativePath, excludePatterns);
|
|
4990
|
+
}
|
|
4991
|
+
function isExcludedDirectory(relativePath, excludePatterns) {
|
|
4992
|
+
const normalized = toPosixRelativePath(relativePath);
|
|
4993
|
+
if (matchesAnyGlob(normalized, excludePatterns)) {
|
|
4994
|
+
return true;
|
|
4094
4995
|
}
|
|
4095
4996
|
for (const pattern of excludePatterns) {
|
|
4096
|
-
|
|
4097
|
-
|
|
4997
|
+
const posixPattern = toPosixRelativePath(pattern).replace(/\/+$/, "");
|
|
4998
|
+
if (!posixPattern.endsWith("/**")) {
|
|
4999
|
+
continue;
|
|
4098
5000
|
}
|
|
4099
|
-
|
|
4100
|
-
|
|
4101
|
-
if (matchGlob(relativePath, pattern)) {
|
|
5001
|
+
const directoryPattern = posixPattern.slice(0, -3);
|
|
5002
|
+
if (directoryPattern && matchesAnyGlob(normalized, [directoryPattern])) {
|
|
4102
5003
|
return true;
|
|
4103
5004
|
}
|
|
4104
5005
|
}
|
|
4105
5006
|
return false;
|
|
4106
5007
|
}
|
|
5008
|
+
function shouldIncludeFile(filePath, projectRoot3, includePatterns, excludePatterns, ignoreFilter) {
|
|
5009
|
+
const relativePath = toPosixRelativePath(path12.relative(projectRoot3, filePath));
|
|
5010
|
+
if (hasFilteredPathSegment(relativePath, "/")) {
|
|
5011
|
+
return false;
|
|
5012
|
+
}
|
|
5013
|
+
if (ignoreFilter.ignores(relativePath)) {
|
|
5014
|
+
return false;
|
|
5015
|
+
}
|
|
5016
|
+
if (isExcludedByPatterns(relativePath, excludePatterns)) {
|
|
5017
|
+
return false;
|
|
5018
|
+
}
|
|
5019
|
+
return matchesAnyGlob(relativePath, includePatterns);
|
|
5020
|
+
}
|
|
4107
5021
|
function matchGlob(filePath, pattern) {
|
|
4108
5022
|
if (pattern.startsWith("**/")) {
|
|
4109
5023
|
const withoutPrefix = pattern.slice(3);
|
|
@@ -4124,8 +5038,8 @@ async function* walkDirectory(dir, projectRoot3, includePatterns, excludePattern
|
|
|
4124
5038
|
const filesInDir = [];
|
|
4125
5039
|
const subdirs = [];
|
|
4126
5040
|
for (const entry of entries) {
|
|
4127
|
-
const fullPath =
|
|
4128
|
-
const relativePath =
|
|
5041
|
+
const fullPath = path12.join(dir, entry.name);
|
|
5042
|
+
const relativePath = toPosixRelativePath(path12.relative(projectRoot3, fullPath));
|
|
4129
5043
|
if (isHiddenPathSegment(entry.name)) {
|
|
4130
5044
|
if (entry.isDirectory()) {
|
|
4131
5045
|
skipped.push({ path: relativePath, reason: "excluded" });
|
|
@@ -4143,6 +5057,10 @@ async function* walkDirectory(dir, projectRoot3, includePatterns, excludePattern
|
|
|
4143
5057
|
continue;
|
|
4144
5058
|
}
|
|
4145
5059
|
if (entry.isDirectory()) {
|
|
5060
|
+
if (isExcludedDirectory(relativePath, excludePatterns)) {
|
|
5061
|
+
skipped.push({ path: relativePath, reason: "excluded" });
|
|
5062
|
+
continue;
|
|
5063
|
+
}
|
|
4146
5064
|
subdirs.push({ fullPath, relativePath });
|
|
4147
5065
|
} else if (entry.isFile()) {
|
|
4148
5066
|
const stat5 = await import_fs7.promises.stat(fullPath);
|
|
@@ -4150,20 +5068,11 @@ async function* walkDirectory(dir, projectRoot3, includePatterns, excludePattern
|
|
|
4150
5068
|
skipped.push({ path: relativePath, reason: "too_large" });
|
|
4151
5069
|
continue;
|
|
4152
5070
|
}
|
|
4153
|
-
|
|
4154
|
-
|
|
4155
|
-
|
|
4156
|
-
continue;
|
|
4157
|
-
}
|
|
4158
|
-
}
|
|
4159
|
-
let matched = false;
|
|
4160
|
-
for (const pattern of includePatterns) {
|
|
4161
|
-
if (matchGlob(relativePath, pattern)) {
|
|
4162
|
-
matched = true;
|
|
4163
|
-
break;
|
|
4164
|
-
}
|
|
5071
|
+
if (isExcludedByPatterns(relativePath, excludePatterns)) {
|
|
5072
|
+
skipped.push({ path: relativePath, reason: "excluded" });
|
|
5073
|
+
continue;
|
|
4165
5074
|
}
|
|
4166
|
-
if (
|
|
5075
|
+
if (matchesAnyGlob(relativePath, includePatterns)) {
|
|
4167
5076
|
filesInDir.push({ path: fullPath, size: stat5.size });
|
|
4168
5077
|
}
|
|
4169
5078
|
}
|
|
@@ -4174,7 +5083,7 @@ async function* walkDirectory(dir, projectRoot3, includePatterns, excludePattern
|
|
|
4174
5083
|
yield f;
|
|
4175
5084
|
}
|
|
4176
5085
|
for (let i = options.maxFilesPerDirectory; i < filesInDir.length; i++) {
|
|
4177
|
-
skipped.push({ path:
|
|
5086
|
+
skipped.push({ path: toPosixRelativePath(path12.relative(projectRoot3, filesInDir[i].path)), reason: "excluded" });
|
|
4178
5087
|
}
|
|
4179
5088
|
const canRecurse = options.maxDepth === -1 || currentDepth < options.maxDepth;
|
|
4180
5089
|
if (canRecurse) {
|
|
@@ -4214,8 +5123,8 @@ async function collectFiles(projectRoot3, includePatterns, excludePatterns, maxF
|
|
|
4214
5123
|
if (additionalRoots && additionalRoots.length > 0) {
|
|
4215
5124
|
const normalizedRoots = /* @__PURE__ */ new Set();
|
|
4216
5125
|
for (const kbRoot of additionalRoots) {
|
|
4217
|
-
const resolved =
|
|
4218
|
-
|
|
5126
|
+
const resolved = path12.normalize(
|
|
5127
|
+
path12.isAbsolute(kbRoot) ? kbRoot : path12.resolve(projectRoot3, kbRoot)
|
|
4219
5128
|
);
|
|
4220
5129
|
normalizedRoots.add(resolved);
|
|
4221
5130
|
}
|
|
@@ -4256,7 +5165,7 @@ function getErrorMessage(error) {
|
|
|
4256
5165
|
return error instanceof Error ? error.message : String(error);
|
|
4257
5166
|
}
|
|
4258
5167
|
function runCommand(file, args, options) {
|
|
4259
|
-
return new Promise((
|
|
5168
|
+
return new Promise((resolve18, reject) => {
|
|
4260
5169
|
childProcess.execFile(
|
|
4261
5170
|
file,
|
|
4262
5171
|
args,
|
|
@@ -4266,7 +5175,7 @@ function runCommand(file, args, options) {
|
|
|
4266
5175
|
reject(error);
|
|
4267
5176
|
return;
|
|
4268
5177
|
}
|
|
4269
|
-
|
|
5178
|
+
resolve18(stdout);
|
|
4270
5179
|
}
|
|
4271
5180
|
);
|
|
4272
5181
|
});
|
|
@@ -4358,8 +5267,8 @@ var AutoIndexCancelledError = class extends Error {
|
|
|
4358
5267
|
function now() {
|
|
4359
5268
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
4360
5269
|
}
|
|
4361
|
-
function
|
|
4362
|
-
const resolved =
|
|
5270
|
+
function canonicalizePath2(targetPath) {
|
|
5271
|
+
const resolved = path13.resolve(targetPath);
|
|
4363
5272
|
if ((0, import_fs8.existsSync)(resolved)) {
|
|
4364
5273
|
try {
|
|
4365
5274
|
return import_fs8.realpathSync.native(resolved);
|
|
@@ -4367,20 +5276,20 @@ function canonicalizePath(targetPath) {
|
|
|
4367
5276
|
return resolved;
|
|
4368
5277
|
}
|
|
4369
5278
|
}
|
|
4370
|
-
const parent =
|
|
5279
|
+
const parent = path13.dirname(resolved);
|
|
4371
5280
|
if (parent === resolved) return resolved;
|
|
4372
|
-
return
|
|
5281
|
+
return path13.join(canonicalizePath2(parent), path13.basename(resolved));
|
|
4373
5282
|
}
|
|
4374
5283
|
function isHomeDirectory(projectRoot3) {
|
|
4375
|
-
return
|
|
5284
|
+
return canonicalizePath2(projectRoot3) === canonicalizePath2(os5.homedir());
|
|
4376
5285
|
}
|
|
4377
|
-
function
|
|
4378
|
-
return `${host}::${
|
|
5286
|
+
function projectLookupKey2(projectRoot3, host) {
|
|
5287
|
+
return `${host}::${canonicalizePath2(projectRoot3)}`;
|
|
4379
5288
|
}
|
|
4380
5289
|
function coordinatorKey(projectRoot3, config, host) {
|
|
4381
|
-
const canonicalProjectRoot =
|
|
5290
|
+
const canonicalProjectRoot = canonicalizePath2(projectRoot3);
|
|
4382
5291
|
const indexPath = resolveProjectIndexPath(projectRoot3, config.scope, host);
|
|
4383
|
-
return `${
|
|
5292
|
+
return `${canonicalizePath2(indexPath)}::${canonicalProjectRoot}`;
|
|
4384
5293
|
}
|
|
4385
5294
|
function getProjectSafety(projectRoot3, config) {
|
|
4386
5295
|
if (isHomeDirectory(projectRoot3)) {
|
|
@@ -4411,10 +5320,10 @@ function safeFailureMessage(error) {
|
|
|
4411
5320
|
}
|
|
4412
5321
|
function cancellableDelay(delayMs, signal) {
|
|
4413
5322
|
if (signal.aborted) return Promise.reject(new AutoIndexCancelledError());
|
|
4414
|
-
return new Promise((
|
|
5323
|
+
return new Promise((resolve18, reject) => {
|
|
4415
5324
|
const timer = setTimeout(() => {
|
|
4416
5325
|
signal.removeEventListener("abort", onAbort);
|
|
4417
|
-
|
|
5326
|
+
resolve18();
|
|
4418
5327
|
}, delayMs);
|
|
4419
5328
|
timer.unref?.();
|
|
4420
5329
|
const onAbort = () => {
|
|
@@ -4426,18 +5335,44 @@ function cancellableDelay(delayMs, signal) {
|
|
|
4426
5335
|
}
|
|
4427
5336
|
function withTimeout(promise, timeoutMs) {
|
|
4428
5337
|
if (timeoutMs <= 0) return Promise.resolve(void 0);
|
|
4429
|
-
return new Promise((
|
|
4430
|
-
const timer = setTimeout(() =>
|
|
5338
|
+
return new Promise((resolve18) => {
|
|
5339
|
+
const timer = setTimeout(() => resolve18(void 0), timeoutMs);
|
|
4431
5340
|
timer.unref?.();
|
|
4432
5341
|
void promise.then((value) => {
|
|
4433
5342
|
clearTimeout(timer);
|
|
4434
|
-
|
|
5343
|
+
resolve18(value);
|
|
4435
5344
|
}, () => {
|
|
4436
5345
|
clearTimeout(timer);
|
|
4437
|
-
|
|
5346
|
+
resolve18(void 0);
|
|
4438
5347
|
});
|
|
4439
5348
|
});
|
|
4440
5349
|
}
|
|
5350
|
+
function settlesWithin(promise, timeoutMs) {
|
|
5351
|
+
if (timeoutMs <= 0) return Promise.resolve(false);
|
|
5352
|
+
return new Promise((resolve18) => {
|
|
5353
|
+
let settled = false;
|
|
5354
|
+
const timer = setTimeout(() => {
|
|
5355
|
+
if (settled) return;
|
|
5356
|
+
settled = true;
|
|
5357
|
+
resolve18(false);
|
|
5358
|
+
}, timeoutMs);
|
|
5359
|
+
timer.unref?.();
|
|
5360
|
+
void promise.then(
|
|
5361
|
+
() => {
|
|
5362
|
+
if (settled) return;
|
|
5363
|
+
settled = true;
|
|
5364
|
+
clearTimeout(timer);
|
|
5365
|
+
resolve18(true);
|
|
5366
|
+
},
|
|
5367
|
+
() => {
|
|
5368
|
+
if (settled) return;
|
|
5369
|
+
settled = true;
|
|
5370
|
+
clearTimeout(timer);
|
|
5371
|
+
resolve18(true);
|
|
5372
|
+
}
|
|
5373
|
+
);
|
|
5374
|
+
});
|
|
5375
|
+
}
|
|
4441
5376
|
function requestPriority(request) {
|
|
4442
5377
|
if (request.force) return 4;
|
|
4443
5378
|
if (request.source === "manual") return 3;
|
|
@@ -4448,6 +5383,7 @@ function mergeRequests(current, next) {
|
|
|
4448
5383
|
if (!current) return next;
|
|
4449
5384
|
const preferred = requestPriority(next) > requestPriority(current) ? next : current;
|
|
4450
5385
|
return {
|
|
5386
|
+
allowDisabledAutoIndex: current.allowDisabledAutoIndex || next.allowDisabledAutoIndex,
|
|
4451
5387
|
checkFreshness: current.checkFreshness && next.checkFreshness,
|
|
4452
5388
|
force: current.force || next.force,
|
|
4453
5389
|
onProgress: next.onProgress ?? current.onProgress,
|
|
@@ -4509,11 +5445,11 @@ var AutoIndexCoordinator = class {
|
|
|
4509
5445
|
progress: this.status.progress ? { ...this.status.progress } : void 0
|
|
4510
5446
|
};
|
|
4511
5447
|
}
|
|
4512
|
-
start(source) {
|
|
5448
|
+
start(source, allowDisabledAutoIndex = false) {
|
|
4513
5449
|
this.refreshSafety();
|
|
4514
|
-
if (!this.registration.config.indexing.autoIndex || !this.registration.safeToRun) return null;
|
|
5450
|
+
if (!this.registration.config.indexing.autoIndex && !allowDisabledAutoIndex || !this.registration.safeToRun) return null;
|
|
4515
5451
|
if (this.status.state === "failed") return this.inFlight;
|
|
4516
|
-
return this.request({ checkFreshness: true, force: false, source });
|
|
5452
|
+
return this.request({ allowDisabledAutoIndex, checkFreshness: true, force: false, source });
|
|
4517
5453
|
}
|
|
4518
5454
|
request(request) {
|
|
4519
5455
|
if (this.stopped) {
|
|
@@ -4588,13 +5524,15 @@ var AutoIndexCoordinator = class {
|
|
|
4588
5524
|
retryAttempt: void 0
|
|
4589
5525
|
});
|
|
4590
5526
|
const inFlight = this.inFlight;
|
|
4591
|
-
|
|
4592
|
-
|
|
4593
|
-
|
|
4594
|
-
|
|
4595
|
-
|
|
4596
|
-
|
|
5527
|
+
const completion = inFlight ? inFlight.then(() => void 0, () => void 0) : Promise.resolve();
|
|
5528
|
+
if (!inFlight) {
|
|
5529
|
+
return { completed: true, completion };
|
|
5530
|
+
}
|
|
5531
|
+
if (waitForCompletion) {
|
|
5532
|
+
await completion;
|
|
5533
|
+
return { completed: true, completion };
|
|
4597
5534
|
}
|
|
5535
|
+
return { completed: await settlesWithin(completion, SHUTDOWN_WAIT_MS), completion };
|
|
4598
5536
|
}
|
|
4599
5537
|
startRequest(request) {
|
|
4600
5538
|
if (this.stopped || !this.canRun(request)) {
|
|
@@ -4783,7 +5721,7 @@ var AutoIndexCoordinator = class {
|
|
|
4783
5721
|
if (request.source === "manual" || request.source === "watcher") {
|
|
4784
5722
|
return true;
|
|
4785
5723
|
}
|
|
4786
|
-
return this.registration.safeToRun && this.registration.config.indexing.autoIndex;
|
|
5724
|
+
return this.registration.safeToRun && (this.registration.config.indexing.autoIndex || request.allowDisabledAutoIndex === true);
|
|
4787
5725
|
}
|
|
4788
5726
|
shouldDeferForBattery(request) {
|
|
4789
5727
|
return this.registration.backgroundIndexingPolicy !== null && (request.source === "startup" || request.source === "watcher");
|
|
@@ -4816,17 +5754,17 @@ var AutoIndexCoordinator = class {
|
|
|
4816
5754
|
}
|
|
4817
5755
|
}
|
|
4818
5756
|
waitForBatteryRetry(delayMs) {
|
|
4819
|
-
return new Promise((
|
|
5757
|
+
return new Promise((resolve18) => {
|
|
4820
5758
|
const timer = setTimeout(() => {
|
|
4821
5759
|
if (this.batteryRetryTimer === timer) {
|
|
4822
5760
|
this.batteryRetryTimer = null;
|
|
4823
5761
|
this.resolveBatteryRetry = null;
|
|
4824
5762
|
}
|
|
4825
|
-
|
|
5763
|
+
resolve18();
|
|
4826
5764
|
}, delayMs);
|
|
4827
5765
|
timer.unref?.();
|
|
4828
5766
|
this.batteryRetryTimer = timer;
|
|
4829
|
-
this.resolveBatteryRetry =
|
|
5767
|
+
this.resolveBatteryRetry = resolve18;
|
|
4830
5768
|
});
|
|
4831
5769
|
}
|
|
4832
5770
|
cancelBatteryRetry() {
|
|
@@ -4834,9 +5772,9 @@ var AutoIndexCoordinator = class {
|
|
|
4834
5772
|
clearTimeout(this.batteryRetryTimer);
|
|
4835
5773
|
this.batteryRetryTimer = null;
|
|
4836
5774
|
}
|
|
4837
|
-
const
|
|
5775
|
+
const resolve18 = this.resolveBatteryRetry;
|
|
4838
5776
|
this.resolveBatteryRetry = null;
|
|
4839
|
-
|
|
5777
|
+
resolve18?.();
|
|
4840
5778
|
}
|
|
4841
5779
|
finishBatteryCheck(batteryCheck) {
|
|
4842
5780
|
if (this.batteryCheck !== batteryCheck) return;
|
|
@@ -4849,12 +5787,25 @@ var AutoIndexCoordinator = class {
|
|
|
4849
5787
|
}
|
|
4850
5788
|
};
|
|
4851
5789
|
function getCoordinator(projectRoot3, host) {
|
|
4852
|
-
const key = coordinatorKeysByProject.get(
|
|
5790
|
+
const key = coordinatorKeysByProject.get(projectLookupKey2(projectRoot3, host));
|
|
4853
5791
|
return key ? coordinators.get(key) ?? null : null;
|
|
4854
5792
|
}
|
|
4855
|
-
function
|
|
4856
|
-
|
|
5793
|
+
function synchronizeBackgroundWorker(projectRoot3, host, config, safeToRun) {
|
|
5794
|
+
if (safeToRun) {
|
|
5795
|
+
updateBackgroundWorkerConfig(projectRoot3, host, config);
|
|
5796
|
+
return;
|
|
5797
|
+
}
|
|
5798
|
+
void stopBackgroundWorker(projectRoot3, host).catch((error) => {
|
|
5799
|
+
console.error("[codebase-index] Failed to stop background worker after project safety changed:", error);
|
|
5800
|
+
});
|
|
5801
|
+
}
|
|
5802
|
+
function configureAutoIndex(projectRoot3, host, config, getIndexer, options = {}) {
|
|
5803
|
+
const projectKey = projectLookupKey2(projectRoot3, host);
|
|
4857
5804
|
const safety = getProjectSafety(projectRoot3, config);
|
|
5805
|
+
const synchronizeWorker = options.synchronizeBackgroundWorker ?? true;
|
|
5806
|
+
if (options.preserveManagedWorker === true && isBackgroundWorkerManaged(projectRoot3, host)) {
|
|
5807
|
+
return;
|
|
5808
|
+
}
|
|
4858
5809
|
const registration = {
|
|
4859
5810
|
backgroundIndexingPolicy: createBackgroundIndexingPolicy(
|
|
4860
5811
|
config.indexing.pauseBackgroundIndexingOnBattery
|
|
@@ -4872,6 +5823,9 @@ function configureAutoIndex(projectRoot3, host, config, getIndexer) {
|
|
|
4872
5823
|
const stopPrevious = previousCoordinator?.stop(true) ?? Promise.resolve();
|
|
4873
5824
|
const activation = Promise.all([previousBarrier, stopPrevious]).then(() => void 0);
|
|
4874
5825
|
coordinatorReplacementBarriers.set(projectKey, activation);
|
|
5826
|
+
if (synchronizeWorker) {
|
|
5827
|
+
synchronizeBackgroundWorker(projectRoot3, host, config, safety.safeToRun);
|
|
5828
|
+
}
|
|
4875
5829
|
coordinators.delete(previousKey);
|
|
4876
5830
|
const coordinator2 = new AutoIndexCoordinator(registration);
|
|
4877
5831
|
coordinator2.activateAfter(activation);
|
|
@@ -4887,8 +5841,17 @@ function configureAutoIndex(projectRoot3, host, config, getIndexer) {
|
|
|
4887
5841
|
coordinator.update(registration);
|
|
4888
5842
|
}
|
|
4889
5843
|
coordinatorKeysByProject.set(projectKey, key);
|
|
5844
|
+
if (synchronizeWorker) {
|
|
5845
|
+
synchronizeBackgroundWorker(projectRoot3, host, config, safety.safeToRun);
|
|
5846
|
+
}
|
|
5847
|
+
}
|
|
5848
|
+
function startAutoIndexForBackgroundWorker(projectRoot3, host, source = "startup", allowDisabledAutoIndex = false) {
|
|
5849
|
+
return getCoordinator(projectRoot3, host)?.start(source, allowDisabledAutoIndex) ?? null;
|
|
4890
5850
|
}
|
|
4891
5851
|
function requestBackgroundIndex(projectRoot3, host) {
|
|
5852
|
+
if (isBackgroundWorkerManaged(projectRoot3, host) && !isBackgroundWorkerLeader(projectRoot3, host)) {
|
|
5853
|
+
return null;
|
|
5854
|
+
}
|
|
4892
5855
|
return getCoordinator(projectRoot3, host)?.request({
|
|
4893
5856
|
checkFreshness: false,
|
|
4894
5857
|
force: false,
|
|
@@ -4928,15 +5891,23 @@ async function waitForAutoIndexForRetrieval(projectRoot3, host) {
|
|
|
4928
5891
|
};
|
|
4929
5892
|
}
|
|
4930
5893
|
try {
|
|
4931
|
-
|
|
5894
|
+
const readiness = await getSearchReadiness(coordinator);
|
|
5895
|
+
if (readiness.searchable) {
|
|
5896
|
+
return { ready: true };
|
|
5897
|
+
}
|
|
5898
|
+
if (readiness.blocked) return unavailableSnapshotResult(readiness.reason);
|
|
4932
5899
|
} catch {
|
|
4933
5900
|
}
|
|
4934
|
-
const job =
|
|
5901
|
+
const job = startRetrievalRefresh(projectRoot3, host, coordinator);
|
|
4935
5902
|
if (job) {
|
|
4936
5903
|
await withTimeout(job, coordinator.getWaitMs());
|
|
5904
|
+
} else if (isBackgroundWorkerManaged(projectRoot3, host)) {
|
|
5905
|
+
await waitForPublishedSnapshot(coordinator, coordinator.getWaitMs());
|
|
4937
5906
|
}
|
|
4938
5907
|
try {
|
|
4939
|
-
|
|
5908
|
+
const readiness = await getSearchReadiness(coordinator);
|
|
5909
|
+
if (readiness.searchable) return { ready: true };
|
|
5910
|
+
if (readiness.blocked) return unavailableSnapshotResult(readiness.reason);
|
|
4940
5911
|
} catch {
|
|
4941
5912
|
}
|
|
4942
5913
|
const status = coordinator.snapshot();
|
|
@@ -4957,21 +5928,52 @@ async function waitForAutoIndexForRetrieval(projectRoot3, host) {
|
|
|
4957
5928
|
text: `Automatic indexing is ${status.state}. Retry shortly or call index_status for progress. You can also run index_codebase explicitly.`
|
|
4958
5929
|
};
|
|
4959
5930
|
}
|
|
4960
|
-
async function
|
|
4961
|
-
|
|
5931
|
+
async function stopAutoIndexForBackgroundWorker(projectRoot3, host, waitForCompletion = false) {
|
|
5932
|
+
const coordinator = getCoordinator(projectRoot3, host);
|
|
5933
|
+
if (!coordinator) {
|
|
5934
|
+
return { completed: true, completion: Promise.resolve() };
|
|
5935
|
+
}
|
|
5936
|
+
return coordinator.stop(waitForCompletion);
|
|
4962
5937
|
}
|
|
4963
|
-
async function
|
|
5938
|
+
async function getSearchReadiness(coordinator) {
|
|
4964
5939
|
const indexer = coordinator.getIndexer();
|
|
4965
5940
|
if (indexer.getIndexFreshness) {
|
|
4966
5941
|
const freshness = await indexer.getIndexFreshness();
|
|
4967
|
-
|
|
5942
|
+
const searchable = freshness.readable && freshness.current && freshness.reason === "current";
|
|
5943
|
+
return {
|
|
5944
|
+
blocked: freshness.reason === "unreadable" || freshness.reason === "incompatible" || freshness.reason === "failed-batches" || freshness.reason === "migration-required",
|
|
5945
|
+
reason: freshness.reason,
|
|
5946
|
+
searchable
|
|
5947
|
+
};
|
|
5948
|
+
}
|
|
5949
|
+
const indexed = (await indexer.getStatus()).indexed;
|
|
5950
|
+
return { blocked: false, searchable: indexed };
|
|
5951
|
+
}
|
|
5952
|
+
function unavailableSnapshotResult(reason) {
|
|
5953
|
+
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.";
|
|
5954
|
+
return {
|
|
5955
|
+
ready: false,
|
|
5956
|
+
text: `${detail} Run index_codebase before retrying retrieval.`
|
|
5957
|
+
};
|
|
5958
|
+
}
|
|
5959
|
+
function startRetrievalRefresh(projectRoot3, host, coordinator) {
|
|
5960
|
+
if (isBackgroundWorkerManaged(projectRoot3, host)) {
|
|
5961
|
+
requestBackgroundWorkerRefresh(projectRoot3, host, true);
|
|
5962
|
+
return isBackgroundWorkerLeader(projectRoot3, host) ? coordinator.currentJob() : null;
|
|
5963
|
+
}
|
|
5964
|
+
return coordinator.start("retrieval") ?? coordinator.currentJob();
|
|
5965
|
+
}
|
|
5966
|
+
async function waitForPublishedSnapshot(coordinator, waitMs) {
|
|
5967
|
+
const deadline = Date.now() + waitMs;
|
|
5968
|
+
while (Date.now() < deadline) {
|
|
5969
|
+
if ((await getSearchReadiness(coordinator)).searchable) return;
|
|
5970
|
+
await new Promise((resolve18) => setTimeout(resolve18, Math.min(250, deadline - Date.now())));
|
|
4968
5971
|
}
|
|
4969
|
-
return (await indexer.getStatus()).indexed;
|
|
4970
5972
|
}
|
|
4971
5973
|
|
|
4972
5974
|
// src/tools/config-state.ts
|
|
4973
5975
|
var import_fs9 = require("fs");
|
|
4974
|
-
var
|
|
5976
|
+
var path14 = __toESM(require("path"), 1);
|
|
4975
5977
|
function normalizeKnowledgeBasePaths(config, projectRoot3) {
|
|
4976
5978
|
const normalized = { ...config };
|
|
4977
5979
|
if (Array.isArray(normalized.knowledgeBases)) {
|
|
@@ -4998,8 +6000,8 @@ function loadEditableConfig(projectRoot3, host) {
|
|
|
4998
6000
|
}
|
|
4999
6001
|
function saveConfig(projectRoot3, config, host) {
|
|
5000
6002
|
const configPath = getConfigPath(projectRoot3, host);
|
|
5001
|
-
const configDir =
|
|
5002
|
-
const configBaseDir =
|
|
6003
|
+
const configDir = path14.dirname(configPath);
|
|
6004
|
+
const configBaseDir = path14.dirname(configDir);
|
|
5003
6005
|
if (!(0, import_fs9.existsSync)(configDir)) {
|
|
5004
6006
|
(0, import_fs9.mkdirSync)(configDir, { recursive: true });
|
|
5005
6007
|
}
|
|
@@ -5014,7 +6016,7 @@ function saveConfig(projectRoot3, config, host) {
|
|
|
5014
6016
|
|
|
5015
6017
|
// src/indexer/index.ts
|
|
5016
6018
|
var import_fs12 = require("fs");
|
|
5017
|
-
var
|
|
6019
|
+
var path20 = __toESM(require("path"), 1);
|
|
5018
6020
|
var import_perf_hooks = require("perf_hooks");
|
|
5019
6021
|
var import_child_process4 = require("child_process");
|
|
5020
6022
|
var import_util4 = require("util");
|
|
@@ -5041,7 +6043,7 @@ function pTimeout(promise, options) {
|
|
|
5041
6043
|
} = options;
|
|
5042
6044
|
let timer;
|
|
5043
6045
|
let abortHandler;
|
|
5044
|
-
const wrappedPromise = new Promise((
|
|
6046
|
+
const wrappedPromise = new Promise((resolve18, reject) => {
|
|
5045
6047
|
if (typeof milliseconds !== "number" || Math.sign(milliseconds) !== 1) {
|
|
5046
6048
|
throw new TypeError(`Expected \`milliseconds\` to be a positive number, got \`${milliseconds}\``);
|
|
5047
6049
|
}
|
|
@@ -5055,7 +6057,7 @@ function pTimeout(promise, options) {
|
|
|
5055
6057
|
};
|
|
5056
6058
|
signal.addEventListener("abort", abortHandler, { once: true });
|
|
5057
6059
|
}
|
|
5058
|
-
promise.then(
|
|
6060
|
+
promise.then(resolve18, reject);
|
|
5059
6061
|
if (milliseconds === Number.POSITIVE_INFINITY) {
|
|
5060
6062
|
return;
|
|
5061
6063
|
}
|
|
@@ -5063,7 +6065,7 @@ function pTimeout(promise, options) {
|
|
|
5063
6065
|
timer = customTimers.setTimeout.call(void 0, () => {
|
|
5064
6066
|
if (fallback) {
|
|
5065
6067
|
try {
|
|
5066
|
-
|
|
6068
|
+
resolve18(fallback());
|
|
5067
6069
|
} catch (error) {
|
|
5068
6070
|
reject(error);
|
|
5069
6071
|
}
|
|
@@ -5073,7 +6075,7 @@ function pTimeout(promise, options) {
|
|
|
5073
6075
|
promise.cancel();
|
|
5074
6076
|
}
|
|
5075
6077
|
if (message === false) {
|
|
5076
|
-
|
|
6078
|
+
resolve18();
|
|
5077
6079
|
} else if (message instanceof Error) {
|
|
5078
6080
|
reject(message);
|
|
5079
6081
|
} else {
|
|
@@ -5475,7 +6477,7 @@ var PQueue = class extends import_index.default {
|
|
|
5475
6477
|
// Assign unique ID if not provided
|
|
5476
6478
|
id: options.id ?? (this.#idAssigner++).toString()
|
|
5477
6479
|
};
|
|
5478
|
-
return new Promise((
|
|
6480
|
+
return new Promise((resolve18, reject) => {
|
|
5479
6481
|
const taskSymbol = /* @__PURE__ */ Symbol(`task-${options.id}`);
|
|
5480
6482
|
let cleanupQueueAbortHandler = () => void 0;
|
|
5481
6483
|
const run = async () => {
|
|
@@ -5515,7 +6517,7 @@ var PQueue = class extends import_index.default {
|
|
|
5515
6517
|
})]);
|
|
5516
6518
|
}
|
|
5517
6519
|
const result = await operation;
|
|
5518
|
-
|
|
6520
|
+
resolve18(result);
|
|
5519
6521
|
this.emit("completed", result);
|
|
5520
6522
|
} catch (error) {
|
|
5521
6523
|
reject(error);
|
|
@@ -5703,13 +6705,13 @@ var PQueue = class extends import_index.default {
|
|
|
5703
6705
|
});
|
|
5704
6706
|
}
|
|
5705
6707
|
async #onEvent(event, filter) {
|
|
5706
|
-
return new Promise((
|
|
6708
|
+
return new Promise((resolve18) => {
|
|
5707
6709
|
const listener = () => {
|
|
5708
6710
|
if (filter && !filter()) {
|
|
5709
6711
|
return;
|
|
5710
6712
|
}
|
|
5711
6713
|
this.off(event, listener);
|
|
5712
|
-
|
|
6714
|
+
resolve18();
|
|
5713
6715
|
};
|
|
5714
6716
|
this.on(event, listener);
|
|
5715
6717
|
});
|
|
@@ -5995,7 +6997,7 @@ async function onAttemptFailure({ error, attemptNumber, retriesConsumed, startTi
|
|
|
5995
6997
|
const finalDelay = Math.min(delayTime, remainingTime);
|
|
5996
6998
|
options.signal?.throwIfAborted();
|
|
5997
6999
|
if (finalDelay > 0) {
|
|
5998
|
-
await new Promise((
|
|
7000
|
+
await new Promise((resolve18, reject) => {
|
|
5999
7001
|
const onAbort = () => {
|
|
6000
7002
|
clearTimeout(timeoutToken);
|
|
6001
7003
|
options.signal?.removeEventListener("abort", onAbort);
|
|
@@ -6003,7 +7005,7 @@ async function onAttemptFailure({ error, attemptNumber, retriesConsumed, startTi
|
|
|
6003
7005
|
};
|
|
6004
7006
|
const timeoutToken = setTimeout(() => {
|
|
6005
7007
|
options.signal?.removeEventListener("abort", onAbort);
|
|
6006
|
-
|
|
7008
|
+
resolve18();
|
|
6007
7009
|
}, finalDelay);
|
|
6008
7010
|
if (options.unref) {
|
|
6009
7011
|
timeoutToken.unref?.();
|
|
@@ -6121,17 +7123,17 @@ function validateExternalUrl(urlString) {
|
|
|
6121
7123
|
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
6122
7124
|
return { valid: false, reason: `Blocked protocol: ${parsed.protocol}` };
|
|
6123
7125
|
}
|
|
6124
|
-
const
|
|
6125
|
-
if (BLOCKED_HOSTNAMES.has(
|
|
6126
|
-
return { valid: false, reason: `Blocked: cloud metadata service (${
|
|
7126
|
+
const hostname3 = parsed.hostname.toLowerCase();
|
|
7127
|
+
if (BLOCKED_HOSTNAMES.has(hostname3)) {
|
|
7128
|
+
return { valid: false, reason: `Blocked: cloud metadata service (${hostname3})` };
|
|
6127
7129
|
}
|
|
6128
7130
|
for (const pattern of BLOCKED_METADATA_IPS) {
|
|
6129
|
-
if (pattern.test(
|
|
6130
|
-
return { valid: false, reason: `Blocked: cloud metadata IP (${
|
|
7131
|
+
if (pattern.test(hostname3)) {
|
|
7132
|
+
return { valid: false, reason: `Blocked: cloud metadata IP (${hostname3})` };
|
|
6131
7133
|
}
|
|
6132
7134
|
}
|
|
6133
|
-
if (/^169\.254\./.test(
|
|
6134
|
-
return { valid: false, reason: `Blocked: link-local address (${
|
|
7135
|
+
if (/^169\.254\./.test(hostname3)) {
|
|
7136
|
+
return { valid: false, reason: `Blocked: link-local address (${hostname3})` };
|
|
6135
7137
|
}
|
|
6136
7138
|
return { valid: true };
|
|
6137
7139
|
}
|
|
@@ -7143,8 +8145,8 @@ function extractParamNames(params) {
|
|
|
7143
8145
|
}
|
|
7144
8146
|
|
|
7145
8147
|
// src/native/binding.ts
|
|
7146
|
-
var
|
|
7147
|
-
var
|
|
8148
|
+
var os6 = __toESM(require("os"), 1);
|
|
8149
|
+
var path15 = __toESM(require("path"), 1);
|
|
7148
8150
|
var module2 = __toESM(require("module"), 1);
|
|
7149
8151
|
var import_node_url = require("url");
|
|
7150
8152
|
|
|
@@ -7181,7 +8183,7 @@ var STABLE_NATIVE_BINARY_NAME = IDENTITY_CATALOG.native.binaryName;
|
|
|
7181
8183
|
|
|
7182
8184
|
// src/native/binding.ts
|
|
7183
8185
|
var import_meta = {};
|
|
7184
|
-
function getNativeBindingFilename(platform2 =
|
|
8186
|
+
function getNativeBindingFilename(platform2 = os6.platform(), arch2 = os6.arch()) {
|
|
7185
8187
|
if (platform2 === "darwin" && arch2 === "arm64") {
|
|
7186
8188
|
return `${STABLE_NATIVE_BINARY_NAME}.darwin-arm64.node`;
|
|
7187
8189
|
}
|
|
@@ -7199,25 +8201,25 @@ function getNativeBindingFilename(platform2 = os5.platform(), arch2 = os5.arch()
|
|
|
7199
8201
|
}
|
|
7200
8202
|
throw new Error(`Unsupported platform: ${platform2}-${arch2}`);
|
|
7201
8203
|
}
|
|
7202
|
-
function resolveNativeBindingPath(packageRoot, platform2 =
|
|
7203
|
-
return
|
|
8204
|
+
function resolveNativeBindingPath(packageRoot, platform2 = os6.platform(), arch2 = os6.arch()) {
|
|
8205
|
+
return path15.join(packageRoot, "native", getNativeBindingFilename(platform2, arch2));
|
|
7204
8206
|
}
|
|
7205
8207
|
function getNativeBinding() {
|
|
7206
8208
|
let currentDir;
|
|
7207
8209
|
let requireTarget;
|
|
7208
8210
|
if (typeof import_meta !== "undefined" && import_meta.url) {
|
|
7209
|
-
currentDir =
|
|
8211
|
+
currentDir = path15.dirname((0, import_node_url.fileURLToPath)(import_meta.url));
|
|
7210
8212
|
requireTarget = import_meta.url;
|
|
7211
8213
|
} else if (typeof __dirname !== "undefined") {
|
|
7212
8214
|
currentDir = __dirname;
|
|
7213
8215
|
requireTarget = __filename;
|
|
7214
8216
|
} else {
|
|
7215
8217
|
currentDir = process.cwd();
|
|
7216
|
-
requireTarget =
|
|
8218
|
+
requireTarget = path15.join(currentDir, "index.js");
|
|
7217
8219
|
}
|
|
7218
8220
|
const normalizedDir = currentDir.replace(/\\/g, "/");
|
|
7219
|
-
const isDevMode = normalizedDir.includes("/src/native") || currentDir.includes(
|
|
7220
|
-
const packageRoot = isDevMode ?
|
|
8221
|
+
const isDevMode = normalizedDir.includes("/src/native") || currentDir.includes(path15.join("src", "native"));
|
|
8222
|
+
const packageRoot = isDevMode ? path15.resolve(currentDir, "../..") : path15.resolve(currentDir, "..");
|
|
7221
8223
|
const nativePath = resolveNativeBindingPath(packageRoot);
|
|
7222
8224
|
const require2 = module2.createRequire(requireTarget);
|
|
7223
8225
|
return require2(nativePath);
|
|
@@ -7801,8 +8803,8 @@ var Database = class _Database {
|
|
|
7801
8803
|
|
|
7802
8804
|
// src/git/branch-materialization.ts
|
|
7803
8805
|
var import_fs10 = require("fs");
|
|
7804
|
-
var
|
|
7805
|
-
var
|
|
8806
|
+
var os7 = __toESM(require("os"), 1);
|
|
8807
|
+
var path16 = __toESM(require("path"), 1);
|
|
7806
8808
|
|
|
7807
8809
|
// src/git/branch-resolution.ts
|
|
7808
8810
|
var import_child_process = require("child_process");
|
|
@@ -8121,13 +9123,13 @@ async function isWorktreeRegistered(projectRoot3, worktreePath) {
|
|
|
8121
9123
|
return false;
|
|
8122
9124
|
}
|
|
8123
9125
|
function isPathWithinRoot(filePath, rootPath) {
|
|
8124
|
-
const relative13 =
|
|
8125
|
-
return relative13 === "" || !relative13.startsWith(`..${
|
|
9126
|
+
const relative13 = path16.relative(path16.resolve(rootPath), path16.resolve(filePath));
|
|
9127
|
+
return relative13 === "" || !relative13.startsWith(`..${path16.sep}`) && relative13 !== ".." && !path16.isAbsolute(relative13);
|
|
8126
9128
|
}
|
|
8127
9129
|
async function pruneExactMissingWorktreeRegistration(projectRoot3, worktreePath) {
|
|
8128
9130
|
if (await pathExists(worktreePath)) return false;
|
|
8129
9131
|
const commonDir = await runGit(projectRoot3, ["rev-parse", "--path-format=absolute", "--git-common-dir"]);
|
|
8130
|
-
const registrationsRoot =
|
|
9132
|
+
const registrationsRoot = path16.join(commonDir, "worktrees");
|
|
8131
9133
|
let entries;
|
|
8132
9134
|
try {
|
|
8133
9135
|
entries = await import_fs10.promises.readdir(registrationsRoot, { withFileTypes: true });
|
|
@@ -8138,16 +9140,16 @@ async function pruneExactMissingWorktreeRegistration(projectRoot3, worktreePath)
|
|
|
8138
9140
|
const target = canonicalizePathForComparison(worktreePath);
|
|
8139
9141
|
for (const entry of entries) {
|
|
8140
9142
|
if (!entry.isDirectory()) continue;
|
|
8141
|
-
const registrationPath =
|
|
9143
|
+
const registrationPath = path16.join(registrationsRoot, entry.name);
|
|
8142
9144
|
if (!isPathWithinRoot(registrationPath, registrationsRoot)) continue;
|
|
8143
9145
|
let gitdirPath;
|
|
8144
9146
|
try {
|
|
8145
|
-
gitdirPath = (await import_fs10.promises.readFile(
|
|
9147
|
+
gitdirPath = (await import_fs10.promises.readFile(path16.join(registrationPath, "gitdir"), "utf8")).trim();
|
|
8146
9148
|
} catch {
|
|
8147
9149
|
continue;
|
|
8148
9150
|
}
|
|
8149
|
-
const resolvedGitdirPath =
|
|
8150
|
-
if (canonicalizePathForComparison(
|
|
9151
|
+
const resolvedGitdirPath = path16.isAbsolute(gitdirPath) ? gitdirPath : path16.resolve(registrationPath, gitdirPath);
|
|
9152
|
+
if (canonicalizePathForComparison(path16.dirname(resolvedGitdirPath)) !== target) continue;
|
|
8151
9153
|
await import_fs10.promises.rm(registrationPath, { recursive: true, force: true });
|
|
8152
9154
|
return true;
|
|
8153
9155
|
}
|
|
@@ -8165,7 +9167,7 @@ async function removeWorktree(projectRoot3, worktreePath) {
|
|
|
8165
9167
|
registered = await isWorktreeRegistered(projectRoot3, worktreePath);
|
|
8166
9168
|
} catch (error) {
|
|
8167
9169
|
errors.push(asError(error));
|
|
8168
|
-
throw new AggregateError(errors, `Could not verify temporary worktree deregistration; preserved ${
|
|
9170
|
+
throw new AggregateError(errors, `Could not verify temporary worktree deregistration; preserved ${path16.dirname(worktreePath)}`);
|
|
8169
9171
|
}
|
|
8170
9172
|
if (registered) {
|
|
8171
9173
|
try {
|
|
@@ -8181,7 +9183,7 @@ async function removeWorktree(projectRoot3, worktreePath) {
|
|
|
8181
9183
|
registered = await isWorktreeRegistered(projectRoot3, worktreePath);
|
|
8182
9184
|
} catch (error) {
|
|
8183
9185
|
errors.push(asError(error));
|
|
8184
|
-
throw new AggregateError(errors, `Could not verify temporary worktree deregistration; preserved ${
|
|
9186
|
+
throw new AggregateError(errors, `Could not verify temporary worktree deregistration; preserved ${path16.dirname(worktreePath)}`);
|
|
8185
9187
|
}
|
|
8186
9188
|
}
|
|
8187
9189
|
if (registered && !await pathExists(worktreePath)) {
|
|
@@ -8194,13 +9196,13 @@ async function removeWorktree(projectRoot3, worktreePath) {
|
|
|
8194
9196
|
}
|
|
8195
9197
|
if (registered) {
|
|
8196
9198
|
errors.push(new Error(`Temporary worktree remains registered: ${worktreePath}`));
|
|
8197
|
-
throw new AggregateError(errors, `Failed to deregister temporary worktree; preserved ${
|
|
9199
|
+
throw new AggregateError(errors, `Failed to deregister temporary worktree; preserved ${path16.dirname(worktreePath)}`);
|
|
8198
9200
|
}
|
|
8199
9201
|
try {
|
|
8200
|
-
await import_fs10.promises.rm(
|
|
9202
|
+
await import_fs10.promises.rm(path16.dirname(worktreePath), { recursive: true, force: true });
|
|
8201
9203
|
} catch (error) {
|
|
8202
9204
|
errors.push(asError(error));
|
|
8203
|
-
throw new AggregateError(errors, `Deregistered the temporary worktree but could not remove ${
|
|
9205
|
+
throw new AggregateError(errors, `Deregistered the temporary worktree but could not remove ${path16.dirname(worktreePath)}`);
|
|
8204
9206
|
}
|
|
8205
9207
|
}
|
|
8206
9208
|
async function cleanupTemporaryWorktree(projectRoot3, worktreePath, temporaryRoot) {
|
|
@@ -8236,9 +9238,9 @@ async function withMaterializedBranch(request, callback) {
|
|
|
8236
9238
|
`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.`
|
|
8237
9239
|
);
|
|
8238
9240
|
}
|
|
8239
|
-
const temporaryRoot = await import_fs10.promises.mkdtemp(
|
|
8240
|
-
const worktreePath =
|
|
8241
|
-
const hooksPath =
|
|
9241
|
+
const temporaryRoot = await import_fs10.promises.mkdtemp(path16.join(os7.tmpdir(), "codebase-index-branch-"));
|
|
9242
|
+
const worktreePath = path16.join(temporaryRoot, "worktree");
|
|
9243
|
+
const hooksPath = path16.join(temporaryRoot, "hooks");
|
|
8242
9244
|
await import_fs10.promises.mkdir(hooksPath);
|
|
8243
9245
|
const info = {
|
|
8244
9246
|
branch: request.branch,
|
|
@@ -8290,7 +9292,7 @@ async function withMaterializedBranch(request, callback) {
|
|
|
8290
9292
|
// src/tools/changed-files.ts
|
|
8291
9293
|
var import_child_process2 = require("child_process");
|
|
8292
9294
|
var import_fs11 = require("fs");
|
|
8293
|
-
var
|
|
9295
|
+
var path17 = __toESM(require("path"), 1);
|
|
8294
9296
|
var import_util2 = require("util");
|
|
8295
9297
|
var execFileAsync2 = (0, import_util2.promisify)(import_child_process2.execFile);
|
|
8296
9298
|
var GH_PR_VIEW_FIELDS = [
|
|
@@ -8432,7 +9434,7 @@ function getHeadRepositoryIdentity(data, host) {
|
|
|
8432
9434
|
return `${host}/${owner.toLowerCase()}/${repository.replace(/\.git$/i, "").toLowerCase()}`;
|
|
8433
9435
|
}
|
|
8434
9436
|
function getLocalRepositoryIdentity(projectRoot3) {
|
|
8435
|
-
let canonicalRoot =
|
|
9437
|
+
let canonicalRoot = path17.resolve(projectRoot3);
|
|
8436
9438
|
try {
|
|
8437
9439
|
canonicalRoot = import_fs11.realpathSync.native(canonicalRoot);
|
|
8438
9440
|
} catch {
|
|
@@ -8493,17 +9495,17 @@ async function getMergeBase(projectRoot3, baseCommit, headCommit) {
|
|
|
8493
9495
|
return commit;
|
|
8494
9496
|
}
|
|
8495
9497
|
function normalizeFiles(rawFiles, projectRoot3) {
|
|
8496
|
-
const root =
|
|
9498
|
+
const root = path17.resolve(projectRoot3);
|
|
8497
9499
|
const seen = /* @__PURE__ */ new Set();
|
|
8498
9500
|
const result = [];
|
|
8499
9501
|
for (const raw of rawFiles) {
|
|
8500
9502
|
if (raw.length === 0) continue;
|
|
8501
|
-
const absolute =
|
|
8502
|
-
const relative13 =
|
|
8503
|
-
if (
|
|
9503
|
+
const absolute = path17.resolve(root, raw);
|
|
9504
|
+
const relative13 = path17.relative(root, absolute);
|
|
9505
|
+
if (path17.isAbsolute(raw) || relative13 === ".." || relative13.startsWith(`..${path17.sep}`) || path17.isAbsolute(relative13)) {
|
|
8504
9506
|
throw new Error(`Changed file escapes the project root: ${JSON.stringify(raw)}`);
|
|
8505
9507
|
}
|
|
8506
|
-
const cleaned = relative13.startsWith(`.${
|
|
9508
|
+
const cleaned = relative13.startsWith(`.${path17.sep}`) ? relative13.slice(2) : relative13;
|
|
8507
9509
|
if (!seen.has(cleaned)) {
|
|
8508
9510
|
seen.add(cleaned);
|
|
8509
9511
|
result.push(cleaned);
|
|
@@ -8514,7 +9516,7 @@ function normalizeFiles(rawFiles, projectRoot3) {
|
|
|
8514
9516
|
|
|
8515
9517
|
// src/indexer/git-blame.ts
|
|
8516
9518
|
var import_child_process3 = require("child_process");
|
|
8517
|
-
var
|
|
9519
|
+
var path18 = __toESM(require("path"), 1);
|
|
8518
9520
|
var import_util3 = require("util");
|
|
8519
9521
|
var execFileAsync3 = (0, import_util3.promisify)(import_child_process3.execFile);
|
|
8520
9522
|
function parseGitBlamePorcelain(output) {
|
|
@@ -8552,7 +9554,7 @@ function parseGitBlamePorcelain(output) {
|
|
|
8552
9554
|
return Array.from(commits.values()).filter((commit) => commit.lines > 0).sort((a, b) => b.lines - a.lines || b.committedAt - a.committedAt)[0];
|
|
8553
9555
|
}
|
|
8554
9556
|
async function getChunkGitBlame(projectRoot3, filePath, startLine, endLine) {
|
|
8555
|
-
const relativePath =
|
|
9557
|
+
const relativePath = path18.relative(projectRoot3, filePath);
|
|
8556
9558
|
try {
|
|
8557
9559
|
const { stdout } = await execFileAsync3(
|
|
8558
9560
|
"git",
|
|
@@ -8884,6 +9886,9 @@ var CALL_GRAPH_SYMBOL_CHUNK_TYPES = /* @__PURE__ */ new Set([
|
|
|
8884
9886
|
"enum_declaration",
|
|
8885
9887
|
"function_definition",
|
|
8886
9888
|
"class_definition",
|
|
9889
|
+
// Ruby module/class symbols that are declaration-bearing and navigable.
|
|
9890
|
+
"class",
|
|
9891
|
+
"module",
|
|
8887
9892
|
"class_specifier",
|
|
8888
9893
|
"struct_specifier",
|
|
8889
9894
|
"namespace_definition",
|
|
@@ -9128,8 +10133,8 @@ function pathSegmentsForAffinityMatch(filePath) {
|
|
|
9128
10133
|
if (segments.length === 0) {
|
|
9129
10134
|
return [];
|
|
9130
10135
|
}
|
|
9131
|
-
const
|
|
9132
|
-
const basenameWithoutExt =
|
|
10136
|
+
const basename8 = segments[segments.length - 1] ?? "";
|
|
10137
|
+
const basenameWithoutExt = basename8.replace(/\.[^/.]+$/u, "");
|
|
9133
10138
|
const normalizedSegments = segments.map((segment) => segment.toLowerCase());
|
|
9134
10139
|
return Array.from(/* @__PURE__ */ new Set([
|
|
9135
10140
|
...normalizedSegments,
|
|
@@ -9438,8 +10443,8 @@ function hasAllEmbeddingParts(parts, expectedPartCount) {
|
|
|
9438
10443
|
|
|
9439
10444
|
// src/indexer/failed-state-persistence.ts
|
|
9440
10445
|
var fs2 = __toESM(require("fs"), 1);
|
|
9441
|
-
var
|
|
9442
|
-
var
|
|
10446
|
+
var import_node_crypto2 = require("crypto");
|
|
10447
|
+
var path19 = __toESM(require("path"), 1);
|
|
9443
10448
|
var import_node_string_decoder = require("string_decoder");
|
|
9444
10449
|
var CURRENT_FAILED_BATCH_VERSION = 1;
|
|
9445
10450
|
var DEFAULT_MALFORMED_LINE_ACTION = "skip";
|
|
@@ -9457,7 +10462,7 @@ function* readFailedBatchRecords(filePath, options = {}) {
|
|
|
9457
10462
|
function createFailedBatchWriter(targetPath) {
|
|
9458
10463
|
const temporaryPath = createTemporaryPath(targetPath);
|
|
9459
10464
|
let finalized = false;
|
|
9460
|
-
fs2.mkdirSync(
|
|
10465
|
+
fs2.mkdirSync(path19.dirname(targetPath), { recursive: true });
|
|
9461
10466
|
fs2.closeSync(fs2.openSync(temporaryPath, "w"));
|
|
9462
10467
|
const write = (record) => {
|
|
9463
10468
|
if (finalized) {
|
|
@@ -9476,7 +10481,7 @@ function createFailedBatchWriter(targetPath) {
|
|
|
9476
10481
|
if (lines.length === 0) {
|
|
9477
10482
|
return;
|
|
9478
10483
|
}
|
|
9479
|
-
fs2.mkdirSync(
|
|
10484
|
+
fs2.mkdirSync(path19.dirname(targetPath), { recursive: true });
|
|
9480
10485
|
fs2.appendFileSync(temporaryPath, `${lines.join("\n")}
|
|
9481
10486
|
`, "utf-8");
|
|
9482
10487
|
};
|
|
@@ -9484,7 +10489,7 @@ function createFailedBatchWriter(targetPath) {
|
|
|
9484
10489
|
if (finalized) {
|
|
9485
10490
|
return;
|
|
9486
10491
|
}
|
|
9487
|
-
fs2.mkdirSync(
|
|
10492
|
+
fs2.mkdirSync(path19.dirname(targetPath), { recursive: true });
|
|
9488
10493
|
fs2.renameSync(temporaryPath, targetPath);
|
|
9489
10494
|
finalized = true;
|
|
9490
10495
|
};
|
|
@@ -9630,10 +10635,10 @@ function stripLeadingBomAndWhitespace(value) {
|
|
|
9630
10635
|
return result;
|
|
9631
10636
|
}
|
|
9632
10637
|
function createTemporaryPath(targetPath) {
|
|
9633
|
-
const randomId = (0,
|
|
9634
|
-
const targetDir =
|
|
9635
|
-
const baseName =
|
|
9636
|
-
return
|
|
10638
|
+
const randomId = (0, import_node_crypto2.createHash)("sha1").update(`${Date.now()}:${(0, import_node_crypto2.randomBytes)(8).toString("hex")}`).digest("hex");
|
|
10639
|
+
const targetDir = path19.dirname(targetPath);
|
|
10640
|
+
const baseName = path19.basename(targetPath);
|
|
10641
|
+
return path19.join(targetDir, `.${baseName}.${randomId}.tmp`);
|
|
9637
10642
|
}
|
|
9638
10643
|
function handleMalformedLine(filePath, lineNumber, line, error, options) {
|
|
9639
10644
|
const action = options.malformedLineAction ?? DEFAULT_MALFORMED_LINE_ACTION;
|
|
@@ -9879,9 +10884,9 @@ var SWIFT_PARSER_VERSION = "1";
|
|
|
9879
10884
|
var METAL_PARSER_VERSION = "1";
|
|
9880
10885
|
var SYMBOL_EXTRACTOR_VERSION = "1";
|
|
9881
10886
|
function isPathWithinRoot2(filePath, rootPath) {
|
|
9882
|
-
const normalizedFilePath =
|
|
9883
|
-
const normalizedRoot =
|
|
9884
|
-
return normalizedFilePath === normalizedRoot || normalizedFilePath.startsWith(`${normalizedRoot}${
|
|
10887
|
+
const normalizedFilePath = path20.resolve(filePath);
|
|
10888
|
+
const normalizedRoot = path20.resolve(rootPath);
|
|
10889
|
+
return normalizedFilePath === normalizedRoot || normalizedFilePath.startsWith(`${normalizedRoot}${path20.sep}`);
|
|
9885
10890
|
}
|
|
9886
10891
|
function promoteIdentifierMatches(query, combined, semanticCandidates, keywordCandidates, database, branchChunkIds, prioritizeSourcePaths = classifyQueryIntentRaw(query) === "source") {
|
|
9887
10892
|
if (combined.length === 0) {
|
|
@@ -10212,10 +11217,10 @@ function matchesHardSearchFilters(candidate, options, projectRoot3) {
|
|
|
10212
11217
|
}
|
|
10213
11218
|
if (options?.directory) {
|
|
10214
11219
|
const candidatePath = canonicalizePathForComparison(
|
|
10215
|
-
|
|
11220
|
+
path20.resolve(projectRoot3, candidate.metadata.filePath.replace(/\\/g, path20.sep))
|
|
10216
11221
|
);
|
|
10217
11222
|
const directoryPath = canonicalizePathForComparison(
|
|
10218
|
-
|
|
11223
|
+
path20.resolve(projectRoot3, options.directory.trim().replace(/\\/g, path20.sep))
|
|
10219
11224
|
);
|
|
10220
11225
|
if (!isPathWithinRoot2(candidatePath, directoryPath)) return false;
|
|
10221
11226
|
}
|
|
@@ -10328,26 +11333,37 @@ var Indexer = class _Indexer {
|
|
|
10328
11333
|
return this.indexPathOverride ?? resolveProjectIndexPath(this.projectRoot, this.config.scope, this.host);
|
|
10329
11334
|
}
|
|
10330
11335
|
toCanonicalFilePath(filePath) {
|
|
10331
|
-
if (!
|
|
11336
|
+
if (!path20.isAbsolute(filePath)) {
|
|
10332
11337
|
return this.resolveStoredFilePath(filePath, this.projectRoot);
|
|
10333
11338
|
}
|
|
10334
|
-
if (
|
|
11339
|
+
if (path20.resolve(this.materializedProjectRoot) === path20.resolve(this.projectRoot) || !isPathWithinRoot2(filePath, this.materializedProjectRoot)) {
|
|
10335
11340
|
return filePath;
|
|
10336
11341
|
}
|
|
10337
|
-
return
|
|
11342
|
+
return path20.resolve(this.projectRoot, path20.relative(this.materializedProjectRoot, filePath));
|
|
10338
11343
|
}
|
|
10339
11344
|
toStoredFilePath(filePath) {
|
|
10340
11345
|
const canonicalFilePath = this.toCanonicalFilePath(filePath);
|
|
10341
11346
|
if (this.config.scope !== "project" || !isPathWithinRoot2(canonicalFilePath, this.projectRoot)) {
|
|
10342
11347
|
return canonicalFilePath;
|
|
10343
11348
|
}
|
|
10344
|
-
return
|
|
11349
|
+
return path20.relative(this.projectRoot, canonicalFilePath).split(path20.sep).join("/");
|
|
11350
|
+
}
|
|
11351
|
+
isStoredPathExcluded(storedPath) {
|
|
11352
|
+
let matchPath = storedPath.split(path20.sep).join("/");
|
|
11353
|
+
if (path20.isAbsolute(storedPath)) {
|
|
11354
|
+
const relativePath = path20.relative(this.projectRoot, storedPath).split(path20.sep).join("/");
|
|
11355
|
+
if (relativePath.startsWith("..") || path20.isAbsolute(relativePath)) {
|
|
11356
|
+
return false;
|
|
11357
|
+
}
|
|
11358
|
+
matchPath = relativePath;
|
|
11359
|
+
}
|
|
11360
|
+
return isExcludedByPatterns(matchPath, this.config.exclude);
|
|
10345
11361
|
}
|
|
10346
11362
|
resolveStoredFilePath(filePath, rootPath = this.projectRoot) {
|
|
10347
|
-
if (
|
|
11363
|
+
if (path20.isAbsolute(filePath)) {
|
|
10348
11364
|
return filePath;
|
|
10349
11365
|
}
|
|
10350
|
-
const resolvedPath =
|
|
11366
|
+
const resolvedPath = path20.resolve(rootPath, ...filePath.split("/"));
|
|
10351
11367
|
if (!isPathWithinRoot2(resolvedPath, rootPath)) {
|
|
10352
11368
|
throw new Error(`Stored project path escapes project root: ${JSON.stringify(filePath)}`);
|
|
10353
11369
|
}
|
|
@@ -10371,7 +11387,7 @@ var Indexer = class _Indexer {
|
|
|
10371
11387
|
}
|
|
10372
11388
|
toMaterializedFilePath(filePath) {
|
|
10373
11389
|
const storedFilePath = this.toStoredFilePath(filePath);
|
|
10374
|
-
if (
|
|
11390
|
+
if (path20.isAbsolute(storedFilePath)) {
|
|
10375
11391
|
return storedFilePath;
|
|
10376
11392
|
}
|
|
10377
11393
|
return this.resolveStoredFilePath(storedFilePath, this.materializedProjectRoot);
|
|
@@ -10388,10 +11404,10 @@ var Indexer = class _Indexer {
|
|
|
10388
11404
|
}
|
|
10389
11405
|
getRuntimeArtifactPath(fileName) {
|
|
10390
11406
|
const namespace = this.getRuntimeArtifactNamespace();
|
|
10391
|
-
if (!namespace) return
|
|
10392
|
-
const extension =
|
|
11407
|
+
if (!namespace) return path20.join(this.indexPath, fileName);
|
|
11408
|
+
const extension = path20.extname(fileName);
|
|
10393
11409
|
const baseName = fileName.slice(0, fileName.length - extension.length);
|
|
10394
|
-
return
|
|
11410
|
+
return path20.join(this.indexPath, `${baseName}.${namespace}${extension}`);
|
|
10395
11411
|
}
|
|
10396
11412
|
refreshRuntimeArtifactPaths() {
|
|
10397
11413
|
this.fileHashCachePath = this.getRuntimeArtifactPath("file-hashes.json");
|
|
@@ -10404,14 +11420,14 @@ var Indexer = class _Indexer {
|
|
|
10404
11420
|
getMaterializedKnowledgeBases() {
|
|
10405
11421
|
const canonicalProjectRoot = this.getCanonicalPath(this.projectRoot);
|
|
10406
11422
|
return this.config.knowledgeBases.map((knowledgeBase) => {
|
|
10407
|
-
const configuredPath =
|
|
11423
|
+
const configuredPath = path20.isAbsolute(knowledgeBase) ? knowledgeBase : path20.resolve(this.projectRoot, knowledgeBase);
|
|
10408
11424
|
const canonicalPath = this.getCanonicalPath(configuredPath);
|
|
10409
11425
|
if (!isPathWithinRoot2(canonicalPath, canonicalProjectRoot)) {
|
|
10410
11426
|
return canonicalPath;
|
|
10411
11427
|
}
|
|
10412
|
-
return
|
|
11428
|
+
return path20.resolve(
|
|
10413
11429
|
this.materializedProjectRoot,
|
|
10414
|
-
|
|
11430
|
+
path20.relative(canonicalProjectRoot, canonicalPath)
|
|
10415
11431
|
);
|
|
10416
11432
|
});
|
|
10417
11433
|
}
|
|
@@ -10419,7 +11435,7 @@ var Indexer = class _Indexer {
|
|
|
10419
11435
|
try {
|
|
10420
11436
|
return canonicalizePathForComparison(targetPath);
|
|
10421
11437
|
} catch {
|
|
10422
|
-
return
|
|
11438
|
+
return path20.resolve(targetPath);
|
|
10423
11439
|
}
|
|
10424
11440
|
}
|
|
10425
11441
|
getProjectIdentityHash(projectRoot3) {
|
|
@@ -10545,7 +11561,7 @@ var Indexer = class _Indexer {
|
|
|
10545
11561
|
atomicWriteSync(targetPath, data) {
|
|
10546
11562
|
const lease = this.requireActiveLease();
|
|
10547
11563
|
const tempPath = createLeaseTemporaryPath(targetPath, lease.owner, "tmp");
|
|
10548
|
-
(0, import_fs12.mkdirSync)(
|
|
11564
|
+
(0, import_fs12.mkdirSync)(path20.dirname(targetPath), { recursive: true });
|
|
10549
11565
|
try {
|
|
10550
11566
|
(0, import_fs12.writeFileSync)(tempPath, data);
|
|
10551
11567
|
(0, import_fs12.renameSync)(tempPath, targetPath);
|
|
@@ -10555,14 +11571,14 @@ var Indexer = class _Indexer {
|
|
|
10555
11571
|
}
|
|
10556
11572
|
saveInvertedIndex(invertedIndex) {
|
|
10557
11573
|
this.atomicWriteSync(
|
|
10558
|
-
|
|
11574
|
+
path20.join(this.indexPath, "inverted-index.json"),
|
|
10559
11575
|
invertedIndex.serialize()
|
|
10560
11576
|
);
|
|
10561
11577
|
}
|
|
10562
11578
|
getScopedRoots(projectRoot3 = this.projectRoot) {
|
|
10563
11579
|
const roots = /* @__PURE__ */ new Set([this.getCanonicalPath(projectRoot3)]);
|
|
10564
11580
|
for (const kbRoot of this.config.knowledgeBases) {
|
|
10565
|
-
roots.add(this.getCanonicalPath(
|
|
11581
|
+
roots.add(this.getCanonicalPath(path20.resolve(projectRoot3, kbRoot)));
|
|
10566
11582
|
}
|
|
10567
11583
|
return Array.from(roots);
|
|
10568
11584
|
}
|
|
@@ -10979,7 +11995,7 @@ var Indexer = class _Indexer {
|
|
|
10979
11995
|
return configuredProviderInfo !== null && recovery.embeddingProvider === configuredProviderInfo.provider && recovery.embeddingModel === configuredProviderInfo.modelInfo.model && recovery.embeddingDimensions === configuredProviderInfo.modelInfo.dimensions && recovery.embeddingStrategyVersion === EMBEDDING_STRATEGY_VERSION;
|
|
10980
11996
|
}
|
|
10981
11997
|
hasUnknownLegacyForceIndexClear(owner) {
|
|
10982
|
-
return owner.operation === "force-index" && owner.clearRecovery === void 0 && owner.recoveryProtocolVersion !== 1 && (0, import_fs12.existsSync)(
|
|
11998
|
+
return owner.operation === "force-index" && owner.clearRecovery === void 0 && owner.recoveryProtocolVersion !== 1 && (0, import_fs12.existsSync)(path20.join(this.indexPath, "force-index-phase"));
|
|
10983
11999
|
}
|
|
10984
12000
|
async recoverFromInterruptedIndexingUnlocked(owners) {
|
|
10985
12001
|
for (const owner of owners) {
|
|
@@ -11367,7 +12383,7 @@ var Indexer = class _Indexer {
|
|
|
11367
12383
|
await options.queue.onSizeLessThan(Math.max(1, options.providerRateLimits.concurrency));
|
|
11368
12384
|
const task = options.queue.add(async () => {
|
|
11369
12385
|
if (options.rateLimitState.backoffMs > 0) {
|
|
11370
|
-
await new Promise((
|
|
12386
|
+
await new Promise((resolve18) => setTimeout(resolve18, options.rateLimitState.backoffMs));
|
|
11371
12387
|
}
|
|
11372
12388
|
try {
|
|
11373
12389
|
const embeddingResult = await pRetry(
|
|
@@ -11786,12 +12802,12 @@ var Indexer = class _Indexer {
|
|
|
11786
12802
|
}
|
|
11787
12803
|
}
|
|
11788
12804
|
captureReaderArtifactFingerprint() {
|
|
11789
|
-
const storePath =
|
|
12805
|
+
const storePath = path20.join(this.indexPath, "vectors");
|
|
11790
12806
|
return {
|
|
11791
12807
|
vectors: `${this.getReaderFileFingerprint(storePath)}|${this.getReaderFileFingerprint(`${storePath}.meta.json`)}`,
|
|
11792
|
-
keyword: this.getReaderFileFingerprint(
|
|
11793
|
-
database: this.getReaderFileFingerprint(
|
|
11794
|
-
databaseIdentity: this.getReaderFileFingerprint(
|
|
12808
|
+
keyword: this.getReaderFileFingerprint(path20.join(this.indexPath, "inverted-index.json")),
|
|
12809
|
+
database: this.getReaderFileFingerprint(path20.join(this.indexPath, "codebase.db")),
|
|
12810
|
+
databaseIdentity: this.getReaderFileFingerprint(path20.join(this.indexPath, "codebase.db"), true)
|
|
11795
12811
|
};
|
|
11796
12812
|
}
|
|
11797
12813
|
refreshReaderArtifacts() {
|
|
@@ -11816,10 +12832,10 @@ var Indexer = class _Indexer {
|
|
|
11816
12832
|
issues.set(component, this.createReadIssue(component, message));
|
|
11817
12833
|
this.readerArtifactRetryAfter.set(component, Date.now() + READER_ARTIFACT_RETRY_INTERVAL_MS);
|
|
11818
12834
|
};
|
|
11819
|
-
const storePath =
|
|
12835
|
+
const storePath = path20.join(this.indexPath, "vectors");
|
|
11820
12836
|
const vectorMetadataPath = `${storePath}.meta.json`;
|
|
11821
|
-
const invertedIndexPath =
|
|
11822
|
-
const dbPath =
|
|
12837
|
+
const invertedIndexPath = path20.join(this.indexPath, "inverted-index.json");
|
|
12838
|
+
const dbPath = path20.join(this.indexPath, "codebase.db");
|
|
11823
12839
|
if (vectorsChanged || retryDue("vectors")) {
|
|
11824
12840
|
const vectorStoreExists = (0, import_fs12.existsSync)(storePath);
|
|
11825
12841
|
const vectorMetadataExists = (0, import_fs12.existsSync)(vectorMetadataPath);
|
|
@@ -11935,10 +12951,10 @@ var Indexer = class _Indexer {
|
|
|
11935
12951
|
});
|
|
11936
12952
|
this.provider = createEmbeddingProvider(this.configuredProviderInfo);
|
|
11937
12953
|
const dimensions = this.configuredProviderInfo.modelInfo.dimensions;
|
|
11938
|
-
const storePath =
|
|
12954
|
+
const storePath = path20.join(this.indexPath, "vectors");
|
|
11939
12955
|
const vectorMetadataPath = `${storePath}.meta.json`;
|
|
11940
|
-
const invertedIndexPath =
|
|
11941
|
-
const dbPath =
|
|
12956
|
+
const invertedIndexPath = path20.join(this.indexPath, "inverted-index.json");
|
|
12957
|
+
const dbPath = path20.join(this.indexPath, "codebase.db");
|
|
11942
12958
|
let dbIsNew = !(0, import_fs12.existsSync)(dbPath);
|
|
11943
12959
|
const readerArtifactFingerprint = mode === "reader" ? this.captureReaderArtifactFingerprint() : null;
|
|
11944
12960
|
if (mode === "writer") {
|
|
@@ -12116,7 +13132,7 @@ var Indexer = class _Indexer {
|
|
|
12116
13132
|
if (await this.tryResetCorruptedIndex("running automatic orphan garbage collection", error)) {
|
|
12117
13133
|
return {
|
|
12118
13134
|
resetCorruptedIndex: true,
|
|
12119
|
-
warning: this.getCorruptedIndexWarning(
|
|
13135
|
+
warning: this.getCorruptedIndexWarning(path20.join(this.indexPath, "codebase.db"))
|
|
12120
13136
|
};
|
|
12121
13137
|
}
|
|
12122
13138
|
throw error;
|
|
@@ -12131,7 +13147,7 @@ var Indexer = class _Indexer {
|
|
|
12131
13147
|
return;
|
|
12132
13148
|
}
|
|
12133
13149
|
const retainedEntries = store.getAllMetadata().filter(({ key }) => !excludedSet.has(key));
|
|
12134
|
-
const storeBasePath =
|
|
13150
|
+
const storeBasePath = path20.join(this.indexPath, "vectors");
|
|
12135
13151
|
const storeIndexPath = storeBasePath;
|
|
12136
13152
|
const storeMetadataPath = `${storeBasePath}.meta.json`;
|
|
12137
13153
|
const lease = this.requireActiveLease();
|
|
@@ -12218,7 +13234,7 @@ var Indexer = class _Indexer {
|
|
|
12218
13234
|
const names = await import_fs12.promises.readdir(this.indexPath);
|
|
12219
13235
|
const runtimeStatePattern = /^(?:file-hashes|failed-batches)(?:\.[a-f0-9]{16})?\.json$/;
|
|
12220
13236
|
await Promise.all(
|
|
12221
|
-
names.filter((name) => runtimeStatePattern.test(name)).map((name) => import_fs12.promises.rm(
|
|
13237
|
+
names.filter((name) => runtimeStatePattern.test(name)).map((name) => import_fs12.promises.rm(path20.join(this.indexPath, name), { force: true }))
|
|
12222
13238
|
);
|
|
12223
13239
|
}
|
|
12224
13240
|
async resetLocalIndexArtifacts() {
|
|
@@ -12234,13 +13250,13 @@ var Indexer = class _Indexer {
|
|
|
12234
13250
|
this.readerArtifactRetryAfter.clear();
|
|
12235
13251
|
this.fileHashCache.clear();
|
|
12236
13252
|
const resetPaths = [
|
|
12237
|
-
|
|
12238
|
-
|
|
12239
|
-
|
|
12240
|
-
|
|
12241
|
-
|
|
12242
|
-
|
|
12243
|
-
|
|
13253
|
+
path20.join(this.indexPath, "codebase.db"),
|
|
13254
|
+
path20.join(this.indexPath, "codebase.db-shm"),
|
|
13255
|
+
path20.join(this.indexPath, "codebase.db-wal"),
|
|
13256
|
+
path20.join(this.indexPath, "vectors"),
|
|
13257
|
+
path20.join(this.indexPath, "vectors.usearch"),
|
|
13258
|
+
path20.join(this.indexPath, "vectors.meta.json"),
|
|
13259
|
+
path20.join(this.indexPath, "inverted-index.json")
|
|
12244
13260
|
];
|
|
12245
13261
|
await Promise.all(resetPaths.map((targetPath) => import_fs12.promises.rm(targetPath, { recursive: true, force: true })));
|
|
12246
13262
|
await this.removeProjectRuntimeStateArtifacts();
|
|
@@ -12250,7 +13266,7 @@ var Indexer = class _Indexer {
|
|
|
12250
13266
|
if (!isSqliteCorruptionError(error)) {
|
|
12251
13267
|
return false;
|
|
12252
13268
|
}
|
|
12253
|
-
const dbPath =
|
|
13269
|
+
const dbPath = path20.join(this.indexPath, "codebase.db");
|
|
12254
13270
|
const warning = this.getCorruptedIndexWarning(dbPath);
|
|
12255
13271
|
const errorMessage = getErrorMessage4(error);
|
|
12256
13272
|
if (this.config.scope === "global") {
|
|
@@ -12484,6 +13500,70 @@ var Indexer = class _Indexer {
|
|
|
12484
13500
|
);
|
|
12485
13501
|
return createCostEstimate(files, configuredProviderInfo);
|
|
12486
13502
|
}
|
|
13503
|
+
// Dry-run counterpart to index()/forceIndex(): parse the real file set and sum
|
|
13504
|
+
// estimateTokens over the embedding text of every indexable chunk, without
|
|
13505
|
+
// calling the embedding provider or writing to the index. Read-only and
|
|
13506
|
+
// lock-free (mirrors estimateCost). The token sum is the exact value "Tokens
|
|
13507
|
+
// used" climbs to for a force index (cache bypassed); for an incremental it is
|
|
13508
|
+
// an upper bound because cached chunks are counted here but not re-embedded.
|
|
13509
|
+
// Used by index_codebase(dryRun:true) to give a stable, monotonic progress
|
|
13510
|
+
// denominator that matches the live "Tokens used" basis.
|
|
13511
|
+
async dryRunCost() {
|
|
13512
|
+
const { configuredProviderInfo } = await this.ensureInitialized();
|
|
13513
|
+
const maxChunkTokens = getSafeEmbeddingChunkTokenLimit(configuredProviderInfo);
|
|
13514
|
+
const includePatterns = [...this.config.include, ...this.config.additionalInclude];
|
|
13515
|
+
const { files } = await collectFiles(
|
|
13516
|
+
this.materializedProjectRoot,
|
|
13517
|
+
includePatterns,
|
|
13518
|
+
this.config.exclude,
|
|
13519
|
+
this.config.indexing.maxFileSize,
|
|
13520
|
+
this.getMaterializedKnowledgeBases(),
|
|
13521
|
+
{ maxDepth: this.config.indexing.maxDepth, maxFilesPerDirectory: this.config.indexing.maxFilesPerDirectory }
|
|
13522
|
+
);
|
|
13523
|
+
let filesCount = 0;
|
|
13524
|
+
let chunksCount = 0;
|
|
13525
|
+
let tokensToEmbed = 0;
|
|
13526
|
+
for (const batch of iterateOrderedFileBatches(files, (f) => f.size, this.fileBatchLimits)) {
|
|
13527
|
+
const loadedFiles = await Promise.all(batch.map(async (f) => {
|
|
13528
|
+
try {
|
|
13529
|
+
return {
|
|
13530
|
+
path: this.toStoredFilePath(f.path),
|
|
13531
|
+
content: await import_fs12.promises.readFile(f.path, "utf-8")
|
|
13532
|
+
};
|
|
13533
|
+
} catch {
|
|
13534
|
+
return null;
|
|
13535
|
+
}
|
|
13536
|
+
}));
|
|
13537
|
+
const readable = loadedFiles.filter(
|
|
13538
|
+
(f) => f !== null
|
|
13539
|
+
);
|
|
13540
|
+
filesCount += readable.length;
|
|
13541
|
+
const contentByPath = new Map(readable.map((f) => [f.path, f.content]));
|
|
13542
|
+
const parsedFiles = parseFiles(readable, this.config.indexing.linesPerChunk);
|
|
13543
|
+
for (const parsed of parsedFiles) {
|
|
13544
|
+
let chunksToProcess = parsed.chunks;
|
|
13545
|
+
if (this.config.indexing.fallbackToTextOnMaxChunks && chunksToProcess.length > this.config.indexing.maxChunksPerFile) {
|
|
13546
|
+
const content = contentByPath.get(parsed.path);
|
|
13547
|
+
if (content !== void 0) {
|
|
13548
|
+
chunksToProcess = parseFileAsText(parsed.path, content, this.config.indexing.linesPerChunk);
|
|
13549
|
+
}
|
|
13550
|
+
}
|
|
13551
|
+
chunksToProcess = selectIndexableChunks(
|
|
13552
|
+
chunksToProcess,
|
|
13553
|
+
this.config.indexing.maxChunksPerFile,
|
|
13554
|
+
this.config.indexing.semanticOnly
|
|
13555
|
+
);
|
|
13556
|
+
for (const chunk of chunksToProcess) {
|
|
13557
|
+
const texts = createEmbeddingTexts(chunk, parsed.path, maxChunkTokens);
|
|
13558
|
+
chunksCount += 1;
|
|
13559
|
+
for (const text3 of texts) {
|
|
13560
|
+
tokensToEmbed += estimateTokens(text3);
|
|
13561
|
+
}
|
|
13562
|
+
}
|
|
13563
|
+
}
|
|
13564
|
+
}
|
|
13565
|
+
return { filesCount, chunksCount, tokensToEmbed };
|
|
13566
|
+
}
|
|
12487
13567
|
async index(onProgress) {
|
|
12488
13568
|
return this.withIndexMutationLease("index", async (recoveredOwners) => {
|
|
12489
13569
|
return this.indexUnlocked(onProgress, recoveredOwners);
|
|
@@ -12573,10 +13653,10 @@ var Indexer = class _Indexer {
|
|
|
12573
13653
|
const reparseCachedMetalFiles = database.getMetadata(metalParserMetadataKey) !== METAL_PARSER_VERSION;
|
|
12574
13654
|
const symbolExtractorMetadataKey = this.getSymbolExtractorVersionMetadataKey();
|
|
12575
13655
|
const refreshCachedSymbols = database.getMetadata(symbolExtractorMetadataKey) !== SYMBOL_EXTRACTOR_VERSION;
|
|
12576
|
-
if (reparseCachedSwiftFiles && Array.from(this.fileHashCache.keys()).some((filePath) =>
|
|
13656
|
+
if (reparseCachedSwiftFiles && Array.from(this.fileHashCache.keys()).some((filePath) => path20.extname(filePath).toLowerCase() === ".swift")) {
|
|
12577
13657
|
this.logger.info("Reindexing cached Swift files for parser support");
|
|
12578
13658
|
}
|
|
12579
|
-
if (reparseCachedMetalFiles && Array.from(this.fileHashCache.keys()).some((filePath) =>
|
|
13659
|
+
if (reparseCachedMetalFiles && Array.from(this.fileHashCache.keys()).some((filePath) => path20.extname(filePath).toLowerCase() === ".metal")) {
|
|
12580
13660
|
this.logger.info("Reindexing cached Metal files for parser support");
|
|
12581
13661
|
}
|
|
12582
13662
|
const includePatterns = [...this.config.include, ...this.config.additionalInclude];
|
|
@@ -12620,8 +13700,8 @@ var Indexer = class _Indexer {
|
|
|
12620
13700
|
const needsCallGraphRefresh = cachedHashMatches && needsCallGraphResolutionMigration && database.getChunksByFile(storedPath).some(
|
|
12621
13701
|
(chunk) => chunk.language === "php" || chunk.language === "c" || chunk.language === "cpp"
|
|
12622
13702
|
);
|
|
12623
|
-
const requiresSwiftParserUpgrade = reparseCachedSwiftFiles &&
|
|
12624
|
-
const requiresMetalParserUpgrade = reparseCachedMetalFiles &&
|
|
13703
|
+
const requiresSwiftParserUpgrade = reparseCachedSwiftFiles && path20.extname(storedPath).toLowerCase() === ".swift";
|
|
13704
|
+
const requiresMetalParserUpgrade = reparseCachedMetalFiles && path20.extname(storedPath).toLowerCase() === ".metal";
|
|
12625
13705
|
const inMigrationScope = forceScopedReembed && scopedRoots !== null && this.isFileInCurrentScope(storedPath, scopedRoots);
|
|
12626
13706
|
if (cachedHashMatches && !inMigrationScope && !needsCallGraphRefresh && !requiresSwiftParserUpgrade && !requiresMetalParserUpgrade && !refreshCachedSymbols) {
|
|
12627
13707
|
unchangedFilePaths.add(storedPath);
|
|
@@ -12680,7 +13760,7 @@ var Indexer = class _Indexer {
|
|
|
12680
13760
|
}
|
|
12681
13761
|
}
|
|
12682
13762
|
}
|
|
12683
|
-
const shouldRetryFailedPath = (filePath) => filePath !== null && currentFileHashes.has(filePath) && unchangedFilePaths.has(filePath);
|
|
13763
|
+
const shouldRetryFailedPath = (filePath) => filePath !== null && !this.isStoredPathExcluded(filePath) && currentFileHashes.has(filePath) && unchangedFilePaths.has(filePath);
|
|
12684
13764
|
const failedProcessing = this.prepareFailedBatchProcessing(scopedRoots, shouldRetryFailedPath);
|
|
12685
13765
|
const maxChunkTokens = getSafeEmbeddingChunkTokenLimit(configuredProviderInfo);
|
|
12686
13766
|
const providerRateLimits = this.getProviderRateLimits(configuredProviderInfo.provider);
|
|
@@ -12784,7 +13864,7 @@ var Indexer = class _Indexer {
|
|
|
12784
13864
|
throw new Error(`Parsed file was not present in its source batch: ${parsed.path}`);
|
|
12785
13865
|
}
|
|
12786
13866
|
if (parsed.chunks.length === 0) {
|
|
12787
|
-
stats.parseFailures.push(
|
|
13867
|
+
stats.parseFailures.push(path20.isAbsolute(parsed.path) ? path20.relative(this.projectRoot, parsed.path) : parsed.path);
|
|
12788
13868
|
}
|
|
12789
13869
|
let chunksToProcess = parsed.chunks;
|
|
12790
13870
|
if (this.config.indexing.fallbackToTextOnMaxChunks && chunksToProcess.length > this.config.indexing.maxChunksPerFile) {
|
|
@@ -13119,7 +14199,7 @@ var Indexer = class _Indexer {
|
|
|
13119
14199
|
previousBranchSymbolIds,
|
|
13120
14200
|
Array.from(allSymbolIds)
|
|
13121
14201
|
);
|
|
13122
|
-
const vectorPath =
|
|
14202
|
+
const vectorPath = path20.join(this.indexPath, "vectors");
|
|
13123
14203
|
const shouldFingerprintLegacyPair = !store.hasFingerprint() && (0, import_fs12.existsSync)(vectorPath) && (0, import_fs12.existsSync)(`${vectorPath}.meta.json`);
|
|
13124
14204
|
if (backfilledBlameMetadata || shouldFingerprintLegacyPair || removedStoredChunks) {
|
|
13125
14205
|
store.save();
|
|
@@ -13978,7 +15058,7 @@ var Indexer = class _Indexer {
|
|
|
13978
15058
|
gcOrphanSymbols: 0,
|
|
13979
15059
|
gcOrphanCallEdges: 0,
|
|
13980
15060
|
resetCorruptedIndex: true,
|
|
13981
|
-
warning: this.getCorruptedIndexWarning(
|
|
15061
|
+
warning: this.getCorruptedIndexWarning(path20.join(this.indexPath, "codebase.db"))
|
|
13982
15062
|
};
|
|
13983
15063
|
}
|
|
13984
15064
|
this.logger.recordGc(removedCount, gcOrphanChunks, gcOrphanEmbeddings);
|
|
@@ -14008,7 +15088,8 @@ var Indexer = class _Indexer {
|
|
|
14008
15088
|
const maxChunkTokens = getSafeEmbeddingChunkTokenLimit(configuredProviderInfo);
|
|
14009
15089
|
const providerRateLimits = this.getProviderRateLimits(configuredProviderInfo.provider);
|
|
14010
15090
|
const roots = this.config.scope === "global" ? this.getScopedRoots() : null;
|
|
14011
|
-
const
|
|
15091
|
+
const shouldProcessFailedPath = (filePath) => filePath === null || !this.isStoredPathExcluded(filePath);
|
|
15092
|
+
const failedProcessing = this.prepareFailedBatchProcessing(roots, shouldProcessFailedPath);
|
|
14012
15093
|
if (failedProcessing.latestById.size === 0) {
|
|
14013
15094
|
this.finalizeFailedBatchWriteState(failedProcessing.state);
|
|
14014
15095
|
return { succeeded: 0, failed: 0, remaining: 0 };
|
|
@@ -14021,7 +15102,7 @@ var Indexer = class _Indexer {
|
|
|
14021
15102
|
const retryableChunks = this.iterateLatestFailedChunks(
|
|
14022
15103
|
failedProcessing.latestById,
|
|
14023
15104
|
roots,
|
|
14024
|
-
|
|
15105
|
+
shouldProcessFailedPath,
|
|
14025
15106
|
maxChunkTokens
|
|
14026
15107
|
);
|
|
14027
15108
|
for (const retryBatch of iterateOrderedFileBatches(
|
|
@@ -14291,9 +15372,9 @@ var Indexer = class _Indexer {
|
|
|
14291
15372
|
this.requireReadableComponents(readIssues, "database");
|
|
14292
15373
|
let shortest = [];
|
|
14293
15374
|
for (const branchKey of this.getBranchCatalogKeys()) {
|
|
14294
|
-
const
|
|
14295
|
-
if (
|
|
14296
|
-
shortest =
|
|
15375
|
+
const path26 = database.findShortestPath(fromName, toName, branchKey, maxDepth);
|
|
15376
|
+
if (path26.length > 0 && (shortest.length === 0 || path26.length < shortest.length)) {
|
|
15377
|
+
shortest = path26;
|
|
14297
15378
|
}
|
|
14298
15379
|
}
|
|
14299
15380
|
return shortest.map((hop) => this.resolveFilePathRecord(hop));
|
|
@@ -14341,13 +15422,13 @@ var Indexer = class _Indexer {
|
|
|
14341
15422
|
}
|
|
14342
15423
|
}
|
|
14343
15424
|
if (!found) continue;
|
|
14344
|
-
const
|
|
15425
|
+
const path26 = [];
|
|
14345
15426
|
let currentSymbolId = toSymbolId;
|
|
14346
15427
|
while (true) {
|
|
14347
15428
|
const symbol = symbolsById.get(currentSymbolId);
|
|
14348
15429
|
if (!symbol) break;
|
|
14349
15430
|
const parent = parentBySymbolId.get(currentSymbolId);
|
|
14350
|
-
|
|
15431
|
+
path26.push({
|
|
14351
15432
|
symbolId: symbol.id,
|
|
14352
15433
|
symbolName: symbol.name,
|
|
14353
15434
|
filePath: symbol.filePath,
|
|
@@ -14357,9 +15438,9 @@ var Indexer = class _Indexer {
|
|
|
14357
15438
|
if (!parent) break;
|
|
14358
15439
|
currentSymbolId = parent.parentId;
|
|
14359
15440
|
}
|
|
14360
|
-
|
|
14361
|
-
if (
|
|
14362
|
-
shortest =
|
|
15441
|
+
path26.reverse();
|
|
15442
|
+
if (path26.length > 0 && (shortest.length === 0 || path26.length < shortest.length)) {
|
|
15443
|
+
shortest = path26;
|
|
14363
15444
|
}
|
|
14364
15445
|
}
|
|
14365
15446
|
return shortest.map((hop) => this.resolveFilePathRecord(hop));
|
|
@@ -14510,7 +15591,7 @@ var Indexer = class _Indexer {
|
|
|
14510
15591
|
);
|
|
14511
15592
|
}
|
|
14512
15593
|
}
|
|
14513
|
-
const toStoredChangedFiles = (filePaths) => filePaths.map((filePath) => this.toStoredFilePath(
|
|
15594
|
+
const toStoredChangedFiles = (filePaths) => filePaths.map((filePath) => this.toStoredFilePath(path20.resolve(this.projectRoot, filePath)));
|
|
14514
15595
|
const storedChangedFiles = toStoredChangedFiles(changedFiles);
|
|
14515
15596
|
const directSymbols = database.getSymbolsForFiles(storedChangedFiles, branchKey);
|
|
14516
15597
|
const directIds = directSymbols.map((s) => s.id);
|
|
@@ -14659,12 +15740,12 @@ var Indexer = class _Indexer {
|
|
|
14659
15740
|
if (meta.filePath) filePaths.add(meta.filePath);
|
|
14660
15741
|
}
|
|
14661
15742
|
const directory = options?.directory?.replace(/\/$/, "");
|
|
14662
|
-
const absoluteDirectoryFilter = directory ?
|
|
15743
|
+
const absoluteDirectoryFilter = directory ? path20.resolve(this.projectRoot, directory) : void 0;
|
|
14663
15744
|
for (const filePath of filePaths) {
|
|
14664
15745
|
if (directory) {
|
|
14665
15746
|
const absoluteFilePath = this.resolveStoredFilePath(filePath);
|
|
14666
15747
|
const matchesRelative = filePath === directory || filePath.startsWith(directory + "/");
|
|
14667
|
-
const matchesProjectRelative = absoluteDirectoryFilter !== void 0 && (absoluteFilePath === absoluteDirectoryFilter || absoluteFilePath.startsWith(absoluteDirectoryFilter +
|
|
15748
|
+
const matchesProjectRelative = absoluteDirectoryFilter !== void 0 && (absoluteFilePath === absoluteDirectoryFilter || absoluteFilePath.startsWith(absoluteDirectoryFilter + path20.sep));
|
|
14668
15749
|
if (!matchesRelative && !matchesProjectRelative) {
|
|
14669
15750
|
continue;
|
|
14670
15751
|
}
|
|
@@ -14781,7 +15862,10 @@ function getOrCreateIndexer(projectRoot3, host) {
|
|
|
14781
15862
|
}
|
|
14782
15863
|
const indexer = new Indexer(projectRoot3, config, host);
|
|
14783
15864
|
indexerCache.set(key, indexer);
|
|
14784
|
-
configureAutoIndex(projectRoot3, host, config, () => getOrCreateIndexer(projectRoot3, host)
|
|
15865
|
+
configureAutoIndex(projectRoot3, host, config, () => getOrCreateIndexer(projectRoot3, host), {
|
|
15866
|
+
preserveManagedWorker: true,
|
|
15867
|
+
synchronizeBackgroundWorker: false
|
|
15868
|
+
});
|
|
14785
15869
|
return indexer;
|
|
14786
15870
|
}
|
|
14787
15871
|
function getIndexerForProject(projectRoot3, host) {
|
|
@@ -14796,7 +15880,9 @@ function refreshIndexerForDirectory(projectRoot3, host, config = parseConfig(loa
|
|
|
14796
15880
|
const key = getIndexerCacheKey(projectRoot3, host);
|
|
14797
15881
|
configCache.set(key, config);
|
|
14798
15882
|
indexerCache.set(key, new Indexer(projectRoot3, config, host));
|
|
14799
|
-
configureAutoIndex(projectRoot3, host, config, () => getOrCreateIndexer(projectRoot3, host)
|
|
15883
|
+
configureAutoIndex(projectRoot3, host, config, () => getOrCreateIndexer(projectRoot3, host), {
|
|
15884
|
+
synchronizeBackgroundWorker: true
|
|
15885
|
+
});
|
|
14800
15886
|
return config;
|
|
14801
15887
|
}
|
|
14802
15888
|
var AutoIndexRetrievalUnavailableError = class extends Error {
|
|
@@ -14823,7 +15909,7 @@ function trimOrUndefined(value) {
|
|
|
14823
15909
|
return normalized || void 0;
|
|
14824
15910
|
}
|
|
14825
15911
|
function normalizeCallGraphPath(value) {
|
|
14826
|
-
let normalized =
|
|
15912
|
+
let normalized = path21.posix.normalize(value.trim().replaceAll("\\", "/"));
|
|
14827
15913
|
if (normalized.startsWith("./")) {
|
|
14828
15914
|
normalized = normalized.slice(2);
|
|
14829
15915
|
}
|
|
@@ -15016,12 +16102,12 @@ async function getCallGraphPath(projectRoot3, host, from, to, maxDepth, fromFile
|
|
|
15016
16102
|
if (fromResolution.status !== "resolved" || toResolution.status !== "resolved") {
|
|
15017
16103
|
return { from: fromResolution, to: toResolution, path: [] };
|
|
15018
16104
|
}
|
|
15019
|
-
const
|
|
16105
|
+
const path26 = await indexer.findCallPathBySymbolIds(
|
|
15020
16106
|
fromResolution.symbolId,
|
|
15021
16107
|
toResolution.symbolId,
|
|
15022
16108
|
maxDepth
|
|
15023
16109
|
);
|
|
15024
|
-
return { from: fromResolution, to: toResolution, path:
|
|
16110
|
+
return { from: fromResolution, to: toResolution, path: path26 };
|
|
15025
16111
|
}
|
|
15026
16112
|
async function runIndexCodebase(projectRoot3, host, args, onProgress) {
|
|
15027
16113
|
const root = getProjectRoot(projectRoot3, host);
|
|
@@ -15030,6 +16116,9 @@ async function runIndexCodebase(projectRoot3, host, args, onProgress) {
|
|
|
15030
16116
|
if (args.estimateOnly) {
|
|
15031
16117
|
return { kind: "estimate", estimate: await indexer.estimateCost() };
|
|
15032
16118
|
}
|
|
16119
|
+
if (args.dryRun) {
|
|
16120
|
+
return { kind: "dryrun", dryrun: await indexer.dryRunCost() };
|
|
16121
|
+
}
|
|
15033
16122
|
const coordinated = runCoordinatedIndex(root, host, args.force ?? false, (progress) => {
|
|
15034
16123
|
if (onProgress) {
|
|
15035
16124
|
void onProgress(formatProgressTitle(progress), {
|
|
@@ -15216,8 +16305,8 @@ async function getIndexLogs(projectRoot3, host, args) {
|
|
|
15216
16305
|
function addKnowledgeBase(projectRoot3, host, knowledgeBasePath) {
|
|
15217
16306
|
const root = getProjectRoot(projectRoot3, host);
|
|
15218
16307
|
const inputPath = knowledgeBasePath.trim();
|
|
15219
|
-
const normalizedPath2 =
|
|
15220
|
-
|
|
16308
|
+
const normalizedPath2 = path21.resolve(
|
|
16309
|
+
path21.isAbsolute(inputPath) ? inputPath : resolveKnowledgeBasePath(inputPath, root)
|
|
15221
16310
|
);
|
|
15222
16311
|
if (!(0, import_fs13.existsSync)(normalizedPath2)) {
|
|
15223
16312
|
return `Error: Directory does not exist: ${normalizedPath2}`;
|
|
@@ -15253,7 +16342,7 @@ function addKnowledgeBase(projectRoot3, host, knowledgeBasePath) {
|
|
|
15253
16342
|
}
|
|
15254
16343
|
}
|
|
15255
16344
|
for (const dotDir of sensitiveDotDirs) {
|
|
15256
|
-
const sensitiveDir =
|
|
16345
|
+
const sensitiveDir = path21.join(homeDir, dotDir);
|
|
15257
16346
|
if (sensitiveDir && (realPath === sensitiveDir || realPath.startsWith(`${sensitiveDir}/`))) {
|
|
15258
16347
|
return `Error: Adding sensitive directory as knowledge base is not allowed: ${normalizedPath2}`;
|
|
15259
16348
|
}
|
|
@@ -15316,7 +16405,7 @@ function listKnowledgeBases(projectRoot3, host) {
|
|
|
15316
16405
|
}
|
|
15317
16406
|
result += "\n";
|
|
15318
16407
|
}
|
|
15319
|
-
const hasHostConfig = (0, import_fs13.existsSync)(
|
|
16408
|
+
const hasHostConfig = (0, import_fs13.existsSync)(path21.join(root, getHostProjectConfigRelativePath(host)));
|
|
15320
16409
|
if (hasHostConfig) {
|
|
15321
16410
|
result += `
|
|
15322
16411
|
Config sources: 1 file(s).`;
|
|
@@ -15789,7 +16878,7 @@ async function resolveCodebaseContextUnmeasured(projectRoot3, host, input) {
|
|
|
15789
16878
|
const directory = input.directory ?? void 0;
|
|
15790
16879
|
const tokenBudget = input.tokenBudget ?? void 0;
|
|
15791
16880
|
if (from && to) {
|
|
15792
|
-
const
|
|
16881
|
+
const path26 = await getCallGraphPath(
|
|
15793
16882
|
projectRoot3,
|
|
15794
16883
|
host,
|
|
15795
16884
|
from,
|
|
@@ -15798,25 +16887,25 @@ async function resolveCodebaseContextUnmeasured(projectRoot3, host, input) {
|
|
|
15798
16887
|
fromFilePath,
|
|
15799
16888
|
toFilePath
|
|
15800
16889
|
);
|
|
15801
|
-
const pathText = formatCallGraphPathResult(
|
|
15802
|
-
if (
|
|
16890
|
+
const pathText = formatCallGraphPathResult(path26);
|
|
16891
|
+
if (path26.path.length > 0) {
|
|
15803
16892
|
const fitted2 = fitTextToContextBudget(
|
|
15804
16893
|
pathText,
|
|
15805
16894
|
tokenBudget
|
|
15806
16895
|
);
|
|
15807
16896
|
return {
|
|
15808
16897
|
text: fitted2.text,
|
|
15809
|
-
details: fittedDetails("path", fitted2,
|
|
16898
|
+
details: fittedDetails("path", fitted2, path26.path.length)
|
|
15810
16899
|
};
|
|
15811
16900
|
}
|
|
15812
|
-
if (
|
|
16901
|
+
if (path26.from.status !== "resolved" || path26.to.status !== "resolved") {
|
|
15813
16902
|
const fitted2 = fitTextToContextBudget(pathText, tokenBudget);
|
|
15814
16903
|
return {
|
|
15815
16904
|
text: fitted2.text,
|
|
15816
16905
|
details: fittedDetails("path", fitted2, 0)
|
|
15817
16906
|
};
|
|
15818
16907
|
}
|
|
15819
|
-
const resolvedFrom =
|
|
16908
|
+
const resolvedFrom = path26.from;
|
|
15820
16909
|
const { callers } = await getCallGraphData(projectRoot3, host, {
|
|
15821
16910
|
name: to,
|
|
15822
16911
|
direction: "callers",
|
|
@@ -16261,7 +17350,7 @@ var import_fs14 = require("fs");
|
|
|
16261
17350
|
|
|
16262
17351
|
// node_modules/chokidar/index.js
|
|
16263
17352
|
var import_node_events = require("events");
|
|
16264
|
-
var
|
|
17353
|
+
var import_node_fs3 = require("fs");
|
|
16265
17354
|
var import_promises3 = require("fs/promises");
|
|
16266
17355
|
var sp2 = __toESM(require("path"), 1);
|
|
16267
17356
|
|
|
@@ -16349,7 +17438,7 @@ var ReaddirpStream = class extends import_node_stream.Readable {
|
|
|
16349
17438
|
this._directoryFilter = normalizeFilter(opts.directoryFilter);
|
|
16350
17439
|
const statMethod = opts.lstat ? import_promises.lstat : import_promises.stat;
|
|
16351
17440
|
if (wantBigintFsStats) {
|
|
16352
|
-
this._stat = (
|
|
17441
|
+
this._stat = (path26) => statMethod(path26, { bigint: true });
|
|
16353
17442
|
} else {
|
|
16354
17443
|
this._stat = statMethod;
|
|
16355
17444
|
}
|
|
@@ -16374,8 +17463,8 @@ var ReaddirpStream = class extends import_node_stream.Readable {
|
|
|
16374
17463
|
const par = this.parent;
|
|
16375
17464
|
const fil = par && par.files;
|
|
16376
17465
|
if (fil && fil.length > 0) {
|
|
16377
|
-
const { path:
|
|
16378
|
-
const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent,
|
|
17466
|
+
const { path: path26, depth } = par;
|
|
17467
|
+
const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path26));
|
|
16379
17468
|
const awaited = await Promise.all(slice);
|
|
16380
17469
|
for (const entry of awaited) {
|
|
16381
17470
|
if (!entry)
|
|
@@ -16415,21 +17504,21 @@ var ReaddirpStream = class extends import_node_stream.Readable {
|
|
|
16415
17504
|
this.reading = false;
|
|
16416
17505
|
}
|
|
16417
17506
|
}
|
|
16418
|
-
async _exploreDir(
|
|
17507
|
+
async _exploreDir(path26, depth) {
|
|
16419
17508
|
let files;
|
|
16420
17509
|
try {
|
|
16421
|
-
files = await (0, import_promises.readdir)(
|
|
17510
|
+
files = await (0, import_promises.readdir)(path26, this._rdOptions);
|
|
16422
17511
|
} catch (error) {
|
|
16423
17512
|
this._onError(error);
|
|
16424
17513
|
}
|
|
16425
|
-
return { files, depth, path:
|
|
17514
|
+
return { files, depth, path: path26 };
|
|
16426
17515
|
}
|
|
16427
|
-
async _formatEntry(dirent,
|
|
17516
|
+
async _formatEntry(dirent, path26) {
|
|
16428
17517
|
let entry;
|
|
16429
|
-
const
|
|
17518
|
+
const basename8 = this._isDirent ? dirent.name : dirent;
|
|
16430
17519
|
try {
|
|
16431
|
-
const fullPath = (0, import_node_path.resolve)((0, import_node_path.join)(
|
|
16432
|
-
entry = { path: (0, import_node_path.relative)(this._root, fullPath), fullPath, basename:
|
|
17520
|
+
const fullPath = (0, import_node_path.resolve)((0, import_node_path.join)(path26, basename8));
|
|
17521
|
+
entry = { path: (0, import_node_path.relative)(this._root, fullPath), fullPath, basename: basename8 };
|
|
16433
17522
|
entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
|
|
16434
17523
|
} catch (err) {
|
|
16435
17524
|
this._onError(err);
|
|
@@ -16499,7 +17588,7 @@ function readdirp(root, options = {}) {
|
|
|
16499
17588
|
}
|
|
16500
17589
|
|
|
16501
17590
|
// node_modules/chokidar/handler.js
|
|
16502
|
-
var
|
|
17591
|
+
var import_node_fs2 = require("fs");
|
|
16503
17592
|
var import_promises2 = require("fs/promises");
|
|
16504
17593
|
var import_node_os = require("os");
|
|
16505
17594
|
var sp = __toESM(require("path"), 1);
|
|
@@ -16828,16 +17917,16 @@ var delFromSet = (main, prop, item) => {
|
|
|
16828
17917
|
};
|
|
16829
17918
|
var isEmptySet = (val) => val instanceof Set ? val.size === 0 : !val;
|
|
16830
17919
|
var FsWatchInstances = /* @__PURE__ */ new Map();
|
|
16831
|
-
function createFsWatchInstance(
|
|
17920
|
+
function createFsWatchInstance(path26, options, listener, errHandler, emitRaw) {
|
|
16832
17921
|
const handleEvent = (rawEvent, evPath) => {
|
|
16833
|
-
listener(
|
|
16834
|
-
emitRaw(rawEvent, evPath, { watchedPath:
|
|
16835
|
-
if (evPath &&
|
|
16836
|
-
fsWatchBroadcast(sp.resolve(
|
|
17922
|
+
listener(path26);
|
|
17923
|
+
emitRaw(rawEvent, evPath, { watchedPath: path26 });
|
|
17924
|
+
if (evPath && path26 !== evPath) {
|
|
17925
|
+
fsWatchBroadcast(sp.resolve(path26, evPath), KEY_LISTENERS, sp.join(path26, evPath));
|
|
16837
17926
|
}
|
|
16838
17927
|
};
|
|
16839
17928
|
try {
|
|
16840
|
-
return (0,
|
|
17929
|
+
return (0, import_node_fs2.watch)(path26, {
|
|
16841
17930
|
persistent: options.persistent
|
|
16842
17931
|
}, handleEvent);
|
|
16843
17932
|
} catch (error) {
|
|
@@ -16853,12 +17942,12 @@ var fsWatchBroadcast = (fullPath, listenerType, val1, val2, val3) => {
|
|
|
16853
17942
|
listener(val1, val2, val3);
|
|
16854
17943
|
});
|
|
16855
17944
|
};
|
|
16856
|
-
var setFsWatchListener = (
|
|
17945
|
+
var setFsWatchListener = (path26, fullPath, options, handlers) => {
|
|
16857
17946
|
const { listener, errHandler, rawEmitter } = handlers;
|
|
16858
17947
|
let cont = FsWatchInstances.get(fullPath);
|
|
16859
17948
|
let watcher;
|
|
16860
17949
|
if (!options.persistent) {
|
|
16861
|
-
watcher = createFsWatchInstance(
|
|
17950
|
+
watcher = createFsWatchInstance(path26, options, listener, errHandler, rawEmitter);
|
|
16862
17951
|
if (!watcher)
|
|
16863
17952
|
return;
|
|
16864
17953
|
return watcher.close.bind(watcher);
|
|
@@ -16869,7 +17958,7 @@ var setFsWatchListener = (path25, fullPath, options, handlers) => {
|
|
|
16869
17958
|
addAndConvert(cont, KEY_RAW, rawEmitter);
|
|
16870
17959
|
} else {
|
|
16871
17960
|
watcher = createFsWatchInstance(
|
|
16872
|
-
|
|
17961
|
+
path26,
|
|
16873
17962
|
options,
|
|
16874
17963
|
fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS),
|
|
16875
17964
|
errHandler,
|
|
@@ -16884,7 +17973,7 @@ var setFsWatchListener = (path25, fullPath, options, handlers) => {
|
|
|
16884
17973
|
cont.watcherUnusable = true;
|
|
16885
17974
|
if (isWindows && error.code === "EPERM") {
|
|
16886
17975
|
try {
|
|
16887
|
-
const fd = await (0, import_promises2.open)(
|
|
17976
|
+
const fd = await (0, import_promises2.open)(path26, "r");
|
|
16888
17977
|
await fd.close();
|
|
16889
17978
|
broadcastErr(error);
|
|
16890
17979
|
} catch (err) {
|
|
@@ -16915,12 +18004,12 @@ var setFsWatchListener = (path25, fullPath, options, handlers) => {
|
|
|
16915
18004
|
};
|
|
16916
18005
|
};
|
|
16917
18006
|
var FsWatchFileInstances = /* @__PURE__ */ new Map();
|
|
16918
|
-
var setFsWatchFileListener = (
|
|
18007
|
+
var setFsWatchFileListener = (path26, fullPath, options, handlers) => {
|
|
16919
18008
|
const { listener, rawEmitter } = handlers;
|
|
16920
18009
|
let cont = FsWatchFileInstances.get(fullPath);
|
|
16921
18010
|
const copts = cont && cont.options;
|
|
16922
18011
|
if (copts && (copts.persistent < options.persistent || copts.interval > options.interval)) {
|
|
16923
|
-
(0,
|
|
18012
|
+
(0, import_node_fs2.unwatchFile)(fullPath);
|
|
16924
18013
|
cont = void 0;
|
|
16925
18014
|
}
|
|
16926
18015
|
if (cont) {
|
|
@@ -16931,13 +18020,13 @@ var setFsWatchFileListener = (path25, fullPath, options, handlers) => {
|
|
|
16931
18020
|
listeners: listener,
|
|
16932
18021
|
rawEmitters: rawEmitter,
|
|
16933
18022
|
options,
|
|
16934
|
-
watcher: (0,
|
|
18023
|
+
watcher: (0, import_node_fs2.watchFile)(fullPath, options, (curr, prev) => {
|
|
16935
18024
|
foreach(cont.rawEmitters, (rawEmitter2) => {
|
|
16936
18025
|
rawEmitter2(EV.CHANGE, fullPath, { curr, prev });
|
|
16937
18026
|
});
|
|
16938
18027
|
const currmtime = curr.mtimeMs;
|
|
16939
18028
|
if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {
|
|
16940
|
-
foreach(cont.listeners, (listener2) => listener2(
|
|
18029
|
+
foreach(cont.listeners, (listener2) => listener2(path26, curr));
|
|
16941
18030
|
}
|
|
16942
18031
|
})
|
|
16943
18032
|
};
|
|
@@ -16948,7 +18037,7 @@ var setFsWatchFileListener = (path25, fullPath, options, handlers) => {
|
|
|
16948
18037
|
delFromSet(cont, KEY_RAW, rawEmitter);
|
|
16949
18038
|
if (isEmptySet(cont.listeners)) {
|
|
16950
18039
|
FsWatchFileInstances.delete(fullPath);
|
|
16951
|
-
(0,
|
|
18040
|
+
(0, import_node_fs2.unwatchFile)(fullPath);
|
|
16952
18041
|
cont.options = cont.watcher = void 0;
|
|
16953
18042
|
Object.freeze(cont);
|
|
16954
18043
|
}
|
|
@@ -16967,13 +18056,13 @@ var NodeFsHandler = class {
|
|
|
16967
18056
|
* @param listener on fs change
|
|
16968
18057
|
* @returns closer for the watcher instance
|
|
16969
18058
|
*/
|
|
16970
|
-
_watchWithNodeFs(
|
|
18059
|
+
_watchWithNodeFs(path26, listener) {
|
|
16971
18060
|
const opts = this.fsw.options;
|
|
16972
|
-
const directory = sp.dirname(
|
|
16973
|
-
const
|
|
18061
|
+
const directory = sp.dirname(path26);
|
|
18062
|
+
const basename8 = sp.basename(path26);
|
|
16974
18063
|
const parent = this.fsw._getWatchedDir(directory);
|
|
16975
|
-
parent.add(
|
|
16976
|
-
const absolutePath = sp.resolve(
|
|
18064
|
+
parent.add(basename8);
|
|
18065
|
+
const absolutePath = sp.resolve(path26);
|
|
16977
18066
|
const options = {
|
|
16978
18067
|
persistent: opts.persistent
|
|
16979
18068
|
};
|
|
@@ -16982,13 +18071,13 @@ var NodeFsHandler = class {
|
|
|
16982
18071
|
let closer;
|
|
16983
18072
|
if (opts.usePolling) {
|
|
16984
18073
|
const enableBin = opts.interval !== opts.binaryInterval;
|
|
16985
|
-
options.interval = enableBin && isBinaryPath(
|
|
16986
|
-
closer = setFsWatchFileListener(
|
|
18074
|
+
options.interval = enableBin && isBinaryPath(basename8) ? opts.binaryInterval : opts.interval;
|
|
18075
|
+
closer = setFsWatchFileListener(path26, absolutePath, options, {
|
|
16987
18076
|
listener,
|
|
16988
18077
|
rawEmitter: this.fsw._emitRaw
|
|
16989
18078
|
});
|
|
16990
18079
|
} else {
|
|
16991
|
-
closer = setFsWatchListener(
|
|
18080
|
+
closer = setFsWatchListener(path26, absolutePath, options, {
|
|
16992
18081
|
listener,
|
|
16993
18082
|
errHandler: this._boundHandleError,
|
|
16994
18083
|
rawEmitter: this.fsw._emitRaw
|
|
@@ -17004,13 +18093,13 @@ var NodeFsHandler = class {
|
|
|
17004
18093
|
if (this.fsw.closed) {
|
|
17005
18094
|
return;
|
|
17006
18095
|
}
|
|
17007
|
-
const
|
|
17008
|
-
const
|
|
17009
|
-
const parent = this.fsw._getWatchedDir(
|
|
18096
|
+
const dirname14 = sp.dirname(file);
|
|
18097
|
+
const basename8 = sp.basename(file);
|
|
18098
|
+
const parent = this.fsw._getWatchedDir(dirname14);
|
|
17010
18099
|
let prevStats = stats;
|
|
17011
|
-
if (parent.has(
|
|
18100
|
+
if (parent.has(basename8))
|
|
17012
18101
|
return;
|
|
17013
|
-
const listener = async (
|
|
18102
|
+
const listener = async (path26, newStats) => {
|
|
17014
18103
|
if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5))
|
|
17015
18104
|
return;
|
|
17016
18105
|
if (!newStats || newStats.mtimeMs === 0) {
|
|
@@ -17024,18 +18113,18 @@ var NodeFsHandler = class {
|
|
|
17024
18113
|
this.fsw._emit(EV.CHANGE, file, newStats2);
|
|
17025
18114
|
}
|
|
17026
18115
|
if ((isMacos || isLinux || isFreeBSD) && prevStats.ino !== newStats2.ino) {
|
|
17027
|
-
this.fsw._closeFile(
|
|
18116
|
+
this.fsw._closeFile(path26);
|
|
17028
18117
|
prevStats = newStats2;
|
|
17029
18118
|
const closer2 = this._watchWithNodeFs(file, listener);
|
|
17030
18119
|
if (closer2)
|
|
17031
|
-
this.fsw._addPathCloser(
|
|
18120
|
+
this.fsw._addPathCloser(path26, closer2);
|
|
17032
18121
|
} else {
|
|
17033
18122
|
prevStats = newStats2;
|
|
17034
18123
|
}
|
|
17035
18124
|
} catch (error) {
|
|
17036
|
-
this.fsw._remove(
|
|
18125
|
+
this.fsw._remove(dirname14, basename8);
|
|
17037
18126
|
}
|
|
17038
|
-
} else if (parent.has(
|
|
18127
|
+
} else if (parent.has(basename8)) {
|
|
17039
18128
|
const at = newStats.atimeMs;
|
|
17040
18129
|
const mt = newStats.mtimeMs;
|
|
17041
18130
|
if (!at || at <= mt || mt !== prevStats.mtimeMs) {
|
|
@@ -17060,7 +18149,7 @@ var NodeFsHandler = class {
|
|
|
17060
18149
|
* @param item basename of this item
|
|
17061
18150
|
* @returns true if no more processing is needed for this entry.
|
|
17062
18151
|
*/
|
|
17063
|
-
async _handleSymlink(entry, directory,
|
|
18152
|
+
async _handleSymlink(entry, directory, path26, item) {
|
|
17064
18153
|
if (this.fsw.closed) {
|
|
17065
18154
|
return;
|
|
17066
18155
|
}
|
|
@@ -17070,7 +18159,7 @@ var NodeFsHandler = class {
|
|
|
17070
18159
|
this.fsw._incrReadyCount();
|
|
17071
18160
|
let linkPath;
|
|
17072
18161
|
try {
|
|
17073
|
-
linkPath = await (0, import_promises2.realpath)(
|
|
18162
|
+
linkPath = await (0, import_promises2.realpath)(path26);
|
|
17074
18163
|
} catch (e) {
|
|
17075
18164
|
this.fsw._emitReady();
|
|
17076
18165
|
return true;
|
|
@@ -17080,12 +18169,12 @@ var NodeFsHandler = class {
|
|
|
17080
18169
|
if (dir.has(item)) {
|
|
17081
18170
|
if (this.fsw._symlinkPaths.get(full) !== linkPath) {
|
|
17082
18171
|
this.fsw._symlinkPaths.set(full, linkPath);
|
|
17083
|
-
this.fsw._emit(EV.CHANGE,
|
|
18172
|
+
this.fsw._emit(EV.CHANGE, path26, entry.stats);
|
|
17084
18173
|
}
|
|
17085
18174
|
} else {
|
|
17086
18175
|
dir.add(item);
|
|
17087
18176
|
this.fsw._symlinkPaths.set(full, linkPath);
|
|
17088
|
-
this.fsw._emit(EV.ADD,
|
|
18177
|
+
this.fsw._emit(EV.ADD, path26, entry.stats);
|
|
17089
18178
|
}
|
|
17090
18179
|
this.fsw._emitReady();
|
|
17091
18180
|
return true;
|
|
@@ -17115,9 +18204,9 @@ var NodeFsHandler = class {
|
|
|
17115
18204
|
return;
|
|
17116
18205
|
}
|
|
17117
18206
|
const item = entry.path;
|
|
17118
|
-
let
|
|
18207
|
+
let path26 = sp.join(directory, item);
|
|
17119
18208
|
current.add(item);
|
|
17120
|
-
if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory,
|
|
18209
|
+
if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path26, item)) {
|
|
17121
18210
|
return;
|
|
17122
18211
|
}
|
|
17123
18212
|
if (this.fsw.closed) {
|
|
@@ -17126,11 +18215,11 @@ var NodeFsHandler = class {
|
|
|
17126
18215
|
}
|
|
17127
18216
|
if (item === target || !target && !previous.has(item)) {
|
|
17128
18217
|
this.fsw._incrReadyCount();
|
|
17129
|
-
|
|
17130
|
-
this._addToNodeFs(
|
|
18218
|
+
path26 = sp.join(dir, sp.relative(dir, path26));
|
|
18219
|
+
this._addToNodeFs(path26, initialAdd, wh, depth + 1);
|
|
17131
18220
|
}
|
|
17132
18221
|
}).on(EV.ERROR, this._boundHandleError);
|
|
17133
|
-
return new Promise((
|
|
18222
|
+
return new Promise((resolve18, reject) => {
|
|
17134
18223
|
if (!stream)
|
|
17135
18224
|
return reject();
|
|
17136
18225
|
stream.once(STR_END, () => {
|
|
@@ -17139,7 +18228,7 @@ var NodeFsHandler = class {
|
|
|
17139
18228
|
return;
|
|
17140
18229
|
}
|
|
17141
18230
|
const wasThrottled = throttler ? throttler.clear() : false;
|
|
17142
|
-
|
|
18231
|
+
resolve18(void 0);
|
|
17143
18232
|
previous.getChildren().filter((item) => {
|
|
17144
18233
|
return item !== directory && !current.has(item);
|
|
17145
18234
|
}).forEach((item) => {
|
|
@@ -17196,13 +18285,13 @@ var NodeFsHandler = class {
|
|
|
17196
18285
|
* @param depth Child path actually targeted for watch
|
|
17197
18286
|
* @param target Child path actually targeted for watch
|
|
17198
18287
|
*/
|
|
17199
|
-
async _addToNodeFs(
|
|
18288
|
+
async _addToNodeFs(path26, initialAdd, priorWh, depth, target) {
|
|
17200
18289
|
const ready = this.fsw._emitReady;
|
|
17201
|
-
if (this.fsw._isIgnored(
|
|
18290
|
+
if (this.fsw._isIgnored(path26) || this.fsw.closed) {
|
|
17202
18291
|
ready();
|
|
17203
18292
|
return false;
|
|
17204
18293
|
}
|
|
17205
|
-
const wh = this.fsw._getWatchHelpers(
|
|
18294
|
+
const wh = this.fsw._getWatchHelpers(path26);
|
|
17206
18295
|
if (priorWh) {
|
|
17207
18296
|
wh.filterPath = (entry) => priorWh.filterPath(entry);
|
|
17208
18297
|
wh.filterDir = (entry) => priorWh.filterDir(entry);
|
|
@@ -17218,8 +18307,8 @@ var NodeFsHandler = class {
|
|
|
17218
18307
|
const follow = this.fsw.options.followSymlinks;
|
|
17219
18308
|
let closer;
|
|
17220
18309
|
if (stats.isDirectory()) {
|
|
17221
|
-
const absPath = sp.resolve(
|
|
17222
|
-
const targetPath = follow ? await (0, import_promises2.realpath)(
|
|
18310
|
+
const absPath = sp.resolve(path26);
|
|
18311
|
+
const targetPath = follow ? await (0, import_promises2.realpath)(path26) : path26;
|
|
17223
18312
|
if (this.fsw.closed)
|
|
17224
18313
|
return;
|
|
17225
18314
|
closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
|
|
@@ -17229,29 +18318,29 @@ var NodeFsHandler = class {
|
|
|
17229
18318
|
this.fsw._symlinkPaths.set(absPath, targetPath);
|
|
17230
18319
|
}
|
|
17231
18320
|
} else if (stats.isSymbolicLink()) {
|
|
17232
|
-
const targetPath = follow ? await (0, import_promises2.realpath)(
|
|
18321
|
+
const targetPath = follow ? await (0, import_promises2.realpath)(path26) : path26;
|
|
17233
18322
|
if (this.fsw.closed)
|
|
17234
18323
|
return;
|
|
17235
18324
|
const parent = sp.dirname(wh.watchPath);
|
|
17236
18325
|
this.fsw._getWatchedDir(parent).add(wh.watchPath);
|
|
17237
18326
|
this.fsw._emit(EV.ADD, wh.watchPath, stats);
|
|
17238
|
-
closer = await this._handleDir(parent, stats, initialAdd, depth,
|
|
18327
|
+
closer = await this._handleDir(parent, stats, initialAdd, depth, path26, wh, targetPath);
|
|
17239
18328
|
if (this.fsw.closed)
|
|
17240
18329
|
return;
|
|
17241
18330
|
if (targetPath !== void 0) {
|
|
17242
|
-
this.fsw._symlinkPaths.set(sp.resolve(
|
|
18331
|
+
this.fsw._symlinkPaths.set(sp.resolve(path26), targetPath);
|
|
17243
18332
|
}
|
|
17244
18333
|
} else {
|
|
17245
18334
|
closer = this._handleFile(wh.watchPath, stats, initialAdd);
|
|
17246
18335
|
}
|
|
17247
18336
|
ready();
|
|
17248
18337
|
if (closer)
|
|
17249
|
-
this.fsw._addPathCloser(
|
|
18338
|
+
this.fsw._addPathCloser(path26, closer);
|
|
17250
18339
|
return false;
|
|
17251
18340
|
} catch (error) {
|
|
17252
18341
|
if (this.fsw._handleError(error)) {
|
|
17253
18342
|
ready();
|
|
17254
|
-
return
|
|
18343
|
+
return path26;
|
|
17255
18344
|
}
|
|
17256
18345
|
}
|
|
17257
18346
|
}
|
|
@@ -17294,24 +18383,24 @@ function createPattern(matcher) {
|
|
|
17294
18383
|
}
|
|
17295
18384
|
return () => false;
|
|
17296
18385
|
}
|
|
17297
|
-
function normalizePath2(
|
|
17298
|
-
if (typeof
|
|
18386
|
+
function normalizePath2(path26) {
|
|
18387
|
+
if (typeof path26 !== "string")
|
|
17299
18388
|
throw new Error("string expected");
|
|
17300
|
-
|
|
17301
|
-
|
|
18389
|
+
path26 = sp2.normalize(path26);
|
|
18390
|
+
path26 = path26.replace(/\\/g, "/");
|
|
17302
18391
|
let prepend = false;
|
|
17303
|
-
if (
|
|
18392
|
+
if (path26.startsWith("//"))
|
|
17304
18393
|
prepend = true;
|
|
17305
|
-
|
|
18394
|
+
path26 = path26.replace(DOUBLE_SLASH_RE, "/");
|
|
17306
18395
|
if (prepend)
|
|
17307
|
-
|
|
17308
|
-
return
|
|
18396
|
+
path26 = "/" + path26;
|
|
18397
|
+
return path26;
|
|
17309
18398
|
}
|
|
17310
18399
|
function matchPatterns(patterns, testString, stats) {
|
|
17311
|
-
const
|
|
18400
|
+
const path26 = normalizePath2(testString);
|
|
17312
18401
|
for (let index = 0; index < patterns.length; index++) {
|
|
17313
18402
|
const pattern = patterns[index];
|
|
17314
|
-
if (pattern(
|
|
18403
|
+
if (pattern(path26, stats)) {
|
|
17315
18404
|
return true;
|
|
17316
18405
|
}
|
|
17317
18406
|
}
|
|
@@ -17349,19 +18438,19 @@ var toUnix = (string) => {
|
|
|
17349
18438
|
}
|
|
17350
18439
|
return str;
|
|
17351
18440
|
};
|
|
17352
|
-
var normalizePathToUnix = (
|
|
17353
|
-
var normalizeIgnored = (cwd = "") => (
|
|
17354
|
-
if (typeof
|
|
17355
|
-
return normalizePathToUnix(sp2.isAbsolute(
|
|
18441
|
+
var normalizePathToUnix = (path26) => toUnix(sp2.normalize(toUnix(path26)));
|
|
18442
|
+
var normalizeIgnored = (cwd = "") => (path26) => {
|
|
18443
|
+
if (typeof path26 === "string") {
|
|
18444
|
+
return normalizePathToUnix(sp2.isAbsolute(path26) ? path26 : sp2.join(cwd, path26));
|
|
17356
18445
|
} else {
|
|
17357
|
-
return
|
|
18446
|
+
return path26;
|
|
17358
18447
|
}
|
|
17359
18448
|
};
|
|
17360
|
-
var getAbsolutePath = (
|
|
17361
|
-
if (sp2.isAbsolute(
|
|
17362
|
-
return
|
|
18449
|
+
var getAbsolutePath = (path26, cwd) => {
|
|
18450
|
+
if (sp2.isAbsolute(path26)) {
|
|
18451
|
+
return path26;
|
|
17363
18452
|
}
|
|
17364
|
-
return sp2.join(cwd,
|
|
18453
|
+
return sp2.join(cwd, path26);
|
|
17365
18454
|
};
|
|
17366
18455
|
var EMPTY_SET = Object.freeze(/* @__PURE__ */ new Set());
|
|
17367
18456
|
var DirEntry = class {
|
|
@@ -17426,10 +18515,10 @@ var WatchHelper = class {
|
|
|
17426
18515
|
dirParts;
|
|
17427
18516
|
followSymlinks;
|
|
17428
18517
|
statMethod;
|
|
17429
|
-
constructor(
|
|
18518
|
+
constructor(path26, follow, fsw) {
|
|
17430
18519
|
this.fsw = fsw;
|
|
17431
|
-
const watchPath =
|
|
17432
|
-
this.path =
|
|
18520
|
+
const watchPath = path26;
|
|
18521
|
+
this.path = path26 = path26.replace(REPLACER_RE, "");
|
|
17433
18522
|
this.watchPath = watchPath;
|
|
17434
18523
|
this.fullWatchPath = sp2.resolve(watchPath);
|
|
17435
18524
|
this.dirParts = [];
|
|
@@ -17569,20 +18658,20 @@ var FSWatcher = class extends import_node_events.EventEmitter {
|
|
|
17569
18658
|
this._closePromise = void 0;
|
|
17570
18659
|
let paths = unifyPaths(paths_);
|
|
17571
18660
|
if (cwd) {
|
|
17572
|
-
paths = paths.map((
|
|
17573
|
-
const absPath = getAbsolutePath(
|
|
18661
|
+
paths = paths.map((path26) => {
|
|
18662
|
+
const absPath = getAbsolutePath(path26, cwd);
|
|
17574
18663
|
return absPath;
|
|
17575
18664
|
});
|
|
17576
18665
|
}
|
|
17577
|
-
paths.forEach((
|
|
17578
|
-
this._removeIgnoredPath(
|
|
18666
|
+
paths.forEach((path26) => {
|
|
18667
|
+
this._removeIgnoredPath(path26);
|
|
17579
18668
|
});
|
|
17580
18669
|
this._userIgnored = void 0;
|
|
17581
18670
|
if (!this._readyCount)
|
|
17582
18671
|
this._readyCount = 0;
|
|
17583
18672
|
this._readyCount += paths.length;
|
|
17584
|
-
Promise.all(paths.map(async (
|
|
17585
|
-
const res = await this._nodeFsHandler._addToNodeFs(
|
|
18673
|
+
Promise.all(paths.map(async (path26) => {
|
|
18674
|
+
const res = await this._nodeFsHandler._addToNodeFs(path26, !_internal, void 0, 0, _origAdd);
|
|
17586
18675
|
if (res)
|
|
17587
18676
|
this._emitReady();
|
|
17588
18677
|
return res;
|
|
@@ -17604,17 +18693,17 @@ var FSWatcher = class extends import_node_events.EventEmitter {
|
|
|
17604
18693
|
return this;
|
|
17605
18694
|
const paths = unifyPaths(paths_);
|
|
17606
18695
|
const { cwd } = this.options;
|
|
17607
|
-
paths.forEach((
|
|
17608
|
-
if (!sp2.isAbsolute(
|
|
18696
|
+
paths.forEach((path26) => {
|
|
18697
|
+
if (!sp2.isAbsolute(path26) && !this._closers.has(path26)) {
|
|
17609
18698
|
if (cwd)
|
|
17610
|
-
|
|
17611
|
-
|
|
18699
|
+
path26 = sp2.join(cwd, path26);
|
|
18700
|
+
path26 = sp2.resolve(path26);
|
|
17612
18701
|
}
|
|
17613
|
-
this._closePath(
|
|
17614
|
-
this._addIgnoredPath(
|
|
17615
|
-
if (this._watched.has(
|
|
18702
|
+
this._closePath(path26);
|
|
18703
|
+
this._addIgnoredPath(path26);
|
|
18704
|
+
if (this._watched.has(path26)) {
|
|
17616
18705
|
this._addIgnoredPath({
|
|
17617
|
-
path:
|
|
18706
|
+
path: path26,
|
|
17618
18707
|
recursive: true
|
|
17619
18708
|
});
|
|
17620
18709
|
}
|
|
@@ -17678,38 +18767,38 @@ var FSWatcher = class extends import_node_events.EventEmitter {
|
|
|
17678
18767
|
* @param stats arguments to be passed with event
|
|
17679
18768
|
* @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag
|
|
17680
18769
|
*/
|
|
17681
|
-
async _emit(event,
|
|
18770
|
+
async _emit(event, path26, stats) {
|
|
17682
18771
|
if (this.closed)
|
|
17683
18772
|
return;
|
|
17684
18773
|
const opts = this.options;
|
|
17685
18774
|
if (isWindows)
|
|
17686
|
-
|
|
18775
|
+
path26 = sp2.normalize(path26);
|
|
17687
18776
|
if (opts.cwd)
|
|
17688
|
-
|
|
17689
|
-
const args = [
|
|
18777
|
+
path26 = sp2.relative(opts.cwd, path26);
|
|
18778
|
+
const args = [path26];
|
|
17690
18779
|
if (stats != null)
|
|
17691
18780
|
args.push(stats);
|
|
17692
18781
|
const awf = opts.awaitWriteFinish;
|
|
17693
18782
|
let pw;
|
|
17694
|
-
if (awf && (pw = this._pendingWrites.get(
|
|
18783
|
+
if (awf && (pw = this._pendingWrites.get(path26))) {
|
|
17695
18784
|
pw.lastChange = /* @__PURE__ */ new Date();
|
|
17696
18785
|
return this;
|
|
17697
18786
|
}
|
|
17698
18787
|
if (opts.atomic) {
|
|
17699
18788
|
if (event === EVENTS.UNLINK) {
|
|
17700
|
-
this._pendingUnlinks.set(
|
|
18789
|
+
this._pendingUnlinks.set(path26, [event, ...args]);
|
|
17701
18790
|
setTimeout(() => {
|
|
17702
|
-
this._pendingUnlinks.forEach((entry,
|
|
18791
|
+
this._pendingUnlinks.forEach((entry, path27) => {
|
|
17703
18792
|
this.emit(...entry);
|
|
17704
18793
|
this.emit(EVENTS.ALL, ...entry);
|
|
17705
|
-
this._pendingUnlinks.delete(
|
|
18794
|
+
this._pendingUnlinks.delete(path27);
|
|
17706
18795
|
});
|
|
17707
18796
|
}, typeof opts.atomic === "number" ? opts.atomic : 100);
|
|
17708
18797
|
return this;
|
|
17709
18798
|
}
|
|
17710
|
-
if (event === EVENTS.ADD && this._pendingUnlinks.has(
|
|
18799
|
+
if (event === EVENTS.ADD && this._pendingUnlinks.has(path26)) {
|
|
17711
18800
|
event = EVENTS.CHANGE;
|
|
17712
|
-
this._pendingUnlinks.delete(
|
|
18801
|
+
this._pendingUnlinks.delete(path26);
|
|
17713
18802
|
}
|
|
17714
18803
|
}
|
|
17715
18804
|
if (awf && (event === EVENTS.ADD || event === EVENTS.CHANGE) && this._readyEmitted) {
|
|
@@ -17727,16 +18816,16 @@ var FSWatcher = class extends import_node_events.EventEmitter {
|
|
|
17727
18816
|
this.emitWithAll(event, args);
|
|
17728
18817
|
}
|
|
17729
18818
|
};
|
|
17730
|
-
this._awaitWriteFinish(
|
|
18819
|
+
this._awaitWriteFinish(path26, awf.stabilityThreshold, event, awfEmit);
|
|
17731
18820
|
return this;
|
|
17732
18821
|
}
|
|
17733
18822
|
if (event === EVENTS.CHANGE) {
|
|
17734
|
-
const isThrottled = !this._throttle(EVENTS.CHANGE,
|
|
18823
|
+
const isThrottled = !this._throttle(EVENTS.CHANGE, path26, 50);
|
|
17735
18824
|
if (isThrottled)
|
|
17736
18825
|
return this;
|
|
17737
18826
|
}
|
|
17738
18827
|
if (opts.alwaysStat && stats === void 0 && (event === EVENTS.ADD || event === EVENTS.ADD_DIR || event === EVENTS.CHANGE)) {
|
|
17739
|
-
const fullPath = opts.cwd ? sp2.join(opts.cwd,
|
|
18828
|
+
const fullPath = opts.cwd ? sp2.join(opts.cwd, path26) : path26;
|
|
17740
18829
|
let stats2;
|
|
17741
18830
|
try {
|
|
17742
18831
|
stats2 = await (0, import_promises3.stat)(fullPath);
|
|
@@ -17767,23 +18856,23 @@ var FSWatcher = class extends import_node_events.EventEmitter {
|
|
|
17767
18856
|
* @param timeout duration of time to suppress duplicate actions
|
|
17768
18857
|
* @returns tracking object or false if action should be suppressed
|
|
17769
18858
|
*/
|
|
17770
|
-
_throttle(actionType,
|
|
18859
|
+
_throttle(actionType, path26, timeout) {
|
|
17771
18860
|
if (!this._throttled.has(actionType)) {
|
|
17772
18861
|
this._throttled.set(actionType, /* @__PURE__ */ new Map());
|
|
17773
18862
|
}
|
|
17774
18863
|
const action = this._throttled.get(actionType);
|
|
17775
18864
|
if (!action)
|
|
17776
18865
|
throw new Error("invalid throttle");
|
|
17777
|
-
const actionPath = action.get(
|
|
18866
|
+
const actionPath = action.get(path26);
|
|
17778
18867
|
if (actionPath) {
|
|
17779
18868
|
actionPath.count++;
|
|
17780
18869
|
return false;
|
|
17781
18870
|
}
|
|
17782
18871
|
let timeoutObject;
|
|
17783
18872
|
const clear = () => {
|
|
17784
|
-
const item = action.get(
|
|
18873
|
+
const item = action.get(path26);
|
|
17785
18874
|
const count = item ? item.count : 0;
|
|
17786
|
-
action.delete(
|
|
18875
|
+
action.delete(path26);
|
|
17787
18876
|
clearTimeout(timeoutObject);
|
|
17788
18877
|
if (item)
|
|
17789
18878
|
clearTimeout(item.timeoutObject);
|
|
@@ -17791,7 +18880,7 @@ var FSWatcher = class extends import_node_events.EventEmitter {
|
|
|
17791
18880
|
};
|
|
17792
18881
|
timeoutObject = setTimeout(clear, timeout);
|
|
17793
18882
|
const thr = { timeoutObject, clear, count: 0 };
|
|
17794
|
-
action.set(
|
|
18883
|
+
action.set(path26, thr);
|
|
17795
18884
|
return thr;
|
|
17796
18885
|
}
|
|
17797
18886
|
_incrReadyCount() {
|
|
@@ -17805,44 +18894,44 @@ var FSWatcher = class extends import_node_events.EventEmitter {
|
|
|
17805
18894
|
* @param event
|
|
17806
18895
|
* @param awfEmit Callback to be called when ready for event to be emitted.
|
|
17807
18896
|
*/
|
|
17808
|
-
_awaitWriteFinish(
|
|
18897
|
+
_awaitWriteFinish(path26, threshold, event, awfEmit) {
|
|
17809
18898
|
const awf = this.options.awaitWriteFinish;
|
|
17810
18899
|
if (typeof awf !== "object")
|
|
17811
18900
|
return;
|
|
17812
18901
|
const pollInterval = awf.pollInterval;
|
|
17813
18902
|
let timeoutHandler;
|
|
17814
|
-
let fullPath =
|
|
17815
|
-
if (this.options.cwd && !sp2.isAbsolute(
|
|
17816
|
-
fullPath = sp2.join(this.options.cwd,
|
|
18903
|
+
let fullPath = path26;
|
|
18904
|
+
if (this.options.cwd && !sp2.isAbsolute(path26)) {
|
|
18905
|
+
fullPath = sp2.join(this.options.cwd, path26);
|
|
17817
18906
|
}
|
|
17818
18907
|
const now2 = /* @__PURE__ */ new Date();
|
|
17819
18908
|
const writes = this._pendingWrites;
|
|
17820
18909
|
function awaitWriteFinishFn(prevStat) {
|
|
17821
|
-
(0,
|
|
17822
|
-
if (err || !writes.has(
|
|
18910
|
+
(0, import_node_fs3.stat)(fullPath, (err, curStat) => {
|
|
18911
|
+
if (err || !writes.has(path26)) {
|
|
17823
18912
|
if (err && err.code !== "ENOENT")
|
|
17824
18913
|
awfEmit(err);
|
|
17825
18914
|
return;
|
|
17826
18915
|
}
|
|
17827
18916
|
const now3 = Number(/* @__PURE__ */ new Date());
|
|
17828
18917
|
if (prevStat && curStat.size !== prevStat.size) {
|
|
17829
|
-
writes.get(
|
|
18918
|
+
writes.get(path26).lastChange = now3;
|
|
17830
18919
|
}
|
|
17831
|
-
const pw = writes.get(
|
|
18920
|
+
const pw = writes.get(path26);
|
|
17832
18921
|
const df = now3 - pw.lastChange;
|
|
17833
18922
|
if (df >= threshold) {
|
|
17834
|
-
writes.delete(
|
|
18923
|
+
writes.delete(path26);
|
|
17835
18924
|
awfEmit(void 0, curStat);
|
|
17836
18925
|
} else {
|
|
17837
18926
|
timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat);
|
|
17838
18927
|
}
|
|
17839
18928
|
});
|
|
17840
18929
|
}
|
|
17841
|
-
if (!writes.has(
|
|
17842
|
-
writes.set(
|
|
18930
|
+
if (!writes.has(path26)) {
|
|
18931
|
+
writes.set(path26, {
|
|
17843
18932
|
lastChange: now2,
|
|
17844
18933
|
cancelWait: () => {
|
|
17845
|
-
writes.delete(
|
|
18934
|
+
writes.delete(path26);
|
|
17846
18935
|
clearTimeout(timeoutHandler);
|
|
17847
18936
|
return event;
|
|
17848
18937
|
}
|
|
@@ -17853,8 +18942,8 @@ var FSWatcher = class extends import_node_events.EventEmitter {
|
|
|
17853
18942
|
/**
|
|
17854
18943
|
* Determines whether user has asked to ignore this path.
|
|
17855
18944
|
*/
|
|
17856
|
-
_isIgnored(
|
|
17857
|
-
if (this.options.atomic && DOT_RE.test(
|
|
18945
|
+
_isIgnored(path26, stats) {
|
|
18946
|
+
if (this.options.atomic && DOT_RE.test(path26))
|
|
17858
18947
|
return true;
|
|
17859
18948
|
if (!this._userIgnored) {
|
|
17860
18949
|
const { cwd } = this.options;
|
|
@@ -17864,17 +18953,17 @@ var FSWatcher = class extends import_node_events.EventEmitter {
|
|
|
17864
18953
|
const list = [...ignoredPaths.map(normalizeIgnored(cwd)), ...ignored];
|
|
17865
18954
|
this._userIgnored = anymatch(list, void 0);
|
|
17866
18955
|
}
|
|
17867
|
-
return this._userIgnored(
|
|
18956
|
+
return this._userIgnored(path26, stats);
|
|
17868
18957
|
}
|
|
17869
|
-
_isntIgnored(
|
|
17870
|
-
return !this._isIgnored(
|
|
18958
|
+
_isntIgnored(path26, stat5) {
|
|
18959
|
+
return !this._isIgnored(path26, stat5);
|
|
17871
18960
|
}
|
|
17872
18961
|
/**
|
|
17873
18962
|
* Provides a set of common helpers and properties relating to symlink handling.
|
|
17874
18963
|
* @param path file or directory pattern being watched
|
|
17875
18964
|
*/
|
|
17876
|
-
_getWatchHelpers(
|
|
17877
|
-
return new WatchHelper(
|
|
18965
|
+
_getWatchHelpers(path26) {
|
|
18966
|
+
return new WatchHelper(path26, this.options.followSymlinks, this);
|
|
17878
18967
|
}
|
|
17879
18968
|
// Directory helpers
|
|
17880
18969
|
// -----------------
|
|
@@ -17906,63 +18995,63 @@ var FSWatcher = class extends import_node_events.EventEmitter {
|
|
|
17906
18995
|
* @param item base path of item/directory
|
|
17907
18996
|
*/
|
|
17908
18997
|
_remove(directory, item, isDirectory) {
|
|
17909
|
-
const
|
|
17910
|
-
const fullPath = sp2.resolve(
|
|
17911
|
-
isDirectory = isDirectory != null ? isDirectory : this._watched.has(
|
|
17912
|
-
if (!this._throttle("remove",
|
|
18998
|
+
const path26 = sp2.join(directory, item);
|
|
18999
|
+
const fullPath = sp2.resolve(path26);
|
|
19000
|
+
isDirectory = isDirectory != null ? isDirectory : this._watched.has(path26) || this._watched.has(fullPath);
|
|
19001
|
+
if (!this._throttle("remove", path26, 100))
|
|
17913
19002
|
return;
|
|
17914
19003
|
if (!isDirectory && this._watched.size === 1) {
|
|
17915
19004
|
this.add(directory, item, true);
|
|
17916
19005
|
}
|
|
17917
|
-
const wp = this._getWatchedDir(
|
|
19006
|
+
const wp = this._getWatchedDir(path26);
|
|
17918
19007
|
const nestedDirectoryChildren = wp.getChildren();
|
|
17919
|
-
nestedDirectoryChildren.forEach((nested) => this._remove(
|
|
19008
|
+
nestedDirectoryChildren.forEach((nested) => this._remove(path26, nested));
|
|
17920
19009
|
const parent = this._getWatchedDir(directory);
|
|
17921
19010
|
const wasTracked = parent.has(item);
|
|
17922
19011
|
parent.remove(item);
|
|
17923
19012
|
if (this._symlinkPaths.has(fullPath)) {
|
|
17924
19013
|
this._symlinkPaths.delete(fullPath);
|
|
17925
19014
|
}
|
|
17926
|
-
let relPath =
|
|
19015
|
+
let relPath = path26;
|
|
17927
19016
|
if (this.options.cwd)
|
|
17928
|
-
relPath = sp2.relative(this.options.cwd,
|
|
19017
|
+
relPath = sp2.relative(this.options.cwd, path26);
|
|
17929
19018
|
if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
|
|
17930
19019
|
const event = this._pendingWrites.get(relPath).cancelWait();
|
|
17931
19020
|
if (event === EVENTS.ADD)
|
|
17932
19021
|
return;
|
|
17933
19022
|
}
|
|
17934
|
-
this._watched.delete(
|
|
19023
|
+
this._watched.delete(path26);
|
|
17935
19024
|
this._watched.delete(fullPath);
|
|
17936
19025
|
const eventName = isDirectory ? EVENTS.UNLINK_DIR : EVENTS.UNLINK;
|
|
17937
|
-
if (wasTracked && !this._isIgnored(
|
|
17938
|
-
this._emit(eventName,
|
|
17939
|
-
this._closePath(
|
|
19026
|
+
if (wasTracked && !this._isIgnored(path26))
|
|
19027
|
+
this._emit(eventName, path26);
|
|
19028
|
+
this._closePath(path26);
|
|
17940
19029
|
}
|
|
17941
19030
|
/**
|
|
17942
19031
|
* Closes all watchers for a path
|
|
17943
19032
|
*/
|
|
17944
|
-
_closePath(
|
|
17945
|
-
this._closeFile(
|
|
17946
|
-
const dir = sp2.dirname(
|
|
17947
|
-
this._getWatchedDir(dir).remove(sp2.basename(
|
|
19033
|
+
_closePath(path26) {
|
|
19034
|
+
this._closeFile(path26);
|
|
19035
|
+
const dir = sp2.dirname(path26);
|
|
19036
|
+
this._getWatchedDir(dir).remove(sp2.basename(path26));
|
|
17948
19037
|
}
|
|
17949
19038
|
/**
|
|
17950
19039
|
* Closes only file-specific watchers
|
|
17951
19040
|
*/
|
|
17952
|
-
_closeFile(
|
|
17953
|
-
const closers = this._closers.get(
|
|
19041
|
+
_closeFile(path26) {
|
|
19042
|
+
const closers = this._closers.get(path26);
|
|
17954
19043
|
if (!closers)
|
|
17955
19044
|
return;
|
|
17956
19045
|
closers.forEach((closer) => closer());
|
|
17957
|
-
this._closers.delete(
|
|
19046
|
+
this._closers.delete(path26);
|
|
17958
19047
|
}
|
|
17959
|
-
_addPathCloser(
|
|
19048
|
+
_addPathCloser(path26, closer) {
|
|
17960
19049
|
if (!closer)
|
|
17961
19050
|
return;
|
|
17962
|
-
let list = this._closers.get(
|
|
19051
|
+
let list = this._closers.get(path26);
|
|
17963
19052
|
if (!list) {
|
|
17964
19053
|
list = [];
|
|
17965
|
-
this._closers.set(
|
|
19054
|
+
this._closers.set(path26, list);
|
|
17966
19055
|
}
|
|
17967
19056
|
list.push(closer);
|
|
17968
19057
|
}
|
|
@@ -17992,11 +19081,11 @@ function watch(paths, options = {}) {
|
|
|
17992
19081
|
var chokidar_default = { watch, FSWatcher };
|
|
17993
19082
|
|
|
17994
19083
|
// src/watcher/file-watcher.ts
|
|
17995
|
-
var
|
|
19084
|
+
var path24 = __toESM(require("path"), 1);
|
|
17996
19085
|
|
|
17997
19086
|
// src/watcher/native-recursive-watcher.ts
|
|
17998
|
-
var
|
|
17999
|
-
var
|
|
19087
|
+
var import_node_fs4 = require("fs");
|
|
19088
|
+
var path22 = __toESM(require("path"), 1);
|
|
18000
19089
|
var NativeRecursiveWatcher = class {
|
|
18001
19090
|
constructor(root, onChange, options = {}) {
|
|
18002
19091
|
this.root = root;
|
|
@@ -18044,26 +19133,26 @@ var NativeRecursiveWatcher = class {
|
|
|
18044
19133
|
toAbsolutePath(filename) {
|
|
18045
19134
|
if (filename == null) return null;
|
|
18046
19135
|
const normalizedFilename = typeof filename === "string" ? filename : filename.toString();
|
|
18047
|
-
const absolutePath =
|
|
18048
|
-
const relativePath =
|
|
18049
|
-
const outsideRoot = relativePath === ".." || relativePath.startsWith(`..${
|
|
19136
|
+
const absolutePath = path22.resolve(this.root, normalizedFilename);
|
|
19137
|
+
const relativePath = path22.relative(this.root, absolutePath);
|
|
19138
|
+
const outsideRoot = relativePath === ".." || relativePath.startsWith(`..${path22.sep}`) || path22.isAbsolute(relativePath);
|
|
18050
19139
|
return outsideRoot ? null : absolutePath;
|
|
18051
19140
|
}
|
|
18052
|
-
defaultWatchFactory = (root, listener, options) => (0,
|
|
19141
|
+
defaultWatchFactory = (root, listener, options) => (0, import_node_fs4.watch)(root, options, listener);
|
|
18053
19142
|
};
|
|
18054
19143
|
|
|
18055
19144
|
// src/watcher/snapshot.ts
|
|
18056
19145
|
var fsPromises4 = __toESM(require("fs/promises"), 1);
|
|
18057
|
-
var
|
|
19146
|
+
var path23 = __toESM(require("path"), 1);
|
|
18058
19147
|
async function buildFileSnapshotScan(projectRoot3, config, configPaths = []) {
|
|
18059
|
-
const normalizedProjectRoot =
|
|
19148
|
+
const normalizedProjectRoot = path23.resolve(projectRoot3);
|
|
18060
19149
|
const ignoreFilter = createIgnoreFilter(normalizedProjectRoot);
|
|
18061
19150
|
const includePatterns = [...config.include, ...config.additionalInclude ?? []];
|
|
18062
19151
|
const maxDepth = config.indexing?.maxDepth ?? -1;
|
|
18063
19152
|
const snapshot = /* @__PURE__ */ new Map();
|
|
18064
19153
|
const unreadablePrefixes = /* @__PURE__ */ new Set();
|
|
18065
19154
|
const includeFile = async (filePath) => {
|
|
18066
|
-
const normalizedPath2 =
|
|
19155
|
+
const normalizedPath2 = path23.resolve(filePath);
|
|
18067
19156
|
if (!shouldIncludeFile(normalizedPath2, normalizedProjectRoot, includePatterns, config.exclude, ignoreFilter)) return;
|
|
18068
19157
|
const stat5 = await readStatIfFile(normalizedPath2, unreadablePrefixes);
|
|
18069
19158
|
if (stat5) snapshot.set(normalizedPath2, { size: stat5.size, mtimeMs: stat5.mtimeMs });
|
|
@@ -18075,16 +19164,16 @@ async function buildFileSnapshotScan(projectRoot3, config, configPaths = []) {
|
|
|
18075
19164
|
} catch (error) {
|
|
18076
19165
|
if (isMissingFsError(error)) return;
|
|
18077
19166
|
if (isPermissionFsError(error)) {
|
|
18078
|
-
unreadablePrefixes.add(
|
|
19167
|
+
unreadablePrefixes.add(path23.resolve(directoryPath));
|
|
18079
19168
|
return;
|
|
18080
19169
|
}
|
|
18081
19170
|
throw error;
|
|
18082
19171
|
}
|
|
18083
19172
|
for (const entry of entries) {
|
|
18084
|
-
const fullPath =
|
|
18085
|
-
const relativePath =
|
|
19173
|
+
const fullPath = path23.join(directoryPath, entry.name);
|
|
19174
|
+
const relativePath = path23.relative(normalizedProjectRoot, fullPath);
|
|
18086
19175
|
if (entry.isDirectory()) {
|
|
18087
|
-
if (hasFilteredPathSegment(relativePath,
|
|
19176
|
+
if (hasFilteredPathSegment(relativePath, path23.sep) || isRestrictedDirectory(relativePath, path23.sep)) continue;
|
|
18088
19177
|
if (ignoreFilter.ignores(relativePath)) continue;
|
|
18089
19178
|
if (maxDepth === -1 || depth < maxDepth) await walk(fullPath, depth + 1);
|
|
18090
19179
|
} else if (entry.isFile()) {
|
|
@@ -18097,19 +19186,19 @@ async function buildFileSnapshotScan(projectRoot3, config, configPaths = []) {
|
|
|
18097
19186
|
return { entries: snapshot, unreadablePrefixes };
|
|
18098
19187
|
}
|
|
18099
19188
|
async function buildFileSnapshotForPathScan(projectRoot3, config, configPaths, targetPath) {
|
|
18100
|
-
const normalizedProjectRoot =
|
|
18101
|
-
const normalizedTargetPath =
|
|
19189
|
+
const normalizedProjectRoot = path23.resolve(projectRoot3);
|
|
19190
|
+
const normalizedTargetPath = path23.resolve(targetPath);
|
|
18102
19191
|
if (!isWithinPath(normalizedProjectRoot, normalizedTargetPath)) {
|
|
18103
19192
|
return { entries: /* @__PURE__ */ new Map(), unreadablePrefixes: /* @__PURE__ */ new Set() };
|
|
18104
19193
|
}
|
|
18105
19194
|
const ignoreFilter = createIgnoreFilter(normalizedProjectRoot);
|
|
18106
19195
|
const includePatterns = [...config.include, ...config.additionalInclude ?? []];
|
|
18107
19196
|
const maxDepth = config.indexing?.maxDepth ?? -1;
|
|
18108
|
-
const explicitConfigPaths = new Set(configPaths.map((configPath) =>
|
|
19197
|
+
const explicitConfigPaths = new Set(configPaths.map((configPath) => path23.resolve(configPath)));
|
|
18109
19198
|
const snapshot = /* @__PURE__ */ new Map();
|
|
18110
19199
|
const unreadablePrefixes = /* @__PURE__ */ new Set();
|
|
18111
19200
|
const includeFile = async (filePath) => {
|
|
18112
|
-
const normalizedPath2 =
|
|
19201
|
+
const normalizedPath2 = path23.resolve(filePath);
|
|
18113
19202
|
if (!explicitConfigPaths.has(normalizedPath2) && !shouldIncludeFile(
|
|
18114
19203
|
normalizedPath2,
|
|
18115
19204
|
normalizedProjectRoot,
|
|
@@ -18127,16 +19216,16 @@ async function buildFileSnapshotForPathScan(projectRoot3, config, configPaths, t
|
|
|
18127
19216
|
} catch (error) {
|
|
18128
19217
|
if (isMissingFsError(error)) return;
|
|
18129
19218
|
if (isPermissionFsError(error)) {
|
|
18130
|
-
unreadablePrefixes.add(
|
|
19219
|
+
unreadablePrefixes.add(path23.resolve(directoryPath));
|
|
18131
19220
|
return;
|
|
18132
19221
|
}
|
|
18133
19222
|
throw error;
|
|
18134
19223
|
}
|
|
18135
19224
|
for (const entry of entries) {
|
|
18136
|
-
const fullPath =
|
|
18137
|
-
const relativePath =
|
|
19225
|
+
const fullPath = path23.join(directoryPath, entry.name);
|
|
19226
|
+
const relativePath = path23.relative(normalizedProjectRoot, fullPath);
|
|
18138
19227
|
if (entry.isDirectory()) {
|
|
18139
|
-
if (hasFilteredPathSegment(relativePath,
|
|
19228
|
+
if (hasFilteredPathSegment(relativePath, path23.sep) || isRestrictedDirectory(relativePath, path23.sep)) continue;
|
|
18140
19229
|
if (ignoreFilter.ignores(relativePath)) continue;
|
|
18141
19230
|
if (maxDepth === -1 || depth < maxDepth) await walk(fullPath, depth + 1);
|
|
18142
19231
|
} else if (entry.isFile()) {
|
|
@@ -18160,7 +19249,7 @@ function completeFileSnapshot(previous, scan) {
|
|
|
18160
19249
|
return completed;
|
|
18161
19250
|
}
|
|
18162
19251
|
async function includeExplicitConfigPaths(snapshot, unreadablePrefixes, configPaths) {
|
|
18163
|
-
for (const configPath of [...new Set(configPaths.map((value) =>
|
|
19252
|
+
for (const configPath of [...new Set(configPaths.map((value) => path23.resolve(value)))]) {
|
|
18164
19253
|
if (snapshot.has(configPath)) continue;
|
|
18165
19254
|
const stat5 = await readStatIfFile(configPath, unreadablePrefixes);
|
|
18166
19255
|
if (stat5) snapshot.set(configPath, { size: stat5.size, mtimeMs: stat5.mtimeMs });
|
|
@@ -18170,12 +19259,12 @@ async function includeExplicitConfigPathsInPath(snapshot, unreadablePrefixes, co
|
|
|
18170
19259
|
await includeExplicitConfigPaths(
|
|
18171
19260
|
snapshot,
|
|
18172
19261
|
unreadablePrefixes,
|
|
18173
|
-
configPaths.filter((configPath) => isWithinPath(targetPath,
|
|
19262
|
+
configPaths.filter((configPath) => isWithinPath(targetPath, path23.resolve(configPath)))
|
|
18174
19263
|
);
|
|
18175
19264
|
}
|
|
18176
19265
|
function isWithinPath(parentPath, childPath) {
|
|
18177
|
-
const relativePath =
|
|
18178
|
-
return relativePath === "" || !relativePath.startsWith(`..${
|
|
19266
|
+
const relativePath = path23.relative(parentPath, childPath);
|
|
19267
|
+
return relativePath === "" || !relativePath.startsWith(`..${path23.sep}`) && relativePath !== ".." && !path23.isAbsolute(relativePath);
|
|
18179
19268
|
}
|
|
18180
19269
|
async function readStatIfFile(filePath, unreadablePrefixes) {
|
|
18181
19270
|
try {
|
|
@@ -18184,7 +19273,7 @@ async function readStatIfFile(filePath, unreadablePrefixes) {
|
|
|
18184
19273
|
} catch (error) {
|
|
18185
19274
|
if (isMissingFsError(error)) return null;
|
|
18186
19275
|
if (isPermissionFsError(error)) {
|
|
18187
|
-
unreadablePrefixes.add(
|
|
19276
|
+
unreadablePrefixes.add(path23.resolve(filePath));
|
|
18188
19277
|
return null;
|
|
18189
19278
|
}
|
|
18190
19279
|
throw error;
|
|
@@ -18321,8 +19410,8 @@ var FileWatcher = class {
|
|
|
18321
19410
|
this.createWatcher();
|
|
18322
19411
|
}
|
|
18323
19412
|
resetReady() {
|
|
18324
|
-
this.readyPromise = new Promise((
|
|
18325
|
-
this.resolveReady =
|
|
19413
|
+
this.readyPromise = new Promise((resolve18) => {
|
|
19414
|
+
this.resolveReady = resolve18;
|
|
18326
19415
|
});
|
|
18327
19416
|
this.startupReadySignals = 1;
|
|
18328
19417
|
}
|
|
@@ -18353,7 +19442,7 @@ var FileWatcher = class {
|
|
|
18353
19442
|
const resolvedWatchTargets = watchTargets ?? this.getFullChokidarWatchTargets();
|
|
18354
19443
|
const watcherOptions = {
|
|
18355
19444
|
ignored: (filePath) => {
|
|
18356
|
-
const relativePath =
|
|
19445
|
+
const relativePath = path24.relative(this.projectRoot, filePath);
|
|
18357
19446
|
if (!relativePath) return false;
|
|
18358
19447
|
if (this.isProjectConfigPathOrAncestor(relativePath)) {
|
|
18359
19448
|
return false;
|
|
@@ -18361,10 +19450,10 @@ var FileWatcher = class {
|
|
|
18361
19450
|
if (this.isOutsideProjectPath(relativePath)) {
|
|
18362
19451
|
return true;
|
|
18363
19452
|
}
|
|
18364
|
-
if (hasFilteredPathSegment(relativePath,
|
|
19453
|
+
if (hasFilteredPathSegment(relativePath, path24.sep)) {
|
|
18365
19454
|
return true;
|
|
18366
19455
|
}
|
|
18367
|
-
if (isRestrictedDirectory(relativePath,
|
|
19456
|
+
if (isRestrictedDirectory(relativePath, path24.sep)) {
|
|
18368
19457
|
return true;
|
|
18369
19458
|
}
|
|
18370
19459
|
if (ignoreFilter.ignores(relativePath)) {
|
|
@@ -18455,13 +19544,13 @@ var FileWatcher = class {
|
|
|
18455
19544
|
getExternalConfigWatchTargets() {
|
|
18456
19545
|
return [...new Set(
|
|
18457
19546
|
this.projectConfigPaths.filter((projectConfigPath) => {
|
|
18458
|
-
const relativeConfigPath =
|
|
19547
|
+
const relativeConfigPath = path24.relative(this.projectRoot, projectConfigPath);
|
|
18459
19548
|
return this.isOutsideProjectPath(relativeConfigPath);
|
|
18460
19549
|
}).map((projectConfigPath) => {
|
|
18461
19550
|
if ((0, import_fs14.existsSync)(projectConfigPath)) {
|
|
18462
19551
|
return projectConfigPath;
|
|
18463
19552
|
}
|
|
18464
|
-
return this.getNearestExistingDirectory(
|
|
19553
|
+
return this.getNearestExistingDirectory(path24.dirname(projectConfigPath));
|
|
18465
19554
|
})
|
|
18466
19555
|
)];
|
|
18467
19556
|
}
|
|
@@ -18523,7 +19612,7 @@ var FileWatcher = class {
|
|
|
18523
19612
|
}
|
|
18524
19613
|
scheduleNativeReconciliation(generation, filePath) {
|
|
18525
19614
|
if (!this.isCurrentNativeSetup(generation)) return;
|
|
18526
|
-
const requiresFullReconciliation = filePath ===
|
|
19615
|
+
const requiresFullReconciliation = filePath === path24.join(this.projectRoot, ".gitignore");
|
|
18527
19616
|
const invalidatedPath = requiresFullReconciliation ? null : filePath;
|
|
18528
19617
|
this.nativeInvalidatedPaths.set(invalidatedPath, invalidatedPath !== null);
|
|
18529
19618
|
if (this.nativeReconcileTimer) {
|
|
@@ -18618,23 +19707,23 @@ var FileWatcher = class {
|
|
|
18618
19707
|
this.scheduleFlush();
|
|
18619
19708
|
}
|
|
18620
19709
|
isProjectConfigPath(filePath) {
|
|
18621
|
-
const relativePath =
|
|
18622
|
-
const normalizedRelativePath =
|
|
19710
|
+
const relativePath = path24.relative(this.projectRoot, filePath);
|
|
19711
|
+
const normalizedRelativePath = path24.normalize(relativePath);
|
|
18623
19712
|
return this.getProjectConfigRelativePaths().some((configPath) => configPath === normalizedRelativePath);
|
|
18624
19713
|
}
|
|
18625
19714
|
isProjectConfigPathOrAncestor(relativePath) {
|
|
18626
|
-
const normalizedRelativePath =
|
|
19715
|
+
const normalizedRelativePath = path24.normalize(relativePath);
|
|
18627
19716
|
return this.getProjectConfigRelativePaths().some(
|
|
18628
|
-
(configPath) => configPath === normalizedRelativePath || configPath.startsWith(`${normalizedRelativePath}${
|
|
19717
|
+
(configPath) => configPath === normalizedRelativePath || configPath.startsWith(`${normalizedRelativePath}${path24.sep}`)
|
|
18629
19718
|
);
|
|
18630
19719
|
}
|
|
18631
19720
|
isOutsideProjectPath(relativePath) {
|
|
18632
|
-
return relativePath === ".." || relativePath.startsWith(`..${
|
|
19721
|
+
return relativePath === ".." || relativePath.startsWith(`..${path24.sep}`) || path24.isAbsolute(relativePath);
|
|
18633
19722
|
}
|
|
18634
19723
|
getNearestExistingDirectory(directoryPath) {
|
|
18635
19724
|
let candidate = directoryPath;
|
|
18636
19725
|
while (!(0, import_fs14.existsSync)(candidate)) {
|
|
18637
|
-
const parent =
|
|
19726
|
+
const parent = path24.dirname(candidate);
|
|
18638
19727
|
if (parent === candidate) break;
|
|
18639
19728
|
candidate = parent;
|
|
18640
19729
|
}
|
|
@@ -18642,7 +19731,7 @@ var FileWatcher = class {
|
|
|
18642
19731
|
}
|
|
18643
19732
|
getProjectConfigRelativePaths() {
|
|
18644
19733
|
return this.projectConfigPaths.map(
|
|
18645
|
-
(configPath) =>
|
|
19734
|
+
(configPath) => path24.normalize(path24.relative(this.projectRoot, configPath))
|
|
18646
19735
|
);
|
|
18647
19736
|
}
|
|
18648
19737
|
getConfigPathStates() {
|
|
@@ -18700,7 +19789,7 @@ var FileWatcher = class {
|
|
|
18700
19789
|
return;
|
|
18701
19790
|
}
|
|
18702
19791
|
const changes = Array.from(this.pendingChanges.entries()).map(
|
|
18703
|
-
([
|
|
19792
|
+
([path26, type]) => ({ path: path26, type })
|
|
18704
19793
|
);
|
|
18705
19794
|
this.pendingChanges.clear();
|
|
18706
19795
|
try {
|
|
@@ -18746,7 +19835,7 @@ var FileWatcher = class {
|
|
|
18746
19835
|
};
|
|
18747
19836
|
|
|
18748
19837
|
// src/watcher/git-head-watcher.ts
|
|
18749
|
-
var
|
|
19838
|
+
var path25 = __toESM(require("path"), 1);
|
|
18750
19839
|
var GitHeadWatcher = class {
|
|
18751
19840
|
watcher = null;
|
|
18752
19841
|
projectRoot;
|
|
@@ -18768,13 +19857,13 @@ var GitHeadWatcher = class {
|
|
|
18768
19857
|
this.readyPromise = Promise.resolve();
|
|
18769
19858
|
return;
|
|
18770
19859
|
}
|
|
18771
|
-
this.readyPromise = new Promise((
|
|
18772
|
-
this.resolveReady =
|
|
19860
|
+
this.readyPromise = new Promise((resolve18) => {
|
|
19861
|
+
this.resolveReady = resolve18;
|
|
18773
19862
|
});
|
|
18774
19863
|
this.onBranchChange = handler;
|
|
18775
19864
|
this.currentBranch = getCurrentBranch(this.projectRoot);
|
|
18776
19865
|
const headPath = getHeadPath(this.projectRoot);
|
|
18777
|
-
const refsPath =
|
|
19866
|
+
const refsPath = path25.join(this.projectRoot, ".git", "refs", "heads");
|
|
18778
19867
|
this.watcher = chokidar_default.watch([headPath, refsPath], {
|
|
18779
19868
|
persistent: true,
|
|
18780
19869
|
ignoreInitial: true,
|
|
@@ -18842,7 +19931,9 @@ var GitHeadWatcher = class {
|
|
|
18842
19931
|
function createWatcherWithIndexer(getIndexer, projectRoot3, config, host, options = {}) {
|
|
18843
19932
|
const fileWatcher = new FileWatcher(projectRoot3, config, host, options);
|
|
18844
19933
|
const configPaths = getConfigPaths(projectRoot3, host, options);
|
|
18845
|
-
configureAutoIndex(projectRoot3, host, parseConfig(config), getIndexer
|
|
19934
|
+
configureAutoIndex(projectRoot3, host, parseConfig(config), getIndexer, {
|
|
19935
|
+
synchronizeBackgroundWorker: false
|
|
19936
|
+
});
|
|
18846
19937
|
let stopped = false;
|
|
18847
19938
|
const requestReindex = () => {
|
|
18848
19939
|
if (stopped) return;
|
|
@@ -18862,7 +19953,9 @@ function createWatcherWithIndexer(getIndexer, projectRoot3, config, host, option
|
|
|
18862
19953
|
const parsedConfig = options.configPath ? parseConfig(loadConfigFile(options.configPath)) : void 0;
|
|
18863
19954
|
const refreshedConfig = refreshIndexerForDirectory(projectRoot3, host, parsedConfig);
|
|
18864
19955
|
if (refreshedConfig) {
|
|
18865
|
-
configureAutoIndex(projectRoot3, host, refreshedConfig, getIndexer
|
|
19956
|
+
configureAutoIndex(projectRoot3, host, refreshedConfig, getIndexer, {
|
|
19957
|
+
synchronizeBackgroundWorker: false
|
|
19958
|
+
});
|
|
18866
19959
|
}
|
|
18867
19960
|
}
|
|
18868
19961
|
requestReindex();
|
|
@@ -18910,7 +20003,6 @@ function getConfigPaths(projectRoot3, host, options) {
|
|
|
18910
20003
|
|
|
18911
20004
|
// src/adapters/pi/extension.ts
|
|
18912
20005
|
var HOST2 = "pi";
|
|
18913
|
-
var activeWatchers = /* @__PURE__ */ new Map();
|
|
18914
20006
|
var ChunkType = import_typebox2.Type.Union([
|
|
18915
20007
|
import_typebox2.Type.Literal("function"),
|
|
18916
20008
|
import_typebox2.Type.Literal("class"),
|
|
@@ -18929,24 +20021,30 @@ function projectRoot2(ctx) {
|
|
|
18929
20021
|
function isValidProject(projectRoot3, requireProjectMarker) {
|
|
18930
20022
|
return !isHomeDirectory(projectRoot3) && (!requireProjectMarker || hasProjectMarker(projectRoot3));
|
|
18931
20023
|
}
|
|
18932
|
-
function ensureWatcher(projectRoot3) {
|
|
18933
|
-
if (activeWatchers.has(projectRoot3)) return;
|
|
20024
|
+
async function ensureWatcher(projectRoot3) {
|
|
18934
20025
|
const config = parseConfig(loadMergedConfig(projectRoot3, HOST2));
|
|
18935
|
-
if (!
|
|
20026
|
+
if (!isValidProject(projectRoot3, config.indexing.requireProjectMarker)) {
|
|
20027
|
+
await stopBackgroundWorker(projectRoot3, HOST2).catch((error) => {
|
|
20028
|
+
console.error("[codebase-index] Failed to stop Pi background worker:", error);
|
|
20029
|
+
});
|
|
18936
20030
|
return;
|
|
18937
20031
|
}
|
|
18938
|
-
|
|
20032
|
+
getIndexerForProject(projectRoot3, HOST2);
|
|
20033
|
+
const watcherFactoryForConfig = (refreshedConfig) => refreshedConfig.indexing.watchFiles ? () => createWatcherWithIndexer(
|
|
18939
20034
|
() => getIndexerForProject(projectRoot3, HOST2),
|
|
18940
20035
|
projectRoot3,
|
|
18941
|
-
|
|
20036
|
+
refreshedConfig,
|
|
18942
20037
|
HOST2
|
|
18943
|
-
)
|
|
18944
|
-
|
|
18945
|
-
|
|
18946
|
-
|
|
18947
|
-
|
|
18948
|
-
|
|
18949
|
-
|
|
20038
|
+
) : null;
|
|
20039
|
+
configureBackgroundWorker(projectRoot3, HOST2, config, {
|
|
20040
|
+
startAutoIndex: (source, allowDisabledAutoIndex) => {
|
|
20041
|
+
startAutoIndexForBackgroundWorker(projectRoot3, HOST2, source, allowDisabledAutoIndex);
|
|
20042
|
+
},
|
|
20043
|
+
stopAutoIndex: () => stopAutoIndexForBackgroundWorker(projectRoot3, HOST2),
|
|
20044
|
+
watcherFactory: watcherFactoryForConfig(config),
|
|
20045
|
+
watcherFactoryForConfig
|
|
20046
|
+
});
|
|
20047
|
+
await waitForBackgroundWorkerStart(projectRoot3, HOST2);
|
|
18950
20048
|
}
|
|
18951
20049
|
function codebaseIndexPiExtension(pi) {
|
|
18952
20050
|
pi.registerTool({
|
|
@@ -19106,12 +20204,14 @@ function codebaseIndexPiExtension(pi) {
|
|
|
19106
20204
|
parameters: import_typebox2.Type.Object({
|
|
19107
20205
|
force: import_typebox2.Type.Optional(import_typebox2.Type.Boolean({ default: false })),
|
|
19108
20206
|
estimateOnly: import_typebox2.Type.Optional(import_typebox2.Type.Boolean({ default: false })),
|
|
20207
|
+
dryRun: import_typebox2.Type.Optional(import_typebox2.Type.Boolean({ default: false })),
|
|
19109
20208
|
verbose: import_typebox2.Type.Optional(import_typebox2.Type.Boolean({ default: false }))
|
|
19110
20209
|
}),
|
|
19111
20210
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
19112
20211
|
try {
|
|
19113
20212
|
const result = await runIndexCodebase(projectRoot2(ctx), HOST2, params);
|
|
19114
20213
|
if (result.kind === "estimate") return text2(formatCostEstimate(result.estimate), result.estimate);
|
|
20214
|
+
if (result.kind === "dryrun") return text2(formatDryRunEstimate(result.dryrun), result.dryrun);
|
|
19115
20215
|
if (result.kind === "busy") return text2(result.text, { code: "INDEX_BUSY" });
|
|
19116
20216
|
if (result.kind === "message") return text2(result.text);
|
|
19117
20217
|
return text2(formatIndexStats(result.stats, params.verbose ?? false), result.stats);
|
|
@@ -19177,16 +20277,16 @@ function codebaseIndexPiExtension(pi) {
|
|
|
19177
20277
|
});
|
|
19178
20278
|
registerPiCallGraphTools(pi);
|
|
19179
20279
|
pi.on("before_agent_start", async (event, ctx) => {
|
|
19180
|
-
ensureWatcher(projectRoot2(ctx));
|
|
20280
|
+
await ensureWatcher(projectRoot2(ctx));
|
|
19181
20281
|
return {
|
|
19182
20282
|
systemPrompt: `${event.systemPrompt}
|
|
19183
20283
|
|
|
19184
|
-
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.`
|
|
20284
|
+
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.`
|
|
19185
20285
|
};
|
|
19186
20286
|
});
|
|
19187
20287
|
pi.on("session_shutdown", async (_event, ctx) => {
|
|
19188
20288
|
const root = projectRoot2(ctx);
|
|
19189
|
-
await
|
|
20289
|
+
await stopBackgroundWorker(root, HOST2);
|
|
19190
20290
|
});
|
|
19191
20291
|
pi.registerTool({
|
|
19192
20292
|
name: TOOL_NAME.PR_IMPACT,
|