opencode-codebase-index 0.22.5 → 0.24.0
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 +6 -5
- package/commands/peek.md +2 -1
- package/commands/search.md +2 -1
- package/dist/cli.cjs +1986 -756
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +1987 -757
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +1663 -672
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1664 -673
- package/dist/index.js.map +1 -1
- package/dist/pi-extension.cjs +5464 -2270
- package/dist/pi-extension.cjs.map +1 -1
- package/dist/pi-extension.js +5453 -2259
- 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 +5 -1
- package/skill/SKILL.md +12 -16
package/dist/index.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(path30, 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(path30);
|
|
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 = (path30, originalPath, doThrow) => {
|
|
367
|
+
if (!isString(path30)) {
|
|
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 (!path30) {
|
|
374
374
|
return doThrow(`path must not be empty`, TypeError);
|
|
375
375
|
}
|
|
376
|
-
if (checkPath.isNotRelative(
|
|
376
|
+
if (checkPath.isNotRelative(path30)) {
|
|
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 = (path30) => REGEX_TEST_INVALID_PATH.test(path30);
|
|
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 path30 = originalPath && checkPath.convert(originalPath);
|
|
416
416
|
checkPath(
|
|
417
|
-
|
|
417
|
+
path30,
|
|
418
418
|
originalPath,
|
|
419
419
|
this._strictPathCheck ? throwError : RETURN_FALSE
|
|
420
420
|
);
|
|
421
|
-
return this._t(
|
|
421
|
+
return this._t(path30, cache, checkUnignored, slices);
|
|
422
422
|
}
|
|
423
|
-
checkIgnore(
|
|
424
|
-
if (!REGEX_TEST_TRAILING_SLASH.test(
|
|
425
|
-
return this.test(
|
|
423
|
+
checkIgnore(path30) {
|
|
424
|
+
if (!REGEX_TEST_TRAILING_SLASH.test(path30)) {
|
|
425
|
+
return this.test(path30);
|
|
426
426
|
}
|
|
427
|
-
const slices =
|
|
427
|
+
const slices = path30.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(path30, false, MODE_CHECK_IGNORE);
|
|
441
441
|
}
|
|
442
|
-
_t(
|
|
443
|
-
if (
|
|
444
|
-
return cache[
|
|
442
|
+
_t(path30, cache, checkUnignored, slices) {
|
|
443
|
+
if (path30 in cache) {
|
|
444
|
+
return cache[path30];
|
|
445
445
|
}
|
|
446
446
|
if (!slices) {
|
|
447
|
-
slices =
|
|
447
|
+
slices = path30.split(SLASH2).filter(Boolean);
|
|
448
448
|
}
|
|
449
449
|
slices.pop();
|
|
450
450
|
if (!slices.length) {
|
|
451
|
-
return cache[
|
|
451
|
+
return cache[path30] = this._rules.test(path30, 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[path30] = parent.ignored ? parent : this._rules.test(path30, checkUnignored, MODE_IGNORE);
|
|
460
460
|
}
|
|
461
|
-
ignores(
|
|
462
|
-
return this._test(
|
|
461
|
+
ignores(path30) {
|
|
462
|
+
return this._test(path30, this._ignoreCache, false).ignored;
|
|
463
463
|
}
|
|
464
464
|
createFilter() {
|
|
465
|
-
return (
|
|
465
|
+
return (path30) => !this.ignores(path30);
|
|
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(path30) {
|
|
472
|
+
return this._test(path30, this._testCache, true);
|
|
473
473
|
}
|
|
474
474
|
};
|
|
475
475
|
var factory = (options) => new Ignore2(options);
|
|
476
|
-
var isPathValid = (
|
|
476
|
+
var isPathValid = (path30) => checkPath(path30 && checkPath.convert(path30), path30, 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 = (path30) => REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path30) || isNotRelative(path30);
|
|
482
482
|
};
|
|
483
483
|
if (
|
|
484
484
|
// Detect `process` so that it can run in browsers.
|
|
@@ -663,7 +663,7 @@ __export(index_exports, {
|
|
|
663
663
|
module.exports = __toCommonJS(index_exports);
|
|
664
664
|
|
|
665
665
|
// src/adapters/opencode.ts
|
|
666
|
-
var
|
|
666
|
+
var path29 = __toESM(require("path"), 1);
|
|
667
667
|
var import_url = require("url");
|
|
668
668
|
|
|
669
669
|
// src/config/constants.ts
|
|
@@ -724,6 +724,17 @@ var EMBEDDING_MODELS = {
|
|
|
724
724
|
maxTokens: 2048,
|
|
725
725
|
costPer1MTokens: 0.15,
|
|
726
726
|
taskAble: true
|
|
727
|
+
},
|
|
728
|
+
"gemini-embedding-2": {
|
|
729
|
+
provider: "google",
|
|
730
|
+
model: "gemini-embedding-2",
|
|
731
|
+
// Keep a conservative, testable default embedding dimension. Gemini Embedding 2 supports
|
|
732
|
+
// flexible dimensions via outputDimensionality.
|
|
733
|
+
dimensions: 1536,
|
|
734
|
+
maxTokens: 8192,
|
|
735
|
+
costPer1MTokens: 0.15,
|
|
736
|
+
taskAble: false,
|
|
737
|
+
promptStyle: "embedding-2"
|
|
727
738
|
}
|
|
728
739
|
},
|
|
729
740
|
"openai": {
|
|
@@ -757,26 +768,15 @@ var EMBEDDING_MODELS = {
|
|
|
757
768
|
maxTokens: 512,
|
|
758
769
|
costPer1MTokens: 0
|
|
759
770
|
}
|
|
760
|
-
},
|
|
761
|
-
"github-copilot": {
|
|
762
|
-
"text-embedding-3-small": {
|
|
763
|
-
provider: "github-copilot",
|
|
764
|
-
model: "text-embedding-3-small",
|
|
765
|
-
dimensions: 1536,
|
|
766
|
-
maxTokens: 8191,
|
|
767
|
-
costPer1MTokens: 0
|
|
768
|
-
}
|
|
769
771
|
}
|
|
770
772
|
};
|
|
771
773
|
var DEFAULT_PROVIDER_MODELS = {
|
|
772
|
-
"github-copilot": "text-embedding-3-small",
|
|
773
774
|
"openai": "text-embedding-3-small",
|
|
774
775
|
"google": "gemini-embedding-001",
|
|
775
776
|
"ollama": "nomic-embed-text"
|
|
776
777
|
};
|
|
777
778
|
var AUTO_DETECT_PROVIDER_ORDER = [
|
|
778
779
|
"ollama",
|
|
779
|
-
"github-copilot",
|
|
780
780
|
"openai",
|
|
781
781
|
"google"
|
|
782
782
|
];
|
|
@@ -802,6 +802,9 @@ function getDefaultIndexingConfig() {
|
|
|
802
802
|
maxDepth: 5,
|
|
803
803
|
maxFilesPerDirectory: 100,
|
|
804
804
|
fallbackToTextOnMaxChunks: true,
|
|
805
|
+
// Must stay in sync with DEFAULT_LINES_PER_CHUNK in native/src/lib.rs (the napi
|
|
806
|
+
// fallback used when a native caller omits the argument).
|
|
807
|
+
linesPerChunk: 30,
|
|
805
808
|
gitBlame: { enabled: false }
|
|
806
809
|
};
|
|
807
810
|
}
|
|
@@ -935,6 +938,7 @@ function parseConfig(raw) {
|
|
|
935
938
|
maxDepth: typeof rawIndexing.maxDepth === "number" ? rawIndexing.maxDepth < -1 ? -1 : rawIndexing.maxDepth : defaultIndexing.maxDepth,
|
|
936
939
|
maxFilesPerDirectory: typeof rawIndexing.maxFilesPerDirectory === "number" ? Math.max(1, rawIndexing.maxFilesPerDirectory) : defaultIndexing.maxFilesPerDirectory,
|
|
937
940
|
fallbackToTextOnMaxChunks: typeof rawIndexing.fallbackToTextOnMaxChunks === "boolean" ? rawIndexing.fallbackToTextOnMaxChunks : defaultIndexing.fallbackToTextOnMaxChunks,
|
|
941
|
+
linesPerChunk: typeof rawIndexing.linesPerChunk === "number" && Number.isFinite(rawIndexing.linesPerChunk) ? Math.min(Math.max(1, Math.floor(rawIndexing.linesPerChunk)), 4294967295) : defaultIndexing.linesPerChunk,
|
|
938
942
|
gitBlame: {
|
|
939
943
|
enabled: rawIndexing.gitBlame && typeof rawIndexing.gitBlame === "object" && typeof rawIndexing.gitBlame.enabled === "boolean" ? rawIndexing.gitBlame.enabled : defaultIndexing.gitBlame.enabled
|
|
940
944
|
}
|
|
@@ -977,6 +981,7 @@ function parseConfig(raw) {
|
|
|
977
981
|
let embeddingModel;
|
|
978
982
|
let customProvider;
|
|
979
983
|
let reranker;
|
|
984
|
+
const githubCopilotDeprecationMessage = '`embeddingProvider: "github-copilot"` is deprecated and no longer available. Migrate existing configs to `embeddingProvider: "google"` and select an explicit Google model. For existing indexes, run `index_codebase` with `force: true` after changing to `gemini-embedding-001` or `gemini-embedding-2` to rebuild embeddings. See docs/configuration.md for details.';
|
|
980
985
|
if (embeddingProviderValue === "custom") {
|
|
981
986
|
embeddingProvider = "custom";
|
|
982
987
|
const rawCustom = input.customProvider && typeof input.customProvider === "object" ? input.customProvider : null;
|
|
@@ -1016,6 +1021,8 @@ function parseConfig(raw) {
|
|
|
1016
1021
|
} else if (rawEmbeddingModel) {
|
|
1017
1022
|
embeddingModel = DEFAULT_PROVIDER_MODELS[embeddingProvider];
|
|
1018
1023
|
}
|
|
1024
|
+
} else if (embeddingProviderValue === "github-copilot") {
|
|
1025
|
+
throw new Error(githubCopilotDeprecationMessage);
|
|
1019
1026
|
} else {
|
|
1020
1027
|
embeddingProvider = "auto";
|
|
1021
1028
|
}
|
|
@@ -1046,10 +1053,21 @@ function parseConfig(raw) {
|
|
|
1046
1053
|
timeoutMs: typeof rawReranker.timeoutMs === "number" ? Math.max(1e3, Math.floor(rawReranker.timeoutMs)) : 1e4
|
|
1047
1054
|
};
|
|
1048
1055
|
}
|
|
1056
|
+
const rawEmbedding = input.embedding && typeof input.embedding === "object" ? input.embedding : {};
|
|
1057
|
+
const rawEmbeddingBatch = rawEmbedding.batch && typeof rawEmbedding.batch === "object" ? rawEmbedding.batch : null;
|
|
1058
|
+
const embeddingMaxBatchItems = typeof rawEmbeddingBatch?.maxBatchItems === "number" && Number.isFinite(rawEmbeddingBatch.maxBatchItems) ? Math.max(1, Math.floor(rawEmbeddingBatch.maxBatchItems)) : void 0;
|
|
1059
|
+
const embeddingMaxBatchTokens = typeof rawEmbeddingBatch?.maxBatchTokens === "number" && Number.isFinite(rawEmbeddingBatch.maxBatchTokens) ? Math.max(1, Math.floor(rawEmbeddingBatch.maxBatchTokens)) : void 0;
|
|
1060
|
+
const embedding = embeddingMaxBatchItems !== void 0 || embeddingMaxBatchTokens !== void 0 ? {
|
|
1061
|
+
batch: {
|
|
1062
|
+
...embeddingMaxBatchItems !== void 0 ? { maxBatchItems: embeddingMaxBatchItems } : {},
|
|
1063
|
+
...embeddingMaxBatchTokens !== void 0 ? { maxBatchTokens: embeddingMaxBatchTokens } : {}
|
|
1064
|
+
}
|
|
1065
|
+
} : {};
|
|
1049
1066
|
return {
|
|
1050
1067
|
embeddingProvider,
|
|
1051
1068
|
embeddingModel,
|
|
1052
1069
|
customProvider,
|
|
1070
|
+
embedding,
|
|
1053
1071
|
scope: isValidScope(scopeValue) ? scopeValue : "project",
|
|
1054
1072
|
include: includeValue ?? DEFAULT_INCLUDE,
|
|
1055
1073
|
exclude: excludeValue ?? DEFAULT_EXCLUDE,
|
|
@@ -1141,11 +1159,11 @@ function resolveGitDir(repoRoot) {
|
|
|
1141
1159
|
return null;
|
|
1142
1160
|
}
|
|
1143
1161
|
try {
|
|
1144
|
-
const
|
|
1145
|
-
if (
|
|
1162
|
+
const stat5 = (0, import_fs2.statSync)(gitPath);
|
|
1163
|
+
if (stat5.isDirectory()) {
|
|
1146
1164
|
return gitPath;
|
|
1147
1165
|
}
|
|
1148
|
-
if (
|
|
1166
|
+
if (stat5.isFile()) {
|
|
1149
1167
|
const content = (0, import_fs2.readFileSync)(gitPath, "utf-8").trim();
|
|
1150
1168
|
const match = content.match(/^gitdir:\s*(.+)$/);
|
|
1151
1169
|
if (match) {
|
|
@@ -2214,7 +2232,7 @@ function analyzeQueryIntent(query) {
|
|
|
2214
2232
|
}
|
|
2215
2233
|
function isTestPath(filePath) {
|
|
2216
2234
|
const normalized = normalizePath(filePath);
|
|
2217
|
-
return /(?:^|\/)(?:test|tests|__tests__|spec|specs)(?:\/|$)/u.test(normalized) ||
|
|
2235
|
+
return /(?:^|\/)(?:test|tests|__tests__|spec|specs)(?:\/|$)/u.test(normalized) || /(?:\.(?:test|spec)|_(?:test|spec))\.[^/]+$/u.test(normalized) || /(?:^|\/)(?:test|spec)_[^/]+\.[^/]+$/u.test(normalized);
|
|
2218
2236
|
}
|
|
2219
2237
|
function isFixturePath(filePath) {
|
|
2220
2238
|
const normalized = normalizePath(filePath);
|
|
@@ -2316,6 +2334,10 @@ function scoreCandidate(query, intent, candidate, originalIndex) {
|
|
|
2316
2334
|
let boost = 0;
|
|
2317
2335
|
if (intent.primary === "conceptual") {
|
|
2318
2336
|
boost += Math.min(0.14, overlap * 0.14);
|
|
2337
|
+
if (intent.preferSourcePaths) {
|
|
2338
|
+
boost += implementationPath ? 0.32 : 0;
|
|
2339
|
+
if (testPath || fixturePath || docsPath) boost -= 0.35;
|
|
2340
|
+
}
|
|
2319
2341
|
if (generatedOrVendor) boost -= 0.18;
|
|
2320
2342
|
if (importChunk || weakContainer) boost -= 0.04;
|
|
2321
2343
|
} else if (intent.primary === "test") {
|
|
@@ -2589,8 +2611,8 @@ function formatExactSearchHandoff(results) {
|
|
|
2589
2611
|
}
|
|
2590
2612
|
function formatContextEvidence(result, index) {
|
|
2591
2613
|
const symbol = result.name ? ` ${JSON.stringify(compactEvidenceValue(result.name, 80))}` : "";
|
|
2592
|
-
const
|
|
2593
|
-
return `[${index}] ${result.chunkType}${symbol} in ${
|
|
2614
|
+
const path30 = compactEvidenceValue(result.filePath, 120);
|
|
2615
|
+
return `[${index}] ${result.chunkType}${symbol} in ${path30}:${result.startLine}-${result.endLine} (score ${result.score.toFixed(2)})`;
|
|
2594
2616
|
}
|
|
2595
2617
|
function formatContextPack(heading, selected, candidateCount, duplicateCount, limitOmittedCount, budgetOmittedCount, includeExactSearchHandoff) {
|
|
2596
2618
|
const lines = selected.map((result, index) => formatContextEvidence(result, index + 1));
|
|
@@ -3283,6 +3305,19 @@ function parseOwner(value) {
|
|
|
3283
3305
|
if (typeof candidate.startedAt !== "string" || Number.isNaN(Date.parse(candidate.startedAt))) return null;
|
|
3284
3306
|
if (typeof candidate.operation !== "string" || !VALID_OPERATIONS.has(candidate.operation)) return null;
|
|
3285
3307
|
if (typeof candidate.token !== "string" || !UUID_PATTERN.test(candidate.token)) return null;
|
|
3308
|
+
if (candidate.recoveryProtocolVersion !== void 0 && candidate.recoveryProtocolVersion !== 1) return null;
|
|
3309
|
+
if (candidate.projectRoot !== void 0 && typeof candidate.projectRoot !== "string") return null;
|
|
3310
|
+
if (candidate.scopedRoots !== void 0) {
|
|
3311
|
+
if (!Array.isArray(candidate.scopedRoots) || candidate.scopedRoots.some((root) => typeof root !== "string")) {
|
|
3312
|
+
return null;
|
|
3313
|
+
}
|
|
3314
|
+
}
|
|
3315
|
+
if (candidate.clearRecovery !== void 0) {
|
|
3316
|
+
const recovery = candidate.clearRecovery;
|
|
3317
|
+
if (typeof recovery !== "object" || recovery === null || recovery.phase !== "clearing" || typeof recovery.embeddingProvider !== "string" || recovery.embeddingProvider.length === 0 || typeof recovery.embeddingModel !== "string" || recovery.embeddingModel.length === 0 || !Number.isInteger(recovery.embeddingDimensions) || (recovery.embeddingDimensions ?? 0) <= 0 || typeof recovery.embeddingStrategyVersion !== "string" || recovery.embeddingStrategyVersion.length === 0 || recovery.compatibilityDecision !== "compatible" && recovery.compatibilityDecision !== "embedding-strategy-mismatch" && recovery.compatibilityDecision !== "incompatible" || candidate.operation !== "clear" && candidate.operation !== "force-index") {
|
|
3318
|
+
return null;
|
|
3319
|
+
}
|
|
3320
|
+
}
|
|
3286
3321
|
return candidate;
|
|
3287
3322
|
}
|
|
3288
3323
|
function parseReclaimOwner(value) {
|
|
@@ -3523,13 +3558,18 @@ function isTransientIndexLockContention(error) {
|
|
|
3523
3558
|
if (!isIndexLockContentionError(error) || !("reason" in error)) return false;
|
|
3524
3559
|
return error.reason === "active" || error.reason === "reclaiming";
|
|
3525
3560
|
}
|
|
3526
|
-
function acquireIndexLock(indexPath, operation) {
|
|
3561
|
+
function acquireIndexLock(indexPath, operation, recoveryScope) {
|
|
3527
3562
|
(0, import_fs5.mkdirSync)(indexPath, { recursive: true });
|
|
3528
3563
|
const canonicalIndexPath = import_fs5.realpathSync.native(indexPath);
|
|
3529
3564
|
const lockPath = path9.join(canonicalIndexPath, "indexing.lock");
|
|
3530
3565
|
cleanupDeadPublicationCandidates(canonicalIndexPath);
|
|
3531
3566
|
for (let attempt = 0; attempt < 6; attempt += 1) {
|
|
3532
|
-
const owner = createOwner(operation)
|
|
3567
|
+
const owner = recoveryScope === void 0 ? createOwner(operation) : {
|
|
3568
|
+
...createOwner(operation),
|
|
3569
|
+
recoveryProtocolVersion: 1,
|
|
3570
|
+
projectRoot: recoveryScope.projectRoot,
|
|
3571
|
+
scopedRoots: recoveryScope.scopedRoots
|
|
3572
|
+
};
|
|
3533
3573
|
if (publishJsonDirectory(lockPath, owner)) {
|
|
3534
3574
|
const lease = {
|
|
3535
3575
|
canonicalIndexPath,
|
|
@@ -3594,6 +3634,33 @@ function releaseIndexLock(lease) {
|
|
|
3594
3634
|
}
|
|
3595
3635
|
return true;
|
|
3596
3636
|
}
|
|
3637
|
+
function setIndexLockClearRecoveryState(lease, clearRecovery) {
|
|
3638
|
+
const currentOwner = readDirectoryOwner(lease.lockPath);
|
|
3639
|
+
if (!currentOwner || !sameOwner(currentOwner, lease.owner)) {
|
|
3640
|
+
throw new Error(`Lost ownership of index mutation lease ${lease.owner.token}`);
|
|
3641
|
+
}
|
|
3642
|
+
const nextOwner = { ...currentOwner };
|
|
3643
|
+
if (clearRecovery === null) {
|
|
3644
|
+
delete nextOwner.clearRecovery;
|
|
3645
|
+
} else {
|
|
3646
|
+
nextOwner.clearRecovery = clearRecovery;
|
|
3647
|
+
}
|
|
3648
|
+
const ownerPath = path9.join(lease.lockPath, OWNER_FILE_NAME);
|
|
3649
|
+
const temporaryPath = path9.join(
|
|
3650
|
+
lease.lockPath,
|
|
3651
|
+
`${OWNER_FILE_NAME}.tmp.${lease.owner.pid}.${lease.owner.token}.${(0, import_crypto.randomUUID)()}`
|
|
3652
|
+
);
|
|
3653
|
+
try {
|
|
3654
|
+
(0, import_fs5.writeFileSync)(temporaryPath, JSON.stringify(nextOwner), {
|
|
3655
|
+
encoding: "utf-8",
|
|
3656
|
+
flag: "wx",
|
|
3657
|
+
mode: 384
|
|
3658
|
+
});
|
|
3659
|
+
retryTransientFilesystemOperation(() => (0, import_fs5.renameSync)(temporaryPath, ownerPath));
|
|
3660
|
+
} finally {
|
|
3661
|
+
if ((0, import_fs5.existsSync)(temporaryPath)) (0, import_fs5.rmSync)(temporaryPath, { force: true });
|
|
3662
|
+
}
|
|
3663
|
+
}
|
|
3597
3664
|
function createLeaseTemporaryPath(targetPath, owner, kind = "tmp") {
|
|
3598
3665
|
if (kind === "bak") return `${targetPath}.bak.${owner.pid}.${owner.token}`;
|
|
3599
3666
|
temporaryCounter += 1;
|
|
@@ -3743,8 +3810,8 @@ async function* walkDirectory(dir, projectRoot, includePatterns, excludePatterns
|
|
|
3743
3810
|
if (entry.isDirectory()) {
|
|
3744
3811
|
subdirs.push({ fullPath, relativePath });
|
|
3745
3812
|
} else if (entry.isFile()) {
|
|
3746
|
-
const
|
|
3747
|
-
if (
|
|
3813
|
+
const stat5 = await import_fs6.promises.stat(fullPath);
|
|
3814
|
+
if (stat5.size > maxFileSize) {
|
|
3748
3815
|
skipped.push({ path: relativePath, reason: "too_large" });
|
|
3749
3816
|
continue;
|
|
3750
3817
|
}
|
|
@@ -3762,7 +3829,7 @@ async function* walkDirectory(dir, projectRoot, includePatterns, excludePatterns
|
|
|
3762
3829
|
}
|
|
3763
3830
|
}
|
|
3764
3831
|
if (matched) {
|
|
3765
|
-
filesInDir.push({ path: fullPath, size:
|
|
3832
|
+
filesInDir.push({ path: fullPath, size: stat5.size });
|
|
3766
3833
|
}
|
|
3767
3834
|
}
|
|
3768
3835
|
}
|
|
@@ -3819,8 +3886,8 @@ async function collectFiles(projectRoot, includePatterns, excludePatterns, maxFi
|
|
|
3819
3886
|
}
|
|
3820
3887
|
for (const resolvedKbRoot of normalizedRoots) {
|
|
3821
3888
|
try {
|
|
3822
|
-
const
|
|
3823
|
-
if (!
|
|
3889
|
+
const stat5 = await import_fs6.promises.stat(resolvedKbRoot);
|
|
3890
|
+
if (!stat5.isDirectory()) {
|
|
3824
3891
|
skipped.push({ path: resolvedKbRoot, reason: "excluded" });
|
|
3825
3892
|
continue;
|
|
3826
3893
|
}
|
|
@@ -3854,7 +3921,7 @@ function getErrorMessage(error) {
|
|
|
3854
3921
|
return error instanceof Error ? error.message : String(error);
|
|
3855
3922
|
}
|
|
3856
3923
|
function runCommand(file, args, options) {
|
|
3857
|
-
return new Promise((
|
|
3924
|
+
return new Promise((resolve17, reject) => {
|
|
3858
3925
|
childProcess.execFile(
|
|
3859
3926
|
file,
|
|
3860
3927
|
args,
|
|
@@ -3864,7 +3931,7 @@ function runCommand(file, args, options) {
|
|
|
3864
3931
|
reject(error);
|
|
3865
3932
|
return;
|
|
3866
3933
|
}
|
|
3867
|
-
|
|
3934
|
+
resolve17(stdout);
|
|
3868
3935
|
}
|
|
3869
3936
|
);
|
|
3870
3937
|
});
|
|
@@ -4009,10 +4076,10 @@ function safeFailureMessage(error) {
|
|
|
4009
4076
|
}
|
|
4010
4077
|
function cancellableDelay(delayMs, signal) {
|
|
4011
4078
|
if (signal.aborted) return Promise.reject(new AutoIndexCancelledError());
|
|
4012
|
-
return new Promise((
|
|
4079
|
+
return new Promise((resolve17, reject) => {
|
|
4013
4080
|
const timer = setTimeout(() => {
|
|
4014
4081
|
signal.removeEventListener("abort", onAbort);
|
|
4015
|
-
|
|
4082
|
+
resolve17();
|
|
4016
4083
|
}, delayMs);
|
|
4017
4084
|
timer.unref?.();
|
|
4018
4085
|
const onAbort = () => {
|
|
@@ -4024,15 +4091,15 @@ function cancellableDelay(delayMs, signal) {
|
|
|
4024
4091
|
}
|
|
4025
4092
|
function withTimeout(promise, timeoutMs) {
|
|
4026
4093
|
if (timeoutMs <= 0) return Promise.resolve(void 0);
|
|
4027
|
-
return new Promise((
|
|
4028
|
-
const timer = setTimeout(() =>
|
|
4094
|
+
return new Promise((resolve17) => {
|
|
4095
|
+
const timer = setTimeout(() => resolve17(void 0), timeoutMs);
|
|
4029
4096
|
timer.unref?.();
|
|
4030
4097
|
void promise.then((value) => {
|
|
4031
4098
|
clearTimeout(timer);
|
|
4032
|
-
|
|
4099
|
+
resolve17(value);
|
|
4033
4100
|
}, () => {
|
|
4034
4101
|
clearTimeout(timer);
|
|
4035
|
-
|
|
4102
|
+
resolve17(void 0);
|
|
4036
4103
|
});
|
|
4037
4104
|
});
|
|
4038
4105
|
}
|
|
@@ -4414,17 +4481,17 @@ var AutoIndexCoordinator = class {
|
|
|
4414
4481
|
}
|
|
4415
4482
|
}
|
|
4416
4483
|
waitForBatteryRetry(delayMs) {
|
|
4417
|
-
return new Promise((
|
|
4484
|
+
return new Promise((resolve17) => {
|
|
4418
4485
|
const timer = setTimeout(() => {
|
|
4419
4486
|
if (this.batteryRetryTimer === timer) {
|
|
4420
4487
|
this.batteryRetryTimer = null;
|
|
4421
4488
|
this.resolveBatteryRetry = null;
|
|
4422
4489
|
}
|
|
4423
|
-
|
|
4490
|
+
resolve17();
|
|
4424
4491
|
}, delayMs);
|
|
4425
4492
|
timer.unref?.();
|
|
4426
4493
|
this.batteryRetryTimer = timer;
|
|
4427
|
-
this.resolveBatteryRetry =
|
|
4494
|
+
this.resolveBatteryRetry = resolve17;
|
|
4428
4495
|
});
|
|
4429
4496
|
}
|
|
4430
4497
|
cancelBatteryRetry() {
|
|
@@ -4432,9 +4499,9 @@ var AutoIndexCoordinator = class {
|
|
|
4432
4499
|
clearTimeout(this.batteryRetryTimer);
|
|
4433
4500
|
this.batteryRetryTimer = null;
|
|
4434
4501
|
}
|
|
4435
|
-
const
|
|
4502
|
+
const resolve17 = this.resolveBatteryRetry;
|
|
4436
4503
|
this.resolveBatteryRetry = null;
|
|
4437
|
-
|
|
4504
|
+
resolve17?.();
|
|
4438
4505
|
}
|
|
4439
4506
|
finishBatteryCheck(batteryCheck) {
|
|
4440
4507
|
if (this.batteryCheck !== batteryCheck) return;
|
|
@@ -4639,7 +4706,7 @@ function pTimeout(promise, options) {
|
|
|
4639
4706
|
} = options;
|
|
4640
4707
|
let timer;
|
|
4641
4708
|
let abortHandler;
|
|
4642
|
-
const wrappedPromise = new Promise((
|
|
4709
|
+
const wrappedPromise = new Promise((resolve17, reject) => {
|
|
4643
4710
|
if (typeof milliseconds !== "number" || Math.sign(milliseconds) !== 1) {
|
|
4644
4711
|
throw new TypeError(`Expected \`milliseconds\` to be a positive number, got \`${milliseconds}\``);
|
|
4645
4712
|
}
|
|
@@ -4653,7 +4720,7 @@ function pTimeout(promise, options) {
|
|
|
4653
4720
|
};
|
|
4654
4721
|
signal.addEventListener("abort", abortHandler, { once: true });
|
|
4655
4722
|
}
|
|
4656
|
-
promise.then(
|
|
4723
|
+
promise.then(resolve17, reject);
|
|
4657
4724
|
if (milliseconds === Number.POSITIVE_INFINITY) {
|
|
4658
4725
|
return;
|
|
4659
4726
|
}
|
|
@@ -4661,7 +4728,7 @@ function pTimeout(promise, options) {
|
|
|
4661
4728
|
timer = customTimers.setTimeout.call(void 0, () => {
|
|
4662
4729
|
if (fallback) {
|
|
4663
4730
|
try {
|
|
4664
|
-
|
|
4731
|
+
resolve17(fallback());
|
|
4665
4732
|
} catch (error) {
|
|
4666
4733
|
reject(error);
|
|
4667
4734
|
}
|
|
@@ -4671,7 +4738,7 @@ function pTimeout(promise, options) {
|
|
|
4671
4738
|
promise.cancel();
|
|
4672
4739
|
}
|
|
4673
4740
|
if (message === false) {
|
|
4674
|
-
|
|
4741
|
+
resolve17();
|
|
4675
4742
|
} else if (message instanceof Error) {
|
|
4676
4743
|
reject(message);
|
|
4677
4744
|
} else {
|
|
@@ -5073,7 +5140,7 @@ var PQueue = class extends import_index.default {
|
|
|
5073
5140
|
// Assign unique ID if not provided
|
|
5074
5141
|
id: options.id ?? (this.#idAssigner++).toString()
|
|
5075
5142
|
};
|
|
5076
|
-
return new Promise((
|
|
5143
|
+
return new Promise((resolve17, reject) => {
|
|
5077
5144
|
const taskSymbol = /* @__PURE__ */ Symbol(`task-${options.id}`);
|
|
5078
5145
|
let cleanupQueueAbortHandler = () => void 0;
|
|
5079
5146
|
const run = async () => {
|
|
@@ -5113,7 +5180,7 @@ var PQueue = class extends import_index.default {
|
|
|
5113
5180
|
})]);
|
|
5114
5181
|
}
|
|
5115
5182
|
const result = await operation;
|
|
5116
|
-
|
|
5183
|
+
resolve17(result);
|
|
5117
5184
|
this.emit("completed", result);
|
|
5118
5185
|
} catch (error) {
|
|
5119
5186
|
reject(error);
|
|
@@ -5301,13 +5368,13 @@ var PQueue = class extends import_index.default {
|
|
|
5301
5368
|
});
|
|
5302
5369
|
}
|
|
5303
5370
|
async #onEvent(event, filter) {
|
|
5304
|
-
return new Promise((
|
|
5371
|
+
return new Promise((resolve17) => {
|
|
5305
5372
|
const listener = () => {
|
|
5306
5373
|
if (filter && !filter()) {
|
|
5307
5374
|
return;
|
|
5308
5375
|
}
|
|
5309
5376
|
this.off(event, listener);
|
|
5310
|
-
|
|
5377
|
+
resolve17();
|
|
5311
5378
|
};
|
|
5312
5379
|
this.on(event, listener);
|
|
5313
5380
|
});
|
|
@@ -5593,7 +5660,7 @@ async function onAttemptFailure({ error, attemptNumber, retriesConsumed, startTi
|
|
|
5593
5660
|
const finalDelay = Math.min(delayTime, remainingTime);
|
|
5594
5661
|
options.signal?.throwIfAborted();
|
|
5595
5662
|
if (finalDelay > 0) {
|
|
5596
|
-
await new Promise((
|
|
5663
|
+
await new Promise((resolve17, reject) => {
|
|
5597
5664
|
const onAbort = () => {
|
|
5598
5665
|
clearTimeout(timeoutToken);
|
|
5599
5666
|
options.signal?.removeEventListener("abort", onAbort);
|
|
@@ -5601,7 +5668,7 @@ async function onAttemptFailure({ error, attemptNumber, retriesConsumed, startTi
|
|
|
5601
5668
|
};
|
|
5602
5669
|
const timeoutToken = setTimeout(() => {
|
|
5603
5670
|
options.signal?.removeEventListener("abort", onAbort);
|
|
5604
|
-
|
|
5671
|
+
resolve17();
|
|
5605
5672
|
}, finalDelay);
|
|
5606
5673
|
if (options.unref) {
|
|
5607
5674
|
timeoutToken.unref?.();
|
|
@@ -5737,8 +5804,6 @@ async function tryDetectProvider() {
|
|
|
5737
5804
|
}
|
|
5738
5805
|
async function getProviderCredentials(provider) {
|
|
5739
5806
|
switch (provider) {
|
|
5740
|
-
case "github-copilot":
|
|
5741
|
-
return getGitHubCopilotCredentials();
|
|
5742
5807
|
case "openai":
|
|
5743
5808
|
return getOpenAICredentials();
|
|
5744
5809
|
case "google":
|
|
@@ -5749,22 +5814,6 @@ async function getProviderCredentials(provider) {
|
|
|
5749
5814
|
return null;
|
|
5750
5815
|
}
|
|
5751
5816
|
}
|
|
5752
|
-
function getGitHubCopilotCredentials() {
|
|
5753
|
-
const authData = loadOpenCodeAuth();
|
|
5754
|
-
const copilotAuth = authData["github-copilot"] || authData["github-copilot-enterprise"];
|
|
5755
|
-
if (!copilotAuth || copilotAuth.type !== "oauth") {
|
|
5756
|
-
return null;
|
|
5757
|
-
}
|
|
5758
|
-
const auth = copilotAuth;
|
|
5759
|
-
const baseUrl = auth.enterpriseUrl ? `https://copilot-api.${auth.enterpriseUrl.replace(/^https?:\/\//, "").replace(/\/$/, "")}` : "https://models.github.ai";
|
|
5760
|
-
return {
|
|
5761
|
-
provider: "github-copilot",
|
|
5762
|
-
baseUrl,
|
|
5763
|
-
refreshToken: copilotAuth.refresh,
|
|
5764
|
-
accessToken: copilotAuth.access,
|
|
5765
|
-
tokenExpires: copilotAuth.expires
|
|
5766
|
-
};
|
|
5767
|
-
}
|
|
5768
5817
|
function getOpenAICredentials() {
|
|
5769
5818
|
const authData = loadOpenCodeAuth();
|
|
5770
5819
|
const openaiAuth = authData["openai"];
|
|
@@ -5890,8 +5939,6 @@ async function tryDetectOllamaProvider() {
|
|
|
5890
5939
|
}
|
|
5891
5940
|
function getProviderDisplayName(provider) {
|
|
5892
5941
|
switch (provider) {
|
|
5893
|
-
case "github-copilot":
|
|
5894
|
-
return "GitHub Copilot";
|
|
5895
5942
|
case "openai":
|
|
5896
5943
|
return "OpenAI";
|
|
5897
5944
|
case "google":
|
|
@@ -6116,44 +6163,6 @@ var CustomEmbeddingProvider = class extends BaseEmbeddingProvider {
|
|
|
6116
6163
|
}
|
|
6117
6164
|
};
|
|
6118
6165
|
|
|
6119
|
-
// src/embeddings/providers/github-copilot.ts
|
|
6120
|
-
var GitHubCopilotEmbeddingProvider = class extends BaseEmbeddingProvider {
|
|
6121
|
-
constructor(credentials, modelInfo) {
|
|
6122
|
-
super(credentials, modelInfo);
|
|
6123
|
-
}
|
|
6124
|
-
getToken() {
|
|
6125
|
-
if (!this.credentials.refreshToken) {
|
|
6126
|
-
throw new Error("No OAuth token available for GitHub");
|
|
6127
|
-
}
|
|
6128
|
-
return this.credentials.refreshToken;
|
|
6129
|
-
}
|
|
6130
|
-
async embedBatch(texts) {
|
|
6131
|
-
const token = this.getToken();
|
|
6132
|
-
const response = await fetch(`${this.credentials.baseUrl}/inference/embeddings`, {
|
|
6133
|
-
method: "POST",
|
|
6134
|
-
headers: {
|
|
6135
|
-
Authorization: `Bearer ${token}`,
|
|
6136
|
-
"Content-Type": "application/json",
|
|
6137
|
-
Accept: "application/vnd.github+json",
|
|
6138
|
-
"X-GitHub-Api-Version": "2022-11-28"
|
|
6139
|
-
},
|
|
6140
|
-
body: JSON.stringify({
|
|
6141
|
-
model: `openai/${this.modelInfo.model}`,
|
|
6142
|
-
input: texts
|
|
6143
|
-
})
|
|
6144
|
-
});
|
|
6145
|
-
if (!response.ok) {
|
|
6146
|
-
const error = (await response.text()).slice(0, 500);
|
|
6147
|
-
throw new Error(`GitHub Copilot embedding API error: ${response.status} - ${error}`);
|
|
6148
|
-
}
|
|
6149
|
-
const data = await response.json();
|
|
6150
|
-
return {
|
|
6151
|
-
embeddings: data.data.map((d) => d.embedding),
|
|
6152
|
-
totalTokensUsed: data.usage.total_tokens
|
|
6153
|
-
};
|
|
6154
|
-
}
|
|
6155
|
-
};
|
|
6156
|
-
|
|
6157
6166
|
// src/embeddings/providers/google.ts
|
|
6158
6167
|
var GoogleEmbeddingProvider = class _GoogleEmbeddingProvider extends BaseEmbeddingProvider {
|
|
6159
6168
|
static BATCH_SIZE = 20;
|
|
@@ -6161,24 +6170,30 @@ var GoogleEmbeddingProvider = class _GoogleEmbeddingProvider extends BaseEmbeddi
|
|
|
6161
6170
|
super(credentials, modelInfo);
|
|
6162
6171
|
}
|
|
6163
6172
|
async embedQuery(query) {
|
|
6164
|
-
const taskType = this.modelInfo.taskAble ? "CODE_RETRIEVAL_QUERY" : void 0;
|
|
6165
|
-
const
|
|
6173
|
+
const taskType = this.modelInfo.model === "gemini-embedding-001" && this.modelInfo.taskAble ? "CODE_RETRIEVAL_QUERY" : void 0;
|
|
6174
|
+
const texts = [
|
|
6175
|
+
this.modelInfo.model === "gemini-embedding-2" ? `task: code retrieval | query: ${query}` : query
|
|
6176
|
+
];
|
|
6177
|
+
const result = await this.embedWithTaskType(texts, taskType);
|
|
6166
6178
|
return {
|
|
6167
6179
|
embedding: result.embeddings[0],
|
|
6168
6180
|
tokensUsed: result.totalTokensUsed
|
|
6169
6181
|
};
|
|
6170
6182
|
}
|
|
6171
6183
|
async embedDocument(document) {
|
|
6172
|
-
const taskType = this.modelInfo.taskAble ? "RETRIEVAL_DOCUMENT" : void 0;
|
|
6173
|
-
const result = await this.embedWithTaskType([
|
|
6184
|
+
const taskType = this.modelInfo.model === "gemini-embedding-001" && this.modelInfo.taskAble ? "RETRIEVAL_DOCUMENT" : void 0;
|
|
6185
|
+
const result = await this.embedWithTaskType([
|
|
6186
|
+
this.modelInfo.model === "gemini-embedding-2" ? `title: none | text: ${document}` : document
|
|
6187
|
+
], taskType);
|
|
6174
6188
|
return {
|
|
6175
6189
|
embedding: result.embeddings[0],
|
|
6176
6190
|
tokensUsed: result.totalTokensUsed
|
|
6177
6191
|
};
|
|
6178
6192
|
}
|
|
6179
6193
|
async embedBatch(texts) {
|
|
6180
|
-
const taskType = this.modelInfo.taskAble ? "RETRIEVAL_DOCUMENT" : void 0;
|
|
6181
|
-
|
|
6194
|
+
const taskType = this.modelInfo.model === "gemini-embedding-001" && this.modelInfo.taskAble ? "RETRIEVAL_DOCUMENT" : void 0;
|
|
6195
|
+
const formattedTexts = this.modelInfo.model === "gemini-embedding-2" ? texts.map((text) => `title: none | text: ${text}`) : texts;
|
|
6196
|
+
return this.embedWithTaskType(formattedTexts, taskType);
|
|
6182
6197
|
}
|
|
6183
6198
|
async embedWithTaskType(texts, taskType) {
|
|
6184
6199
|
const batches = [];
|
|
@@ -6228,6 +6243,10 @@ var GoogleEmbeddingProvider = class _GoogleEmbeddingProvider extends BaseEmbeddi
|
|
|
6228
6243
|
var OllamaEmbeddingProvider = class _OllamaEmbeddingProvider extends BaseEmbeddingProvider {
|
|
6229
6244
|
static MIN_TRUNCATION_CHARS = 512;
|
|
6230
6245
|
static REQUEST_TIMEOUT_MS = 12e4;
|
|
6246
|
+
// Set when /api/embed returns 404 so subsequent multi-text batches skip the
|
|
6247
|
+
// batched endpoint and go straight to the legacy per-text path (one probe per
|
|
6248
|
+
// old ollama install, not one probe per batch).
|
|
6249
|
+
batchEndpointUnavailable = false;
|
|
6231
6250
|
constructor(credentials, modelInfo) {
|
|
6232
6251
|
super(credentials, modelInfo);
|
|
6233
6252
|
}
|
|
@@ -6245,6 +6264,21 @@ var OllamaEmbeddingProvider = class _OllamaEmbeddingProvider extends BaseEmbeddi
|
|
|
6245
6264
|
const message = (error instanceof Error ? error.message : String(error)).toLowerCase();
|
|
6246
6265
|
return message.includes("context length") && (message.includes("exceed") || message.includes("exceeded") || message.includes("too long")) || message.includes("input length exceeds the context length") || message.includes("context length exceeded");
|
|
6247
6266
|
}
|
|
6267
|
+
// True for a 404 from the newer /api/embed endpoint, i.e. an ollama version that
|
|
6268
|
+
// does not provide it. embedBatch uses this to fall back to the legacy per-text
|
|
6269
|
+
// /api/embeddings path so old ollama installs do not regress.
|
|
6270
|
+
isBatchEndpointUnavailableError(error) {
|
|
6271
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
6272
|
+
return message.includes("Ollama /api/embed not available");
|
|
6273
|
+
}
|
|
6274
|
+
// True for a malformed /api/embed response (wrong vector count or a bad vector).
|
|
6275
|
+
// embedBatch falls back to the per-text path on this so a bad batch response
|
|
6276
|
+
// re-embeds each text cleanly. A text that then fails per-text is not isolated
|
|
6277
|
+
// here; it is isolated on the recovery run, which re-embeds one text per request.
|
|
6278
|
+
isBatchValidationError(error) {
|
|
6279
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
6280
|
+
return message.includes("invalid embedding batch");
|
|
6281
|
+
}
|
|
6248
6282
|
buildTruncationCandidates(text) {
|
|
6249
6283
|
const baseMaxChars = Math.max(1, this.modelInfo.maxTokens * 4);
|
|
6250
6284
|
const candidateLimits = /* @__PURE__ */ new Set();
|
|
@@ -6346,7 +6380,74 @@ var OllamaEmbeddingProvider = class _OllamaEmbeddingProvider extends BaseEmbeddi
|
|
|
6346
6380
|
tokensUsed: this.estimateTokens(text)
|
|
6347
6381
|
};
|
|
6348
6382
|
}
|
|
6349
|
-
|
|
6383
|
+
// Embeds many texts in one POST /api/embed request (input: string[]). Ollama
|
|
6384
|
+
// encodes each input independently, so the model context length applies per input
|
|
6385
|
+
// (the upstream splitter already bounds each input), not over the batch. This
|
|
6386
|
+
// amortizes N HTTP round-trips into one.
|
|
6387
|
+
async embedMany(texts) {
|
|
6388
|
+
const controller = new AbortController();
|
|
6389
|
+
const timeout = setTimeout(
|
|
6390
|
+
() => controller.abort(),
|
|
6391
|
+
_OllamaEmbeddingProvider.REQUEST_TIMEOUT_MS
|
|
6392
|
+
);
|
|
6393
|
+
let response;
|
|
6394
|
+
try {
|
|
6395
|
+
response = await fetch(`${this.credentials.baseUrl}/api/embed`, {
|
|
6396
|
+
method: "POST",
|
|
6397
|
+
headers: {
|
|
6398
|
+
"Content-Type": "application/json"
|
|
6399
|
+
},
|
|
6400
|
+
body: JSON.stringify({
|
|
6401
|
+
model: this.modelInfo.model,
|
|
6402
|
+
input: texts,
|
|
6403
|
+
truncate: false
|
|
6404
|
+
}),
|
|
6405
|
+
signal: controller.signal
|
|
6406
|
+
});
|
|
6407
|
+
} catch (error) {
|
|
6408
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
6409
|
+
throw new Error(
|
|
6410
|
+
`Ollama embedding request timed out after ${_OllamaEmbeddingProvider.REQUEST_TIMEOUT_MS}ms`
|
|
6411
|
+
);
|
|
6412
|
+
}
|
|
6413
|
+
throw error;
|
|
6414
|
+
} finally {
|
|
6415
|
+
clearTimeout(timeout);
|
|
6416
|
+
}
|
|
6417
|
+
if (!response.ok) {
|
|
6418
|
+
const error = (await response.text()).slice(0, 500);
|
|
6419
|
+
if (response.status === 404) {
|
|
6420
|
+
throw new Error(`Ollama /api/embed not available: ${response.status} - ${error}`);
|
|
6421
|
+
}
|
|
6422
|
+
throw new Error(`Ollama embedding API error: ${response.status} - ${error}`);
|
|
6423
|
+
}
|
|
6424
|
+
let parsed;
|
|
6425
|
+
try {
|
|
6426
|
+
parsed = await response.json();
|
|
6427
|
+
} catch {
|
|
6428
|
+
throw new Error(
|
|
6429
|
+
`Ollama returned an invalid embedding batch; expected ${texts.length} vectors of ${this.modelInfo.dimensions} finite dimensions`
|
|
6430
|
+
);
|
|
6431
|
+
}
|
|
6432
|
+
const data = parsed && typeof parsed === "object" ? parsed : {};
|
|
6433
|
+
if (!Array.isArray(data.embeddings) || data.embeddings.length !== texts.length || data.embeddings.some(
|
|
6434
|
+
(value) => !Array.isArray(value) || value.length !== this.modelInfo.dimensions || value.some((v) => typeof v !== "number" || !Number.isFinite(v))
|
|
6435
|
+
)) {
|
|
6436
|
+
throw new Error(
|
|
6437
|
+
`Ollama returned an invalid embedding batch; expected ${texts.length} vectors of ${this.modelInfo.dimensions} finite dimensions`
|
|
6438
|
+
);
|
|
6439
|
+
}
|
|
6440
|
+
return {
|
|
6441
|
+
embeddings: data.embeddings,
|
|
6442
|
+
totalTokensUsed: texts.reduce((sum, text) => sum + this.estimateTokens(text), 0)
|
|
6443
|
+
};
|
|
6444
|
+
}
|
|
6445
|
+
// Per-text /api/embeddings path shared by the single-text fast path and the
|
|
6446
|
+
// batch fallback. Uses the legacy endpoint one text at a time, so each text gets
|
|
6447
|
+
// its own truncation safety net and a vector validated on its own. A text that
|
|
6448
|
+
// hard-fails per-text throws here and fails the whole request batch; the recovery
|
|
6449
|
+
// run re-embeds one text per request to isolate it.
|
|
6450
|
+
async embedOneByOne(texts) {
|
|
6350
6451
|
const results = [];
|
|
6351
6452
|
for (const text of texts) {
|
|
6352
6453
|
results.push(await this.embedSingleWithFallback(text));
|
|
@@ -6356,6 +6457,26 @@ var OllamaEmbeddingProvider = class _OllamaEmbeddingProvider extends BaseEmbeddi
|
|
|
6356
6457
|
totalTokensUsed: results.reduce((sum, r) => sum + r.tokensUsed, 0)
|
|
6357
6458
|
};
|
|
6358
6459
|
}
|
|
6460
|
+
async embedBatch(texts) {
|
|
6461
|
+
if (texts.length === 0) {
|
|
6462
|
+
return { embeddings: [], totalTokensUsed: 0 };
|
|
6463
|
+
}
|
|
6464
|
+
if (texts.length === 1 || this.batchEndpointUnavailable) {
|
|
6465
|
+
return this.embedOneByOne(texts);
|
|
6466
|
+
}
|
|
6467
|
+
try {
|
|
6468
|
+
return await this.embedMany(texts);
|
|
6469
|
+
} catch (error) {
|
|
6470
|
+
if (this.isBatchEndpointUnavailableError(error)) {
|
|
6471
|
+
this.batchEndpointUnavailable = true;
|
|
6472
|
+
return this.embedOneByOne(texts);
|
|
6473
|
+
}
|
|
6474
|
+
if (!this.isContextLengthError(error) && !this.isBatchValidationError(error)) {
|
|
6475
|
+
throw error;
|
|
6476
|
+
}
|
|
6477
|
+
return this.embedOneByOne(texts);
|
|
6478
|
+
}
|
|
6479
|
+
}
|
|
6359
6480
|
};
|
|
6360
6481
|
|
|
6361
6482
|
// src/embeddings/providers/openai.ts
|
|
@@ -6390,8 +6511,6 @@ var OpenAIEmbeddingProvider = class extends BaseEmbeddingProvider {
|
|
|
6390
6511
|
// src/embeddings/provider.ts
|
|
6391
6512
|
function createEmbeddingProvider(configuredProviderInfo) {
|
|
6392
6513
|
switch (configuredProviderInfo.provider) {
|
|
6393
|
-
case "github-copilot":
|
|
6394
|
-
return new GitHubCopilotEmbeddingProvider(configuredProviderInfo.credentials, configuredProviderInfo.modelInfo);
|
|
6395
6514
|
case "openai":
|
|
6396
6515
|
return new OpenAIEmbeddingProvider(configuredProviderInfo.credentials, configuredProviderInfo.modelInfo);
|
|
6397
6516
|
case "google":
|
|
@@ -6407,85 +6526,6 @@ function createEmbeddingProvider(configuredProviderInfo) {
|
|
|
6407
6526
|
}
|
|
6408
6527
|
}
|
|
6409
6528
|
|
|
6410
|
-
// src/rerank/index.ts
|
|
6411
|
-
function createReranker(config) {
|
|
6412
|
-
if (!config.enabled) {
|
|
6413
|
-
return new NoOpReranker();
|
|
6414
|
-
}
|
|
6415
|
-
return new SiliconFlowReranker(config);
|
|
6416
|
-
}
|
|
6417
|
-
var NoOpReranker = class {
|
|
6418
|
-
isAvailable() {
|
|
6419
|
-
return false;
|
|
6420
|
-
}
|
|
6421
|
-
async rerank(_query, documents, _topN) {
|
|
6422
|
-
return {
|
|
6423
|
-
results: documents.map((_, index) => ({ index, relevanceScore: 0 }))
|
|
6424
|
-
};
|
|
6425
|
-
}
|
|
6426
|
-
};
|
|
6427
|
-
var SiliconFlowReranker = class {
|
|
6428
|
-
config;
|
|
6429
|
-
constructor(config) {
|
|
6430
|
-
this.config = config;
|
|
6431
|
-
}
|
|
6432
|
-
isAvailable() {
|
|
6433
|
-
return this.config.enabled && !!this.config.baseUrl && !!this.config.model;
|
|
6434
|
-
}
|
|
6435
|
-
async rerank(query, documents, topN) {
|
|
6436
|
-
if (documents.length === 0) {
|
|
6437
|
-
return { results: [] };
|
|
6438
|
-
}
|
|
6439
|
-
const headers = {
|
|
6440
|
-
"Content-Type": "application/json"
|
|
6441
|
-
};
|
|
6442
|
-
if (this.config.apiKey) {
|
|
6443
|
-
headers["Authorization"] = `Bearer ${this.config.apiKey}`;
|
|
6444
|
-
}
|
|
6445
|
-
const baseUrl = this.config.baseUrl;
|
|
6446
|
-
if (!baseUrl) {
|
|
6447
|
-
throw new Error("Reranker baseUrl is required. Configure reranker.baseUrl in your codebase-index.json.");
|
|
6448
|
-
}
|
|
6449
|
-
const timeoutMs = this.config.timeoutMs ?? 3e4;
|
|
6450
|
-
const controller = new AbortController();
|
|
6451
|
-
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
6452
|
-
try {
|
|
6453
|
-
const response = await fetch(`${baseUrl}/rerank`, {
|
|
6454
|
-
method: "POST",
|
|
6455
|
-
headers,
|
|
6456
|
-
body: JSON.stringify({
|
|
6457
|
-
model: this.config.model,
|
|
6458
|
-
query,
|
|
6459
|
-
documents,
|
|
6460
|
-
top_n: topN ?? this.config.topN ?? 20,
|
|
6461
|
-
return_documents: false
|
|
6462
|
-
}),
|
|
6463
|
-
signal: controller.signal
|
|
6464
|
-
});
|
|
6465
|
-
clearTimeout(timeout);
|
|
6466
|
-
if (!response.ok) {
|
|
6467
|
-
const errorText = await response.text();
|
|
6468
|
-
throw new Error(`Rerank API error: ${response.status} - ${errorText}`);
|
|
6469
|
-
}
|
|
6470
|
-
const data = await response.json();
|
|
6471
|
-
return {
|
|
6472
|
-
results: data.results.map((r) => ({
|
|
6473
|
-
index: r.index,
|
|
6474
|
-
relevanceScore: r.relevance_score,
|
|
6475
|
-
document: r.document?.text
|
|
6476
|
-
})),
|
|
6477
|
-
tokensUsed: data.meta?.tokens?.input_tokens
|
|
6478
|
-
};
|
|
6479
|
-
} catch (error) {
|
|
6480
|
-
clearTimeout(timeout);
|
|
6481
|
-
if (error instanceof Error && error.name === "AbortError") {
|
|
6482
|
-
throw new Error(`Rerank API request timed out after ${timeoutMs}ms`);
|
|
6483
|
-
}
|
|
6484
|
-
throw error;
|
|
6485
|
-
}
|
|
6486
|
-
}
|
|
6487
|
-
};
|
|
6488
|
-
|
|
6489
6529
|
// src/utils/cost.ts
|
|
6490
6530
|
function estimateChunksFromFiles(files) {
|
|
6491
6531
|
let totalChunks = 0;
|
|
@@ -7222,12 +7262,12 @@ try {
|
|
|
7222
7262
|
}
|
|
7223
7263
|
|
|
7224
7264
|
// src/native/parsing.ts
|
|
7225
|
-
function parseFileAsText(filePath, content) {
|
|
7226
|
-
const result = native.parseFileAsText(filePath, content);
|
|
7265
|
+
function parseFileAsText(filePath, content, linesPerChunk) {
|
|
7266
|
+
const result = native.parseFileAsText(filePath, content, linesPerChunk);
|
|
7227
7267
|
return result.map(mapChunk);
|
|
7228
7268
|
}
|
|
7229
|
-
function parseFiles(files) {
|
|
7230
|
-
const result = native.parseFiles(files);
|
|
7269
|
+
function parseFiles(files, linesPerChunk) {
|
|
7270
|
+
const result = native.parseFiles(files, linesPerChunk);
|
|
7231
7271
|
return result.map((f) => ({
|
|
7232
7272
|
path: f.path,
|
|
7233
7273
|
chunks: f.chunks.map(mapChunk),
|
|
@@ -7304,13 +7344,13 @@ var VectorStore = class {
|
|
|
7304
7344
|
const metadata = items.map((i) => JSON.stringify(i.metadata));
|
|
7305
7345
|
this.inner.addBatch(ids, vectors, metadata);
|
|
7306
7346
|
}
|
|
7307
|
-
search(queryVector, limit = 10) {
|
|
7347
|
+
search(queryVector, limit = 10, allowedIds) {
|
|
7308
7348
|
if (queryVector.length !== this.dimensions) {
|
|
7309
7349
|
throw new Error(
|
|
7310
7350
|
`Query vector dimension mismatch: expected ${this.dimensions}, got ${queryVector.length}`
|
|
7311
7351
|
);
|
|
7312
7352
|
}
|
|
7313
|
-
const results = this.inner.search(queryVector, limit);
|
|
7353
|
+
const results = allowedIds === void 0 ? this.inner.search(queryVector, limit) : this.inner.searchFiltered(queryVector, limit, allowedIds);
|
|
7314
7354
|
return results.map((r) => ({
|
|
7315
7355
|
id: r.id,
|
|
7316
7356
|
score: r.score,
|
|
@@ -7538,6 +7578,10 @@ var Database = class _Database {
|
|
|
7538
7578
|
this.throwIfClosed();
|
|
7539
7579
|
return this.inner.getBranchChunkIds(branch);
|
|
7540
7580
|
}
|
|
7581
|
+
getChunkIdsByBlameDate(since, until) {
|
|
7582
|
+
this.throwIfClosed();
|
|
7583
|
+
return this.inner.getChunkIdsByBlameDate(since, until);
|
|
7584
|
+
}
|
|
7541
7585
|
getBranchDelta(branch, baseBranch) {
|
|
7542
7586
|
this.throwIfClosed();
|
|
7543
7587
|
return this.inner.getBranchDelta(branch, baseBranch);
|
|
@@ -8046,8 +8090,8 @@ async function isWorktreeRegistered(projectRoot, worktreePath) {
|
|
|
8046
8090
|
return false;
|
|
8047
8091
|
}
|
|
8048
8092
|
function isPathWithinRoot(filePath, rootPath) {
|
|
8049
|
-
const
|
|
8050
|
-
return
|
|
8093
|
+
const relative14 = path15.relative(path15.resolve(rootPath), path15.resolve(filePath));
|
|
8094
|
+
return relative14 === "" || !relative14.startsWith(`..${path15.sep}`) && relative14 !== ".." && !path15.isAbsolute(relative14);
|
|
8051
8095
|
}
|
|
8052
8096
|
async function pruneExactMissingWorktreeRegistration(projectRoot, worktreePath) {
|
|
8053
8097
|
if (await pathExists(worktreePath)) return false;
|
|
@@ -8424,11 +8468,11 @@ function normalizeFiles(rawFiles, projectRoot) {
|
|
|
8424
8468
|
for (const raw of rawFiles) {
|
|
8425
8469
|
if (raw.length === 0) continue;
|
|
8426
8470
|
const absolute = path16.resolve(root, raw);
|
|
8427
|
-
const
|
|
8428
|
-
if (path16.isAbsolute(raw) ||
|
|
8471
|
+
const relative14 = path16.relative(root, absolute);
|
|
8472
|
+
if (path16.isAbsolute(raw) || relative14 === ".." || relative14.startsWith(`..${path16.sep}`) || path16.isAbsolute(relative14)) {
|
|
8429
8473
|
throw new Error(`Changed file escapes the project root: ${JSON.stringify(raw)}`);
|
|
8430
8474
|
}
|
|
8431
|
-
const cleaned =
|
|
8475
|
+
const cleaned = relative14.startsWith(`.${path16.sep}`) ? relative14.slice(2) : relative14;
|
|
8432
8476
|
if (!seen.has(cleaned)) {
|
|
8433
8477
|
seen.add(cleaned);
|
|
8434
8478
|
result.push(cleaned);
|
|
@@ -8660,7 +8704,8 @@ function rankHybridResults(query, semanticResults, keywordResults, options) {
|
|
|
8660
8704
|
return cached;
|
|
8661
8705
|
}
|
|
8662
8706
|
}
|
|
8663
|
-
const
|
|
8707
|
+
const overfetchFactor = prioritizeSourcePaths ? 12 : 4;
|
|
8708
|
+
const overfetchLimit = Math.max(options.limit * overfetchFactor, options.limit);
|
|
8664
8709
|
const fused = options.fusionStrategy === "rrf" ? fuseResultsRrf(semanticResults, keywordResults, options.rrfK, overfetchLimit) : fuseResultsWeighted(semanticResults, keywordResults, options.hybridWeight, overfetchLimit);
|
|
8665
8710
|
const rerankPoolLimit = Math.max(overfetchLimit, options.rerankTopN * 3, options.limit * 6);
|
|
8666
8711
|
const rerankPool = fused.slice(0, rerankPoolLimit);
|
|
@@ -9425,6 +9470,18 @@ function createFailedBatchWriter(targetPath) {
|
|
|
9425
9470
|
temporaryPath
|
|
9426
9471
|
};
|
|
9427
9472
|
}
|
|
9473
|
+
function writeFailedBatchRecords(targetPath, records) {
|
|
9474
|
+
const writer = createFailedBatchWriter(targetPath);
|
|
9475
|
+
try {
|
|
9476
|
+
for (const record of records) {
|
|
9477
|
+
writer.write(record);
|
|
9478
|
+
}
|
|
9479
|
+
writer.commit();
|
|
9480
|
+
} catch (error) {
|
|
9481
|
+
writer.cleanup();
|
|
9482
|
+
throw error;
|
|
9483
|
+
}
|
|
9484
|
+
}
|
|
9428
9485
|
function* readLegacyFailedBatchRecords(filePath, options) {
|
|
9429
9486
|
const rawData = fs2.readFileSync(filePath, "utf-8");
|
|
9430
9487
|
const trimmed = stripLeadingBomAndWhitespace(rawData).trim();
|
|
@@ -9707,14 +9764,18 @@ function getSafeEmbeddingChunkTokenLimit(provider) {
|
|
|
9707
9764
|
const maxChunkTokens = Math.max(256, Math.floor(providerMaxTokens * 0.75));
|
|
9708
9765
|
return Math.min(2e3, maxChunkTokens);
|
|
9709
9766
|
}
|
|
9710
|
-
|
|
9711
|
-
|
|
9712
|
-
|
|
9713
|
-
|
|
9714
|
-
|
|
9715
|
-
};
|
|
9767
|
+
var DEFAULT_OLLAMA_MAX_BATCH_ITEMS = 16;
|
|
9768
|
+
var DEFAULT_OLLAMA_MAX_BATCH_TOKENS = 65536;
|
|
9769
|
+
function getDynamicBatchOptions(provider, embeddingBatch) {
|
|
9770
|
+
if (provider.provider !== "ollama") {
|
|
9771
|
+
return {};
|
|
9716
9772
|
}
|
|
9717
|
-
|
|
9773
|
+
const base = { maxBatchTokens: DEFAULT_OLLAMA_MAX_BATCH_TOKENS, maxBatchItems: DEFAULT_OLLAMA_MAX_BATCH_ITEMS };
|
|
9774
|
+
return {
|
|
9775
|
+
...base,
|
|
9776
|
+
...typeof embeddingBatch?.maxBatchTokens === "number" && Number.isFinite(embeddingBatch.maxBatchTokens) ? { maxBatchTokens: embeddingBatch.maxBatchTokens } : {},
|
|
9777
|
+
...typeof embeddingBatch?.maxBatchItems === "number" && Number.isFinite(embeddingBatch.maxBatchItems) ? { maxBatchItems: embeddingBatch.maxBatchItems } : {}
|
|
9778
|
+
};
|
|
9718
9779
|
}
|
|
9719
9780
|
function isSqliteCorruptionError(error) {
|
|
9720
9781
|
const message = getErrorMessage4(error).toLowerCase();
|
|
@@ -9732,6 +9793,14 @@ function getPendingChunkId(rawChunk) {
|
|
|
9732
9793
|
const id = rawChunk.id;
|
|
9733
9794
|
return typeof id === "string" ? id : null;
|
|
9734
9795
|
}
|
|
9796
|
+
function parseBlameTimestamp(value, endOfDay) {
|
|
9797
|
+
let timestampMs = Date.parse(value);
|
|
9798
|
+
if (Number.isNaN(timestampMs)) return null;
|
|
9799
|
+
if (endOfDay && /^\d{4}-\d{2}-\d{2}$/.test(value.trim())) {
|
|
9800
|
+
timestampMs += 24 * 60 * 60 * 1e3 - 1;
|
|
9801
|
+
}
|
|
9802
|
+
return Math.floor(timestampMs / 1e3);
|
|
9803
|
+
}
|
|
9735
9804
|
function metadataFromBlame(blame) {
|
|
9736
9805
|
if (!blame) {
|
|
9737
9806
|
return {};
|
|
@@ -9878,7 +9947,7 @@ function promoteIdentifierMatches(query, combined, semanticCandidates, keywordCa
|
|
|
9878
9947
|
const remainder = combined.filter((candidate) => !promotedIds.has(candidate.id));
|
|
9879
9948
|
return [...promoted, ...remainder];
|
|
9880
9949
|
}
|
|
9881
|
-
function buildSymbolDefinitionLane(query, database, branchChunkIds, branchSymbolIds, limit, fallbackCandidates, prioritizeSourcePaths = classifyQueryIntentRaw(query) === "source") {
|
|
9950
|
+
function buildSymbolDefinitionLane(query, database, branchChunkIds, branchSymbolIds, limit, fallbackCandidates, prioritizeSourcePaths = classifyQueryIntentRaw(query) === "source", allowNonSourcePaths = false) {
|
|
9882
9951
|
if (!prioritizeSourcePaths) {
|
|
9883
9952
|
return [];
|
|
9884
9953
|
}
|
|
@@ -9898,7 +9967,7 @@ function buildSymbolDefinitionLane(query, database, branchChunkIds, branchSymbol
|
|
|
9898
9967
|
if (!isImplementationChunkType(chunkType)) {
|
|
9899
9968
|
return false;
|
|
9900
9969
|
}
|
|
9901
|
-
if (!isLikelyImplementationPath2(chunk.filePath)) {
|
|
9970
|
+
if (!allowNonSourcePaths && !isLikelyImplementationPath2(chunk.filePath)) {
|
|
9902
9971
|
return false;
|
|
9903
9972
|
}
|
|
9904
9973
|
const nameLower = (chunk.name ?? "").toLowerCase();
|
|
@@ -9962,7 +10031,7 @@ function buildSymbolDefinitionLane(query, database, branchChunkIds, branchSymbol
|
|
|
9962
10031
|
}
|
|
9963
10032
|
foundCoveringChunk = upsertChunkCandidate(chunk, identifier, normalizedIdentifier) || foundCoveringChunk;
|
|
9964
10033
|
}
|
|
9965
|
-
if (foundCoveringChunk || !isLikelyImplementationPath2(symbol.filePath)) {
|
|
10034
|
+
if (foundCoveringChunk || !allowNonSourcePaths && !isLikelyImplementationPath2(symbol.filePath)) {
|
|
9966
10035
|
continue;
|
|
9967
10036
|
}
|
|
9968
10037
|
const symbolName = symbol.name.toLowerCase();
|
|
@@ -10016,7 +10085,7 @@ function buildSymbolDefinitionLane(query, database, branchChunkIds, branchSymbol
|
|
|
10016
10085
|
const ranked = Array.from(symbolCandidates.values()).sort((a, b) => b.score - a.score || a.id.localeCompare(b.id));
|
|
10017
10086
|
if (ranked.length === 0) {
|
|
10018
10087
|
const implementationFallback = fallbackCandidates.filter(
|
|
10019
|
-
(candidate) => isImplementationChunkType(candidate.metadata.chunkType) && isLikelyImplementationPath2(candidate.metadata.filePath)
|
|
10088
|
+
(candidate) => isImplementationChunkType(candidate.metadata.chunkType) && (allowNonSourcePaths || isLikelyImplementationPath2(candidate.metadata.filePath))
|
|
10020
10089
|
);
|
|
10021
10090
|
for (const candidate of implementationFallback) {
|
|
10022
10091
|
const nameLower = (candidate.metadata.name ?? "").toLowerCase();
|
|
@@ -10132,10 +10201,16 @@ function matchesHardSearchFilters(candidate, options, projectRoot) {
|
|
|
10132
10201
|
return false;
|
|
10133
10202
|
}
|
|
10134
10203
|
if (options?.blameSince) {
|
|
10135
|
-
const
|
|
10136
|
-
if (
|
|
10204
|
+
const since = parseBlameTimestamp(options.blameSince, false);
|
|
10205
|
+
if (since === null) return false;
|
|
10206
|
+
const committedAt = candidate.metadata.blameCommittedAt;
|
|
10207
|
+
if (committedAt === void 0 || committedAt < since) return false;
|
|
10208
|
+
}
|
|
10209
|
+
if (options?.blameUntil) {
|
|
10210
|
+
const until = parseBlameTimestamp(options.blameUntil, true);
|
|
10211
|
+
if (until === null) return false;
|
|
10137
10212
|
const committedAt = candidate.metadata.blameCommittedAt;
|
|
10138
|
-
if (committedAt === void 0 || committedAt
|
|
10213
|
+
if (committedAt === void 0 || committedAt > until) return false;
|
|
10139
10214
|
}
|
|
10140
10215
|
return true;
|
|
10141
10216
|
}
|
|
@@ -10171,7 +10246,6 @@ var Indexer = class _Indexer {
|
|
|
10171
10246
|
database = null;
|
|
10172
10247
|
provider = null;
|
|
10173
10248
|
configuredProviderInfo = null;
|
|
10174
|
-
reranker = null;
|
|
10175
10249
|
fileHashCache = /* @__PURE__ */ new Map();
|
|
10176
10250
|
fileHashCachePath = "";
|
|
10177
10251
|
failedBatchesPath = "";
|
|
@@ -10192,9 +10266,10 @@ var Indexer = class _Indexer {
|
|
|
10192
10266
|
writerArtifactFingerprint = null;
|
|
10193
10267
|
readerArtifactRetryAfter = /* @__PURE__ */ new Map();
|
|
10194
10268
|
fileBatchLimits;
|
|
10269
|
+
checkpointIntervalChunks;
|
|
10195
10270
|
constructor(projectRoot, config, host, runtimeOptions = {}) {
|
|
10196
10271
|
this.projectRoot = projectRoot;
|
|
10197
|
-
this.projectIdentityHash =
|
|
10272
|
+
this.projectIdentityHash = this.getProjectIdentityHash(projectRoot);
|
|
10198
10273
|
this.materializedProjectRoot = runtimeOptions.materializedProjectRoot ?? projectRoot;
|
|
10199
10274
|
this.branchNameOverride = runtimeOptions.branchName;
|
|
10200
10275
|
this.catalogIdentityOverride = runtimeOptions.catalogIdentity;
|
|
@@ -10204,6 +10279,7 @@ var Indexer = class _Indexer {
|
|
|
10204
10279
|
this.expectedCommitOverride = runtimeOptions.expectedCommit?.toLowerCase();
|
|
10205
10280
|
this.indexPathOverride = runtimeOptions.indexPath;
|
|
10206
10281
|
this.fileBatchLimits = runtimeOptions.fileBatchLimits;
|
|
10282
|
+
this.checkpointIntervalChunks = runtimeOptions.checkpointIntervalChunks;
|
|
10207
10283
|
this.config = config;
|
|
10208
10284
|
this.host = host;
|
|
10209
10285
|
if (isGitRepo(this.materializedProjectRoot)) {
|
|
@@ -10315,6 +10391,9 @@ var Indexer = class _Indexer {
|
|
|
10315
10391
|
return path19.resolve(targetPath);
|
|
10316
10392
|
}
|
|
10317
10393
|
}
|
|
10394
|
+
getProjectIdentityHash(projectRoot) {
|
|
10395
|
+
return hashContent(this.getCanonicalPath(projectRoot)).slice(0, 16);
|
|
10396
|
+
}
|
|
10318
10397
|
isProjectOwnedIndexPath() {
|
|
10319
10398
|
return isProjectIndexPathOwnedByProject(this.projectRoot, this.indexPath, this.host);
|
|
10320
10399
|
}
|
|
@@ -10331,7 +10410,6 @@ var Indexer = class _Indexer {
|
|
|
10331
10410
|
this.database = null;
|
|
10332
10411
|
this.provider = null;
|
|
10333
10412
|
this.configuredProviderInfo = null;
|
|
10334
|
-
this.reranker = null;
|
|
10335
10413
|
this.indexCompatibility = null;
|
|
10336
10414
|
this.initializationMode = "none";
|
|
10337
10415
|
this.readIssues = [];
|
|
@@ -10352,7 +10430,10 @@ var Indexer = class _Indexer {
|
|
|
10352
10430
|
}
|
|
10353
10431
|
async withIndexMutationLease(operation, callback) {
|
|
10354
10432
|
this.refreshBranchInfo();
|
|
10355
|
-
const lease = acquireIndexLock(this.indexPath, operation
|
|
10433
|
+
const lease = acquireIndexLock(this.indexPath, operation, {
|
|
10434
|
+
projectRoot: this.projectRoot,
|
|
10435
|
+
scopedRoots: this.getScopedRoots()
|
|
10436
|
+
});
|
|
10356
10437
|
this.indexPath = lease.canonicalIndexPath;
|
|
10357
10438
|
this.refreshRuntimeArtifactPaths();
|
|
10358
10439
|
this.activeIndexLease = lease;
|
|
@@ -10407,6 +10488,7 @@ var Indexer = class _Indexer {
|
|
|
10407
10488
|
}
|
|
10408
10489
|
loadFileHashCache() {
|
|
10409
10490
|
if (!(0, import_fs12.existsSync)(this.fileHashCachePath)) {
|
|
10491
|
+
this.fileHashCache = /* @__PURE__ */ new Map();
|
|
10410
10492
|
return;
|
|
10411
10493
|
}
|
|
10412
10494
|
try {
|
|
@@ -10446,10 +10528,10 @@ var Indexer = class _Indexer {
|
|
|
10446
10528
|
invertedIndex.serialize()
|
|
10447
10529
|
);
|
|
10448
10530
|
}
|
|
10449
|
-
getScopedRoots() {
|
|
10450
|
-
const roots = /* @__PURE__ */ new Set([this.getCanonicalPath(
|
|
10531
|
+
getScopedRoots(projectRoot = this.projectRoot) {
|
|
10532
|
+
const roots = /* @__PURE__ */ new Set([this.getCanonicalPath(projectRoot)]);
|
|
10451
10533
|
for (const kbRoot of this.config.knowledgeBases) {
|
|
10452
|
-
roots.add(this.getCanonicalPath(path19.resolve(
|
|
10534
|
+
roots.add(this.getCanonicalPath(path19.resolve(projectRoot, kbRoot)));
|
|
10453
10535
|
}
|
|
10454
10536
|
return Array.from(roots);
|
|
10455
10537
|
}
|
|
@@ -10520,14 +10602,17 @@ var Indexer = class _Indexer {
|
|
|
10520
10602
|
getLegacyBranchCatalogKey() {
|
|
10521
10603
|
return this.currentBranch || "default";
|
|
10522
10604
|
}
|
|
10523
|
-
getLegacyMigrationMetadataKey() {
|
|
10524
|
-
return `index.globalBranchMigration.${
|
|
10605
|
+
getLegacyMigrationMetadataKey(projectIdentityHash = this.projectIdentityHash) {
|
|
10606
|
+
return `index.globalBranchMigration.${projectIdentityHash}`;
|
|
10525
10607
|
}
|
|
10526
|
-
getProjectEmbeddingStrategyMetadataKey() {
|
|
10527
|
-
return `index.embeddingStrategyVersion.${
|
|
10608
|
+
getProjectEmbeddingStrategyMetadataKey(projectIdentityHash = this.projectIdentityHash) {
|
|
10609
|
+
return `index.embeddingStrategyVersion.${projectIdentityHash}`;
|
|
10528
10610
|
}
|
|
10529
|
-
getProjectForceReembedMetadataKey() {
|
|
10530
|
-
return `index.forceReembed.${
|
|
10611
|
+
getProjectForceReembedMetadataKey(projectIdentityHash = this.projectIdentityHash) {
|
|
10612
|
+
return `index.forceReembed.${projectIdentityHash}`;
|
|
10613
|
+
}
|
|
10614
|
+
getProjectMigrationFinalizedMetadataKey(projectIdentityHash = this.projectIdentityHash) {
|
|
10615
|
+
return `index.migrationFinalized.${projectIdentityHash}`;
|
|
10531
10616
|
}
|
|
10532
10617
|
getBranchMigrationMetadataKey(prefix, catalogIdentity = this.getBranchCatalogIdentity()) {
|
|
10533
10618
|
const branchKey = this.getBranchCatalogKeyFor(catalogIdentity);
|
|
@@ -10633,7 +10718,7 @@ var Indexer = class _Indexer {
|
|
|
10633
10718
|
const legacy = this.getLegacyBranchCatalogKey();
|
|
10634
10719
|
return primary === legacy ? [primary] : [primary, legacy];
|
|
10635
10720
|
}
|
|
10636
|
-
getProjectLocalScopedOwnershipIds(roots) {
|
|
10721
|
+
getProjectLocalScopedOwnershipIds(roots, projectRoot = this.projectRoot) {
|
|
10637
10722
|
const chunkIds = /* @__PURE__ */ new Set();
|
|
10638
10723
|
const symbolIds = /* @__PURE__ */ new Set();
|
|
10639
10724
|
if (!this.database) {
|
|
@@ -10641,10 +10726,10 @@ var Indexer = class _Indexer {
|
|
|
10641
10726
|
}
|
|
10642
10727
|
const projectLocalFilePaths = /* @__PURE__ */ new Set([
|
|
10643
10728
|
...Array.from(this.fileHashCache.keys()).filter(
|
|
10644
|
-
(filePath) => this.isFileInCurrentScope(filePath, roots) && this.isFileInProjectRoot(filePath)
|
|
10729
|
+
(filePath) => this.isFileInCurrentScope(filePath, roots) && this.isFileInProjectRoot(filePath, projectRoot)
|
|
10645
10730
|
),
|
|
10646
10731
|
...(this.store?.getAllMetadata() ?? []).map(({ metadata }) => metadata.filePath).filter(
|
|
10647
|
-
(filePath) => this.isFileInCurrentScope(filePath, roots) && this.isFileInProjectRoot(filePath)
|
|
10732
|
+
(filePath) => this.isFileInCurrentScope(filePath, roots) && this.isFileInProjectRoot(filePath, projectRoot)
|
|
10648
10733
|
)
|
|
10649
10734
|
]);
|
|
10650
10735
|
for (const filePath of projectLocalFilePaths) {
|
|
@@ -10657,15 +10742,16 @@ var Indexer = class _Indexer {
|
|
|
10657
10742
|
}
|
|
10658
10743
|
return { chunkIds, symbolIds };
|
|
10659
10744
|
}
|
|
10660
|
-
getProjectScopedBranchCatalogCleanupKeys(projectChunkIds, projectSymbolIds) {
|
|
10745
|
+
getProjectScopedBranchCatalogCleanupKeys(projectChunkIds, projectSymbolIds, projectRoot = this.projectRoot) {
|
|
10661
10746
|
if (this.config.scope !== "global") {
|
|
10662
10747
|
return this.getBranchCatalogCleanupKeys();
|
|
10663
10748
|
}
|
|
10664
10749
|
const keys = /* @__PURE__ */ new Set();
|
|
10665
10750
|
const projectChunkIdSet = new Set(projectChunkIds);
|
|
10666
10751
|
const projectSymbolIdSet = new Set(projectSymbolIds);
|
|
10752
|
+
const projectIdentityHash = this.getProjectIdentityHash(projectRoot);
|
|
10667
10753
|
for (const branchKey of this.database?.getAllBranches() ?? []) {
|
|
10668
|
-
if (branchKey.startsWith(`${
|
|
10754
|
+
if (branchKey.startsWith(`${projectIdentityHash}:`)) {
|
|
10669
10755
|
keys.add(branchKey);
|
|
10670
10756
|
continue;
|
|
10671
10757
|
}
|
|
@@ -10675,8 +10761,10 @@ var Indexer = class _Indexer {
|
|
|
10675
10761
|
keys.add(branchKey);
|
|
10676
10762
|
}
|
|
10677
10763
|
}
|
|
10678
|
-
|
|
10679
|
-
|
|
10764
|
+
if (projectRoot === this.projectRoot) {
|
|
10765
|
+
for (const branchKey of this.getBranchCatalogCleanupKeys()) {
|
|
10766
|
+
keys.add(branchKey);
|
|
10767
|
+
}
|
|
10680
10768
|
}
|
|
10681
10769
|
return Array.from(keys);
|
|
10682
10770
|
}
|
|
@@ -10684,10 +10772,10 @@ var Indexer = class _Indexer {
|
|
|
10684
10772
|
const canonicalFilePath = this.getCanonicalStoredFilePath(filePath);
|
|
10685
10773
|
return roots.some((root) => isPathWithinRoot2(canonicalFilePath, root));
|
|
10686
10774
|
}
|
|
10687
|
-
isFileInProjectRoot(filePath) {
|
|
10775
|
+
isFileInProjectRoot(filePath, projectRoot = this.projectRoot) {
|
|
10688
10776
|
return isPathWithinRoot2(
|
|
10689
10777
|
this.getCanonicalStoredFilePath(filePath),
|
|
10690
|
-
this.getCanonicalPath(
|
|
10778
|
+
this.getCanonicalPath(projectRoot)
|
|
10691
10779
|
);
|
|
10692
10780
|
}
|
|
10693
10781
|
clearScopedFileHashCache(roots) {
|
|
@@ -10729,12 +10817,12 @@ var Indexer = class _Indexer {
|
|
|
10729
10817
|
}
|
|
10730
10818
|
return false;
|
|
10731
10819
|
}
|
|
10732
|
-
hasForeignScopedBranchData() {
|
|
10820
|
+
hasForeignScopedBranchData(projectRoot = this.projectRoot, roots = this.getScopedRoots(projectRoot)) {
|
|
10733
10821
|
if (!this.database || this.config.scope !== "global") {
|
|
10734
10822
|
return false;
|
|
10735
10823
|
}
|
|
10736
|
-
const
|
|
10737
|
-
const { chunkIds: projectLocalChunkIds, symbolIds: projectLocalSymbolIds } = this.getProjectLocalScopedOwnershipIds(roots);
|
|
10824
|
+
const projectIdentityHash = this.getProjectIdentityHash(projectRoot);
|
|
10825
|
+
const { chunkIds: projectLocalChunkIds, symbolIds: projectLocalSymbolIds } = this.getProjectLocalScopedOwnershipIds(roots, projectRoot);
|
|
10738
10826
|
return this.database.getAllBranches().some(
|
|
10739
10827
|
(branchKey) => {
|
|
10740
10828
|
const branchChunkIds = this.database.getBranchChunkIds(branchKey);
|
|
@@ -10743,7 +10831,7 @@ var Indexer = class _Indexer {
|
|
|
10743
10831
|
if (!hasBranchData) {
|
|
10744
10832
|
return false;
|
|
10745
10833
|
}
|
|
10746
|
-
if (branchKey.startsWith(`${
|
|
10834
|
+
if (branchKey.startsWith(`${projectIdentityHash}:`)) {
|
|
10747
10835
|
return false;
|
|
10748
10836
|
}
|
|
10749
10837
|
const referencesCurrentProjectChunks = branchChunkIds.some((chunkId) => projectLocalChunkIds.has(chunkId));
|
|
@@ -10752,7 +10840,7 @@ var Indexer = class _Indexer {
|
|
|
10752
10840
|
}
|
|
10753
10841
|
);
|
|
10754
10842
|
}
|
|
10755
|
-
clearSharedIndexProjectData(store, invertedIndex, database, roots) {
|
|
10843
|
+
clearSharedIndexProjectData(store, invertedIndex, database, roots, projectRoot = this.projectRoot) {
|
|
10756
10844
|
const allMetadata = store.getAllMetadata();
|
|
10757
10845
|
const scopedEntries = allMetadata.filter(({ metadata }) => this.isFileInCurrentScope(metadata.filePath, roots));
|
|
10758
10846
|
const filePaths = /* @__PURE__ */ new Set([
|
|
@@ -10760,7 +10848,7 @@ var Indexer = class _Indexer {
|
|
|
10760
10848
|
...scopedEntries.map(({ metadata }) => metadata.filePath)
|
|
10761
10849
|
]);
|
|
10762
10850
|
const projectLocalFilePaths = new Set(
|
|
10763
|
-
Array.from(filePaths).filter((filePath) => this.isFileInProjectRoot(filePath))
|
|
10851
|
+
Array.from(filePaths).filter((filePath) => this.isFileInProjectRoot(filePath, projectRoot))
|
|
10764
10852
|
);
|
|
10765
10853
|
const removedChunkIds = new Set(scopedEntries.map(({ key }) => key));
|
|
10766
10854
|
for (const filePath of filePaths) {
|
|
@@ -10770,7 +10858,7 @@ var Indexer = class _Indexer {
|
|
|
10770
10858
|
}
|
|
10771
10859
|
const removedChunkIdList = Array.from(removedChunkIds);
|
|
10772
10860
|
const projectLocalChunkIds = new Set(
|
|
10773
|
-
scopedEntries.filter(({ metadata }) => this.isFileInProjectRoot(metadata.filePath)).map(({ key }) => key)
|
|
10861
|
+
scopedEntries.filter(({ metadata }) => this.isFileInProjectRoot(metadata.filePath, projectRoot)).map(({ key }) => key)
|
|
10774
10862
|
);
|
|
10775
10863
|
for (const filePath of projectLocalFilePaths) {
|
|
10776
10864
|
for (const chunk of database.getChunksByFile(filePath)) {
|
|
@@ -10789,7 +10877,8 @@ var Indexer = class _Indexer {
|
|
|
10789
10877
|
}
|
|
10790
10878
|
const branchCleanupKeys = this.getProjectScopedBranchCatalogCleanupKeys(
|
|
10791
10879
|
Array.from(projectLocalChunkIds),
|
|
10792
|
-
Array.from(projectLocalSymbolIds)
|
|
10880
|
+
Array.from(projectLocalSymbolIds),
|
|
10881
|
+
projectRoot
|
|
10793
10882
|
);
|
|
10794
10883
|
for (const branchKey of branchCleanupKeys) {
|
|
10795
10884
|
database.deleteBranchChunksForBranch(branchKey, removedChunkIdList);
|
|
@@ -10824,29 +10913,96 @@ var Indexer = class _Indexer {
|
|
|
10824
10913
|
database.gcOrphanSymbols();
|
|
10825
10914
|
database.gcOrphanEmbeddings();
|
|
10826
10915
|
database.gcOrphanChunks();
|
|
10827
|
-
store.save();
|
|
10828
10916
|
this.saveInvertedIndex(invertedIndex);
|
|
10917
|
+
store.save();
|
|
10829
10918
|
return {
|
|
10830
10919
|
removedChunkIds: removedChunkIdList,
|
|
10831
10920
|
hasForeignData: allMetadata.some(({ metadata }) => !this.isFileInCurrentScope(metadata.filePath, roots))
|
|
10832
10921
|
};
|
|
10833
10922
|
}
|
|
10923
|
+
getCurrentClearRecoveryState() {
|
|
10924
|
+
if (!this.configuredProviderInfo) {
|
|
10925
|
+
throw new Error("Cannot persist clear recovery state before the embedding provider is initialized");
|
|
10926
|
+
}
|
|
10927
|
+
const compatibility = this.checkCompatibility();
|
|
10928
|
+
const compatibilityDecision = compatibility.compatible ? "compatible" : compatibility.code === "EMBEDDING_STRATEGY_MISMATCH" /* EMBEDDING_STRATEGY_MISMATCH */ ? "embedding-strategy-mismatch" : "incompatible";
|
|
10929
|
+
return {
|
|
10930
|
+
phase: "clearing",
|
|
10931
|
+
embeddingProvider: this.configuredProviderInfo.provider,
|
|
10932
|
+
embeddingModel: this.configuredProviderInfo.modelInfo.model,
|
|
10933
|
+
embeddingDimensions: this.configuredProviderInfo.modelInfo.dimensions,
|
|
10934
|
+
embeddingStrategyVersion: EMBEDDING_STRATEGY_VERSION,
|
|
10935
|
+
compatibilityDecision
|
|
10936
|
+
};
|
|
10937
|
+
}
|
|
10938
|
+
beginClearRecoveryState() {
|
|
10939
|
+
const recovery = this.getCurrentClearRecoveryState();
|
|
10940
|
+
setIndexLockClearRecoveryState(this.requireActiveLease(), recovery);
|
|
10941
|
+
return recovery;
|
|
10942
|
+
}
|
|
10943
|
+
finishClearRecoveryState() {
|
|
10944
|
+
setIndexLockClearRecoveryState(this.requireActiveLease(), null);
|
|
10945
|
+
}
|
|
10946
|
+
matchesCurrentClearRecoveryConfiguration(recovery) {
|
|
10947
|
+
const configuredProviderInfo = this.configuredProviderInfo;
|
|
10948
|
+
return configuredProviderInfo !== null && recovery.embeddingProvider === configuredProviderInfo.provider && recovery.embeddingModel === configuredProviderInfo.modelInfo.model && recovery.embeddingDimensions === configuredProviderInfo.modelInfo.dimensions && recovery.embeddingStrategyVersion === EMBEDDING_STRATEGY_VERSION;
|
|
10949
|
+
}
|
|
10950
|
+
hasUnknownLegacyForceIndexClear(owner) {
|
|
10951
|
+
return owner.operation === "force-index" && owner.clearRecovery === void 0 && owner.recoveryProtocolVersion !== 1 && (0, import_fs12.existsSync)(path19.join(this.indexPath, "force-index-phase"));
|
|
10952
|
+
}
|
|
10834
10953
|
async recoverFromInterruptedIndexingUnlocked(owners) {
|
|
10835
10954
|
for (const owner of owners) {
|
|
10836
10955
|
this.logger.warn("Detected interrupted indexing session, recovering...", {
|
|
10837
10956
|
pid: owner.pid,
|
|
10838
10957
|
hostname: owner.hostname,
|
|
10839
10958
|
operation: owner.operation,
|
|
10840
|
-
startedAt: owner.startedAt
|
|
10959
|
+
startedAt: owner.startedAt,
|
|
10960
|
+
projectRoot: owner.projectRoot
|
|
10841
10961
|
});
|
|
10842
10962
|
}
|
|
10843
10963
|
if (this.config.scope === "global") {
|
|
10844
|
-
|
|
10845
|
-
|
|
10964
|
+
const clearScopes = [];
|
|
10965
|
+
for (const owner of owners) {
|
|
10966
|
+
if (this.hasUnknownLegacyForceIndexClear(owner)) {
|
|
10967
|
+
throw new Error(
|
|
10968
|
+
`Cannot automatically recover interrupted force-index ${owner.token}: the legacy clearing phase ownership is unknown. The recovery marker was retained for manual inspection.`
|
|
10969
|
+
);
|
|
10970
|
+
}
|
|
10971
|
+
if (owner.operation === "clear" && owner.clearRecovery === void 0 && owner.recoveryProtocolVersion !== 1) {
|
|
10972
|
+
throw new Error(
|
|
10973
|
+
`Cannot automatically recover interrupted global clear ${owner.token}: the originating recovery state is unknown. The recovery marker was retained for manual inspection.`
|
|
10974
|
+
);
|
|
10975
|
+
}
|
|
10976
|
+
if (owner.clearRecovery === void 0) continue;
|
|
10977
|
+
if (!owner.projectRoot || !owner.scopedRoots || owner.scopedRoots.length === 0) {
|
|
10978
|
+
throw new Error(
|
|
10979
|
+
`Cannot automatically recover interrupted global clear ${owner.token}: the originating project scope is unknown. The recovery marker was retained for manual inspection.`
|
|
10980
|
+
);
|
|
10981
|
+
}
|
|
10982
|
+
if (!this.matchesCurrentClearRecoveryConfiguration(owner.clearRecovery)) {
|
|
10983
|
+
throw new Error(
|
|
10984
|
+
`Cannot automatically recover interrupted global clear ${owner.token}: the current embedding configuration does not match the originating lease. The recovery marker was retained; retry from the originating project with matching settings.`
|
|
10985
|
+
);
|
|
10986
|
+
}
|
|
10987
|
+
clearScopes.push({
|
|
10988
|
+
projectRoot: owner.projectRoot,
|
|
10989
|
+
scopedRoots: owner.scopedRoots,
|
|
10990
|
+
compatibilityDecision: owner.clearRecovery.compatibilityDecision
|
|
10991
|
+
});
|
|
10992
|
+
}
|
|
10993
|
+
if (clearScopes.length > 0) {
|
|
10994
|
+
this.loadFileHashCache();
|
|
10995
|
+
}
|
|
10996
|
+
for (const { projectRoot, scopedRoots, compatibilityDecision } of clearScopes) {
|
|
10997
|
+
this.clearGlobalIndexUnlocked(projectRoot, scopedRoots, compatibilityDecision);
|
|
10846
10998
|
}
|
|
10847
10999
|
await this.healthCheckUnlocked();
|
|
11000
|
+
this.logger.info(
|
|
11001
|
+
clearScopes.length > 0 ? "Recovery complete, next index will rebuild all files" : "Recovery complete, next index will resume from the last checkpoint"
|
|
11002
|
+
);
|
|
11003
|
+
return;
|
|
10848
11004
|
}
|
|
10849
|
-
this.logger.info("Recovery complete, next index will
|
|
11005
|
+
this.logger.info("Recovery complete, next index will resume from the last checkpoint");
|
|
10850
11006
|
}
|
|
10851
11007
|
*loadSerializedFailedBatches() {
|
|
10852
11008
|
let warned = false;
|
|
@@ -10884,40 +11040,126 @@ var Indexer = class _Indexer {
|
|
|
10884
11040
|
state.writer.write(record);
|
|
10885
11041
|
state.recordsWritten += record.chunks.length;
|
|
10886
11042
|
}
|
|
10887
|
-
finalizeFailedBatchWriteState(state) {
|
|
11043
|
+
finalizeFailedBatchWriteState(state, resolvedChunkIds = /* @__PURE__ */ new Set()) {
|
|
10888
11044
|
if (state.recordsWritten > 0) {
|
|
10889
|
-
|
|
10890
|
-
|
|
10891
|
-
|
|
10892
|
-
|
|
10893
|
-
|
|
10894
|
-
|
|
10895
|
-
|
|
10896
|
-
|
|
10897
|
-
|
|
10898
|
-
|
|
10899
|
-
|
|
10900
|
-
|
|
10901
|
-
|
|
10902
|
-
|
|
10903
|
-
|
|
10904
|
-
const state = this.createFailedBatchWriteState();
|
|
10905
|
-
try {
|
|
10906
|
-
for (const batch of this.loadSerializedFailedBatches()) {
|
|
10907
|
-
const retainedChunks = batch.chunks.filter(shouldRetain);
|
|
10908
|
-
if (retainedChunks.length > 0) {
|
|
10909
|
-
this.writeFailedBatchRecord(state, { ...batch, chunks: retainedChunks });
|
|
11045
|
+
const seenChunkIds = /* @__PURE__ */ new Set();
|
|
11046
|
+
const retained = [];
|
|
11047
|
+
const records = Array.from(readFailedBatchRecords(state.writer.temporaryPath));
|
|
11048
|
+
for (let i = records.length - 1; i >= 0; i--) {
|
|
11049
|
+
const chunks = records[i].chunks.filter((rawChunk) => {
|
|
11050
|
+
const chunkId = getPendingChunkId(rawChunk);
|
|
11051
|
+
if (chunkId !== null) {
|
|
11052
|
+
if (resolvedChunkIds.has(chunkId)) return false;
|
|
11053
|
+
if (seenChunkIds.has(chunkId)) return false;
|
|
11054
|
+
seenChunkIds.add(chunkId);
|
|
11055
|
+
}
|
|
11056
|
+
return true;
|
|
11057
|
+
});
|
|
11058
|
+
if (chunks.length > 0) {
|
|
11059
|
+
retained.unshift({ ...records[i], chunks });
|
|
10910
11060
|
}
|
|
10911
11061
|
}
|
|
10912
|
-
this.finalizeFailedBatchWriteState(state);
|
|
10913
|
-
} catch (error) {
|
|
10914
11062
|
state.writer.cleanup();
|
|
10915
|
-
|
|
11063
|
+
if (retained.length > 0) {
|
|
11064
|
+
writeFailedBatchRecords(this.failedBatchesPath, retained);
|
|
11065
|
+
} else {
|
|
11066
|
+
writeFailedBatchRecords(this.failedBatchesPath, []);
|
|
11067
|
+
this.clearFailedBatchState();
|
|
11068
|
+
}
|
|
11069
|
+
return;
|
|
11070
|
+
}
|
|
11071
|
+
state.writer.commit();
|
|
11072
|
+
this.clearFailedBatchState();
|
|
11073
|
+
}
|
|
11074
|
+
getCheckpointIntervalChunks(totalChunks) {
|
|
11075
|
+
return Math.max(
|
|
11076
|
+
this.checkpointIntervalChunks ?? 2e3,
|
|
11077
|
+
Math.floor(totalChunks / 10)
|
|
11078
|
+
);
|
|
11079
|
+
}
|
|
11080
|
+
checkpointIndexRun(database, store, invertedIndex, failedProcessing, resolvedRetryChunkIds, currentFileHashes, committedFilePaths, scopedRoots, configuredProviderInfo) {
|
|
11081
|
+
if (!this.hasProjectForceReembedPending()) {
|
|
11082
|
+
this.saveIndexMetadata(configuredProviderInfo);
|
|
11083
|
+
this.indexCompatibility = { compatible: true };
|
|
11084
|
+
}
|
|
11085
|
+
database.commitWriteTransaction();
|
|
11086
|
+
database.beginWriteTransaction();
|
|
11087
|
+
this.saveInvertedIndex(invertedIndex);
|
|
11088
|
+
store.save();
|
|
11089
|
+
if (failedProcessing.state.recordsWritten > 0 || failedProcessing.latestById.size > 0 || failedProcessing.discardedExistingRecords) {
|
|
11090
|
+
for (const metadata of failedProcessing.latestById.values()) {
|
|
11091
|
+
const alreadyMaterialized = metadata.chunks.some((rawChunk) => {
|
|
11092
|
+
const chunkId = getPendingChunkId(rawChunk);
|
|
11093
|
+
return chunkId !== null && failedProcessing.materializedRetryIds.has(chunkId);
|
|
11094
|
+
});
|
|
11095
|
+
if (alreadyMaterialized) continue;
|
|
11096
|
+
this.writeFailedBatchRecord(failedProcessing.state, {
|
|
11097
|
+
chunks: metadata.chunks,
|
|
11098
|
+
attemptCount: metadata.attemptCount,
|
|
11099
|
+
error: metadata.error,
|
|
11100
|
+
lastAttempt: metadata.lastAttempt
|
|
11101
|
+
});
|
|
11102
|
+
for (const rawChunk of metadata.chunks) {
|
|
11103
|
+
const chunkId = getPendingChunkId(rawChunk);
|
|
11104
|
+
if (chunkId !== null) {
|
|
11105
|
+
failedProcessing.materializedRetryIds.add(chunkId);
|
|
11106
|
+
}
|
|
11107
|
+
}
|
|
11108
|
+
}
|
|
11109
|
+
this.finalizeFailedBatchWriteState(failedProcessing.state, resolvedRetryChunkIds);
|
|
11110
|
+
failedProcessing.state = this.createFailedBatchWriteState();
|
|
11111
|
+
failedProcessing.discardedExistingRecords = false;
|
|
11112
|
+
for (const record of this.loadSerializedFailedBatches()) {
|
|
11113
|
+
for (const rawChunk of record.chunks) {
|
|
11114
|
+
const chunkId = getPendingChunkId(rawChunk);
|
|
11115
|
+
this.writeFailedBatchRecord(failedProcessing.state, { ...record, chunks: [rawChunk] });
|
|
11116
|
+
if (chunkId !== null) {
|
|
11117
|
+
failedProcessing.materializedRetryIds.add(chunkId);
|
|
11118
|
+
}
|
|
11119
|
+
}
|
|
11120
|
+
}
|
|
11121
|
+
}
|
|
11122
|
+
const partialHashes = /* @__PURE__ */ new Map();
|
|
11123
|
+
for (const filePath of committedFilePaths) {
|
|
11124
|
+
const hash = currentFileHashes.get(filePath);
|
|
11125
|
+
if (hash !== void 0) {
|
|
11126
|
+
partialHashes.set(filePath, hash);
|
|
11127
|
+
}
|
|
11128
|
+
}
|
|
11129
|
+
if (scopedRoots) {
|
|
11130
|
+
this.replaceScopedFileHashCache(partialHashes, scopedRoots);
|
|
11131
|
+
} else {
|
|
11132
|
+
this.fileHashCache = partialHashes;
|
|
11133
|
+
this.saveFileHashCache();
|
|
11134
|
+
}
|
|
11135
|
+
}
|
|
11136
|
+
clearFailedBatchState() {
|
|
11137
|
+
if ((0, import_fs12.existsSync)(this.failedBatchesPath)) {
|
|
11138
|
+
try {
|
|
11139
|
+
(0, import_fs12.unlinkSync)(this.failedBatchesPath);
|
|
11140
|
+
} catch {
|
|
11141
|
+
}
|
|
11142
|
+
}
|
|
11143
|
+
}
|
|
11144
|
+
rewriteFailedBatchState(shouldRetain) {
|
|
11145
|
+
const state = this.createFailedBatchWriteState();
|
|
11146
|
+
try {
|
|
11147
|
+
for (const batch of this.loadSerializedFailedBatches()) {
|
|
11148
|
+
const retainedChunks = batch.chunks.filter(shouldRetain);
|
|
11149
|
+
if (retainedChunks.length > 0) {
|
|
11150
|
+
this.writeFailedBatchRecord(state, { ...batch, chunks: retainedChunks });
|
|
11151
|
+
}
|
|
11152
|
+
}
|
|
11153
|
+
this.finalizeFailedBatchWriteState(state);
|
|
11154
|
+
} catch (error) {
|
|
11155
|
+
state.writer.cleanup();
|
|
11156
|
+
throw error;
|
|
10916
11157
|
}
|
|
10917
11158
|
}
|
|
10918
11159
|
prepareFailedBatchProcessing(roots, shouldProcess) {
|
|
10919
11160
|
const state = this.createFailedBatchWriteState();
|
|
10920
11161
|
const latestById = /* @__PURE__ */ new Map();
|
|
11162
|
+
let discardedExistingRecords = false;
|
|
10921
11163
|
try {
|
|
10922
11164
|
for (const batch of this.loadSerializedFailedBatches()) {
|
|
10923
11165
|
for (const rawChunk of batch.chunks) {
|
|
@@ -10928,10 +11170,12 @@ var Indexer = class _Indexer {
|
|
|
10928
11170
|
continue;
|
|
10929
11171
|
}
|
|
10930
11172
|
if (!shouldProcess(filePath)) {
|
|
11173
|
+
discardedExistingRecords = true;
|
|
10931
11174
|
continue;
|
|
10932
11175
|
}
|
|
10933
11176
|
const chunkId = getPendingChunkId(rawChunk);
|
|
10934
11177
|
if (!chunkId) {
|
|
11178
|
+
discardedExistingRecords = true;
|
|
10935
11179
|
continue;
|
|
10936
11180
|
}
|
|
10937
11181
|
const existing = latestById.get(chunkId);
|
|
@@ -10939,12 +11183,18 @@ var Indexer = class _Indexer {
|
|
|
10939
11183
|
latestById.set(chunkId, {
|
|
10940
11184
|
attemptCount: batch.attemptCount,
|
|
10941
11185
|
error: batch.error,
|
|
10942
|
-
lastAttempt: batch.lastAttempt
|
|
11186
|
+
lastAttempt: batch.lastAttempt,
|
|
11187
|
+
chunks: [rawChunk]
|
|
10943
11188
|
});
|
|
10944
11189
|
}
|
|
10945
11190
|
}
|
|
10946
11191
|
}
|
|
10947
|
-
return {
|
|
11192
|
+
return {
|
|
11193
|
+
state,
|
|
11194
|
+
latestById,
|
|
11195
|
+
materializedRetryIds: /* @__PURE__ */ new Set(),
|
|
11196
|
+
discardedExistingRecords
|
|
11197
|
+
};
|
|
10948
11198
|
} catch (error) {
|
|
10949
11199
|
state.writer.cleanup();
|
|
10950
11200
|
throw error;
|
|
@@ -10980,10 +11230,34 @@ var Indexer = class _Indexer {
|
|
|
10980
11230
|
}
|
|
10981
11231
|
}
|
|
10982
11232
|
}
|
|
11233
|
+
restoreMissingChunkRows(database, chunks) {
|
|
11234
|
+
const missing = [];
|
|
11235
|
+
for (const chunk of chunks) {
|
|
11236
|
+
if (database.getChunk(chunk.id)) {
|
|
11237
|
+
continue;
|
|
11238
|
+
}
|
|
11239
|
+
missing.push({
|
|
11240
|
+
chunkId: chunk.id,
|
|
11241
|
+
contentHash: chunk.contentHash,
|
|
11242
|
+
filePath: chunk.metadata.filePath,
|
|
11243
|
+
startLine: chunk.metadata.startLine,
|
|
11244
|
+
endLine: chunk.metadata.endLine,
|
|
11245
|
+
nodeType: chunk.metadata.chunkType,
|
|
11246
|
+
name: chunk.metadata.name,
|
|
11247
|
+
language: chunk.metadata.language,
|
|
11248
|
+
blameSha: chunk.metadata.blameSha,
|
|
11249
|
+
blameAuthor: chunk.metadata.blameAuthor,
|
|
11250
|
+
blameAuthorEmail: chunk.metadata.blameAuthorEmail,
|
|
11251
|
+
blameCommittedAt: chunk.metadata.blameCommittedAt,
|
|
11252
|
+
blameSummary: chunk.metadata.blameSummary
|
|
11253
|
+
});
|
|
11254
|
+
}
|
|
11255
|
+
if (missing.length > 0) {
|
|
11256
|
+
database.upsertChunksBatch(missing);
|
|
11257
|
+
}
|
|
11258
|
+
}
|
|
10983
11259
|
getProviderRateLimits(provider) {
|
|
10984
11260
|
switch (provider) {
|
|
10985
|
-
case "github-copilot":
|
|
10986
|
-
return { concurrency: 1, intervalMs: 4e3, minRetryMs: 5e3, maxRetryMs: 6e4 };
|
|
10987
11261
|
case "openai":
|
|
10988
11262
|
return { concurrency: 3, intervalMs: 500, minRetryMs: 1e3, maxRetryMs: 3e4 };
|
|
10989
11263
|
case "google":
|
|
@@ -11052,16 +11326,17 @@ var Indexer = class _Indexer {
|
|
|
11052
11326
|
const embeddingPartsByChunk = /* @__PURE__ */ new Map();
|
|
11053
11327
|
const completedVectorsByChunkId = /* @__PURE__ */ new Map();
|
|
11054
11328
|
const completedChunkIds = /* @__PURE__ */ new Set();
|
|
11055
|
-
const
|
|
11056
|
-
|
|
11057
|
-
|
|
11058
|
-
|
|
11329
|
+
const batchOptions = getDynamicBatchOptions(options.configuredProviderInfo, this.config.embedding?.batch);
|
|
11330
|
+
if (options.forceSingleItemBatches && options.configuredProviderInfo.provider === "ollama") {
|
|
11331
|
+
batchOptions.maxBatchItems = 1;
|
|
11332
|
+
}
|
|
11333
|
+
const requestBatches = createPendingEmbeddingRequestBatches(chunksNeedingEmbedding, batchOptions);
|
|
11059
11334
|
let fatalError;
|
|
11060
11335
|
for (const requestBatch of requestBatches) {
|
|
11061
11336
|
await options.queue.onSizeLessThan(Math.max(1, options.providerRateLimits.concurrency));
|
|
11062
11337
|
const task = options.queue.add(async () => {
|
|
11063
11338
|
if (options.rateLimitState.backoffMs > 0) {
|
|
11064
|
-
await new Promise((
|
|
11339
|
+
await new Promise((resolve17) => setTimeout(resolve17, options.rateLimitState.backoffMs));
|
|
11065
11340
|
}
|
|
11066
11341
|
try {
|
|
11067
11342
|
const embeddingResult = await pRetry(
|
|
@@ -11618,7 +11893,7 @@ var Indexer = class _Indexer {
|
|
|
11618
11893
|
}
|
|
11619
11894
|
if (!this.configuredProviderInfo) {
|
|
11620
11895
|
throw new Error(
|
|
11621
|
-
"No embedding provider available. Configure
|
|
11896
|
+
"No embedding provider available. Configure OpenAI, Google, Ollama, or a custom OpenAI-compatible endpoint."
|
|
11622
11897
|
);
|
|
11623
11898
|
}
|
|
11624
11899
|
this.logger.info("Initializing indexer", {
|
|
@@ -11628,15 +11903,6 @@ var Indexer = class _Indexer {
|
|
|
11628
11903
|
rerankerEnabled: this.config.reranker?.enabled ?? false
|
|
11629
11904
|
});
|
|
11630
11905
|
this.provider = createEmbeddingProvider(this.configuredProviderInfo);
|
|
11631
|
-
if (this.config.reranker?.enabled) {
|
|
11632
|
-
this.reranker = createReranker(this.config.reranker);
|
|
11633
|
-
if (this.reranker.isAvailable()) {
|
|
11634
|
-
this.logger.info("Reranker initialized", {
|
|
11635
|
-
model: this.config.reranker.model,
|
|
11636
|
-
baseUrl: this.config.reranker.baseUrl
|
|
11637
|
-
});
|
|
11638
|
-
}
|
|
11639
|
-
}
|
|
11640
11906
|
const dimensions = this.configuredProviderInfo.modelInfo.dimensions;
|
|
11641
11907
|
const storePath = path19.join(this.indexPath, "vectors");
|
|
11642
11908
|
const vectorMetadataPath = `${storePath}.meta.json`;
|
|
@@ -11658,7 +11924,20 @@ var Indexer = class _Indexer {
|
|
|
11658
11924
|
]);
|
|
11659
11925
|
}
|
|
11660
11926
|
if (recoveredOwners.length > 0 && this.config.scope === "project") {
|
|
11661
|
-
|
|
11927
|
+
const unknownLegacyForceIndex = recoveredOwners.find(
|
|
11928
|
+
(owner) => this.hasUnknownLegacyForceIndexClear(owner)
|
|
11929
|
+
);
|
|
11930
|
+
if (unknownLegacyForceIndex) {
|
|
11931
|
+
throw new Error(
|
|
11932
|
+
`Cannot automatically recover interrupted force-index ${unknownLegacyForceIndex.token}: the legacy clearing phase ownership is unknown. The recovery marker was retained for manual inspection.`
|
|
11933
|
+
);
|
|
11934
|
+
}
|
|
11935
|
+
const shouldReset = recoveredOwners.some(
|
|
11936
|
+
(owner) => owner.clearRecovery !== void 0 || owner.operation === "clear" && owner.recoveryProtocolVersion !== 1
|
|
11937
|
+
);
|
|
11938
|
+
if (shouldReset) {
|
|
11939
|
+
await this.resetLocalIndexArtifacts();
|
|
11940
|
+
}
|
|
11662
11941
|
}
|
|
11663
11942
|
this.store = new VectorStore(storePath, dimensions);
|
|
11664
11943
|
if ((0, import_fs12.existsSync)(storePath) || (0, import_fs12.existsSync)(vectorMetadataPath)) {
|
|
@@ -12294,7 +12573,17 @@ var Indexer = class _Indexer {
|
|
|
12294
12573
|
const needsCallGraphResolutionMigration = database.getMetadata(this.getCallGraphResolutionMetadataKey()) !== CALL_GRAPH_RESOLUTION_VERSION;
|
|
12295
12574
|
for (const file of files) {
|
|
12296
12575
|
const storedPath = this.toStoredFilePath(file.path);
|
|
12297
|
-
|
|
12576
|
+
let currentHash;
|
|
12577
|
+
try {
|
|
12578
|
+
currentHash = hashFile(file.path);
|
|
12579
|
+
} catch (error) {
|
|
12580
|
+
stats.skippedFiles.push({ path: this.toCanonicalFilePath(file.path), reason: "unreadable" });
|
|
12581
|
+
this.logger.warn("Skipped unreadable file during indexing", {
|
|
12582
|
+
path: file.path,
|
|
12583
|
+
error: getErrorMessage4(error)
|
|
12584
|
+
});
|
|
12585
|
+
continue;
|
|
12586
|
+
}
|
|
12298
12587
|
currentFileHashes.set(storedPath, currentHash);
|
|
12299
12588
|
const cachedHashMatches = this.fileHashCache.get(storedPath) === currentHash;
|
|
12300
12589
|
const needsCallGraphRefresh = cachedHashMatches && needsCallGraphResolutionMigration && database.getChunksByFile(storedPath).some(
|
|
@@ -12302,7 +12591,8 @@ var Indexer = class _Indexer {
|
|
|
12302
12591
|
);
|
|
12303
12592
|
const requiresSwiftParserUpgrade = reparseCachedSwiftFiles && path19.extname(storedPath).toLowerCase() === ".swift";
|
|
12304
12593
|
const requiresMetalParserUpgrade = reparseCachedMetalFiles && path19.extname(storedPath).toLowerCase() === ".metal";
|
|
12305
|
-
|
|
12594
|
+
const inMigrationScope = forceScopedReembed && scopedRoots !== null && this.isFileInCurrentScope(storedPath, scopedRoots);
|
|
12595
|
+
if (cachedHashMatches && !inMigrationScope && !needsCallGraphRefresh && !requiresSwiftParserUpgrade && !requiresMetalParserUpgrade && !refreshCachedSymbols) {
|
|
12306
12596
|
unchangedFilePaths.add(storedPath);
|
|
12307
12597
|
this.logger.recordCacheHit();
|
|
12308
12598
|
} else {
|
|
@@ -12428,6 +12718,9 @@ var Indexer = class _Indexer {
|
|
|
12428
12718
|
}
|
|
12429
12719
|
}
|
|
12430
12720
|
let processedChangedFiles = 0;
|
|
12721
|
+
let lastCheckpointChunks = 0;
|
|
12722
|
+
const committedFilePaths = new Set(unchangedFilePaths);
|
|
12723
|
+
const resolvedRetryChunkIds = /* @__PURE__ */ new Set();
|
|
12431
12724
|
for (const descriptorBatch of iterateOrderedFileBatches(
|
|
12432
12725
|
changedFileDescriptors,
|
|
12433
12726
|
(descriptor) => descriptor.sourceBytes,
|
|
@@ -12441,7 +12734,7 @@ var Indexer = class _Indexer {
|
|
|
12441
12734
|
const loadedByPath = new Map(loadedFiles.map((file) => [file.path, file]));
|
|
12442
12735
|
const descriptorByPath = new Map(descriptorBatch.map((descriptor) => [descriptor.storedPath, descriptor]));
|
|
12443
12736
|
const parseStartTime = import_perf_hooks.performance.now();
|
|
12444
|
-
const parsedFiles = parseFiles(loadedFiles);
|
|
12737
|
+
const parsedFiles = parseFiles(loadedFiles, this.config.indexing.linesPerChunk);
|
|
12445
12738
|
const parseMs = import_perf_hooks.performance.now() - parseStartTime;
|
|
12446
12739
|
this.logger.recordFilesParsed(parsedFiles.length);
|
|
12447
12740
|
this.logger.recordParseDuration(parseMs);
|
|
@@ -12464,7 +12757,7 @@ var Indexer = class _Indexer {
|
|
|
12464
12757
|
}
|
|
12465
12758
|
let chunksToProcess = parsed.chunks;
|
|
12466
12759
|
if (this.config.indexing.fallbackToTextOnMaxChunks && chunksToProcess.length > this.config.indexing.maxChunksPerFile) {
|
|
12467
|
-
chunksToProcess = parseFileAsText(parsed.path, loadedFile.content);
|
|
12760
|
+
chunksToProcess = parseFileAsText(parsed.path, loadedFile.content, this.config.indexing.linesPerChunk);
|
|
12468
12761
|
}
|
|
12469
12762
|
chunksToProcess = selectIndexableChunks(
|
|
12470
12763
|
chunksToProcess,
|
|
@@ -12598,6 +12891,10 @@ var Indexer = class _Indexer {
|
|
|
12598
12891
|
}
|
|
12599
12892
|
if (symbolBatch.length > 0) {
|
|
12600
12893
|
database.upsertSymbolsBatch(symbolBatch);
|
|
12894
|
+
database.addSymbolsToBranchBatch(
|
|
12895
|
+
this.getBranchCatalogKey(),
|
|
12896
|
+
symbolBatch.map((symbol) => symbol.id)
|
|
12897
|
+
);
|
|
12601
12898
|
}
|
|
12602
12899
|
if (edgeBatch.length > 0) {
|
|
12603
12900
|
database.upsertCallEdgesBatch(edgeBatch);
|
|
@@ -12633,6 +12930,12 @@ var Indexer = class _Indexer {
|
|
|
12633
12930
|
forceReembed: forceScopedReembed,
|
|
12634
12931
|
reuseCachedEmbeddings: true,
|
|
12635
12932
|
incrementRepeatedFailures: true,
|
|
12933
|
+
onSucceeded: (succeededChunks) => {
|
|
12934
|
+
database.addChunksToBranchBatch(
|
|
12935
|
+
this.getBranchCatalogKey(),
|
|
12936
|
+
succeededChunks.map((chunk) => chunk.id)
|
|
12937
|
+
);
|
|
12938
|
+
},
|
|
12636
12939
|
onProgress: (batchProgress) => onProgress?.({
|
|
12637
12940
|
phase: "embedding",
|
|
12638
12941
|
filesProcessed: unchangedFilePaths.size + processedChangedFiles,
|
|
@@ -12651,6 +12954,27 @@ var Indexer = class _Indexer {
|
|
|
12651
12954
|
}
|
|
12652
12955
|
}
|
|
12653
12956
|
}
|
|
12957
|
+
for (const descriptor of descriptorBatch) {
|
|
12958
|
+
const existingFileChunks = existingChunksByFile.get(descriptor.storedPath);
|
|
12959
|
+
if (!existingFileChunks || existingFileChunks.size === 0) {
|
|
12960
|
+
committedFilePaths.add(descriptor.storedPath);
|
|
12961
|
+
}
|
|
12962
|
+
}
|
|
12963
|
+
const checkpointInterval = this.getCheckpointIntervalChunks(stats.totalChunks);
|
|
12964
|
+
if (stats.totalChunks - lastCheckpointChunks >= checkpointInterval) {
|
|
12965
|
+
lastCheckpointChunks = stats.totalChunks;
|
|
12966
|
+
this.checkpointIndexRun(
|
|
12967
|
+
database,
|
|
12968
|
+
store,
|
|
12969
|
+
invertedIndex,
|
|
12970
|
+
failedProcessing,
|
|
12971
|
+
resolvedRetryChunkIds,
|
|
12972
|
+
currentFileHashes,
|
|
12973
|
+
committedFilePaths,
|
|
12974
|
+
scopedRoots,
|
|
12975
|
+
configuredProviderInfo
|
|
12976
|
+
);
|
|
12977
|
+
}
|
|
12654
12978
|
}
|
|
12655
12979
|
const retryableFailedChunks = this.iterateLatestFailedChunks(
|
|
12656
12980
|
failedProcessing.latestById,
|
|
@@ -12671,6 +12995,7 @@ var Indexer = class _Indexer {
|
|
|
12671
12995
|
retryableChunksWithExistingData.add(chunk.id);
|
|
12672
12996
|
}
|
|
12673
12997
|
}
|
|
12998
|
+
this.restoreMissingChunkRows(database, pendingChunks);
|
|
12674
12999
|
stats.totalChunks += pendingChunks.length;
|
|
12675
13000
|
onProgress?.({
|
|
12676
13001
|
phase: "embedding",
|
|
@@ -12693,6 +13018,17 @@ var Indexer = class _Indexer {
|
|
|
12693
13018
|
forceReembed: forceScopedReembed,
|
|
12694
13019
|
reuseCachedEmbeddings: true,
|
|
12695
13020
|
incrementRepeatedFailures: true,
|
|
13021
|
+
forceSingleItemBatches: true,
|
|
13022
|
+
onSucceeded: (succeededChunks) => {
|
|
13023
|
+
database.addChunksToBranchBatch(
|
|
13024
|
+
this.getBranchCatalogKey(),
|
|
13025
|
+
succeededChunks.map((chunk) => chunk.id)
|
|
13026
|
+
);
|
|
13027
|
+
for (const chunk of succeededChunks) {
|
|
13028
|
+
failedProcessing.latestById.delete(chunk.id);
|
|
13029
|
+
resolvedRetryChunkIds.add(chunk.id);
|
|
13030
|
+
}
|
|
13031
|
+
},
|
|
12696
13032
|
onProgress: (batchProgress) => onProgress?.({
|
|
12697
13033
|
phase: "embedding",
|
|
12698
13034
|
filesProcessed: files.length,
|
|
@@ -12710,6 +13046,20 @@ var Indexer = class _Indexer {
|
|
|
12710
13046
|
failedForcedChunkIds.add(chunkId);
|
|
12711
13047
|
}
|
|
12712
13048
|
}
|
|
13049
|
+
if (stats.totalChunks - lastCheckpointChunks >= this.getCheckpointIntervalChunks(stats.totalChunks)) {
|
|
13050
|
+
lastCheckpointChunks = stats.totalChunks;
|
|
13051
|
+
this.checkpointIndexRun(
|
|
13052
|
+
database,
|
|
13053
|
+
store,
|
|
13054
|
+
invertedIndex,
|
|
13055
|
+
failedProcessing,
|
|
13056
|
+
resolvedRetryChunkIds,
|
|
13057
|
+
currentFileHashes,
|
|
13058
|
+
committedFilePaths,
|
|
13059
|
+
scopedRoots,
|
|
13060
|
+
configuredProviderInfo
|
|
13061
|
+
);
|
|
13062
|
+
}
|
|
12713
13063
|
}
|
|
12714
13064
|
const removedChunkIds = [];
|
|
12715
13065
|
for (const [chunkId] of existingChunks) {
|
|
@@ -12746,13 +13096,6 @@ var Indexer = class _Indexer {
|
|
|
12746
13096
|
if (removedStoredChunks) {
|
|
12747
13097
|
this.saveInvertedIndex(invertedIndex);
|
|
12748
13098
|
}
|
|
12749
|
-
if (scopedRoots) {
|
|
12750
|
-
this.replaceScopedFileHashCache(currentFileHashes, scopedRoots);
|
|
12751
|
-
} else {
|
|
12752
|
-
this.fileHashCache = currentFileHashes;
|
|
12753
|
-
this.saveFileHashCache();
|
|
12754
|
-
}
|
|
12755
|
-
this.finalizeFailedBatchWriteState(failedProcessing.state);
|
|
12756
13099
|
database.setMetadata(swiftParserMetadataKey, SWIFT_PARSER_VERSION);
|
|
12757
13100
|
database.setMetadata(metalParserMetadataKey, METAL_PARSER_VERSION);
|
|
12758
13101
|
database.setMetadata(symbolExtractorMetadataKey, SYMBOL_EXTRACTOR_VERSION);
|
|
@@ -12761,6 +13104,13 @@ var Indexer = class _Indexer {
|
|
|
12761
13104
|
this.indexCompatibility = { compatible: true };
|
|
12762
13105
|
database.commitWriteTransaction();
|
|
12763
13106
|
writeTransactionActive = false;
|
|
13107
|
+
this.finalizeFailedBatchWriteState(failedProcessing.state, resolvedRetryChunkIds);
|
|
13108
|
+
if (scopedRoots) {
|
|
13109
|
+
this.replaceScopedFileHashCache(currentFileHashes, scopedRoots);
|
|
13110
|
+
} else {
|
|
13111
|
+
this.fileHashCache = currentFileHashes;
|
|
13112
|
+
this.saveFileHashCache();
|
|
13113
|
+
}
|
|
12764
13114
|
stats.durationMs = Date.now() - startTime;
|
|
12765
13115
|
onProgress?.({
|
|
12766
13116
|
phase: "complete",
|
|
@@ -12784,13 +13134,6 @@ var Indexer = class _Indexer {
|
|
|
12784
13134
|
);
|
|
12785
13135
|
store.save();
|
|
12786
13136
|
this.saveInvertedIndex(invertedIndex);
|
|
12787
|
-
if (scopedRoots) {
|
|
12788
|
-
this.replaceScopedFileHashCache(currentFileHashes, scopedRoots);
|
|
12789
|
-
} else {
|
|
12790
|
-
this.fileHashCache = currentFileHashes;
|
|
12791
|
-
this.saveFileHashCache();
|
|
12792
|
-
}
|
|
12793
|
-
this.finalizeFailedBatchWriteState(failedProcessing.state);
|
|
12794
13137
|
database.setMetadata(swiftParserMetadataKey, SWIFT_PARSER_VERSION);
|
|
12795
13138
|
database.setMetadata(metalParserMetadataKey, METAL_PARSER_VERSION);
|
|
12796
13139
|
database.setMetadata(symbolExtractorMetadataKey, SYMBOL_EXTRACTOR_VERSION);
|
|
@@ -12799,6 +13142,13 @@ var Indexer = class _Indexer {
|
|
|
12799
13142
|
this.indexCompatibility = { compatible: true };
|
|
12800
13143
|
database.commitWriteTransaction();
|
|
12801
13144
|
writeTransactionActive = false;
|
|
13145
|
+
this.finalizeFailedBatchWriteState(failedProcessing.state, resolvedRetryChunkIds);
|
|
13146
|
+
if (scopedRoots) {
|
|
13147
|
+
this.replaceScopedFileHashCache(currentFileHashes, scopedRoots);
|
|
13148
|
+
} else {
|
|
13149
|
+
this.fileHashCache = currentFileHashes;
|
|
13150
|
+
this.saveFileHashCache();
|
|
13151
|
+
}
|
|
12802
13152
|
stats.durationMs = Date.now() - startTime;
|
|
12803
13153
|
onProgress?.({
|
|
12804
13154
|
phase: "complete",
|
|
@@ -12833,15 +13183,15 @@ var Indexer = class _Indexer {
|
|
|
12833
13183
|
);
|
|
12834
13184
|
store.save();
|
|
12835
13185
|
this.saveInvertedIndex(invertedIndex);
|
|
13186
|
+
database.commitWriteTransaction();
|
|
13187
|
+
writeTransactionActive = false;
|
|
13188
|
+
this.finalizeFailedBatchWriteState(failedProcessing.state, resolvedRetryChunkIds);
|
|
12836
13189
|
if (scopedRoots) {
|
|
12837
13190
|
this.replaceScopedFileHashCache(currentFileHashes, scopedRoots);
|
|
12838
13191
|
} else {
|
|
12839
13192
|
this.fileHashCache = currentFileHashes;
|
|
12840
13193
|
this.saveFileHashCache();
|
|
12841
13194
|
}
|
|
12842
|
-
this.finalizeFailedBatchWriteState(failedProcessing.state);
|
|
12843
|
-
database.commitWriteTransaction();
|
|
12844
|
-
writeTransactionActive = false;
|
|
12845
13195
|
if (this.config.indexing.autoGc && stats.removedChunks > 0) {
|
|
12846
13196
|
const gcReset = await this.maybeRunOrphanGc();
|
|
12847
13197
|
if (gcReset) {
|
|
@@ -12865,6 +13215,9 @@ var Indexer = class _Indexer {
|
|
|
12865
13215
|
if (forceScopedReembed && failedForcedChunkIds.size === 0) {
|
|
12866
13216
|
database.deleteMetadata(this.getProjectForceReembedMetadataKey());
|
|
12867
13217
|
}
|
|
13218
|
+
if (forceScopedReembed) {
|
|
13219
|
+
database.setMetadata(this.getProjectMigrationFinalizedMetadataKey(), "true");
|
|
13220
|
+
}
|
|
12868
13221
|
database.setMetadata(swiftParserMetadataKey, SWIFT_PARSER_VERSION);
|
|
12869
13222
|
database.setMetadata(metalParserMetadataKey, METAL_PARSER_VERSION);
|
|
12870
13223
|
database.setMetadata(symbolExtractorMetadataKey, SYMBOL_EXTRACTOR_VERSION);
|
|
@@ -12975,26 +13328,41 @@ var Indexer = class _Indexer {
|
|
|
12975
13328
|
shouldPrefilterByBranch: branchChunkIds !== null && (this.config.scope === "global" || hasInitializedBranchCatalog)
|
|
12976
13329
|
};
|
|
12977
13330
|
}
|
|
12978
|
-
|
|
13331
|
+
searchCandidatesWithAllowedIds(initialLimit, totalCount, allowedChunkIds, shouldPrefilter, search, getChunkId) {
|
|
12979
13332
|
const normalizedLimit = Math.max(0, Math.floor(initialLimit));
|
|
12980
13333
|
if (normalizedLimit === 0) return [];
|
|
12981
|
-
if (!
|
|
13334
|
+
if (!shouldPrefilter || !allowedChunkIds) {
|
|
12982
13335
|
return search(normalizedLimit);
|
|
12983
13336
|
}
|
|
12984
|
-
const targetCount = Math.min(normalizedLimit,
|
|
13337
|
+
const targetCount = Math.min(normalizedLimit, allowedChunkIds.size);
|
|
12985
13338
|
if (targetCount === 0 || totalCount === 0) return [];
|
|
12986
13339
|
let requestedLimit = Math.min(normalizedLimit, totalCount);
|
|
12987
13340
|
while (true) {
|
|
12988
13341
|
const results = search(requestedLimit);
|
|
12989
|
-
const
|
|
12990
|
-
if (
|
|
12991
|
-
return
|
|
13342
|
+
const allowedResults = results.filter((candidate) => allowedChunkIds.has(getChunkId(candidate)));
|
|
13343
|
+
if (allowedResults.length >= targetCount || results.length < requestedLimit || requestedLimit >= totalCount) {
|
|
13344
|
+
return allowedResults;
|
|
12992
13345
|
}
|
|
12993
13346
|
const nextLimit = Math.min(totalCount, Math.max(requestedLimit + 1, requestedLimit * 2));
|
|
12994
|
-
if (nextLimit === requestedLimit) return
|
|
13347
|
+
if (nextLimit === requestedLimit) return allowedResults;
|
|
12995
13348
|
requestedLimit = nextLimit;
|
|
12996
13349
|
}
|
|
12997
13350
|
}
|
|
13351
|
+
getTemporalChunkIds(database, options) {
|
|
13352
|
+
if (!options?.blameSince && !options?.blameUntil) return null;
|
|
13353
|
+
const since = options.blameSince ? parseBlameTimestamp(options.blameSince, false) : void 0;
|
|
13354
|
+
const until = options.blameUntil ? parseBlameTimestamp(options.blameUntil, true) : void 0;
|
|
13355
|
+
if (since === null || until === null) {
|
|
13356
|
+
return /* @__PURE__ */ new Set();
|
|
13357
|
+
}
|
|
13358
|
+
return new Set(database.getChunkIdsByBlameDate(since, until));
|
|
13359
|
+
}
|
|
13360
|
+
intersectChunkIdSets(first, second) {
|
|
13361
|
+
if (first === null) return second;
|
|
13362
|
+
if (second === null) return first;
|
|
13363
|
+
const [smaller, larger] = first.size <= second.size ? [first, second] : [second, first];
|
|
13364
|
+
return new Set(Array.from(smaller).filter((chunkId) => larger.has(chunkId)));
|
|
13365
|
+
}
|
|
12998
13366
|
buildCandidateSnapshot(candidate) {
|
|
12999
13367
|
return {
|
|
13000
13368
|
id: candidate.id,
|
|
@@ -13009,13 +13377,16 @@ var Indexer = class _Indexer {
|
|
|
13009
13377
|
buildCandidateSnapshotList(candidates) {
|
|
13010
13378
|
return candidates.map((candidate) => this.buildCandidateSnapshot(candidate));
|
|
13011
13379
|
}
|
|
13012
|
-
searchSemanticCandidates(store, embedding, initialLimit, branchChunkIds, shouldPrefilterByBranch) {
|
|
13013
|
-
|
|
13014
|
-
|
|
13015
|
-
|
|
13380
|
+
searchSemanticCandidates(store, embedding, initialLimit, branchChunkIds, shouldPrefilterByBranch, temporalChunkIds) {
|
|
13381
|
+
const availableCount = temporalChunkIds?.size ?? store.count();
|
|
13382
|
+
if (availableCount === 0) return [];
|
|
13383
|
+
const allowedIds = temporalChunkIds === null ? void 0 : Array.from(temporalChunkIds);
|
|
13384
|
+
return this.searchCandidatesWithAllowedIds(
|
|
13385
|
+
Math.min(initialLimit, availableCount),
|
|
13386
|
+
availableCount,
|
|
13016
13387
|
branchChunkIds,
|
|
13017
13388
|
shouldPrefilterByBranch,
|
|
13018
|
-
(requestedLimit) => store.search(embedding, requestedLimit),
|
|
13389
|
+
(requestedLimit) => store.search(embedding, requestedLimit, allowedIds),
|
|
13019
13390
|
(candidate) => candidate.id
|
|
13020
13391
|
);
|
|
13021
13392
|
}
|
|
@@ -13040,7 +13411,9 @@ var Indexer = class _Indexer {
|
|
|
13040
13411
|
const rerankTopN = this.config.search.rerankTopN;
|
|
13041
13412
|
const filterByBranch = options?.filterByBranch ?? true;
|
|
13042
13413
|
const sourceIntent = options?.definitionIntent === true || classifyQueryIntentRaw(query) === "source";
|
|
13414
|
+
const prioritizeSourcePaths = sourceIntent || options?.prioritizeSourcePaths === true;
|
|
13043
13415
|
const identifierHints = extractIdentifierHints(query);
|
|
13416
|
+
const candidateLimit = maxResults * (prioritizeSourcePaths ? 12 : 4);
|
|
13044
13417
|
this.logger.search("debug", "Starting search", {
|
|
13045
13418
|
query,
|
|
13046
13419
|
maxResults,
|
|
@@ -13071,25 +13444,28 @@ var Indexer = class _Indexer {
|
|
|
13071
13444
|
branchChunkIds = new Set(branchCatalogKeys.flatMap((branchKey) => database.getBranchChunkIds(branchKey)));
|
|
13072
13445
|
branchSymbolIds = new Set(branchCatalogKeys.flatMap((branchKey) => database.getBranchSymbolIds(branchKey)));
|
|
13073
13446
|
}
|
|
13447
|
+
const temporalChunkIds = this.getTemporalChunkIds(database, options);
|
|
13074
13448
|
const { hasInitializedBranchCatalog, shouldPrefilterByBranch } = this.getBranchPrefilterState(database, branchChunkIds);
|
|
13075
13449
|
const prefilterMs = import_perf_hooks.performance.now() - prefilterStartTime;
|
|
13076
13450
|
const vectorStartTime = import_perf_hooks.performance.now();
|
|
13077
13451
|
const semanticCandidates = embedding ? this.searchSemanticCandidates(
|
|
13078
13452
|
store,
|
|
13079
13453
|
embedding,
|
|
13080
|
-
|
|
13454
|
+
candidateLimit,
|
|
13081
13455
|
branchChunkIds,
|
|
13082
|
-
shouldPrefilterByBranch
|
|
13456
|
+
shouldPrefilterByBranch,
|
|
13457
|
+
temporalChunkIds
|
|
13083
13458
|
) : [];
|
|
13084
13459
|
const vectorMs = import_perf_hooks.performance.now() - vectorStartTime;
|
|
13085
13460
|
const keywordStartTime = import_perf_hooks.performance.now();
|
|
13086
13461
|
const keywordCandidates = await this.keywordSearch(
|
|
13087
13462
|
query,
|
|
13088
|
-
|
|
13463
|
+
candidateLimit,
|
|
13089
13464
|
store,
|
|
13090
13465
|
invertedIndex,
|
|
13091
13466
|
branchChunkIds,
|
|
13092
|
-
shouldPrefilterByBranch
|
|
13467
|
+
shouldPrefilterByBranch,
|
|
13468
|
+
temporalChunkIds
|
|
13093
13469
|
);
|
|
13094
13470
|
const keywordMs = import_perf_hooks.performance.now() - keywordStartTime;
|
|
13095
13471
|
const scopedSemanticCandidates = semanticCandidates.filter(
|
|
@@ -13111,7 +13487,7 @@ var Indexer = class _Indexer {
|
|
|
13111
13487
|
rerankTopN,
|
|
13112
13488
|
limit: maxResults,
|
|
13113
13489
|
hybridWeight: rankingHybridWeight,
|
|
13114
|
-
prioritizeSourcePaths
|
|
13490
|
+
prioritizeSourcePaths
|
|
13115
13491
|
});
|
|
13116
13492
|
const rerankedCombined = await this.rerankCandidatesWithApi(query, combined, {
|
|
13117
13493
|
definitionIntent: options?.definitionIntent === true,
|
|
@@ -13147,10 +13523,11 @@ var Indexer = class _Indexer {
|
|
|
13147
13523
|
branchSymbolIds,
|
|
13148
13524
|
maxResults,
|
|
13149
13525
|
union,
|
|
13150
|
-
sourceIntent
|
|
13526
|
+
sourceIntent,
|
|
13527
|
+
options?.definitionIntent === true && ((options.directory?.trim().length ?? 0) > 0 || (options.fileType?.trim().length ?? 0) > 0)
|
|
13151
13528
|
);
|
|
13152
13529
|
const prePrimaryLane = mergeTieredResults(deterministicIdentifierLane, identifierLane, maxResults * 4);
|
|
13153
|
-
const primaryLane = mergeTieredResults(prePrimaryLane, symbolLane, maxResults * 4);
|
|
13530
|
+
const primaryLane = options?.definitionIntent === true ? mergeTieredResults(symbolLane, prePrimaryLane, maxResults * 4) : mergeTieredResults(prePrimaryLane, symbolLane, maxResults * 4);
|
|
13154
13531
|
const tiered = mergeTieredResults(primaryLane, rescued, maxResults * 4);
|
|
13155
13532
|
const hasCodeHints = extractCodeTermHints(query).length > 0 || identifierHints.length > 0;
|
|
13156
13533
|
const baseFiltered = tiered.filter(
|
|
@@ -13245,14 +13622,18 @@ var Indexer = class _Indexer {
|
|
|
13245
13622
|
})
|
|
13246
13623
|
);
|
|
13247
13624
|
}
|
|
13248
|
-
async keywordSearch(query, limit, store, invertedIndex, branchChunkIds = null, shouldPrefilterByBranch = false) {
|
|
13625
|
+
async keywordSearch(query, limit, store, invertedIndex, branchChunkIds = null, shouldPrefilterByBranch = false, temporalChunkIds = null) {
|
|
13249
13626
|
const normalizedLimit = Math.max(0, Math.floor(limit));
|
|
13250
13627
|
if (normalizedLimit === 0) return [];
|
|
13251
|
-
const
|
|
13628
|
+
const allowedChunkIds = this.intersectChunkIdSets(
|
|
13629
|
+
shouldPrefilterByBranch ? branchChunkIds : null,
|
|
13630
|
+
temporalChunkIds
|
|
13631
|
+
);
|
|
13632
|
+
const scoreEntries = this.searchCandidatesWithAllowedIds(
|
|
13252
13633
|
normalizedLimit,
|
|
13253
13634
|
invertedIndex.getDocumentCount(),
|
|
13254
|
-
|
|
13255
|
-
|
|
13635
|
+
allowedChunkIds,
|
|
13636
|
+
allowedChunkIds !== null,
|
|
13256
13637
|
(requestedLimit) => Array.from(invertedIndex.search(query, requestedLimit)),
|
|
13257
13638
|
([chunkId]) => chunkId
|
|
13258
13639
|
);
|
|
@@ -13337,7 +13718,17 @@ var Indexer = class _Indexer {
|
|
|
13337
13718
|
);
|
|
13338
13719
|
const currentFileHashes = /* @__PURE__ */ new Map();
|
|
13339
13720
|
for (const file of files) {
|
|
13340
|
-
|
|
13721
|
+
let hash;
|
|
13722
|
+
try {
|
|
13723
|
+
hash = hashFile(file.path);
|
|
13724
|
+
} catch (error) {
|
|
13725
|
+
this.logger.warn("Skipped unreadable file during freshness check", {
|
|
13726
|
+
path: file.path,
|
|
13727
|
+
error: getErrorMessage4(error)
|
|
13728
|
+
});
|
|
13729
|
+
return { readable: false, current: false, reason: "unreadable" };
|
|
13730
|
+
}
|
|
13731
|
+
currentFileHashes.set(this.toStoredFilePath(file.path), hash);
|
|
13341
13732
|
}
|
|
13342
13733
|
const scopedRoots = this.config.scope === "global" ? this.getScopedRoots() : null;
|
|
13343
13734
|
const cachedFileHashes = scopedRoots ? new Map(Array.from(this.fileHashCache).filter(([filePath]) => this.isFileInCurrentScope(filePath, scopedRoots))) : this.fileHashCache;
|
|
@@ -13363,69 +13754,87 @@ var Indexer = class _Indexer {
|
|
|
13363
13754
|
async forceIndex(onProgress) {
|
|
13364
13755
|
return this.withIndexMutationLease("force-index", async (recoveredOwners) => {
|
|
13365
13756
|
await this.ensureInitializedUnlocked(recoveredOwners);
|
|
13366
|
-
|
|
13757
|
+
const recovery = this.beginClearRecoveryState();
|
|
13758
|
+
await this.clearIndexUnlocked(recovery.compatibilityDecision);
|
|
13759
|
+
this.finishClearRecoveryState();
|
|
13367
13760
|
return this.indexUnlocked(onProgress, [], true);
|
|
13368
13761
|
});
|
|
13369
13762
|
}
|
|
13370
13763
|
async clearIndex() {
|
|
13371
13764
|
await this.withIndexMutationLease("clear", async (recoveredOwners) => {
|
|
13372
13765
|
await this.ensureInitializedUnlocked(recoveredOwners);
|
|
13373
|
-
|
|
13766
|
+
const recovery = this.beginClearRecoveryState();
|
|
13767
|
+
await this.clearIndexUnlocked(recovery.compatibilityDecision);
|
|
13374
13768
|
});
|
|
13375
13769
|
}
|
|
13376
|
-
|
|
13770
|
+
clearGlobalIndexDataUnlocked(projectRoot = this.projectRoot) {
|
|
13377
13771
|
const { store, invertedIndex, database } = this.requireLoadedIndexState();
|
|
13378
|
-
|
|
13379
|
-
|
|
13380
|
-
|
|
13381
|
-
|
|
13382
|
-
|
|
13383
|
-
|
|
13384
|
-
|
|
13385
|
-
|
|
13386
|
-
|
|
13387
|
-
|
|
13388
|
-
|
|
13389
|
-
|
|
13390
|
-
|
|
13391
|
-
|
|
13392
|
-
|
|
13772
|
+
const clearedBranchKeys = database.getAllBranches();
|
|
13773
|
+
store.clear();
|
|
13774
|
+
store.save();
|
|
13775
|
+
invertedIndex.clear();
|
|
13776
|
+
this.saveInvertedIndex(invertedIndex);
|
|
13777
|
+
this.fileHashCache.clear();
|
|
13778
|
+
this.saveFileHashCache();
|
|
13779
|
+
database.clearAllIndexedData();
|
|
13780
|
+
this.deleteBranchCommitMetadata(database, clearedBranchKeys);
|
|
13781
|
+
this.clearFailedBatchState();
|
|
13782
|
+
database.deleteMetadata("index.version");
|
|
13783
|
+
database.deleteMetadata("index.pathStorageVersion");
|
|
13784
|
+
database.deleteMetadata("index.embeddingProvider");
|
|
13785
|
+
database.deleteMetadata("index.embeddingModel");
|
|
13786
|
+
database.deleteMetadata("index.embeddingDimensions");
|
|
13787
|
+
database.deleteMetadata("index.embeddingStrategyVersion");
|
|
13788
|
+
const projectIdentityHash = this.getProjectIdentityHash(projectRoot);
|
|
13789
|
+
database.deleteMetadata(this.getProjectEmbeddingStrategyMetadataKey(projectIdentityHash));
|
|
13790
|
+
database.deleteMetadata(this.getProjectForceReembedMetadataKey(projectIdentityHash));
|
|
13791
|
+
database.deleteMetadata(this.getLegacyMigrationMetadataKey(projectIdentityHash));
|
|
13792
|
+
database.deleteMetadata("index.createdAt");
|
|
13793
|
+
database.deleteMetadata("index.updatedAt");
|
|
13794
|
+
this.indexCompatibility = this.validateIndexCompatibility(this.configuredProviderInfo);
|
|
13795
|
+
}
|
|
13796
|
+
clearGlobalIndexUnlocked(projectRoot = this.projectRoot, roots = this.getScopedRoots(), recoveryDecision) {
|
|
13797
|
+
const { store, invertedIndex, database } = this.requireLoadedIndexState();
|
|
13798
|
+
store.load();
|
|
13799
|
+
invertedIndex.load();
|
|
13800
|
+
this.loadFileHashCache();
|
|
13801
|
+
const compatibility = this.checkCompatibility();
|
|
13802
|
+
const compatibilityDecision = recoveryDecision ?? (compatibility.compatible ? "compatible" : compatibility.code === "EMBEDDING_STRATEGY_MISMATCH" /* EMBEDDING_STRATEGY_MISMATCH */ ? "embedding-strategy-mismatch" : "incompatible");
|
|
13803
|
+
const allMetadata = store.getAllMetadata();
|
|
13804
|
+
const hasForeignData = allMetadata.some(({ metadata }) => !this.isFileInCurrentScope(metadata.filePath, roots)) || this.hasForeignScopedBranchData(projectRoot, roots) || this.hasForeignScopedFileHashData(roots) || this.hasForeignScopedFailedBatches(roots);
|
|
13805
|
+
if (compatibilityDecision !== "compatible" && hasForeignData) {
|
|
13806
|
+
if (compatibilityDecision === "embedding-strategy-mismatch") {
|
|
13807
|
+
this.clearSharedIndexProjectData(store, invertedIndex, database, roots, projectRoot);
|
|
13808
|
+
this.clearScopedFileHashCache(roots);
|
|
13809
|
+
this.clearScopedFailedBatches(roots);
|
|
13810
|
+
const projectIdentityHash = this.getProjectIdentityHash(projectRoot);
|
|
13811
|
+
database.setMetadata(this.getProjectForceReembedMetadataKey(projectIdentityHash), "true");
|
|
13812
|
+
database.deleteMetadata(this.getProjectEmbeddingStrategyMetadataKey(projectIdentityHash));
|
|
13813
|
+
database.deleteMetadata(this.getProjectMigrationFinalizedMetadataKey(projectIdentityHash));
|
|
13814
|
+
if (projectRoot === this.projectRoot) {
|
|
13393
13815
|
this.indexCompatibility = { compatible: true };
|
|
13394
|
-
return;
|
|
13395
13816
|
}
|
|
13396
|
-
throw new Error(
|
|
13397
|
-
`Global index compatibility reset is unsafe because the shared index contains files from other projects. The current global index cannot be force-rebuilt for ${this.projectRoot} without deleting other repositories' indexed data. Use scope="project" for isolated rebuilds, or manually delete the shared global index if you intend to rebuild all projects.`
|
|
13398
|
-
);
|
|
13399
|
-
}
|
|
13400
|
-
if (!hasForeignData) {
|
|
13401
|
-
const clearedBranchKeys2 = database.getAllBranches();
|
|
13402
|
-
store.clear();
|
|
13403
|
-
store.save();
|
|
13404
|
-
invertedIndex.clear();
|
|
13405
|
-
this.saveInvertedIndex(invertedIndex);
|
|
13406
|
-
this.fileHashCache.clear();
|
|
13407
|
-
this.saveFileHashCache();
|
|
13408
|
-
database.clearAllIndexedData();
|
|
13409
|
-
this.deleteBranchCommitMetadata(database, clearedBranchKeys2);
|
|
13410
|
-
this.clearFailedBatchState();
|
|
13411
|
-
database.deleteMetadata("index.version");
|
|
13412
|
-
database.deleteMetadata("index.pathStorageVersion");
|
|
13413
|
-
database.deleteMetadata("index.embeddingProvider");
|
|
13414
|
-
database.deleteMetadata("index.embeddingModel");
|
|
13415
|
-
database.deleteMetadata("index.embeddingDimensions");
|
|
13416
|
-
database.deleteMetadata("index.embeddingStrategyVersion");
|
|
13417
|
-
database.deleteMetadata(this.getProjectEmbeddingStrategyMetadataKey());
|
|
13418
|
-
database.deleteMetadata(this.getProjectForceReembedMetadataKey());
|
|
13419
|
-
database.deleteMetadata(this.getLegacyMigrationMetadataKey());
|
|
13420
|
-
database.deleteMetadata("index.createdAt");
|
|
13421
|
-
database.deleteMetadata("index.updatedAt");
|
|
13422
|
-
this.indexCompatibility = this.validateIndexCompatibility(this.configuredProviderInfo);
|
|
13423
13817
|
return;
|
|
13424
13818
|
}
|
|
13425
|
-
|
|
13426
|
-
|
|
13427
|
-
|
|
13819
|
+
throw new Error(
|
|
13820
|
+
`Global index compatibility reset is unsafe because the shared index contains files from other projects. The current global index cannot be force-rebuilt for ${projectRoot} without deleting other repositories' indexed data. Use scope="project" for isolated rebuilds, or manually delete the shared global index if you intend to rebuild all projects.`
|
|
13821
|
+
);
|
|
13822
|
+
}
|
|
13823
|
+
if (!hasForeignData) {
|
|
13824
|
+
this.clearGlobalIndexDataUnlocked(projectRoot);
|
|
13825
|
+
return;
|
|
13826
|
+
}
|
|
13827
|
+
this.clearSharedIndexProjectData(store, invertedIndex, database, roots, projectRoot);
|
|
13828
|
+
this.clearScopedFileHashCache(roots);
|
|
13829
|
+
this.clearScopedFailedBatches(roots);
|
|
13830
|
+
if (projectRoot === this.projectRoot) {
|
|
13428
13831
|
this.indexCompatibility = compatibility;
|
|
13832
|
+
}
|
|
13833
|
+
}
|
|
13834
|
+
async clearIndexUnlocked(recoveryDecision) {
|
|
13835
|
+
const { store, invertedIndex, database } = this.requireLoadedIndexState();
|
|
13836
|
+
if (this.config.scope === "global") {
|
|
13837
|
+
this.clearGlobalIndexUnlocked(this.projectRoot, this.getScopedRoots(), recoveryDecision);
|
|
13429
13838
|
return;
|
|
13430
13839
|
}
|
|
13431
13840
|
if (!this.isProjectOwnedIndexPath()) {
|
|
@@ -13591,6 +14000,7 @@ var Indexer = class _Indexer {
|
|
|
13591
14000
|
)) {
|
|
13592
14001
|
const chunks = retryBatch.map(({ chunk }) => chunk);
|
|
13593
14002
|
const attemptCounts = new Map(retryBatch.map(({ chunk, attemptCount }) => [chunk.id, attemptCount]));
|
|
14003
|
+
this.restoreMissingChunkRows(database, chunks);
|
|
13594
14004
|
const batchResult = await this.processPendingChunkBatch(chunks, {
|
|
13595
14005
|
store,
|
|
13596
14006
|
provider,
|
|
@@ -13605,6 +14015,7 @@ var Indexer = class _Indexer {
|
|
|
13605
14015
|
forceReembed: false,
|
|
13606
14016
|
reuseCachedEmbeddings: false,
|
|
13607
14017
|
incrementRepeatedFailures: false,
|
|
14018
|
+
forceSingleItemBatches: true,
|
|
13608
14019
|
onSucceeded: (succeededChunks) => {
|
|
13609
14020
|
database.addChunksToBranchBatch(
|
|
13610
14021
|
this.getBranchCatalogKey(),
|
|
@@ -13626,9 +14037,12 @@ var Indexer = class _Indexer {
|
|
|
13626
14037
|
this.saveInvertedIndex(invertedIndex);
|
|
13627
14038
|
}
|
|
13628
14039
|
if (roots && succeeded > 0 && remaining === 0 && this.hasProjectForceReembedPending()) {
|
|
13629
|
-
database.
|
|
13630
|
-
|
|
13631
|
-
|
|
14040
|
+
const migrationFinalized = database.getMetadata(this.getProjectMigrationFinalizedMetadataKey()) === "true";
|
|
14041
|
+
if (migrationFinalized) {
|
|
14042
|
+
database.deleteMetadata(this.getProjectForceReembedMetadataKey());
|
|
14043
|
+
this.saveIndexMetadata(configuredProviderInfo);
|
|
14044
|
+
this.indexCompatibility = { compatible: true };
|
|
14045
|
+
}
|
|
13632
14046
|
}
|
|
13633
14047
|
return { succeeded, failed, remaining };
|
|
13634
14048
|
}
|
|
@@ -13650,7 +14064,8 @@ var Indexer = class _Indexer {
|
|
|
13650
14064
|
latestById.set(chunkId, {
|
|
13651
14065
|
attemptCount: batch.attemptCount,
|
|
13652
14066
|
error: batch.error,
|
|
13653
|
-
lastAttempt: batch.lastAttempt
|
|
14067
|
+
lastAttempt: batch.lastAttempt,
|
|
14068
|
+
chunks: [rawChunk]
|
|
13654
14069
|
});
|
|
13655
14070
|
}
|
|
13656
14071
|
}
|
|
@@ -13717,6 +14132,7 @@ var Indexer = class _Indexer {
|
|
|
13717
14132
|
this.getBranchCatalogKeys().flatMap((branchKey) => database.getBranchChunkIds(branchKey))
|
|
13718
14133
|
);
|
|
13719
14134
|
}
|
|
14135
|
+
const temporalChunkIds = this.getTemporalChunkIds(database, options);
|
|
13720
14136
|
const { hasInitializedBranchCatalog, shouldPrefilterByBranch } = this.getBranchPrefilterState(database, branchChunkIds);
|
|
13721
14137
|
const prefilterMs = import_perf_hooks.performance.now() - prefilterStartTime;
|
|
13722
14138
|
const vectorStartTime = import_perf_hooks.performance.now();
|
|
@@ -13725,7 +14141,8 @@ var Indexer = class _Indexer {
|
|
|
13725
14141
|
embedding,
|
|
13726
14142
|
limit * 2,
|
|
13727
14143
|
branchChunkIds,
|
|
13728
|
-
shouldPrefilterByBranch
|
|
14144
|
+
shouldPrefilterByBranch,
|
|
14145
|
+
temporalChunkIds
|
|
13729
14146
|
);
|
|
13730
14147
|
const vectorMs = import_perf_hooks.performance.now() - vectorStartTime;
|
|
13731
14148
|
if (this.config.scope !== "global" && branchChunkIds && !hasInitializedBranchCatalog) {
|
|
@@ -13843,9 +14260,9 @@ var Indexer = class _Indexer {
|
|
|
13843
14260
|
this.requireReadableComponents(readIssues, "database");
|
|
13844
14261
|
let shortest = [];
|
|
13845
14262
|
for (const branchKey of this.getBranchCatalogKeys()) {
|
|
13846
|
-
const
|
|
13847
|
-
if (
|
|
13848
|
-
shortest =
|
|
14263
|
+
const path30 = database.findShortestPath(fromName, toName, branchKey, maxDepth);
|
|
14264
|
+
if (path30.length > 0 && (shortest.length === 0 || path30.length < shortest.length)) {
|
|
14265
|
+
shortest = path30;
|
|
13849
14266
|
}
|
|
13850
14267
|
}
|
|
13851
14268
|
return shortest.map((hop) => this.resolveFilePathRecord(hop));
|
|
@@ -13893,13 +14310,13 @@ var Indexer = class _Indexer {
|
|
|
13893
14310
|
}
|
|
13894
14311
|
}
|
|
13895
14312
|
if (!found) continue;
|
|
13896
|
-
const
|
|
14313
|
+
const path30 = [];
|
|
13897
14314
|
let currentSymbolId = toSymbolId;
|
|
13898
14315
|
while (true) {
|
|
13899
14316
|
const symbol = symbolsById.get(currentSymbolId);
|
|
13900
14317
|
if (!symbol) break;
|
|
13901
14318
|
const parent = parentBySymbolId.get(currentSymbolId);
|
|
13902
|
-
|
|
14319
|
+
path30.push({
|
|
13903
14320
|
symbolId: symbol.id,
|
|
13904
14321
|
symbolName: symbol.name,
|
|
13905
14322
|
filePath: symbol.filePath,
|
|
@@ -13909,9 +14326,9 @@ var Indexer = class _Indexer {
|
|
|
13909
14326
|
if (!parent) break;
|
|
13910
14327
|
currentSymbolId = parent.parentId;
|
|
13911
14328
|
}
|
|
13912
|
-
|
|
13913
|
-
if (
|
|
13914
|
-
shortest =
|
|
14329
|
+
path30.reverse();
|
|
14330
|
+
if (path30.length > 0 && (shortest.length === 0 || path30.length < shortest.length)) {
|
|
14331
|
+
shortest = path30;
|
|
13915
14332
|
}
|
|
13916
14333
|
}
|
|
13917
14334
|
return shortest.map((hop) => this.resolveFilePathRecord(hop));
|
|
@@ -14247,7 +14664,6 @@ var Indexer = class _Indexer {
|
|
|
14247
14664
|
this.store = null;
|
|
14248
14665
|
this.invertedIndex = null;
|
|
14249
14666
|
this.provider = null;
|
|
14250
|
-
this.reranker = null;
|
|
14251
14667
|
this.configuredProviderInfo = null;
|
|
14252
14668
|
this.indexCompatibility = null;
|
|
14253
14669
|
this.initializationMode = "none";
|
|
@@ -14475,9 +14891,11 @@ async function searchCodebase(projectRoot, host, query, options = {}) {
|
|
|
14475
14891
|
contextLines: options.contextLines,
|
|
14476
14892
|
metadataOnly: options.metadataOnly,
|
|
14477
14893
|
definitionIntent: options.definitionIntent,
|
|
14894
|
+
prioritizeSourcePaths: options.prioritizeSourcePaths,
|
|
14478
14895
|
blameAuthor: options.blameAuthor,
|
|
14479
14896
|
blameSha: options.blameSha,
|
|
14480
14897
|
blameSince: options.blameSince,
|
|
14898
|
+
blameUntil: options.blameUntil,
|
|
14481
14899
|
trace: options.trace
|
|
14482
14900
|
});
|
|
14483
14901
|
}
|
|
@@ -14523,7 +14941,9 @@ async function findSimilarCode(projectRoot, host, code, options = {}) {
|
|
|
14523
14941
|
fileType: options.fileType,
|
|
14524
14942
|
directory: options.directory,
|
|
14525
14943
|
chunkType: options.chunkType,
|
|
14526
|
-
excludeFile: options.excludeFile
|
|
14944
|
+
excludeFile: options.excludeFile,
|
|
14945
|
+
blameSince: options.blameSince,
|
|
14946
|
+
blameUntil: options.blameUntil
|
|
14527
14947
|
});
|
|
14528
14948
|
}
|
|
14529
14949
|
async function implementationLookup(projectRoot, host, query, options = {}) {
|
|
@@ -14572,12 +14992,12 @@ async function getCallGraphPath(projectRoot, host, from, to, maxDepth, fromFileP
|
|
|
14572
14992
|
if (fromResolution.status !== "resolved" || toResolution.status !== "resolved") {
|
|
14573
14993
|
return { from: fromResolution, to: toResolution, path: [] };
|
|
14574
14994
|
}
|
|
14575
|
-
const
|
|
14995
|
+
const path30 = await indexer.findCallPathBySymbolIds(
|
|
14576
14996
|
fromResolution.symbolId,
|
|
14577
14997
|
toResolution.symbolId,
|
|
14578
14998
|
maxDepth
|
|
14579
14999
|
);
|
|
14580
|
-
return { from: fromResolution, to: toResolution, path:
|
|
15000
|
+
return { from: fromResolution, to: toResolution, path: path30 };
|
|
14581
15001
|
}
|
|
14582
15002
|
async function runIndexCodebase(projectRoot, host, args, onProgress) {
|
|
14583
15003
|
const root = getProjectRoot(projectRoot, host);
|
|
@@ -14803,8 +15223,8 @@ function addKnowledgeBase(projectRoot, host, knowledgeBasePath) {
|
|
|
14803
15223
|
}
|
|
14804
15224
|
}
|
|
14805
15225
|
try {
|
|
14806
|
-
const
|
|
14807
|
-
if (!
|
|
15226
|
+
const stat5 = (0, import_fs13.statSync)(normalizedPath2);
|
|
15227
|
+
if (!stat5.isDirectory()) {
|
|
14808
15228
|
return `Error: Path is not a directory: ${normalizedPath2}`;
|
|
14809
15229
|
}
|
|
14810
15230
|
} catch (error) {
|
|
@@ -14852,8 +15272,8 @@ function listKnowledgeBases(projectRoot, host) {
|
|
|
14852
15272
|
`;
|
|
14853
15273
|
if (exists) {
|
|
14854
15274
|
try {
|
|
14855
|
-
const
|
|
14856
|
-
result += ` Type: ${
|
|
15275
|
+
const stat5 = (0, import_fs13.statSync)(resolvedPath);
|
|
15276
|
+
result += ` Type: ${stat5.isDirectory() ? "Directory" : "File"}
|
|
14857
15277
|
`;
|
|
14858
15278
|
} catch {
|
|
14859
15279
|
}
|
|
@@ -14986,7 +15406,7 @@ var ReaddirpStream = class extends import_node_stream.Readable {
|
|
|
14986
15406
|
this._directoryFilter = normalizeFilter(opts.directoryFilter);
|
|
14987
15407
|
const statMethod = opts.lstat ? import_promises.lstat : import_promises.stat;
|
|
14988
15408
|
if (wantBigintFsStats) {
|
|
14989
|
-
this._stat = (
|
|
15409
|
+
this._stat = (path30) => statMethod(path30, { bigint: true });
|
|
14990
15410
|
} else {
|
|
14991
15411
|
this._stat = statMethod;
|
|
14992
15412
|
}
|
|
@@ -15011,8 +15431,8 @@ var ReaddirpStream = class extends import_node_stream.Readable {
|
|
|
15011
15431
|
const par = this.parent;
|
|
15012
15432
|
const fil = par && par.files;
|
|
15013
15433
|
if (fil && fil.length > 0) {
|
|
15014
|
-
const { path:
|
|
15015
|
-
const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent,
|
|
15434
|
+
const { path: path30, depth } = par;
|
|
15435
|
+
const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path30));
|
|
15016
15436
|
const awaited = await Promise.all(slice);
|
|
15017
15437
|
for (const entry of awaited) {
|
|
15018
15438
|
if (!entry)
|
|
@@ -15052,20 +15472,20 @@ var ReaddirpStream = class extends import_node_stream.Readable {
|
|
|
15052
15472
|
this.reading = false;
|
|
15053
15473
|
}
|
|
15054
15474
|
}
|
|
15055
|
-
async _exploreDir(
|
|
15475
|
+
async _exploreDir(path30, depth) {
|
|
15056
15476
|
let files;
|
|
15057
15477
|
try {
|
|
15058
|
-
files = await (0, import_promises.readdir)(
|
|
15478
|
+
files = await (0, import_promises.readdir)(path30, this._rdOptions);
|
|
15059
15479
|
} catch (error) {
|
|
15060
15480
|
this._onError(error);
|
|
15061
15481
|
}
|
|
15062
|
-
return { files, depth, path:
|
|
15482
|
+
return { files, depth, path: path30 };
|
|
15063
15483
|
}
|
|
15064
|
-
async _formatEntry(dirent,
|
|
15484
|
+
async _formatEntry(dirent, path30) {
|
|
15065
15485
|
let entry;
|
|
15066
15486
|
const basename9 = this._isDirent ? dirent.name : dirent;
|
|
15067
15487
|
try {
|
|
15068
|
-
const fullPath = (0, import_node_path.resolve)((0, import_node_path.join)(
|
|
15488
|
+
const fullPath = (0, import_node_path.resolve)((0, import_node_path.join)(path30, basename9));
|
|
15069
15489
|
entry = { path: (0, import_node_path.relative)(this._root, fullPath), fullPath, basename: basename9 };
|
|
15070
15490
|
entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
|
|
15071
15491
|
} catch (err) {
|
|
@@ -15465,16 +15885,16 @@ var delFromSet = (main, prop, item) => {
|
|
|
15465
15885
|
};
|
|
15466
15886
|
var isEmptySet = (val) => val instanceof Set ? val.size === 0 : !val;
|
|
15467
15887
|
var FsWatchInstances = /* @__PURE__ */ new Map();
|
|
15468
|
-
function createFsWatchInstance(
|
|
15888
|
+
function createFsWatchInstance(path30, options, listener, errHandler, emitRaw) {
|
|
15469
15889
|
const handleEvent = (rawEvent, evPath) => {
|
|
15470
|
-
listener(
|
|
15471
|
-
emitRaw(rawEvent, evPath, { watchedPath:
|
|
15472
|
-
if (evPath &&
|
|
15473
|
-
fsWatchBroadcast(sp.resolve(
|
|
15890
|
+
listener(path30);
|
|
15891
|
+
emitRaw(rawEvent, evPath, { watchedPath: path30 });
|
|
15892
|
+
if (evPath && path30 !== evPath) {
|
|
15893
|
+
fsWatchBroadcast(sp.resolve(path30, evPath), KEY_LISTENERS, sp.join(path30, evPath));
|
|
15474
15894
|
}
|
|
15475
15895
|
};
|
|
15476
15896
|
try {
|
|
15477
|
-
return (0, import_node_fs.watch)(
|
|
15897
|
+
return (0, import_node_fs.watch)(path30, {
|
|
15478
15898
|
persistent: options.persistent
|
|
15479
15899
|
}, handleEvent);
|
|
15480
15900
|
} catch (error) {
|
|
@@ -15490,12 +15910,12 @@ var fsWatchBroadcast = (fullPath, listenerType, val1, val2, val3) => {
|
|
|
15490
15910
|
listener(val1, val2, val3);
|
|
15491
15911
|
});
|
|
15492
15912
|
};
|
|
15493
|
-
var setFsWatchListener = (
|
|
15913
|
+
var setFsWatchListener = (path30, fullPath, options, handlers) => {
|
|
15494
15914
|
const { listener, errHandler, rawEmitter } = handlers;
|
|
15495
15915
|
let cont = FsWatchInstances.get(fullPath);
|
|
15496
15916
|
let watcher;
|
|
15497
15917
|
if (!options.persistent) {
|
|
15498
|
-
watcher = createFsWatchInstance(
|
|
15918
|
+
watcher = createFsWatchInstance(path30, options, listener, errHandler, rawEmitter);
|
|
15499
15919
|
if (!watcher)
|
|
15500
15920
|
return;
|
|
15501
15921
|
return watcher.close.bind(watcher);
|
|
@@ -15506,7 +15926,7 @@ var setFsWatchListener = (path28, fullPath, options, handlers) => {
|
|
|
15506
15926
|
addAndConvert(cont, KEY_RAW, rawEmitter);
|
|
15507
15927
|
} else {
|
|
15508
15928
|
watcher = createFsWatchInstance(
|
|
15509
|
-
|
|
15929
|
+
path30,
|
|
15510
15930
|
options,
|
|
15511
15931
|
fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS),
|
|
15512
15932
|
errHandler,
|
|
@@ -15521,7 +15941,7 @@ var setFsWatchListener = (path28, fullPath, options, handlers) => {
|
|
|
15521
15941
|
cont.watcherUnusable = true;
|
|
15522
15942
|
if (isWindows && error.code === "EPERM") {
|
|
15523
15943
|
try {
|
|
15524
|
-
const fd = await (0, import_promises2.open)(
|
|
15944
|
+
const fd = await (0, import_promises2.open)(path30, "r");
|
|
15525
15945
|
await fd.close();
|
|
15526
15946
|
broadcastErr(error);
|
|
15527
15947
|
} catch (err) {
|
|
@@ -15552,7 +15972,7 @@ var setFsWatchListener = (path28, fullPath, options, handlers) => {
|
|
|
15552
15972
|
};
|
|
15553
15973
|
};
|
|
15554
15974
|
var FsWatchFileInstances = /* @__PURE__ */ new Map();
|
|
15555
|
-
var setFsWatchFileListener = (
|
|
15975
|
+
var setFsWatchFileListener = (path30, fullPath, options, handlers) => {
|
|
15556
15976
|
const { listener, rawEmitter } = handlers;
|
|
15557
15977
|
let cont = FsWatchFileInstances.get(fullPath);
|
|
15558
15978
|
const copts = cont && cont.options;
|
|
@@ -15574,7 +15994,7 @@ var setFsWatchFileListener = (path28, fullPath, options, handlers) => {
|
|
|
15574
15994
|
});
|
|
15575
15995
|
const currmtime = curr.mtimeMs;
|
|
15576
15996
|
if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {
|
|
15577
|
-
foreach(cont.listeners, (listener2) => listener2(
|
|
15997
|
+
foreach(cont.listeners, (listener2) => listener2(path30, curr));
|
|
15578
15998
|
}
|
|
15579
15999
|
})
|
|
15580
16000
|
};
|
|
@@ -15604,13 +16024,13 @@ var NodeFsHandler = class {
|
|
|
15604
16024
|
* @param listener on fs change
|
|
15605
16025
|
* @returns closer for the watcher instance
|
|
15606
16026
|
*/
|
|
15607
|
-
_watchWithNodeFs(
|
|
16027
|
+
_watchWithNodeFs(path30, listener) {
|
|
15608
16028
|
const opts = this.fsw.options;
|
|
15609
|
-
const directory = sp.dirname(
|
|
15610
|
-
const basename9 = sp.basename(
|
|
16029
|
+
const directory = sp.dirname(path30);
|
|
16030
|
+
const basename9 = sp.basename(path30);
|
|
15611
16031
|
const parent = this.fsw._getWatchedDir(directory);
|
|
15612
16032
|
parent.add(basename9);
|
|
15613
|
-
const absolutePath = sp.resolve(
|
|
16033
|
+
const absolutePath = sp.resolve(path30);
|
|
15614
16034
|
const options = {
|
|
15615
16035
|
persistent: opts.persistent
|
|
15616
16036
|
};
|
|
@@ -15620,12 +16040,12 @@ var NodeFsHandler = class {
|
|
|
15620
16040
|
if (opts.usePolling) {
|
|
15621
16041
|
const enableBin = opts.interval !== opts.binaryInterval;
|
|
15622
16042
|
options.interval = enableBin && isBinaryPath(basename9) ? opts.binaryInterval : opts.interval;
|
|
15623
|
-
closer = setFsWatchFileListener(
|
|
16043
|
+
closer = setFsWatchFileListener(path30, absolutePath, options, {
|
|
15624
16044
|
listener,
|
|
15625
16045
|
rawEmitter: this.fsw._emitRaw
|
|
15626
16046
|
});
|
|
15627
16047
|
} else {
|
|
15628
|
-
closer = setFsWatchListener(
|
|
16048
|
+
closer = setFsWatchListener(path30, absolutePath, options, {
|
|
15629
16049
|
listener,
|
|
15630
16050
|
errHandler: this._boundHandleError,
|
|
15631
16051
|
rawEmitter: this.fsw._emitRaw
|
|
@@ -15647,7 +16067,7 @@ var NodeFsHandler = class {
|
|
|
15647
16067
|
let prevStats = stats;
|
|
15648
16068
|
if (parent.has(basename9))
|
|
15649
16069
|
return;
|
|
15650
|
-
const listener = async (
|
|
16070
|
+
const listener = async (path30, newStats) => {
|
|
15651
16071
|
if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5))
|
|
15652
16072
|
return;
|
|
15653
16073
|
if (!newStats || newStats.mtimeMs === 0) {
|
|
@@ -15661,11 +16081,11 @@ var NodeFsHandler = class {
|
|
|
15661
16081
|
this.fsw._emit(EV.CHANGE, file, newStats2);
|
|
15662
16082
|
}
|
|
15663
16083
|
if ((isMacos || isLinux || isFreeBSD) && prevStats.ino !== newStats2.ino) {
|
|
15664
|
-
this.fsw._closeFile(
|
|
16084
|
+
this.fsw._closeFile(path30);
|
|
15665
16085
|
prevStats = newStats2;
|
|
15666
16086
|
const closer2 = this._watchWithNodeFs(file, listener);
|
|
15667
16087
|
if (closer2)
|
|
15668
|
-
this.fsw._addPathCloser(
|
|
16088
|
+
this.fsw._addPathCloser(path30, closer2);
|
|
15669
16089
|
} else {
|
|
15670
16090
|
prevStats = newStats2;
|
|
15671
16091
|
}
|
|
@@ -15697,7 +16117,7 @@ var NodeFsHandler = class {
|
|
|
15697
16117
|
* @param item basename of this item
|
|
15698
16118
|
* @returns true if no more processing is needed for this entry.
|
|
15699
16119
|
*/
|
|
15700
|
-
async _handleSymlink(entry, directory,
|
|
16120
|
+
async _handleSymlink(entry, directory, path30, item) {
|
|
15701
16121
|
if (this.fsw.closed) {
|
|
15702
16122
|
return;
|
|
15703
16123
|
}
|
|
@@ -15707,7 +16127,7 @@ var NodeFsHandler = class {
|
|
|
15707
16127
|
this.fsw._incrReadyCount();
|
|
15708
16128
|
let linkPath;
|
|
15709
16129
|
try {
|
|
15710
|
-
linkPath = await (0, import_promises2.realpath)(
|
|
16130
|
+
linkPath = await (0, import_promises2.realpath)(path30);
|
|
15711
16131
|
} catch (e) {
|
|
15712
16132
|
this.fsw._emitReady();
|
|
15713
16133
|
return true;
|
|
@@ -15717,12 +16137,12 @@ var NodeFsHandler = class {
|
|
|
15717
16137
|
if (dir.has(item)) {
|
|
15718
16138
|
if (this.fsw._symlinkPaths.get(full) !== linkPath) {
|
|
15719
16139
|
this.fsw._symlinkPaths.set(full, linkPath);
|
|
15720
|
-
this.fsw._emit(EV.CHANGE,
|
|
16140
|
+
this.fsw._emit(EV.CHANGE, path30, entry.stats);
|
|
15721
16141
|
}
|
|
15722
16142
|
} else {
|
|
15723
16143
|
dir.add(item);
|
|
15724
16144
|
this.fsw._symlinkPaths.set(full, linkPath);
|
|
15725
|
-
this.fsw._emit(EV.ADD,
|
|
16145
|
+
this.fsw._emit(EV.ADD, path30, entry.stats);
|
|
15726
16146
|
}
|
|
15727
16147
|
this.fsw._emitReady();
|
|
15728
16148
|
return true;
|
|
@@ -15752,9 +16172,9 @@ var NodeFsHandler = class {
|
|
|
15752
16172
|
return;
|
|
15753
16173
|
}
|
|
15754
16174
|
const item = entry.path;
|
|
15755
|
-
let
|
|
16175
|
+
let path30 = sp.join(directory, item);
|
|
15756
16176
|
current.add(item);
|
|
15757
|
-
if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory,
|
|
16177
|
+
if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path30, item)) {
|
|
15758
16178
|
return;
|
|
15759
16179
|
}
|
|
15760
16180
|
if (this.fsw.closed) {
|
|
@@ -15763,11 +16183,11 @@ var NodeFsHandler = class {
|
|
|
15763
16183
|
}
|
|
15764
16184
|
if (item === target || !target && !previous.has(item)) {
|
|
15765
16185
|
this.fsw._incrReadyCount();
|
|
15766
|
-
|
|
15767
|
-
this._addToNodeFs(
|
|
16186
|
+
path30 = sp.join(dir, sp.relative(dir, path30));
|
|
16187
|
+
this._addToNodeFs(path30, initialAdd, wh, depth + 1);
|
|
15768
16188
|
}
|
|
15769
16189
|
}).on(EV.ERROR, this._boundHandleError);
|
|
15770
|
-
return new Promise((
|
|
16190
|
+
return new Promise((resolve17, reject) => {
|
|
15771
16191
|
if (!stream)
|
|
15772
16192
|
return reject();
|
|
15773
16193
|
stream.once(STR_END, () => {
|
|
@@ -15776,7 +16196,7 @@ var NodeFsHandler = class {
|
|
|
15776
16196
|
return;
|
|
15777
16197
|
}
|
|
15778
16198
|
const wasThrottled = throttler ? throttler.clear() : false;
|
|
15779
|
-
|
|
16199
|
+
resolve17(void 0);
|
|
15780
16200
|
previous.getChildren().filter((item) => {
|
|
15781
16201
|
return item !== directory && !current.has(item);
|
|
15782
16202
|
}).forEach((item) => {
|
|
@@ -15833,13 +16253,13 @@ var NodeFsHandler = class {
|
|
|
15833
16253
|
* @param depth Child path actually targeted for watch
|
|
15834
16254
|
* @param target Child path actually targeted for watch
|
|
15835
16255
|
*/
|
|
15836
|
-
async _addToNodeFs(
|
|
16256
|
+
async _addToNodeFs(path30, initialAdd, priorWh, depth, target) {
|
|
15837
16257
|
const ready = this.fsw._emitReady;
|
|
15838
|
-
if (this.fsw._isIgnored(
|
|
16258
|
+
if (this.fsw._isIgnored(path30) || this.fsw.closed) {
|
|
15839
16259
|
ready();
|
|
15840
16260
|
return false;
|
|
15841
16261
|
}
|
|
15842
|
-
const wh = this.fsw._getWatchHelpers(
|
|
16262
|
+
const wh = this.fsw._getWatchHelpers(path30);
|
|
15843
16263
|
if (priorWh) {
|
|
15844
16264
|
wh.filterPath = (entry) => priorWh.filterPath(entry);
|
|
15845
16265
|
wh.filterDir = (entry) => priorWh.filterDir(entry);
|
|
@@ -15855,8 +16275,8 @@ var NodeFsHandler = class {
|
|
|
15855
16275
|
const follow = this.fsw.options.followSymlinks;
|
|
15856
16276
|
let closer;
|
|
15857
16277
|
if (stats.isDirectory()) {
|
|
15858
|
-
const absPath = sp.resolve(
|
|
15859
|
-
const targetPath = follow ? await (0, import_promises2.realpath)(
|
|
16278
|
+
const absPath = sp.resolve(path30);
|
|
16279
|
+
const targetPath = follow ? await (0, import_promises2.realpath)(path30) : path30;
|
|
15860
16280
|
if (this.fsw.closed)
|
|
15861
16281
|
return;
|
|
15862
16282
|
closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
|
|
@@ -15866,29 +16286,29 @@ var NodeFsHandler = class {
|
|
|
15866
16286
|
this.fsw._symlinkPaths.set(absPath, targetPath);
|
|
15867
16287
|
}
|
|
15868
16288
|
} else if (stats.isSymbolicLink()) {
|
|
15869
|
-
const targetPath = follow ? await (0, import_promises2.realpath)(
|
|
16289
|
+
const targetPath = follow ? await (0, import_promises2.realpath)(path30) : path30;
|
|
15870
16290
|
if (this.fsw.closed)
|
|
15871
16291
|
return;
|
|
15872
16292
|
const parent = sp.dirname(wh.watchPath);
|
|
15873
16293
|
this.fsw._getWatchedDir(parent).add(wh.watchPath);
|
|
15874
16294
|
this.fsw._emit(EV.ADD, wh.watchPath, stats);
|
|
15875
|
-
closer = await this._handleDir(parent, stats, initialAdd, depth,
|
|
16295
|
+
closer = await this._handleDir(parent, stats, initialAdd, depth, path30, wh, targetPath);
|
|
15876
16296
|
if (this.fsw.closed)
|
|
15877
16297
|
return;
|
|
15878
16298
|
if (targetPath !== void 0) {
|
|
15879
|
-
this.fsw._symlinkPaths.set(sp.resolve(
|
|
16299
|
+
this.fsw._symlinkPaths.set(sp.resolve(path30), targetPath);
|
|
15880
16300
|
}
|
|
15881
16301
|
} else {
|
|
15882
16302
|
closer = this._handleFile(wh.watchPath, stats, initialAdd);
|
|
15883
16303
|
}
|
|
15884
16304
|
ready();
|
|
15885
16305
|
if (closer)
|
|
15886
|
-
this.fsw._addPathCloser(
|
|
16306
|
+
this.fsw._addPathCloser(path30, closer);
|
|
15887
16307
|
return false;
|
|
15888
16308
|
} catch (error) {
|
|
15889
16309
|
if (this.fsw._handleError(error)) {
|
|
15890
16310
|
ready();
|
|
15891
|
-
return
|
|
16311
|
+
return path30;
|
|
15892
16312
|
}
|
|
15893
16313
|
}
|
|
15894
16314
|
}
|
|
@@ -15920,35 +16340,35 @@ function createPattern(matcher) {
|
|
|
15920
16340
|
if (matcher.path === string)
|
|
15921
16341
|
return true;
|
|
15922
16342
|
if (matcher.recursive) {
|
|
15923
|
-
const
|
|
15924
|
-
if (!
|
|
16343
|
+
const relative14 = sp2.relative(matcher.path, string);
|
|
16344
|
+
if (!relative14) {
|
|
15925
16345
|
return false;
|
|
15926
16346
|
}
|
|
15927
|
-
return !
|
|
16347
|
+
return !relative14.startsWith("..") && !sp2.isAbsolute(relative14);
|
|
15928
16348
|
}
|
|
15929
16349
|
return false;
|
|
15930
16350
|
};
|
|
15931
16351
|
}
|
|
15932
16352
|
return () => false;
|
|
15933
16353
|
}
|
|
15934
|
-
function normalizePath2(
|
|
15935
|
-
if (typeof
|
|
16354
|
+
function normalizePath2(path30) {
|
|
16355
|
+
if (typeof path30 !== "string")
|
|
15936
16356
|
throw new Error("string expected");
|
|
15937
|
-
|
|
15938
|
-
|
|
16357
|
+
path30 = sp2.normalize(path30);
|
|
16358
|
+
path30 = path30.replace(/\\/g, "/");
|
|
15939
16359
|
let prepend = false;
|
|
15940
|
-
if (
|
|
16360
|
+
if (path30.startsWith("//"))
|
|
15941
16361
|
prepend = true;
|
|
15942
|
-
|
|
16362
|
+
path30 = path30.replace(DOUBLE_SLASH_RE, "/");
|
|
15943
16363
|
if (prepend)
|
|
15944
|
-
|
|
15945
|
-
return
|
|
16364
|
+
path30 = "/" + path30;
|
|
16365
|
+
return path30;
|
|
15946
16366
|
}
|
|
15947
16367
|
function matchPatterns(patterns, testString, stats) {
|
|
15948
|
-
const
|
|
16368
|
+
const path30 = normalizePath2(testString);
|
|
15949
16369
|
for (let index = 0; index < patterns.length; index++) {
|
|
15950
16370
|
const pattern = patterns[index];
|
|
15951
|
-
if (pattern(
|
|
16371
|
+
if (pattern(path30, stats)) {
|
|
15952
16372
|
return true;
|
|
15953
16373
|
}
|
|
15954
16374
|
}
|
|
@@ -15986,19 +16406,19 @@ var toUnix = (string) => {
|
|
|
15986
16406
|
}
|
|
15987
16407
|
return str;
|
|
15988
16408
|
};
|
|
15989
|
-
var normalizePathToUnix = (
|
|
15990
|
-
var normalizeIgnored = (cwd = "") => (
|
|
15991
|
-
if (typeof
|
|
15992
|
-
return normalizePathToUnix(sp2.isAbsolute(
|
|
16409
|
+
var normalizePathToUnix = (path30) => toUnix(sp2.normalize(toUnix(path30)));
|
|
16410
|
+
var normalizeIgnored = (cwd = "") => (path30) => {
|
|
16411
|
+
if (typeof path30 === "string") {
|
|
16412
|
+
return normalizePathToUnix(sp2.isAbsolute(path30) ? path30 : sp2.join(cwd, path30));
|
|
15993
16413
|
} else {
|
|
15994
|
-
return
|
|
16414
|
+
return path30;
|
|
15995
16415
|
}
|
|
15996
16416
|
};
|
|
15997
|
-
var getAbsolutePath = (
|
|
15998
|
-
if (sp2.isAbsolute(
|
|
15999
|
-
return
|
|
16417
|
+
var getAbsolutePath = (path30, cwd) => {
|
|
16418
|
+
if (sp2.isAbsolute(path30)) {
|
|
16419
|
+
return path30;
|
|
16000
16420
|
}
|
|
16001
|
-
return sp2.join(cwd,
|
|
16421
|
+
return sp2.join(cwd, path30);
|
|
16002
16422
|
};
|
|
16003
16423
|
var EMPTY_SET = Object.freeze(/* @__PURE__ */ new Set());
|
|
16004
16424
|
var DirEntry = class {
|
|
@@ -16063,10 +16483,10 @@ var WatchHelper = class {
|
|
|
16063
16483
|
dirParts;
|
|
16064
16484
|
followSymlinks;
|
|
16065
16485
|
statMethod;
|
|
16066
|
-
constructor(
|
|
16486
|
+
constructor(path30, follow, fsw) {
|
|
16067
16487
|
this.fsw = fsw;
|
|
16068
|
-
const watchPath =
|
|
16069
|
-
this.path =
|
|
16488
|
+
const watchPath = path30;
|
|
16489
|
+
this.path = path30 = path30.replace(REPLACER_RE, "");
|
|
16070
16490
|
this.watchPath = watchPath;
|
|
16071
16491
|
this.fullWatchPath = sp2.resolve(watchPath);
|
|
16072
16492
|
this.dirParts = [];
|
|
@@ -16206,20 +16626,20 @@ var FSWatcher = class extends import_node_events.EventEmitter {
|
|
|
16206
16626
|
this._closePromise = void 0;
|
|
16207
16627
|
let paths = unifyPaths(paths_);
|
|
16208
16628
|
if (cwd) {
|
|
16209
|
-
paths = paths.map((
|
|
16210
|
-
const absPath = getAbsolutePath(
|
|
16629
|
+
paths = paths.map((path30) => {
|
|
16630
|
+
const absPath = getAbsolutePath(path30, cwd);
|
|
16211
16631
|
return absPath;
|
|
16212
16632
|
});
|
|
16213
16633
|
}
|
|
16214
|
-
paths.forEach((
|
|
16215
|
-
this._removeIgnoredPath(
|
|
16634
|
+
paths.forEach((path30) => {
|
|
16635
|
+
this._removeIgnoredPath(path30);
|
|
16216
16636
|
});
|
|
16217
16637
|
this._userIgnored = void 0;
|
|
16218
16638
|
if (!this._readyCount)
|
|
16219
16639
|
this._readyCount = 0;
|
|
16220
16640
|
this._readyCount += paths.length;
|
|
16221
|
-
Promise.all(paths.map(async (
|
|
16222
|
-
const res = await this._nodeFsHandler._addToNodeFs(
|
|
16641
|
+
Promise.all(paths.map(async (path30) => {
|
|
16642
|
+
const res = await this._nodeFsHandler._addToNodeFs(path30, !_internal, void 0, 0, _origAdd);
|
|
16223
16643
|
if (res)
|
|
16224
16644
|
this._emitReady();
|
|
16225
16645
|
return res;
|
|
@@ -16241,17 +16661,17 @@ var FSWatcher = class extends import_node_events.EventEmitter {
|
|
|
16241
16661
|
return this;
|
|
16242
16662
|
const paths = unifyPaths(paths_);
|
|
16243
16663
|
const { cwd } = this.options;
|
|
16244
|
-
paths.forEach((
|
|
16245
|
-
if (!sp2.isAbsolute(
|
|
16664
|
+
paths.forEach((path30) => {
|
|
16665
|
+
if (!sp2.isAbsolute(path30) && !this._closers.has(path30)) {
|
|
16246
16666
|
if (cwd)
|
|
16247
|
-
|
|
16248
|
-
|
|
16667
|
+
path30 = sp2.join(cwd, path30);
|
|
16668
|
+
path30 = sp2.resolve(path30);
|
|
16249
16669
|
}
|
|
16250
|
-
this._closePath(
|
|
16251
|
-
this._addIgnoredPath(
|
|
16252
|
-
if (this._watched.has(
|
|
16670
|
+
this._closePath(path30);
|
|
16671
|
+
this._addIgnoredPath(path30);
|
|
16672
|
+
if (this._watched.has(path30)) {
|
|
16253
16673
|
this._addIgnoredPath({
|
|
16254
|
-
path:
|
|
16674
|
+
path: path30,
|
|
16255
16675
|
recursive: true
|
|
16256
16676
|
});
|
|
16257
16677
|
}
|
|
@@ -16315,38 +16735,38 @@ var FSWatcher = class extends import_node_events.EventEmitter {
|
|
|
16315
16735
|
* @param stats arguments to be passed with event
|
|
16316
16736
|
* @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag
|
|
16317
16737
|
*/
|
|
16318
|
-
async _emit(event,
|
|
16738
|
+
async _emit(event, path30, stats) {
|
|
16319
16739
|
if (this.closed)
|
|
16320
16740
|
return;
|
|
16321
16741
|
const opts = this.options;
|
|
16322
16742
|
if (isWindows)
|
|
16323
|
-
|
|
16743
|
+
path30 = sp2.normalize(path30);
|
|
16324
16744
|
if (opts.cwd)
|
|
16325
|
-
|
|
16326
|
-
const args = [
|
|
16745
|
+
path30 = sp2.relative(opts.cwd, path30);
|
|
16746
|
+
const args = [path30];
|
|
16327
16747
|
if (stats != null)
|
|
16328
16748
|
args.push(stats);
|
|
16329
16749
|
const awf = opts.awaitWriteFinish;
|
|
16330
16750
|
let pw;
|
|
16331
|
-
if (awf && (pw = this._pendingWrites.get(
|
|
16751
|
+
if (awf && (pw = this._pendingWrites.get(path30))) {
|
|
16332
16752
|
pw.lastChange = /* @__PURE__ */ new Date();
|
|
16333
16753
|
return this;
|
|
16334
16754
|
}
|
|
16335
16755
|
if (opts.atomic) {
|
|
16336
16756
|
if (event === EVENTS.UNLINK) {
|
|
16337
|
-
this._pendingUnlinks.set(
|
|
16757
|
+
this._pendingUnlinks.set(path30, [event, ...args]);
|
|
16338
16758
|
setTimeout(() => {
|
|
16339
|
-
this._pendingUnlinks.forEach((entry,
|
|
16759
|
+
this._pendingUnlinks.forEach((entry, path31) => {
|
|
16340
16760
|
this.emit(...entry);
|
|
16341
16761
|
this.emit(EVENTS.ALL, ...entry);
|
|
16342
|
-
this._pendingUnlinks.delete(
|
|
16762
|
+
this._pendingUnlinks.delete(path31);
|
|
16343
16763
|
});
|
|
16344
16764
|
}, typeof opts.atomic === "number" ? opts.atomic : 100);
|
|
16345
16765
|
return this;
|
|
16346
16766
|
}
|
|
16347
|
-
if (event === EVENTS.ADD && this._pendingUnlinks.has(
|
|
16767
|
+
if (event === EVENTS.ADD && this._pendingUnlinks.has(path30)) {
|
|
16348
16768
|
event = EVENTS.CHANGE;
|
|
16349
|
-
this._pendingUnlinks.delete(
|
|
16769
|
+
this._pendingUnlinks.delete(path30);
|
|
16350
16770
|
}
|
|
16351
16771
|
}
|
|
16352
16772
|
if (awf && (event === EVENTS.ADD || event === EVENTS.CHANGE) && this._readyEmitted) {
|
|
@@ -16364,16 +16784,16 @@ var FSWatcher = class extends import_node_events.EventEmitter {
|
|
|
16364
16784
|
this.emitWithAll(event, args);
|
|
16365
16785
|
}
|
|
16366
16786
|
};
|
|
16367
|
-
this._awaitWriteFinish(
|
|
16787
|
+
this._awaitWriteFinish(path30, awf.stabilityThreshold, event, awfEmit);
|
|
16368
16788
|
return this;
|
|
16369
16789
|
}
|
|
16370
16790
|
if (event === EVENTS.CHANGE) {
|
|
16371
|
-
const isThrottled = !this._throttle(EVENTS.CHANGE,
|
|
16791
|
+
const isThrottled = !this._throttle(EVENTS.CHANGE, path30, 50);
|
|
16372
16792
|
if (isThrottled)
|
|
16373
16793
|
return this;
|
|
16374
16794
|
}
|
|
16375
16795
|
if (opts.alwaysStat && stats === void 0 && (event === EVENTS.ADD || event === EVENTS.ADD_DIR || event === EVENTS.CHANGE)) {
|
|
16376
|
-
const fullPath = opts.cwd ? sp2.join(opts.cwd,
|
|
16796
|
+
const fullPath = opts.cwd ? sp2.join(opts.cwd, path30) : path30;
|
|
16377
16797
|
let stats2;
|
|
16378
16798
|
try {
|
|
16379
16799
|
stats2 = await (0, import_promises3.stat)(fullPath);
|
|
@@ -16404,23 +16824,23 @@ var FSWatcher = class extends import_node_events.EventEmitter {
|
|
|
16404
16824
|
* @param timeout duration of time to suppress duplicate actions
|
|
16405
16825
|
* @returns tracking object or false if action should be suppressed
|
|
16406
16826
|
*/
|
|
16407
|
-
_throttle(actionType,
|
|
16827
|
+
_throttle(actionType, path30, timeout) {
|
|
16408
16828
|
if (!this._throttled.has(actionType)) {
|
|
16409
16829
|
this._throttled.set(actionType, /* @__PURE__ */ new Map());
|
|
16410
16830
|
}
|
|
16411
16831
|
const action = this._throttled.get(actionType);
|
|
16412
16832
|
if (!action)
|
|
16413
16833
|
throw new Error("invalid throttle");
|
|
16414
|
-
const actionPath = action.get(
|
|
16834
|
+
const actionPath = action.get(path30);
|
|
16415
16835
|
if (actionPath) {
|
|
16416
16836
|
actionPath.count++;
|
|
16417
16837
|
return false;
|
|
16418
16838
|
}
|
|
16419
16839
|
let timeoutObject;
|
|
16420
16840
|
const clear = () => {
|
|
16421
|
-
const item = action.get(
|
|
16841
|
+
const item = action.get(path30);
|
|
16422
16842
|
const count = item ? item.count : 0;
|
|
16423
|
-
action.delete(
|
|
16843
|
+
action.delete(path30);
|
|
16424
16844
|
clearTimeout(timeoutObject);
|
|
16425
16845
|
if (item)
|
|
16426
16846
|
clearTimeout(item.timeoutObject);
|
|
@@ -16428,7 +16848,7 @@ var FSWatcher = class extends import_node_events.EventEmitter {
|
|
|
16428
16848
|
};
|
|
16429
16849
|
timeoutObject = setTimeout(clear, timeout);
|
|
16430
16850
|
const thr = { timeoutObject, clear, count: 0 };
|
|
16431
|
-
action.set(
|
|
16851
|
+
action.set(path30, thr);
|
|
16432
16852
|
return thr;
|
|
16433
16853
|
}
|
|
16434
16854
|
_incrReadyCount() {
|
|
@@ -16442,44 +16862,44 @@ var FSWatcher = class extends import_node_events.EventEmitter {
|
|
|
16442
16862
|
* @param event
|
|
16443
16863
|
* @param awfEmit Callback to be called when ready for event to be emitted.
|
|
16444
16864
|
*/
|
|
16445
|
-
_awaitWriteFinish(
|
|
16865
|
+
_awaitWriteFinish(path30, threshold, event, awfEmit) {
|
|
16446
16866
|
const awf = this.options.awaitWriteFinish;
|
|
16447
16867
|
if (typeof awf !== "object")
|
|
16448
16868
|
return;
|
|
16449
16869
|
const pollInterval = awf.pollInterval;
|
|
16450
16870
|
let timeoutHandler;
|
|
16451
|
-
let fullPath =
|
|
16452
|
-
if (this.options.cwd && !sp2.isAbsolute(
|
|
16453
|
-
fullPath = sp2.join(this.options.cwd,
|
|
16871
|
+
let fullPath = path30;
|
|
16872
|
+
if (this.options.cwd && !sp2.isAbsolute(path30)) {
|
|
16873
|
+
fullPath = sp2.join(this.options.cwd, path30);
|
|
16454
16874
|
}
|
|
16455
16875
|
const now2 = /* @__PURE__ */ new Date();
|
|
16456
16876
|
const writes = this._pendingWrites;
|
|
16457
16877
|
function awaitWriteFinishFn(prevStat) {
|
|
16458
16878
|
(0, import_node_fs2.stat)(fullPath, (err, curStat) => {
|
|
16459
|
-
if (err || !writes.has(
|
|
16879
|
+
if (err || !writes.has(path30)) {
|
|
16460
16880
|
if (err && err.code !== "ENOENT")
|
|
16461
16881
|
awfEmit(err);
|
|
16462
16882
|
return;
|
|
16463
16883
|
}
|
|
16464
16884
|
const now3 = Number(/* @__PURE__ */ new Date());
|
|
16465
16885
|
if (prevStat && curStat.size !== prevStat.size) {
|
|
16466
|
-
writes.get(
|
|
16886
|
+
writes.get(path30).lastChange = now3;
|
|
16467
16887
|
}
|
|
16468
|
-
const pw = writes.get(
|
|
16888
|
+
const pw = writes.get(path30);
|
|
16469
16889
|
const df = now3 - pw.lastChange;
|
|
16470
16890
|
if (df >= threshold) {
|
|
16471
|
-
writes.delete(
|
|
16891
|
+
writes.delete(path30);
|
|
16472
16892
|
awfEmit(void 0, curStat);
|
|
16473
16893
|
} else {
|
|
16474
16894
|
timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat);
|
|
16475
16895
|
}
|
|
16476
16896
|
});
|
|
16477
16897
|
}
|
|
16478
|
-
if (!writes.has(
|
|
16479
|
-
writes.set(
|
|
16898
|
+
if (!writes.has(path30)) {
|
|
16899
|
+
writes.set(path30, {
|
|
16480
16900
|
lastChange: now2,
|
|
16481
16901
|
cancelWait: () => {
|
|
16482
|
-
writes.delete(
|
|
16902
|
+
writes.delete(path30);
|
|
16483
16903
|
clearTimeout(timeoutHandler);
|
|
16484
16904
|
return event;
|
|
16485
16905
|
}
|
|
@@ -16490,8 +16910,8 @@ var FSWatcher = class extends import_node_events.EventEmitter {
|
|
|
16490
16910
|
/**
|
|
16491
16911
|
* Determines whether user has asked to ignore this path.
|
|
16492
16912
|
*/
|
|
16493
|
-
_isIgnored(
|
|
16494
|
-
if (this.options.atomic && DOT_RE.test(
|
|
16913
|
+
_isIgnored(path30, stats) {
|
|
16914
|
+
if (this.options.atomic && DOT_RE.test(path30))
|
|
16495
16915
|
return true;
|
|
16496
16916
|
if (!this._userIgnored) {
|
|
16497
16917
|
const { cwd } = this.options;
|
|
@@ -16501,17 +16921,17 @@ var FSWatcher = class extends import_node_events.EventEmitter {
|
|
|
16501
16921
|
const list = [...ignoredPaths.map(normalizeIgnored(cwd)), ...ignored];
|
|
16502
16922
|
this._userIgnored = anymatch(list, void 0);
|
|
16503
16923
|
}
|
|
16504
|
-
return this._userIgnored(
|
|
16924
|
+
return this._userIgnored(path30, stats);
|
|
16505
16925
|
}
|
|
16506
|
-
_isntIgnored(
|
|
16507
|
-
return !this._isIgnored(
|
|
16926
|
+
_isntIgnored(path30, stat5) {
|
|
16927
|
+
return !this._isIgnored(path30, stat5);
|
|
16508
16928
|
}
|
|
16509
16929
|
/**
|
|
16510
16930
|
* Provides a set of common helpers and properties relating to symlink handling.
|
|
16511
16931
|
* @param path file or directory pattern being watched
|
|
16512
16932
|
*/
|
|
16513
|
-
_getWatchHelpers(
|
|
16514
|
-
return new WatchHelper(
|
|
16933
|
+
_getWatchHelpers(path30) {
|
|
16934
|
+
return new WatchHelper(path30, this.options.followSymlinks, this);
|
|
16515
16935
|
}
|
|
16516
16936
|
// Directory helpers
|
|
16517
16937
|
// -----------------
|
|
@@ -16543,63 +16963,63 @@ var FSWatcher = class extends import_node_events.EventEmitter {
|
|
|
16543
16963
|
* @param item base path of item/directory
|
|
16544
16964
|
*/
|
|
16545
16965
|
_remove(directory, item, isDirectory) {
|
|
16546
|
-
const
|
|
16547
|
-
const fullPath = sp2.resolve(
|
|
16548
|
-
isDirectory = isDirectory != null ? isDirectory : this._watched.has(
|
|
16549
|
-
if (!this._throttle("remove",
|
|
16966
|
+
const path30 = sp2.join(directory, item);
|
|
16967
|
+
const fullPath = sp2.resolve(path30);
|
|
16968
|
+
isDirectory = isDirectory != null ? isDirectory : this._watched.has(path30) || this._watched.has(fullPath);
|
|
16969
|
+
if (!this._throttle("remove", path30, 100))
|
|
16550
16970
|
return;
|
|
16551
16971
|
if (!isDirectory && this._watched.size === 1) {
|
|
16552
16972
|
this.add(directory, item, true);
|
|
16553
16973
|
}
|
|
16554
|
-
const wp = this._getWatchedDir(
|
|
16974
|
+
const wp = this._getWatchedDir(path30);
|
|
16555
16975
|
const nestedDirectoryChildren = wp.getChildren();
|
|
16556
|
-
nestedDirectoryChildren.forEach((nested) => this._remove(
|
|
16976
|
+
nestedDirectoryChildren.forEach((nested) => this._remove(path30, nested));
|
|
16557
16977
|
const parent = this._getWatchedDir(directory);
|
|
16558
16978
|
const wasTracked = parent.has(item);
|
|
16559
16979
|
parent.remove(item);
|
|
16560
16980
|
if (this._symlinkPaths.has(fullPath)) {
|
|
16561
16981
|
this._symlinkPaths.delete(fullPath);
|
|
16562
16982
|
}
|
|
16563
|
-
let relPath =
|
|
16983
|
+
let relPath = path30;
|
|
16564
16984
|
if (this.options.cwd)
|
|
16565
|
-
relPath = sp2.relative(this.options.cwd,
|
|
16985
|
+
relPath = sp2.relative(this.options.cwd, path30);
|
|
16566
16986
|
if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
|
|
16567
16987
|
const event = this._pendingWrites.get(relPath).cancelWait();
|
|
16568
16988
|
if (event === EVENTS.ADD)
|
|
16569
16989
|
return;
|
|
16570
16990
|
}
|
|
16571
|
-
this._watched.delete(
|
|
16991
|
+
this._watched.delete(path30);
|
|
16572
16992
|
this._watched.delete(fullPath);
|
|
16573
16993
|
const eventName = isDirectory ? EVENTS.UNLINK_DIR : EVENTS.UNLINK;
|
|
16574
|
-
if (wasTracked && !this._isIgnored(
|
|
16575
|
-
this._emit(eventName,
|
|
16576
|
-
this._closePath(
|
|
16994
|
+
if (wasTracked && !this._isIgnored(path30))
|
|
16995
|
+
this._emit(eventName, path30);
|
|
16996
|
+
this._closePath(path30);
|
|
16577
16997
|
}
|
|
16578
16998
|
/**
|
|
16579
16999
|
* Closes all watchers for a path
|
|
16580
17000
|
*/
|
|
16581
|
-
_closePath(
|
|
16582
|
-
this._closeFile(
|
|
16583
|
-
const dir = sp2.dirname(
|
|
16584
|
-
this._getWatchedDir(dir).remove(sp2.basename(
|
|
17001
|
+
_closePath(path30) {
|
|
17002
|
+
this._closeFile(path30);
|
|
17003
|
+
const dir = sp2.dirname(path30);
|
|
17004
|
+
this._getWatchedDir(dir).remove(sp2.basename(path30));
|
|
16585
17005
|
}
|
|
16586
17006
|
/**
|
|
16587
17007
|
* Closes only file-specific watchers
|
|
16588
17008
|
*/
|
|
16589
|
-
_closeFile(
|
|
16590
|
-
const closers = this._closers.get(
|
|
17009
|
+
_closeFile(path30) {
|
|
17010
|
+
const closers = this._closers.get(path30);
|
|
16591
17011
|
if (!closers)
|
|
16592
17012
|
return;
|
|
16593
17013
|
closers.forEach((closer) => closer());
|
|
16594
|
-
this._closers.delete(
|
|
17014
|
+
this._closers.delete(path30);
|
|
16595
17015
|
}
|
|
16596
|
-
_addPathCloser(
|
|
17016
|
+
_addPathCloser(path30, closer) {
|
|
16597
17017
|
if (!closer)
|
|
16598
17018
|
return;
|
|
16599
|
-
let list = this._closers.get(
|
|
17019
|
+
let list = this._closers.get(path30);
|
|
16600
17020
|
if (!list) {
|
|
16601
17021
|
list = [];
|
|
16602
|
-
this._closers.set(
|
|
17022
|
+
this._closers.set(path30, list);
|
|
16603
17023
|
}
|
|
16604
17024
|
list.push(closer);
|
|
16605
17025
|
}
|
|
@@ -16629,12 +17049,291 @@ function watch(paths, options = {}) {
|
|
|
16629
17049
|
var chokidar_default = { watch, FSWatcher };
|
|
16630
17050
|
|
|
16631
17051
|
// src/watcher/file-watcher.ts
|
|
17052
|
+
var path23 = __toESM(require("path"), 1);
|
|
17053
|
+
|
|
17054
|
+
// src/watcher/native-recursive-watcher.ts
|
|
17055
|
+
var import_node_fs3 = require("fs");
|
|
16632
17056
|
var path21 = __toESM(require("path"), 1);
|
|
17057
|
+
var NativeRecursiveWatcher = class {
|
|
17058
|
+
constructor(root, onChange, options = {}) {
|
|
17059
|
+
this.root = root;
|
|
17060
|
+
this.onChange = onChange;
|
|
17061
|
+
this.watchFactory = options.watchFactory ?? this.defaultWatchFactory;
|
|
17062
|
+
this.onError = options.onError;
|
|
17063
|
+
}
|
|
17064
|
+
root;
|
|
17065
|
+
onChange;
|
|
17066
|
+
watcher = null;
|
|
17067
|
+
listenerToken = 0;
|
|
17068
|
+
watchFactory;
|
|
17069
|
+
onError;
|
|
17070
|
+
start() {
|
|
17071
|
+
if (this.watcher) return;
|
|
17072
|
+
const token = ++this.listenerToken;
|
|
17073
|
+
const listener = (_eventType, filename) => {
|
|
17074
|
+
if (this.watcher === null || this.listenerToken !== token) return;
|
|
17075
|
+
const absolutePath = this.toAbsolutePath(filename);
|
|
17076
|
+
const nextResult = this.onChange(absolutePath);
|
|
17077
|
+
if (nextResult instanceof Promise) {
|
|
17078
|
+
void nextResult.catch((error) => {
|
|
17079
|
+
console.error("[codebase-index] Error handling native watcher event:", error);
|
|
17080
|
+
});
|
|
17081
|
+
}
|
|
17082
|
+
};
|
|
17083
|
+
const watcher = this.watchFactory(this.root, listener, {
|
|
17084
|
+
persistent: true,
|
|
17085
|
+
recursive: true
|
|
17086
|
+
});
|
|
17087
|
+
watcher.on?.("error", (error) => {
|
|
17088
|
+
if (this.watcher === watcher && this.listenerToken === token) {
|
|
17089
|
+
this.onError?.(error);
|
|
17090
|
+
}
|
|
17091
|
+
});
|
|
17092
|
+
this.watcher = watcher;
|
|
17093
|
+
}
|
|
17094
|
+
async stop() {
|
|
17095
|
+
const watcher = this.watcher;
|
|
17096
|
+
this.watcher = null;
|
|
17097
|
+
this.listenerToken += 1;
|
|
17098
|
+
if (!watcher) return;
|
|
17099
|
+
await watcher.close();
|
|
17100
|
+
}
|
|
17101
|
+
toAbsolutePath(filename) {
|
|
17102
|
+
if (filename == null) return null;
|
|
17103
|
+
const normalizedFilename = typeof filename === "string" ? filename : filename.toString();
|
|
17104
|
+
const absolutePath = path21.resolve(this.root, normalizedFilename);
|
|
17105
|
+
const relativePath = path21.relative(this.root, absolutePath);
|
|
17106
|
+
const outsideRoot = relativePath === ".." || relativePath.startsWith(`..${path21.sep}`) || path21.isAbsolute(relativePath);
|
|
17107
|
+
return outsideRoot ? null : absolutePath;
|
|
17108
|
+
}
|
|
17109
|
+
defaultWatchFactory = (root, listener, options) => (0, import_node_fs3.watch)(root, options, listener);
|
|
17110
|
+
};
|
|
17111
|
+
|
|
17112
|
+
// src/watcher/snapshot.ts
|
|
17113
|
+
var fsPromises4 = __toESM(require("fs/promises"), 1);
|
|
17114
|
+
var path22 = __toESM(require("path"), 1);
|
|
17115
|
+
async function buildFileSnapshotScan(projectRoot, config, configPaths = []) {
|
|
17116
|
+
const normalizedProjectRoot = path22.resolve(projectRoot);
|
|
17117
|
+
const ignoreFilter = createIgnoreFilter(normalizedProjectRoot);
|
|
17118
|
+
const includePatterns = [...config.include, ...config.additionalInclude ?? []];
|
|
17119
|
+
const maxDepth = config.indexing?.maxDepth ?? -1;
|
|
17120
|
+
const snapshot = /* @__PURE__ */ new Map();
|
|
17121
|
+
const unreadablePrefixes = /* @__PURE__ */ new Set();
|
|
17122
|
+
const includeFile = async (filePath) => {
|
|
17123
|
+
const normalizedPath2 = path22.resolve(filePath);
|
|
17124
|
+
if (!shouldIncludeFile(normalizedPath2, normalizedProjectRoot, includePatterns, config.exclude, ignoreFilter)) return;
|
|
17125
|
+
const stat5 = await readStatIfFile(normalizedPath2, unreadablePrefixes);
|
|
17126
|
+
if (stat5) snapshot.set(normalizedPath2, { size: stat5.size, mtimeMs: stat5.mtimeMs });
|
|
17127
|
+
};
|
|
17128
|
+
const walk = async (directoryPath, depth) => {
|
|
17129
|
+
let entries;
|
|
17130
|
+
try {
|
|
17131
|
+
entries = await fsPromises4.readdir(directoryPath, { withFileTypes: true });
|
|
17132
|
+
} catch (error) {
|
|
17133
|
+
if (isMissingFsError(error)) return;
|
|
17134
|
+
if (isPermissionFsError(error)) {
|
|
17135
|
+
unreadablePrefixes.add(path22.resolve(directoryPath));
|
|
17136
|
+
return;
|
|
17137
|
+
}
|
|
17138
|
+
throw error;
|
|
17139
|
+
}
|
|
17140
|
+
for (const entry of entries) {
|
|
17141
|
+
const fullPath = path22.join(directoryPath, entry.name);
|
|
17142
|
+
const relativePath = path22.relative(normalizedProjectRoot, fullPath);
|
|
17143
|
+
if (entry.isDirectory()) {
|
|
17144
|
+
if (hasFilteredPathSegment(relativePath, path22.sep) || isRestrictedDirectory(relativePath, path22.sep)) continue;
|
|
17145
|
+
if (ignoreFilter.ignores(relativePath)) continue;
|
|
17146
|
+
if (maxDepth === -1 || depth < maxDepth) await walk(fullPath, depth + 1);
|
|
17147
|
+
} else if (entry.isFile()) {
|
|
17148
|
+
await includeFile(fullPath);
|
|
17149
|
+
}
|
|
17150
|
+
}
|
|
17151
|
+
};
|
|
17152
|
+
await walk(normalizedProjectRoot, 0);
|
|
17153
|
+
await includeExplicitConfigPaths(snapshot, unreadablePrefixes, configPaths);
|
|
17154
|
+
return { entries: snapshot, unreadablePrefixes };
|
|
17155
|
+
}
|
|
17156
|
+
async function buildFileSnapshotForPathScan(projectRoot, config, configPaths, targetPath) {
|
|
17157
|
+
const normalizedProjectRoot = path22.resolve(projectRoot);
|
|
17158
|
+
const normalizedTargetPath = path22.resolve(targetPath);
|
|
17159
|
+
if (!isWithinPath(normalizedProjectRoot, normalizedTargetPath)) {
|
|
17160
|
+
return { entries: /* @__PURE__ */ new Map(), unreadablePrefixes: /* @__PURE__ */ new Set() };
|
|
17161
|
+
}
|
|
17162
|
+
const ignoreFilter = createIgnoreFilter(normalizedProjectRoot);
|
|
17163
|
+
const includePatterns = [...config.include, ...config.additionalInclude ?? []];
|
|
17164
|
+
const maxDepth = config.indexing?.maxDepth ?? -1;
|
|
17165
|
+
const explicitConfigPaths = new Set(configPaths.map((configPath) => path22.resolve(configPath)));
|
|
17166
|
+
const snapshot = /* @__PURE__ */ new Map();
|
|
17167
|
+
const unreadablePrefixes = /* @__PURE__ */ new Set();
|
|
17168
|
+
const includeFile = async (filePath) => {
|
|
17169
|
+
const normalizedPath2 = path22.resolve(filePath);
|
|
17170
|
+
if (!explicitConfigPaths.has(normalizedPath2) && !shouldIncludeFile(
|
|
17171
|
+
normalizedPath2,
|
|
17172
|
+
normalizedProjectRoot,
|
|
17173
|
+
includePatterns,
|
|
17174
|
+
config.exclude,
|
|
17175
|
+
ignoreFilter
|
|
17176
|
+
)) return;
|
|
17177
|
+
const stat5 = await readStatIfFile(normalizedPath2, unreadablePrefixes);
|
|
17178
|
+
if (stat5) snapshot.set(normalizedPath2, { size: stat5.size, mtimeMs: stat5.mtimeMs });
|
|
17179
|
+
};
|
|
17180
|
+
const walk = async (directoryPath, depth) => {
|
|
17181
|
+
let entries;
|
|
17182
|
+
try {
|
|
17183
|
+
entries = await fsPromises4.readdir(directoryPath, { withFileTypes: true });
|
|
17184
|
+
} catch (error) {
|
|
17185
|
+
if (isMissingFsError(error)) return;
|
|
17186
|
+
if (isPermissionFsError(error)) {
|
|
17187
|
+
unreadablePrefixes.add(path22.resolve(directoryPath));
|
|
17188
|
+
return;
|
|
17189
|
+
}
|
|
17190
|
+
throw error;
|
|
17191
|
+
}
|
|
17192
|
+
for (const entry of entries) {
|
|
17193
|
+
const fullPath = path22.join(directoryPath, entry.name);
|
|
17194
|
+
const relativePath = path22.relative(normalizedProjectRoot, fullPath);
|
|
17195
|
+
if (entry.isDirectory()) {
|
|
17196
|
+
if (hasFilteredPathSegment(relativePath, path22.sep) || isRestrictedDirectory(relativePath, path22.sep)) continue;
|
|
17197
|
+
if (ignoreFilter.ignores(relativePath)) continue;
|
|
17198
|
+
if (maxDepth === -1 || depth < maxDepth) await walk(fullPath, depth + 1);
|
|
17199
|
+
} else if (entry.isFile()) {
|
|
17200
|
+
await includeFile(fullPath);
|
|
17201
|
+
}
|
|
17202
|
+
}
|
|
17203
|
+
};
|
|
17204
|
+
const targetStat = await readStatIfFile(normalizedTargetPath, unreadablePrefixes);
|
|
17205
|
+
if (targetStat) await includeFile(normalizedTargetPath);
|
|
17206
|
+
else await walk(normalizedTargetPath, 0);
|
|
17207
|
+
await includeExplicitConfigPathsInPath(snapshot, unreadablePrefixes, configPaths, normalizedTargetPath);
|
|
17208
|
+
return { entries: snapshot, unreadablePrefixes };
|
|
17209
|
+
}
|
|
17210
|
+
function completeFileSnapshot(previous, scan) {
|
|
17211
|
+
const completed = new Map(scan.entries);
|
|
17212
|
+
for (const unreadablePrefix of scan.unreadablePrefixes) {
|
|
17213
|
+
for (const [entryPath, entry] of previous) {
|
|
17214
|
+
if (isWithinPath(unreadablePrefix, entryPath) && !completed.has(entryPath)) completed.set(entryPath, entry);
|
|
17215
|
+
}
|
|
17216
|
+
}
|
|
17217
|
+
return completed;
|
|
17218
|
+
}
|
|
17219
|
+
async function includeExplicitConfigPaths(snapshot, unreadablePrefixes, configPaths) {
|
|
17220
|
+
for (const configPath of [...new Set(configPaths.map((value) => path22.resolve(value)))]) {
|
|
17221
|
+
if (snapshot.has(configPath)) continue;
|
|
17222
|
+
const stat5 = await readStatIfFile(configPath, unreadablePrefixes);
|
|
17223
|
+
if (stat5) snapshot.set(configPath, { size: stat5.size, mtimeMs: stat5.mtimeMs });
|
|
17224
|
+
}
|
|
17225
|
+
}
|
|
17226
|
+
async function includeExplicitConfigPathsInPath(snapshot, unreadablePrefixes, configPaths, targetPath) {
|
|
17227
|
+
await includeExplicitConfigPaths(
|
|
17228
|
+
snapshot,
|
|
17229
|
+
unreadablePrefixes,
|
|
17230
|
+
configPaths.filter((configPath) => isWithinPath(targetPath, path22.resolve(configPath)))
|
|
17231
|
+
);
|
|
17232
|
+
}
|
|
17233
|
+
function isWithinPath(parentPath, childPath) {
|
|
17234
|
+
const relativePath = path22.relative(parentPath, childPath);
|
|
17235
|
+
return relativePath === "" || !relativePath.startsWith(`..${path22.sep}`) && relativePath !== ".." && !path22.isAbsolute(relativePath);
|
|
17236
|
+
}
|
|
17237
|
+
async function readStatIfFile(filePath, unreadablePrefixes) {
|
|
17238
|
+
try {
|
|
17239
|
+
const stat5 = await fsPromises4.stat(filePath);
|
|
17240
|
+
return stat5.isFile() ? stat5 : null;
|
|
17241
|
+
} catch (error) {
|
|
17242
|
+
if (isMissingFsError(error)) return null;
|
|
17243
|
+
if (isPermissionFsError(error)) {
|
|
17244
|
+
unreadablePrefixes.add(path22.resolve(filePath));
|
|
17245
|
+
return null;
|
|
17246
|
+
}
|
|
17247
|
+
throw error;
|
|
17248
|
+
}
|
|
17249
|
+
}
|
|
17250
|
+
function isMissingFsError(error) {
|
|
17251
|
+
return error instanceof Error && ["ENOENT", "ENOTDIR"].includes(error.code ?? "");
|
|
17252
|
+
}
|
|
17253
|
+
function isPermissionFsError(error) {
|
|
17254
|
+
return error instanceof Error && ["EACCES", "EPERM"].includes(error.code ?? "");
|
|
17255
|
+
}
|
|
17256
|
+
var diffTypeOrder = { add: 0, change: 1, unlink: 2 };
|
|
17257
|
+
function diffFileSnapshots(previous, current, forcedChanges = /* @__PURE__ */ new Set()) {
|
|
17258
|
+
const changes = [];
|
|
17259
|
+
for (const [filePath, previousEntry] of previous) {
|
|
17260
|
+
const currentEntry = current.get(filePath);
|
|
17261
|
+
if (!currentEntry) changes.push({ type: "unlink", path: filePath });
|
|
17262
|
+
else if (forcedChanges.has(filePath) || currentEntry.size !== previousEntry.size || currentEntry.mtimeMs !== previousEntry.mtimeMs) {
|
|
17263
|
+
changes.push({ type: "change", path: filePath });
|
|
17264
|
+
}
|
|
17265
|
+
}
|
|
17266
|
+
for (const [filePath] of current) {
|
|
17267
|
+
if (!previous.has(filePath)) changes.push({ type: "add", path: filePath });
|
|
17268
|
+
}
|
|
17269
|
+
return changes.sort((left, right) => left.path.localeCompare(right.path) || diffTypeOrder[left.type] - diffTypeOrder[right.type]);
|
|
17270
|
+
}
|
|
17271
|
+
|
|
17272
|
+
// src/watcher/snapshot-reconciler.ts
|
|
17273
|
+
var FileSnapshotReconciler = class {
|
|
17274
|
+
constructor(projectRoot, config, configPaths) {
|
|
17275
|
+
this.projectRoot = projectRoot;
|
|
17276
|
+
this.config = config;
|
|
17277
|
+
this.configPaths = configPaths;
|
|
17278
|
+
}
|
|
17279
|
+
projectRoot;
|
|
17280
|
+
config;
|
|
17281
|
+
configPaths;
|
|
17282
|
+
snapshot = null;
|
|
17283
|
+
reconciliationTail = Promise.resolve();
|
|
17284
|
+
async initialize() {
|
|
17285
|
+
this.snapshot = (await buildFileSnapshotScan(this.projectRoot, this.config, this.configPaths)).entries;
|
|
17286
|
+
}
|
|
17287
|
+
async reconcile(invalidations = []) {
|
|
17288
|
+
if (this.snapshot === null) {
|
|
17289
|
+
throw new Error("FileSnapshotReconciler is not initialized. Call initialize() before reconcile().");
|
|
17290
|
+
}
|
|
17291
|
+
const reconciliation = this.reconciliationTail.then(async () => {
|
|
17292
|
+
const previousSnapshot = this.snapshot;
|
|
17293
|
+
if (previousSnapshot === null) {
|
|
17294
|
+
throw new Error("FileSnapshotReconciler is not initialized. Call initialize() before reconcile().");
|
|
17295
|
+
}
|
|
17296
|
+
const normalizedInvalidations = invalidations.map((invalidation) => typeof invalidation === "string" || invalidation === null ? { path: invalidation, forceChange: false } : { path: invalidation.path, forceChange: invalidation.forceChange === true });
|
|
17297
|
+
const scopedPaths = normalizedInvalidations.map((invalidation) => invalidation.path).filter((filePath) => filePath !== null);
|
|
17298
|
+
const scan = scopedPaths.length === 0 || scopedPaths.length !== normalizedInvalidations.length ? await buildFileSnapshotScan(this.projectRoot, this.config, this.configPaths) : await this.reconcilePaths(previousSnapshot, scopedPaths);
|
|
17299
|
+
const nextSnapshot = completeFileSnapshot(previousSnapshot, scan);
|
|
17300
|
+
const forcedChanges = new Set(normalizedInvalidations.filter((invalidation) => invalidation.path !== null && invalidation.forceChange).map((invalidation) => invalidation.path));
|
|
17301
|
+
const changes = diffFileSnapshots(previousSnapshot, nextSnapshot, forcedChanges);
|
|
17302
|
+
this.snapshot = nextSnapshot;
|
|
17303
|
+
return changes;
|
|
17304
|
+
});
|
|
17305
|
+
this.reconciliationTail = reconciliation.then(() => void 0, () => void 0);
|
|
17306
|
+
return reconciliation;
|
|
17307
|
+
}
|
|
17308
|
+
async reconcilePaths(previousSnapshot, invalidatedPaths) {
|
|
17309
|
+
const scopes = this.getScopes(invalidatedPaths);
|
|
17310
|
+
const entries = new Map(previousSnapshot);
|
|
17311
|
+
const unreadablePrefixes = /* @__PURE__ */ new Set();
|
|
17312
|
+
for (const scope of scopes) {
|
|
17313
|
+
for (const previousPath of entries.keys()) {
|
|
17314
|
+
if (isWithinPath(scope, previousPath)) entries.delete(previousPath);
|
|
17315
|
+
}
|
|
17316
|
+
const scopedScan = await buildFileSnapshotForPathScan(this.projectRoot, this.config, this.configPaths, scope);
|
|
17317
|
+
for (const [filePath, entry] of scopedScan.entries) entries.set(filePath, entry);
|
|
17318
|
+
for (const unreadablePrefix of scopedScan.unreadablePrefixes) unreadablePrefixes.add(unreadablePrefix);
|
|
17319
|
+
}
|
|
17320
|
+
return { entries, unreadablePrefixes };
|
|
17321
|
+
}
|
|
17322
|
+
getScopes(invalidatedPaths) {
|
|
17323
|
+
const uniquePaths = [...new Set(invalidatedPaths)].sort((left, right) => left.length - right.length);
|
|
17324
|
+
return uniquePaths.filter((candidate, index) => !uniquePaths.slice(0, index).some(
|
|
17325
|
+
(ancestor) => isWithinPath(ancestor, candidate)
|
|
17326
|
+
));
|
|
17327
|
+
}
|
|
17328
|
+
};
|
|
17329
|
+
|
|
17330
|
+
// src/watcher/file-watcher.ts
|
|
16633
17331
|
var FileWatcher = class {
|
|
16634
17332
|
watcher = null;
|
|
16635
17333
|
projectRoot;
|
|
16636
17334
|
config;
|
|
16637
17335
|
configPath;
|
|
17336
|
+
backend;
|
|
16638
17337
|
projectConfigPaths;
|
|
16639
17338
|
pendingChanges = /* @__PURE__ */ new Map();
|
|
16640
17339
|
debounceTimer = null;
|
|
@@ -16644,44 +17343,74 @@ var FileWatcher = class {
|
|
|
16644
17343
|
resolveReady = null;
|
|
16645
17344
|
pollingFallbackAttempted = false;
|
|
16646
17345
|
pendingClose = null;
|
|
17346
|
+
startupReadySignals = 1;
|
|
17347
|
+
nativeWatcher = null;
|
|
17348
|
+
nativeReconciler = null;
|
|
17349
|
+
nativeSetupGeneration = 0;
|
|
17350
|
+
nativeStarting = false;
|
|
17351
|
+
nativeInitializing = false;
|
|
17352
|
+
nativeReconcileTimer = null;
|
|
17353
|
+
nativeInvalidatedPaths = /* @__PURE__ */ new Map();
|
|
17354
|
+
configPathStates = /* @__PURE__ */ new Map();
|
|
16647
17355
|
constructor(projectRoot, config, host, options = {}) {
|
|
16648
17356
|
this.projectRoot = projectRoot;
|
|
16649
17357
|
this.config = config;
|
|
17358
|
+
this.backend = options.backend ?? "auto";
|
|
16650
17359
|
this.configPath = options.configPath;
|
|
16651
17360
|
this.projectConfigPaths = options.configPath ? [options.configPath] : getProjectConfigCandidatePaths(projectRoot, host);
|
|
16652
17361
|
}
|
|
16653
17362
|
start(handler) {
|
|
16654
|
-
if (this.watcher) {
|
|
17363
|
+
if (this.watcher || this.nativeWatcher || this.nativeStarting) {
|
|
16655
17364
|
return;
|
|
16656
17365
|
}
|
|
16657
17366
|
this.onChanges = handler;
|
|
16658
17367
|
this.pollingFallbackAttempted = false;
|
|
16659
17368
|
this.resetReady();
|
|
17369
|
+
if (this.shouldUseNativeWatcher()) {
|
|
17370
|
+
if (this.hasExternalConfigWatchTarget()) {
|
|
17371
|
+
this.setStartupReadySignals(2);
|
|
17372
|
+
this.startExternalConfigWatcher();
|
|
17373
|
+
}
|
|
17374
|
+
this.nativeStarting = true;
|
|
17375
|
+
void this.createNativeWatcher();
|
|
17376
|
+
return;
|
|
17377
|
+
}
|
|
16660
17378
|
this.createWatcher();
|
|
16661
17379
|
}
|
|
16662
17380
|
resetReady() {
|
|
16663
|
-
this.readyPromise = new Promise((
|
|
16664
|
-
this.resolveReady =
|
|
17381
|
+
this.readyPromise = new Promise((resolve17) => {
|
|
17382
|
+
this.resolveReady = resolve17;
|
|
16665
17383
|
});
|
|
17384
|
+
this.startupReadySignals = 1;
|
|
16666
17385
|
}
|
|
16667
|
-
|
|
16668
|
-
|
|
16669
|
-
|
|
16670
|
-
|
|
16671
|
-
|
|
16672
|
-
|
|
16673
|
-
|
|
16674
|
-
|
|
16675
|
-
|
|
16676
|
-
|
|
16677
|
-
|
|
16678
|
-
|
|
16679
|
-
watchTargets = [this.projectRoot, ...uniqueExternalConfigTargets];
|
|
16680
|
-
}
|
|
17386
|
+
setStartupReadySignals(expectedSignals) {
|
|
17387
|
+
if (!this.readyPromise) {
|
|
17388
|
+
return;
|
|
17389
|
+
}
|
|
17390
|
+
this.startupReadySignals = Math.max(0, expectedSignals);
|
|
17391
|
+
}
|
|
17392
|
+
reportStartupReadySignal() {
|
|
17393
|
+
if (!this.readyPromise || !this.resolveReady) {
|
|
17394
|
+
return;
|
|
17395
|
+
}
|
|
17396
|
+
if (this.startupReadySignals <= 0) {
|
|
17397
|
+
return;
|
|
16681
17398
|
}
|
|
17399
|
+
this.startupReadySignals -= 1;
|
|
17400
|
+
if (this.startupReadySignals !== 0) {
|
|
17401
|
+
return;
|
|
17402
|
+
}
|
|
17403
|
+
this.resolveReady();
|
|
17404
|
+
this.resolveReady = null;
|
|
17405
|
+
}
|
|
17406
|
+
createWatcher(watchTargets, usePolling = false, reportsStartupReady = true) {
|
|
17407
|
+
let reportedStartupReady = false;
|
|
17408
|
+
this.configPathStates = this.getConfigPathStates();
|
|
17409
|
+
const ignoreFilter = createIgnoreFilter(this.projectRoot);
|
|
17410
|
+
const resolvedWatchTargets = watchTargets ?? this.getFullChokidarWatchTargets();
|
|
16682
17411
|
const watcherOptions = {
|
|
16683
17412
|
ignored: (filePath) => {
|
|
16684
|
-
const relativePath =
|
|
17413
|
+
const relativePath = path23.relative(this.projectRoot, filePath);
|
|
16685
17414
|
if (!relativePath) return false;
|
|
16686
17415
|
if (this.isProjectConfigPathOrAncestor(relativePath)) {
|
|
16687
17416
|
return false;
|
|
@@ -16689,10 +17418,10 @@ var FileWatcher = class {
|
|
|
16689
17418
|
if (this.isOutsideProjectPath(relativePath)) {
|
|
16690
17419
|
return true;
|
|
16691
17420
|
}
|
|
16692
|
-
if (hasFilteredPathSegment(relativePath,
|
|
17421
|
+
if (hasFilteredPathSegment(relativePath, path23.sep)) {
|
|
16693
17422
|
return true;
|
|
16694
17423
|
}
|
|
16695
|
-
if (isRestrictedDirectory(relativePath,
|
|
17424
|
+
if (isRestrictedDirectory(relativePath, path23.sep)) {
|
|
16696
17425
|
return true;
|
|
16697
17426
|
}
|
|
16698
17427
|
if (ignoreFilter.ignores(relativePath)) {
|
|
@@ -16725,10 +17454,13 @@ var FileWatcher = class {
|
|
|
16725
17454
|
watcher = new FSWatcher(watcherOptions);
|
|
16726
17455
|
}
|
|
16727
17456
|
this.watcher = watcher;
|
|
16728
|
-
watcher.
|
|
17457
|
+
watcher.on("ready", () => {
|
|
16729
17458
|
if (this.watcher !== watcher) return;
|
|
16730
|
-
this.
|
|
16731
|
-
|
|
17459
|
+
this.reconcileConfigPathStates();
|
|
17460
|
+
if (reportsStartupReady) {
|
|
17461
|
+
this.reportStartupReadySignal();
|
|
17462
|
+
reportedStartupReady = true;
|
|
17463
|
+
}
|
|
16732
17464
|
});
|
|
16733
17465
|
watcher.on("error", (error) => {
|
|
16734
17466
|
const err = error instanceof Error ? error : null;
|
|
@@ -16742,10 +17474,13 @@ var FileWatcher = class {
|
|
|
16742
17474
|
console.error("[codebase-index] Failed to close exhausted file watcher:", closeError);
|
|
16743
17475
|
});
|
|
16744
17476
|
if (this.onChanges) {
|
|
17477
|
+
const replacementReportsStartupReady = reportsStartupReady || reportedStartupReady;
|
|
16745
17478
|
if (!this.resolveReady) {
|
|
16746
17479
|
this.resetReady();
|
|
17480
|
+
} else if (reportedStartupReady) {
|
|
17481
|
+
this.startupReadySignals += 1;
|
|
16747
17482
|
}
|
|
16748
|
-
this.createWatcher(true);
|
|
17483
|
+
this.createWatcher(resolvedWatchTargets, true, replacementReportsStartupReady);
|
|
16749
17484
|
} else {
|
|
16750
17485
|
this.watcher = null;
|
|
16751
17486
|
}
|
|
@@ -16756,13 +17491,166 @@ var FileWatcher = class {
|
|
|
16756
17491
|
watcher.on("add", (filePath) => this.handleChange(watcher, "add", filePath));
|
|
16757
17492
|
watcher.on("change", (filePath) => this.handleChange(watcher, "change", filePath));
|
|
16758
17493
|
watcher.on("unlink", (filePath) => this.handleChange(watcher, "unlink", filePath));
|
|
16759
|
-
watcher.add(
|
|
17494
|
+
watcher.add(resolvedWatchTargets);
|
|
17495
|
+
}
|
|
17496
|
+
shouldUseNativeWatcher() {
|
|
17497
|
+
if (this.backend === "chokidar") {
|
|
17498
|
+
return false;
|
|
17499
|
+
}
|
|
17500
|
+
return true;
|
|
17501
|
+
}
|
|
17502
|
+
getFullChokidarWatchTargets() {
|
|
17503
|
+
if (this.configPath) {
|
|
17504
|
+
return [this.projectRoot, this.configPath];
|
|
17505
|
+
}
|
|
17506
|
+
const externalConfigTargets = this.getExternalConfigWatchTargets();
|
|
17507
|
+
if (externalConfigTargets.length === 0) {
|
|
17508
|
+
return this.projectRoot;
|
|
17509
|
+
}
|
|
17510
|
+
return [this.projectRoot, ...externalConfigTargets];
|
|
17511
|
+
}
|
|
17512
|
+
getExternalConfigWatchTargets() {
|
|
17513
|
+
return [...new Set(
|
|
17514
|
+
this.projectConfigPaths.filter((projectConfigPath) => {
|
|
17515
|
+
const relativeConfigPath = path23.relative(this.projectRoot, projectConfigPath);
|
|
17516
|
+
return this.isOutsideProjectPath(relativeConfigPath);
|
|
17517
|
+
}).map((projectConfigPath) => {
|
|
17518
|
+
if ((0, import_fs14.existsSync)(projectConfigPath)) {
|
|
17519
|
+
return projectConfigPath;
|
|
17520
|
+
}
|
|
17521
|
+
return this.getNearestExistingDirectory(path23.dirname(projectConfigPath));
|
|
17522
|
+
})
|
|
17523
|
+
)];
|
|
17524
|
+
}
|
|
17525
|
+
hasExternalConfigWatchTarget() {
|
|
17526
|
+
return this.getExternalConfigWatchTargets().length > 0;
|
|
17527
|
+
}
|
|
17528
|
+
startExternalConfigWatcher(usePolling = false) {
|
|
17529
|
+
const externalTargets = this.getExternalConfigWatchTargets();
|
|
17530
|
+
if (externalTargets.length === 0) {
|
|
17531
|
+
return;
|
|
17532
|
+
}
|
|
17533
|
+
this.createWatcher(externalTargets, usePolling);
|
|
17534
|
+
}
|
|
17535
|
+
async createNativeWatcher() {
|
|
17536
|
+
const generation = ++this.nativeSetupGeneration;
|
|
17537
|
+
const reconciler = new FileSnapshotReconciler(this.projectRoot, this.config, this.projectConfigPaths);
|
|
17538
|
+
const watcher = new NativeRecursiveWatcher(
|
|
17539
|
+
this.projectRoot,
|
|
17540
|
+
(filePath) => this.scheduleNativeReconciliation(generation, filePath),
|
|
17541
|
+
{ onError: (error) => void this.fallbackFromNativeWatcher(generation, error) }
|
|
17542
|
+
);
|
|
17543
|
+
this.nativeReconciler = reconciler;
|
|
17544
|
+
this.nativeWatcher = watcher;
|
|
17545
|
+
this.nativeInitializing = true;
|
|
17546
|
+
try {
|
|
17547
|
+
watcher.start();
|
|
17548
|
+
if (!this.isCurrentNativeSetup(generation)) {
|
|
17549
|
+
await watcher.stop();
|
|
17550
|
+
return;
|
|
17551
|
+
}
|
|
17552
|
+
await reconciler.initialize();
|
|
17553
|
+
if (!this.isCurrentNativeSetup(generation) || this.nativeWatcher !== watcher) {
|
|
17554
|
+
await watcher.stop();
|
|
17555
|
+
return;
|
|
17556
|
+
}
|
|
17557
|
+
this.nativeStarting = false;
|
|
17558
|
+
this.nativeInitializing = false;
|
|
17559
|
+
await this.reconcileNativeWatcherWithPendingInvalidations(generation);
|
|
17560
|
+
this.reportStartupReadySignal();
|
|
17561
|
+
} catch (error) {
|
|
17562
|
+
if (!this.isCurrentNativeSetup(generation)) return;
|
|
17563
|
+
this.nativeInitializing = false;
|
|
17564
|
+
if (this.nativeWatcher) {
|
|
17565
|
+
await this.fallbackFromNativeWatcher(generation, error);
|
|
17566
|
+
return;
|
|
17567
|
+
}
|
|
17568
|
+
this.nativeStarting = false;
|
|
17569
|
+
const externalWatcher = this.watcher;
|
|
17570
|
+
this.watcher = null;
|
|
17571
|
+
this.nativeReconciler = null;
|
|
17572
|
+
await externalWatcher?.close();
|
|
17573
|
+
console.warn("[codebase-index] Native recursive watcher unavailable; using Chokidar fallback.", error);
|
|
17574
|
+
this.setStartupReadySignals(1);
|
|
17575
|
+
this.createWatcher();
|
|
17576
|
+
}
|
|
17577
|
+
}
|
|
17578
|
+
isCurrentNativeSetup(generation) {
|
|
17579
|
+
return this.nativeSetupGeneration === generation && this.onChanges !== null;
|
|
17580
|
+
}
|
|
17581
|
+
scheduleNativeReconciliation(generation, filePath) {
|
|
17582
|
+
if (!this.isCurrentNativeSetup(generation)) return;
|
|
17583
|
+
const requiresFullReconciliation = filePath === path23.join(this.projectRoot, ".gitignore");
|
|
17584
|
+
const invalidatedPath = requiresFullReconciliation ? null : filePath;
|
|
17585
|
+
this.nativeInvalidatedPaths.set(invalidatedPath, invalidatedPath !== null);
|
|
17586
|
+
if (this.nativeReconcileTimer) {
|
|
17587
|
+
clearTimeout(this.nativeReconcileTimer);
|
|
17588
|
+
}
|
|
17589
|
+
this.nativeReconcileTimer = setTimeout(() => {
|
|
17590
|
+
this.nativeReconcileTimer = null;
|
|
17591
|
+
void this.reconcileNativeWatcherFromQueue(generation);
|
|
17592
|
+
}, 100);
|
|
17593
|
+
}
|
|
17594
|
+
reconcileNativeWatcherFromQueue(generation) {
|
|
17595
|
+
if (!this.isCurrentNativeSetup(generation) || this.nativeInitializing) return;
|
|
17596
|
+
const invalidatedPaths = this.popNativeInvalidations();
|
|
17597
|
+
if (invalidatedPaths.length === 0) return;
|
|
17598
|
+
void this.reconcileNativeWatcher(generation, invalidatedPaths);
|
|
17599
|
+
}
|
|
17600
|
+
async reconcileNativeWatcher(generation, invalidatedPaths) {
|
|
17601
|
+
if (!this.isCurrentNativeSetup(generation) || !this.nativeReconciler) return;
|
|
17602
|
+
try {
|
|
17603
|
+
const reconciler = this.nativeReconciler;
|
|
17604
|
+
const changes = await reconciler.reconcile(invalidatedPaths);
|
|
17605
|
+
if (!this.isCurrentNativeSetup(generation) || this.nativeReconciler !== reconciler) return;
|
|
17606
|
+
this.recordChanges(changes);
|
|
17607
|
+
} catch (error) {
|
|
17608
|
+
await this.fallbackFromNativeWatcher(generation, error);
|
|
17609
|
+
}
|
|
17610
|
+
}
|
|
17611
|
+
async reconcileNativeWatcherWithPendingInvalidations(generation) {
|
|
17612
|
+
const invalidatedPaths = this.popNativeInvalidations();
|
|
17613
|
+
if (invalidatedPaths.length === 0) return;
|
|
17614
|
+
await this.reconcileNativeWatcher(generation, invalidatedPaths);
|
|
17615
|
+
}
|
|
17616
|
+
popNativeInvalidations() {
|
|
17617
|
+
if (this.nativeInvalidatedPaths.size === 0) return [];
|
|
17618
|
+
const invalidations = [...this.nativeInvalidatedPaths].map(([invalidatedPath, forceChange]) => ({
|
|
17619
|
+
path: invalidatedPath,
|
|
17620
|
+
forceChange
|
|
17621
|
+
}));
|
|
17622
|
+
this.nativeInvalidatedPaths.clear();
|
|
17623
|
+
return invalidations;
|
|
17624
|
+
}
|
|
17625
|
+
async fallbackFromNativeWatcher(generation, error) {
|
|
17626
|
+
if (!this.isCurrentNativeSetup(generation)) return;
|
|
17627
|
+
const watcher = this.nativeWatcher;
|
|
17628
|
+
const externalWatcher = this.watcher;
|
|
17629
|
+
this.nativeWatcher = null;
|
|
17630
|
+
this.watcher = null;
|
|
17631
|
+
this.nativeReconciler = null;
|
|
17632
|
+
this.nativeStarting = false;
|
|
17633
|
+
this.nativeInitializing = false;
|
|
17634
|
+
this.nativeSetupGeneration += 1;
|
|
17635
|
+
if (this.nativeReconcileTimer) {
|
|
17636
|
+
clearTimeout(this.nativeReconcileTimer);
|
|
17637
|
+
this.nativeReconcileTimer = null;
|
|
17638
|
+
}
|
|
17639
|
+
this.nativeInvalidatedPaths.clear();
|
|
17640
|
+
this.setStartupReadySignals(1);
|
|
17641
|
+
console.warn("[codebase-index] Native recursive watcher failed; using Chokidar fallback.", error);
|
|
17642
|
+
await watcher?.stop();
|
|
17643
|
+
await externalWatcher?.close();
|
|
17644
|
+
if (this.onChanges) {
|
|
17645
|
+
this.createWatcher();
|
|
17646
|
+
}
|
|
16760
17647
|
}
|
|
16761
17648
|
handleChange(watcher, type, filePath) {
|
|
16762
17649
|
if (this.watcher !== watcher) {
|
|
16763
17650
|
return;
|
|
16764
17651
|
}
|
|
16765
17652
|
if (this.isProjectConfigPath(filePath)) {
|
|
17653
|
+
this.updateConfigPathState(filePath);
|
|
16766
17654
|
this.pendingChanges.set(filePath, type);
|
|
16767
17655
|
this.scheduleFlush();
|
|
16768
17656
|
return;
|
|
@@ -16777,27 +17665,33 @@ var FileWatcher = class {
|
|
|
16777
17665
|
)) {
|
|
16778
17666
|
return;
|
|
16779
17667
|
}
|
|
16780
|
-
this.
|
|
17668
|
+
this.recordChanges([{ path: filePath, type }]);
|
|
17669
|
+
}
|
|
17670
|
+
recordChanges(changes) {
|
|
17671
|
+
if (changes.length === 0) return;
|
|
17672
|
+
for (const change of changes) {
|
|
17673
|
+
this.pendingChanges.set(change.path, change.type);
|
|
17674
|
+
}
|
|
16781
17675
|
this.scheduleFlush();
|
|
16782
17676
|
}
|
|
16783
17677
|
isProjectConfigPath(filePath) {
|
|
16784
|
-
const relativePath =
|
|
16785
|
-
const normalizedRelativePath =
|
|
17678
|
+
const relativePath = path23.relative(this.projectRoot, filePath);
|
|
17679
|
+
const normalizedRelativePath = path23.normalize(relativePath);
|
|
16786
17680
|
return this.getProjectConfigRelativePaths().some((configPath) => configPath === normalizedRelativePath);
|
|
16787
17681
|
}
|
|
16788
17682
|
isProjectConfigPathOrAncestor(relativePath) {
|
|
16789
|
-
const normalizedRelativePath =
|
|
17683
|
+
const normalizedRelativePath = path23.normalize(relativePath);
|
|
16790
17684
|
return this.getProjectConfigRelativePaths().some(
|
|
16791
|
-
(configPath) => configPath === normalizedRelativePath || configPath.startsWith(`${normalizedRelativePath}${
|
|
17685
|
+
(configPath) => configPath === normalizedRelativePath || configPath.startsWith(`${normalizedRelativePath}${path23.sep}`)
|
|
16792
17686
|
);
|
|
16793
17687
|
}
|
|
16794
17688
|
isOutsideProjectPath(relativePath) {
|
|
16795
|
-
return relativePath === ".." || relativePath.startsWith(`..${
|
|
17689
|
+
return relativePath === ".." || relativePath.startsWith(`..${path23.sep}`) || path23.isAbsolute(relativePath);
|
|
16796
17690
|
}
|
|
16797
17691
|
getNearestExistingDirectory(directoryPath) {
|
|
16798
17692
|
let candidate = directoryPath;
|
|
16799
17693
|
while (!(0, import_fs14.existsSync)(candidate)) {
|
|
16800
|
-
const parent =
|
|
17694
|
+
const parent = path23.dirname(candidate);
|
|
16801
17695
|
if (parent === candidate) break;
|
|
16802
17696
|
candidate = parent;
|
|
16803
17697
|
}
|
|
@@ -16805,9 +17699,51 @@ var FileWatcher = class {
|
|
|
16805
17699
|
}
|
|
16806
17700
|
getProjectConfigRelativePaths() {
|
|
16807
17701
|
return this.projectConfigPaths.map(
|
|
16808
|
-
(configPath) =>
|
|
17702
|
+
(configPath) => path23.normalize(path23.relative(this.projectRoot, configPath))
|
|
16809
17703
|
);
|
|
16810
17704
|
}
|
|
17705
|
+
getConfigPathStates() {
|
|
17706
|
+
const states = /* @__PURE__ */ new Map();
|
|
17707
|
+
for (const configPath of this.projectConfigPaths) {
|
|
17708
|
+
const state = this.getConfigPathState(configPath);
|
|
17709
|
+
if (state) states.set(configPath, state);
|
|
17710
|
+
}
|
|
17711
|
+
return states;
|
|
17712
|
+
}
|
|
17713
|
+
getConfigPathState(configPath) {
|
|
17714
|
+
try {
|
|
17715
|
+
const stats = (0, import_fs14.statSync)(configPath);
|
|
17716
|
+
return stats.isFile() ? { mtimeMs: stats.mtimeMs, size: stats.size } : void 0;
|
|
17717
|
+
} catch (error) {
|
|
17718
|
+
void error;
|
|
17719
|
+
return void 0;
|
|
17720
|
+
}
|
|
17721
|
+
}
|
|
17722
|
+
updateConfigPathState(configPath) {
|
|
17723
|
+
const state = this.getConfigPathState(configPath);
|
|
17724
|
+
if (state) {
|
|
17725
|
+
this.configPathStates.set(configPath, state);
|
|
17726
|
+
} else {
|
|
17727
|
+
this.configPathStates.delete(configPath);
|
|
17728
|
+
}
|
|
17729
|
+
}
|
|
17730
|
+
reconcileConfigPathStates() {
|
|
17731
|
+
const nextStates = this.getConfigPathStates();
|
|
17732
|
+
const changes = [];
|
|
17733
|
+
for (const configPath of this.projectConfigPaths) {
|
|
17734
|
+
const previous = this.configPathStates.get(configPath);
|
|
17735
|
+
const next = nextStates.get(configPath);
|
|
17736
|
+
if (!previous && next) {
|
|
17737
|
+
changes.push({ path: configPath, type: "add" });
|
|
17738
|
+
} else if (previous && !next) {
|
|
17739
|
+
changes.push({ path: configPath, type: "unlink" });
|
|
17740
|
+
} else if (previous && next && (previous.size !== next.size || previous.mtimeMs !== next.mtimeMs)) {
|
|
17741
|
+
changes.push({ path: configPath, type: "change" });
|
|
17742
|
+
}
|
|
17743
|
+
}
|
|
17744
|
+
this.configPathStates = nextStates;
|
|
17745
|
+
this.recordChanges(changes);
|
|
17746
|
+
}
|
|
16811
17747
|
scheduleFlush() {
|
|
16812
17748
|
if (this.debounceTimer) {
|
|
16813
17749
|
clearTimeout(this.debounceTimer);
|
|
@@ -16821,7 +17757,7 @@ var FileWatcher = class {
|
|
|
16821
17757
|
return;
|
|
16822
17758
|
}
|
|
16823
17759
|
const changes = Array.from(this.pendingChanges.entries()).map(
|
|
16824
|
-
([
|
|
17760
|
+
([path30, type]) => ({ path: path30, type })
|
|
16825
17761
|
);
|
|
16826
17762
|
this.pendingChanges.clear();
|
|
16827
17763
|
try {
|
|
@@ -16835,20 +17771,31 @@ var FileWatcher = class {
|
|
|
16835
17771
|
clearTimeout(this.debounceTimer);
|
|
16836
17772
|
this.debounceTimer = null;
|
|
16837
17773
|
}
|
|
17774
|
+
if (this.nativeReconcileTimer) {
|
|
17775
|
+
clearTimeout(this.nativeReconcileTimer);
|
|
17776
|
+
this.nativeReconcileTimer = null;
|
|
17777
|
+
}
|
|
17778
|
+
this.nativeInvalidatedPaths.clear();
|
|
16838
17779
|
const watcher = this.watcher;
|
|
17780
|
+
const nativeWatcher = this.nativeWatcher;
|
|
16839
17781
|
const pendingClose = this.pendingClose;
|
|
16840
17782
|
const resolveReady = this.resolveReady;
|
|
16841
17783
|
this.watcher = null;
|
|
17784
|
+
this.nativeWatcher = null;
|
|
17785
|
+
this.nativeReconciler = null;
|
|
17786
|
+
this.nativeStarting = false;
|
|
17787
|
+
this.nativeInitializing = false;
|
|
17788
|
+
this.nativeSetupGeneration += 1;
|
|
16842
17789
|
this.pendingClose = null;
|
|
16843
17790
|
this.resolveReady = null;
|
|
16844
17791
|
this.readyPromise = null;
|
|
16845
17792
|
this.pendingChanges.clear();
|
|
16846
17793
|
this.onChanges = null;
|
|
16847
|
-
await Promise.all([watcher?.close(), pendingClose]);
|
|
17794
|
+
await Promise.all([watcher?.close(), nativeWatcher?.stop(), pendingClose]);
|
|
16848
17795
|
resolveReady?.();
|
|
16849
17796
|
}
|
|
16850
17797
|
isRunning() {
|
|
16851
|
-
return this.watcher !== null;
|
|
17798
|
+
return this.watcher !== null || this.nativeWatcher !== null || this.nativeStarting;
|
|
16852
17799
|
}
|
|
16853
17800
|
async waitUntilReady() {
|
|
16854
17801
|
await (this.readyPromise ?? Promise.resolve());
|
|
@@ -16856,7 +17803,7 @@ var FileWatcher = class {
|
|
|
16856
17803
|
};
|
|
16857
17804
|
|
|
16858
17805
|
// src/watcher/git-head-watcher.ts
|
|
16859
|
-
var
|
|
17806
|
+
var path24 = __toESM(require("path"), 1);
|
|
16860
17807
|
var GitHeadWatcher = class {
|
|
16861
17808
|
watcher = null;
|
|
16862
17809
|
projectRoot;
|
|
@@ -16878,13 +17825,13 @@ var GitHeadWatcher = class {
|
|
|
16878
17825
|
this.readyPromise = Promise.resolve();
|
|
16879
17826
|
return;
|
|
16880
17827
|
}
|
|
16881
|
-
this.readyPromise = new Promise((
|
|
16882
|
-
this.resolveReady =
|
|
17828
|
+
this.readyPromise = new Promise((resolve17) => {
|
|
17829
|
+
this.resolveReady = resolve17;
|
|
16883
17830
|
});
|
|
16884
17831
|
this.onBranchChange = handler;
|
|
16885
17832
|
this.currentBranch = getCurrentBranch(this.projectRoot);
|
|
16886
17833
|
const headPath = getHeadPath(this.projectRoot);
|
|
16887
|
-
const refsPath =
|
|
17834
|
+
const refsPath = path24.join(this.projectRoot, ".git", "refs", "heads");
|
|
16888
17835
|
this.watcher = chokidar_default.watch([headPath, refsPath], {
|
|
16889
17836
|
persistent: true,
|
|
16890
17837
|
ignoreInitial: true,
|
|
@@ -17535,13 +18482,19 @@ async function resolveSearchContext(input, operations) {
|
|
|
17535
18482
|
(trace) => operations.lookup(symbol, MAX_CONTEXT_RESULT_LIMIT, scope, input.diagnostic ? trace : void 0)
|
|
17536
18483
|
);
|
|
17537
18484
|
};
|
|
17538
|
-
const tryConceptualSearch = async (searchQuery, scope, relaxedFieldsForAttempt) => {
|
|
18485
|
+
const tryConceptualSearch = async (searchQuery, scope, relaxedFieldsForAttempt, prioritizeSourcePaths) => {
|
|
17539
18486
|
return recordAttempt(
|
|
17540
18487
|
"conceptual",
|
|
17541
18488
|
searchQuery,
|
|
17542
18489
|
scope,
|
|
17543
18490
|
relaxedFieldsForAttempt,
|
|
17544
|
-
(trace) => operations.search(
|
|
18491
|
+
(trace) => operations.search(
|
|
18492
|
+
searchQuery,
|
|
18493
|
+
MAX_CONTEXT_RESULT_LIMIT,
|
|
18494
|
+
scope,
|
|
18495
|
+
input.diagnostic ? trace : void 0,
|
|
18496
|
+
{ prioritizeSourcePaths }
|
|
18497
|
+
)
|
|
17545
18498
|
);
|
|
17546
18499
|
};
|
|
17547
18500
|
const findSuccessfulAttemptState = (route) => {
|
|
@@ -17669,10 +18622,12 @@ Explicit symbol lookup only; conceptual search was not attempted.`
|
|
|
17669
18622
|
}
|
|
17670
18623
|
}
|
|
17671
18624
|
for (const attempt of conceptualAttemptPlan) {
|
|
18625
|
+
const attemptIntent = analyzeQueryIntent(attempt.queryText);
|
|
18626
|
+
const prioritizeSourcePaths = attemptIntent.primary !== "docs" && attemptIntent.primary !== "test";
|
|
17672
18627
|
if (inferredSymbol && attempt.queryText === inferredSymbol && attempt.queryText !== query) {
|
|
17673
18628
|
decisions.fallbackFromOriginalConceptualToInferred = true;
|
|
17674
18629
|
}
|
|
17675
|
-
const results = await tryConceptualSearch(attempt.queryText, attempt.scope, attempt.relaxed);
|
|
18630
|
+
const results = await tryConceptualSearch(attempt.queryText, attempt.scope, attempt.relaxed, prioritizeSourcePaths);
|
|
17676
18631
|
if (results.length > 0) {
|
|
17677
18632
|
const heading = buildPackHeading("conceptual", decisions);
|
|
17678
18633
|
const intent = analyzeQueryIntent(attempt.queryText);
|
|
@@ -17740,7 +18695,7 @@ async function resolveCodebaseContextUnmeasured(projectRoot, host, input) {
|
|
|
17740
18695
|
const directory = input.directory ?? void 0;
|
|
17741
18696
|
const tokenBudget = input.tokenBudget ?? void 0;
|
|
17742
18697
|
if (from && to) {
|
|
17743
|
-
const
|
|
18698
|
+
const path30 = await getCallGraphPath(
|
|
17744
18699
|
projectRoot,
|
|
17745
18700
|
host,
|
|
17746
18701
|
from,
|
|
@@ -17749,25 +18704,25 @@ async function resolveCodebaseContextUnmeasured(projectRoot, host, input) {
|
|
|
17749
18704
|
fromFilePath,
|
|
17750
18705
|
toFilePath
|
|
17751
18706
|
);
|
|
17752
|
-
const pathText = formatCallGraphPathResult(
|
|
17753
|
-
if (
|
|
18707
|
+
const pathText = formatCallGraphPathResult(path30);
|
|
18708
|
+
if (path30.path.length > 0) {
|
|
17754
18709
|
const fitted2 = fitTextToContextBudget(
|
|
17755
18710
|
pathText,
|
|
17756
18711
|
tokenBudget
|
|
17757
18712
|
);
|
|
17758
18713
|
return {
|
|
17759
18714
|
text: fitted2.text,
|
|
17760
|
-
details: fittedDetails("path", fitted2,
|
|
18715
|
+
details: fittedDetails("path", fitted2, path30.path.length)
|
|
17761
18716
|
};
|
|
17762
18717
|
}
|
|
17763
|
-
if (
|
|
18718
|
+
if (path30.from.status !== "resolved" || path30.to.status !== "resolved") {
|
|
17764
18719
|
const fitted2 = fitTextToContextBudget(pathText, tokenBudget);
|
|
17765
18720
|
return {
|
|
17766
18721
|
text: fitted2.text,
|
|
17767
18722
|
details: fittedDetails("path", fitted2, 0)
|
|
17768
18723
|
};
|
|
17769
18724
|
}
|
|
17770
|
-
const resolvedFrom =
|
|
18725
|
+
const resolvedFrom = path30.from;
|
|
17771
18726
|
const { callers } = await getCallGraphData(projectRoot, host, {
|
|
17772
18727
|
name: to,
|
|
17773
18728
|
direction: "callers",
|
|
@@ -17809,12 +18764,13 @@ async function resolveCodebaseContextUnmeasured(projectRoot, host, input) {
|
|
|
17809
18764
|
directory: scope.directory,
|
|
17810
18765
|
trace
|
|
17811
18766
|
}),
|
|
17812
|
-
search: (queryText, retrievalLimit, scope, trace) => searchCodebase(projectRoot, host, queryText, {
|
|
18767
|
+
search: (queryText, retrievalLimit, scope, trace, searchOptions) => searchCodebase(projectRoot, host, queryText, {
|
|
17813
18768
|
limit: retrievalLimit,
|
|
17814
18769
|
fileType: scope.fileType,
|
|
17815
18770
|
directory: scope.directory,
|
|
17816
18771
|
metadataOnly: true,
|
|
17817
|
-
trace
|
|
18772
|
+
trace,
|
|
18773
|
+
prioritizeSourcePaths: searchOptions?.prioritizeSourcePaths
|
|
17818
18774
|
})
|
|
17819
18775
|
});
|
|
17820
18776
|
}
|
|
@@ -17926,7 +18882,7 @@ async function executeCallGraph(projectRoot, host, args) {
|
|
|
17926
18882
|
return { text: formatCallGraphResult(await getCallGraphData(projectRoot, host, args)) };
|
|
17927
18883
|
}
|
|
17928
18884
|
async function executeCallGraphPath(projectRoot, host, args) {
|
|
17929
|
-
const
|
|
18885
|
+
const path30 = await getCallGraphPath(
|
|
17930
18886
|
projectRoot,
|
|
17931
18887
|
host,
|
|
17932
18888
|
args.from,
|
|
@@ -17935,7 +18891,7 @@ async function executeCallGraphPath(projectRoot, host, args) {
|
|
|
17935
18891
|
args.fromFilePath,
|
|
17936
18892
|
args.toFilePath
|
|
17937
18893
|
);
|
|
17938
|
-
return { text: formatCallGraphPathResult(
|
|
18894
|
+
return { text: formatCallGraphPathResult(path30) };
|
|
17939
18895
|
}
|
|
17940
18896
|
async function executeCodeCommunities(projectRoot, host, args) {
|
|
17941
18897
|
const result = await getCodeCommunities(projectRoot, host, args);
|
|
@@ -17945,11 +18901,11 @@ async function executeCodeCommunities(projectRoot, host, args) {
|
|
|
17945
18901
|
// src/adapters/opencode/tools.ts
|
|
17946
18902
|
var import_fs15 = require("fs");
|
|
17947
18903
|
var os7 = __toESM(require("os"), 1);
|
|
17948
|
-
var
|
|
18904
|
+
var path27 = __toESM(require("path"), 1);
|
|
17949
18905
|
|
|
17950
18906
|
// src/tools/visualize/activity.ts
|
|
17951
18907
|
var import_child_process5 = require("child_process");
|
|
17952
|
-
var
|
|
18908
|
+
var path25 = __toESM(require("path"), 1);
|
|
17953
18909
|
function attachRecentActivity(data, projectRoot) {
|
|
17954
18910
|
const activity = readGitActivity(projectRoot);
|
|
17955
18911
|
const changes = activity.size > 0 ? buildGitChanges(data, activity, projectRoot) : buildGraphChanges(data);
|
|
@@ -18111,7 +19067,7 @@ function normalizePath3(filePath) {
|
|
|
18111
19067
|
return filePath.replace(/\\/g, "/");
|
|
18112
19068
|
}
|
|
18113
19069
|
function toGitRelativePath(projectRoot, filePath) {
|
|
18114
|
-
const relativePath =
|
|
19070
|
+
const relativePath = path25.isAbsolute(filePath) ? path25.relative(projectRoot, filePath) : filePath;
|
|
18115
19071
|
return normalizePath3(relativePath);
|
|
18116
19072
|
}
|
|
18117
19073
|
|
|
@@ -18369,7 +19325,7 @@ render();
|
|
|
18369
19325
|
}
|
|
18370
19326
|
|
|
18371
19327
|
// src/tools/visualize/transform.ts
|
|
18372
|
-
var
|
|
19328
|
+
var path26 = __toESM(require("path"), 1);
|
|
18373
19329
|
|
|
18374
19330
|
// src/tools/visualize/modules.ts
|
|
18375
19331
|
var MAX_MODULES = 18;
|
|
@@ -18502,8 +19458,8 @@ function compactModules(prefixToNodes) {
|
|
|
18502
19458
|
function deriveModules(nodes) {
|
|
18503
19459
|
const initial = /* @__PURE__ */ new Map();
|
|
18504
19460
|
for (const node of nodes) {
|
|
18505
|
-
const
|
|
18506
|
-
const prefix = modulePrefixFromRelativePath(
|
|
19461
|
+
const relative14 = stripToProjectRelative(node.filePath);
|
|
19462
|
+
const prefix = modulePrefixFromRelativePath(relative14);
|
|
18507
19463
|
if (!initial.has(prefix)) initial.set(prefix, []);
|
|
18508
19464
|
initial.get(prefix)?.push(node);
|
|
18509
19465
|
}
|
|
@@ -18629,7 +19585,7 @@ function transformForVisualization(symbols, edges, options = {}) {
|
|
|
18629
19585
|
filePath: s.filePath,
|
|
18630
19586
|
kind: s.kind,
|
|
18631
19587
|
line: s.startLine,
|
|
18632
|
-
directory:
|
|
19588
|
+
directory: path26.dirname(s.filePath),
|
|
18633
19589
|
moduleId: "",
|
|
18634
19590
|
moduleLabel: ""
|
|
18635
19591
|
}));
|
|
@@ -18729,7 +19685,8 @@ var codebase_peek = tool({
|
|
|
18729
19685
|
chunkType: z3.enum(CHUNK_TYPE_VALUES).optional().describe("Filter by code chunk type"),
|
|
18730
19686
|
blameAuthor: z3.string().optional().describe("Filter by git blame author name or email"),
|
|
18731
19687
|
blameSha: z3.string().optional().describe("Filter by git blame commit SHA or prefix"),
|
|
18732
|
-
blameSince: z3.string().optional().describe("Filter to chunks last changed on or after this date (e.g., 2025-01-01)")
|
|
19688
|
+
blameSince: z3.string().optional().describe("Filter to chunks last changed on or after this date (e.g., 2025-01-01)"),
|
|
19689
|
+
blameUntil: z3.string().optional().describe("Filter to chunks last changed on or before this date (e.g., 2025-01-31)")
|
|
18733
19690
|
},
|
|
18734
19691
|
async execute(args, context) {
|
|
18735
19692
|
return searchCodebaseWithEffectiveness(context?.worktree, DEFAULT_HOST, "peek", args.query, {
|
|
@@ -18740,7 +19697,8 @@ var codebase_peek = tool({
|
|
|
18740
19697
|
metadataOnly: true,
|
|
18741
19698
|
blameAuthor: args.blameAuthor,
|
|
18742
19699
|
blameSha: args.blameSha,
|
|
18743
|
-
blameSince: args.blameSince
|
|
19700
|
+
blameSince: args.blameSince,
|
|
19701
|
+
blameUntil: args.blameUntil
|
|
18744
19702
|
}, (results) => {
|
|
18745
19703
|
const text = formatCodebasePeek(results);
|
|
18746
19704
|
return { output: text, text };
|
|
@@ -18802,7 +19760,9 @@ var find_similar = tool({
|
|
|
18802
19760
|
fileType: z3.string().optional().describe("Filter by file extension (e.g., 'ts', 'py', 'rs')"),
|
|
18803
19761
|
directory: z3.string().optional().describe("Filter by directory path (e.g., 'src/utils', 'lib')"),
|
|
18804
19762
|
chunkType: z3.enum(CHUNK_TYPE_VALUES).optional().describe("Filter by code chunk type"),
|
|
18805
|
-
excludeFile: z3.string().optional().describe("Exclude results from this file path (useful when searching for duplicates of code from a specific file)")
|
|
19763
|
+
excludeFile: z3.string().optional().describe("Exclude results from this file path (useful when searching for duplicates of code from a specific file)"),
|
|
19764
|
+
blameSince: z3.string().optional().describe("Filter to chunks last changed on or after this date (e.g., 2025-01-01)"),
|
|
19765
|
+
blameUntil: z3.string().optional().describe("Filter to chunks last changed on or before this date (e.g., 2025-01-31)")
|
|
18806
19766
|
},
|
|
18807
19767
|
async execute(args, context) {
|
|
18808
19768
|
const results = await findSimilarCode(context?.worktree, DEFAULT_HOST, args.code, {
|
|
@@ -18810,7 +19770,9 @@ var find_similar = tool({
|
|
|
18810
19770
|
fileType: args.fileType,
|
|
18811
19771
|
directory: args.directory,
|
|
18812
19772
|
chunkType: args.chunkType,
|
|
18813
|
-
excludeFile: args.excludeFile
|
|
19773
|
+
excludeFile: args.excludeFile,
|
|
19774
|
+
blameSince: args.blameSince,
|
|
19775
|
+
blameUntil: args.blameUntil
|
|
18814
19776
|
});
|
|
18815
19777
|
if (results.length === 0) {
|
|
18816
19778
|
return "No similar code found. Try a different snippet or run index_codebase first.";
|
|
@@ -18829,7 +19791,8 @@ var codebase_search = tool({
|
|
|
18829
19791
|
contextLines: z3.number().optional().describe("Number of extra lines to include before/after each match (default: 0)"),
|
|
18830
19792
|
blameAuthor: z3.string().optional().describe("Filter by git blame author name or email"),
|
|
18831
19793
|
blameSha: z3.string().optional().describe("Filter by git blame commit SHA or prefix"),
|
|
18832
|
-
blameSince: z3.string().optional().describe("Filter to chunks last changed on or after this date (e.g., 2025-01-01)")
|
|
19794
|
+
blameSince: z3.string().optional().describe("Filter to chunks last changed on or after this date (e.g., 2025-01-01)"),
|
|
19795
|
+
blameUntil: z3.string().optional().describe("Filter to chunks last changed on or before this date (e.g., 2025-01-31)")
|
|
18833
19796
|
},
|
|
18834
19797
|
async execute(args, context) {
|
|
18835
19798
|
return searchCodebaseWithEffectiveness(context?.worktree, DEFAULT_HOST, "search", args.query, {
|
|
@@ -18840,7 +19803,8 @@ var codebase_search = tool({
|
|
|
18840
19803
|
contextLines: args.contextLines,
|
|
18841
19804
|
blameAuthor: args.blameAuthor,
|
|
18842
19805
|
blameSha: args.blameSha,
|
|
18843
|
-
blameSince: args.blameSince
|
|
19806
|
+
blameSince: args.blameSince,
|
|
19807
|
+
blameUntil: args.blameUntil
|
|
18844
19808
|
}, (results) => {
|
|
18845
19809
|
const text = results.length === 0 ? "No matching code found. Try a different query or run index_codebase first." : formatSearchResults(results, "score");
|
|
18846
19810
|
return { output: text, text };
|
|
@@ -18949,7 +19913,7 @@ var index_visualize = tool({
|
|
|
18949
19913
|
return "No connected symbols found for visualization. Try including orphans with includeOrphans=true, or check that the call graph has resolved edges.";
|
|
18950
19914
|
}
|
|
18951
19915
|
const html = generateVisualizationHtml(vizData);
|
|
18952
|
-
const outputPath =
|
|
19916
|
+
const outputPath = path27.join(os7.tmpdir(), `call-graph-${Date.now()}.html`);
|
|
18953
19917
|
(0, import_fs15.writeFileSync)(outputPath, html, "utf-8");
|
|
18954
19918
|
let result = `Temporal call graph visualization generated: ${outputPath}
|
|
18955
19919
|
|
|
@@ -19053,10 +20017,16 @@ var PI_TOOL_NAMES = [
|
|
|
19053
20017
|
TOOL_NAME.PI_KNOWLEDGE_BASE_ADD,
|
|
19054
20018
|
TOOL_NAME.PI_KNOWLEDGE_BASE_REMOVE
|
|
19055
20019
|
];
|
|
20020
|
+
var MCP_TOOL_NAMES = [
|
|
20021
|
+
...PORTABLE_TOOL_NAMES,
|
|
20022
|
+
TOOL_NAME.ADD_KNOWLEDGE_BASE,
|
|
20023
|
+
TOOL_NAME.LIST_KNOWLEDGE_BASES,
|
|
20024
|
+
TOOL_NAME.REMOVE_KNOWLEDGE_BASE
|
|
20025
|
+
];
|
|
19056
20026
|
|
|
19057
20027
|
// src/commands/loader.ts
|
|
19058
20028
|
var import_fs16 = require("fs");
|
|
19059
|
-
var
|
|
20029
|
+
var path28 = __toESM(require("path"), 1);
|
|
19060
20030
|
function parseFrontmatter(content) {
|
|
19061
20031
|
const frontmatterRegex = /^---\s*\n([\s\S]*?)\n---\s*\n([\s\S]*)$/;
|
|
19062
20032
|
const match = content.match(frontmatterRegex);
|
|
@@ -19082,7 +20052,7 @@ function loadCommandsFromDirectory(commandsDir) {
|
|
|
19082
20052
|
}
|
|
19083
20053
|
const files = (0, import_fs16.readdirSync)(commandsDir).filter((f) => f.endsWith(".md"));
|
|
19084
20054
|
for (const file of files) {
|
|
19085
|
-
const filePath =
|
|
20055
|
+
const filePath = path28.join(commandsDir, file);
|
|
19086
20056
|
let content;
|
|
19087
20057
|
try {
|
|
19088
20058
|
content = (0, import_fs16.readFileSync)(filePath, "utf-8");
|
|
@@ -19091,7 +20061,7 @@ function loadCommandsFromDirectory(commandsDir) {
|
|
|
19091
20061
|
throw new Error(`Failed to load command file ${filePath}: ${message}`);
|
|
19092
20062
|
}
|
|
19093
20063
|
const { frontmatter, body } = parseFrontmatter(content);
|
|
19094
|
-
const name =
|
|
20064
|
+
const name = path28.basename(file, ".md");
|
|
19095
20065
|
const description = frontmatter.description || `Run the ${name} command`;
|
|
19096
20066
|
commands.set(name, {
|
|
19097
20067
|
description,
|
|
@@ -19426,23 +20396,41 @@ var RoutingHintController = class {
|
|
|
19426
20396
|
// src/adapters/opencode.ts
|
|
19427
20397
|
var import_meta2 = {};
|
|
19428
20398
|
var activeWatchers = /* @__PURE__ */ new Map();
|
|
19429
|
-
|
|
19430
|
-
|
|
19431
|
-
|
|
19432
|
-
existing.
|
|
19433
|
-
|
|
19434
|
-
|
|
19435
|
-
|
|
19436
|
-
|
|
20399
|
+
var watcherReplacementChains = /* @__PURE__ */ new Map();
|
|
20400
|
+
async function replaceActiveWatcher(projectRoot, createNextWatcher) {
|
|
20401
|
+
const chain = (watcherReplacementChains.get(projectRoot) ?? Promise.resolve()).catch(() => void 0).then(async () => {
|
|
20402
|
+
const existing = activeWatchers.get(projectRoot);
|
|
20403
|
+
if (existing) {
|
|
20404
|
+
try {
|
|
20405
|
+
await existing.stop();
|
|
20406
|
+
} catch (error) {
|
|
20407
|
+
console.error("[codebase-index] Failed to stop replaced watcher:", error);
|
|
20408
|
+
throw error;
|
|
20409
|
+
}
|
|
20410
|
+
if (activeWatchers.get(projectRoot) === existing) {
|
|
20411
|
+
activeWatchers.delete(projectRoot);
|
|
20412
|
+
}
|
|
20413
|
+
}
|
|
20414
|
+
if (createNextWatcher) {
|
|
20415
|
+
activeWatchers.set(projectRoot, createNextWatcher());
|
|
20416
|
+
}
|
|
20417
|
+
});
|
|
20418
|
+
watcherReplacementChains.set(projectRoot, chain);
|
|
20419
|
+
try {
|
|
20420
|
+
await chain;
|
|
20421
|
+
} finally {
|
|
20422
|
+
if (watcherReplacementChains.get(projectRoot) === chain) {
|
|
20423
|
+
watcherReplacementChains.delete(projectRoot);
|
|
20424
|
+
}
|
|
19437
20425
|
}
|
|
19438
20426
|
}
|
|
19439
20427
|
function getCommandsDir() {
|
|
19440
20428
|
let currentDir = process.cwd();
|
|
19441
20429
|
if (typeof import_meta2 !== "undefined" && import_meta2.url) {
|
|
19442
|
-
currentDir =
|
|
20430
|
+
currentDir = path29.dirname((0, import_url.fileURLToPath)(import_meta2.url));
|
|
19443
20431
|
}
|
|
19444
|
-
const packageRoot =
|
|
19445
|
-
return
|
|
20432
|
+
const packageRoot = path29.basename(currentDir) === "adapters" ? path29.join(currentDir, "..", "..") : path29.join(currentDir, "..");
|
|
20433
|
+
return path29.join(packageRoot, "commands");
|
|
19446
20434
|
}
|
|
19447
20435
|
function appendRoutingHints(output, hints, preferredRole) {
|
|
19448
20436
|
const preferredBucket = preferredRole === "developer" ? output.developer : output.system;
|
|
@@ -19483,9 +20471,12 @@ var plugin = async ({ directory, worktree }) => {
|
|
|
19483
20471
|
startAutoIndex(projectRoot, "opencode", "startup");
|
|
19484
20472
|
}
|
|
19485
20473
|
if (config.indexing.watchFiles && isValidProject) {
|
|
19486
|
-
replaceActiveWatcher(
|
|
20474
|
+
await replaceActiveWatcher(
|
|
20475
|
+
projectRoot,
|
|
20476
|
+
() => createWatcherWithIndexer(getProjectIndexer, projectRoot, config, "opencode")
|
|
20477
|
+
);
|
|
19487
20478
|
} else {
|
|
19488
|
-
replaceActiveWatcher(projectRoot, null);
|
|
20479
|
+
await replaceActiveWatcher(projectRoot, null);
|
|
19489
20480
|
}
|
|
19490
20481
|
return {
|
|
19491
20482
|
tool: {
|