opencode-codebase-index 0.19.1 → 0.20.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 +7 -5
- package/dist/cli.cjs +765 -124
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +765 -124
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +400 -55
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +400 -55
- package/dist/index.js.map +1 -1
- package/dist/pi-extension.cjs +361 -48
- package/dist/pi-extension.cjs.map +1 -1
- package/dist/pi-extension.js +361 -48
- 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 +4 -3
package/dist/index.cjs
CHANGED
|
@@ -787,6 +787,7 @@ function getDefaultIndexingConfig() {
|
|
|
787
787
|
autoIndexMaxRetries: 5,
|
|
788
788
|
autoIndexRetryDelayMs: 100,
|
|
789
789
|
watchFiles: true,
|
|
790
|
+
pauseBackgroundIndexingOnBattery: false,
|
|
790
791
|
maxFileSize: 1048576,
|
|
791
792
|
maxChunksPerFile: 100,
|
|
792
793
|
semanticOnly: false,
|
|
@@ -918,6 +919,7 @@ function parseConfig(raw) {
|
|
|
918
919
|
autoIndexMaxRetries: typeof rawIndexing.autoIndexMaxRetries === "number" ? Math.min(10, Math.max(0, Math.floor(rawIndexing.autoIndexMaxRetries))) : defaultIndexing.autoIndexMaxRetries,
|
|
919
920
|
autoIndexRetryDelayMs: typeof rawIndexing.autoIndexRetryDelayMs === "number" ? Math.min(1e4, Math.max(10, Math.floor(rawIndexing.autoIndexRetryDelayMs))) : defaultIndexing.autoIndexRetryDelayMs,
|
|
920
921
|
watchFiles: typeof rawIndexing.watchFiles === "boolean" ? rawIndexing.watchFiles : defaultIndexing.watchFiles,
|
|
922
|
+
pauseBackgroundIndexingOnBattery: typeof rawIndexing.pauseBackgroundIndexingOnBattery === "boolean" ? rawIndexing.pauseBackgroundIndexingOnBattery : defaultIndexing.pauseBackgroundIndexingOnBattery,
|
|
921
923
|
maxFileSize: typeof rawIndexing.maxFileSize === "number" ? rawIndexing.maxFileSize : defaultIndexing.maxFileSize,
|
|
922
924
|
maxChunksPerFile: typeof rawIndexing.maxChunksPerFile === "number" ? Math.max(1, rawIndexing.maxChunksPerFile) : defaultIndexing.maxChunksPerFile,
|
|
923
925
|
semanticOnly: typeof rawIndexing.semanticOnly === "boolean" ? rawIndexing.semanticOnly : defaultIndexing.semanticOnly,
|
|
@@ -4188,9 +4190,21 @@ function parseFiles(files) {
|
|
|
4188
4190
|
return result.map((f) => ({
|
|
4189
4191
|
path: f.path,
|
|
4190
4192
|
chunks: f.chunks.map(mapChunk),
|
|
4193
|
+
symbols: (f.symbols ?? []).map(mapParsedSymbol),
|
|
4191
4194
|
hash: f.hash
|
|
4192
4195
|
}));
|
|
4193
4196
|
}
|
|
4197
|
+
function mapParsedSymbol(symbol) {
|
|
4198
|
+
return {
|
|
4199
|
+
name: symbol.name,
|
|
4200
|
+
kind: symbol.kind,
|
|
4201
|
+
startLine: symbol.startLine ?? symbol.start_line,
|
|
4202
|
+
startCol: symbol.startCol ?? symbol.start_col,
|
|
4203
|
+
endLine: symbol.endLine ?? symbol.end_line,
|
|
4204
|
+
endCol: symbol.endCol ?? symbol.end_col,
|
|
4205
|
+
language: symbol.language
|
|
4206
|
+
};
|
|
4207
|
+
}
|
|
4194
4208
|
function mapChunk(c) {
|
|
4195
4209
|
return {
|
|
4196
4210
|
content: c.content,
|
|
@@ -6707,6 +6721,7 @@ var INDEX_METADATA_VERSION = "1";
|
|
|
6707
6721
|
var EMBEDDING_STRATEGY_VERSION = "2";
|
|
6708
6722
|
var SWIFT_PARSER_VERSION = "1";
|
|
6709
6723
|
var METAL_PARSER_VERSION = "1";
|
|
6724
|
+
var SYMBOL_EXTRACTOR_VERSION = "1";
|
|
6710
6725
|
var RANKING_TOKEN_CACHE_LIMIT = 4096;
|
|
6711
6726
|
var RANK_HYBRID_CACHE_LIMIT = 256;
|
|
6712
6727
|
function createPendingChunkStorageText(texts) {
|
|
@@ -7008,7 +7023,7 @@ function classifyQueryIntentRaw(query) {
|
|
|
7008
7023
|
return "neutral";
|
|
7009
7024
|
}
|
|
7010
7025
|
function isImplementationChunkType(chunkType) {
|
|
7011
|
-
return [
|
|
7026
|
+
return CALL_GRAPH_SYMBOL_CHUNK_TYPES.has(chunkType) || [
|
|
7012
7027
|
"export_statement",
|
|
7013
7028
|
"function",
|
|
7014
7029
|
"function_declaration",
|
|
@@ -7453,7 +7468,7 @@ function promoteIdentifierMatches(query, combined, semanticCandidates, keywordCa
|
|
|
7453
7468
|
const remainder = combined.filter((candidate) => !promotedIds.has(candidate.id));
|
|
7454
7469
|
return [...promoted, ...remainder];
|
|
7455
7470
|
}
|
|
7456
|
-
function buildSymbolDefinitionLane(query, database, branchChunkIds, limit, fallbackCandidates, prioritizeSourcePaths = classifyQueryIntentRaw(query) === "source") {
|
|
7471
|
+
function buildSymbolDefinitionLane(query, database, branchChunkIds, branchSymbolIds, limit, fallbackCandidates, prioritizeSourcePaths = classifyQueryIntentRaw(query) === "source") {
|
|
7457
7472
|
if (!prioritizeSourcePaths) {
|
|
7458
7473
|
return [];
|
|
7459
7474
|
}
|
|
@@ -7467,14 +7482,14 @@ function buildSymbolDefinitionLane(query, database, branchChunkIds, limit, fallb
|
|
|
7467
7482
|
const primaryHint = extractPrimaryIdentifierQueryHint(query);
|
|
7468
7483
|
const upsertChunkCandidate = (chunk, identifier, normalizedIdentifier, baseScore) => {
|
|
7469
7484
|
if (branchChunkIds && !branchChunkIds.has(chunk.chunkId)) {
|
|
7470
|
-
return;
|
|
7485
|
+
return false;
|
|
7471
7486
|
}
|
|
7472
7487
|
const chunkType = chunk.nodeType ?? "other";
|
|
7473
7488
|
if (!isImplementationChunkType(chunkType)) {
|
|
7474
|
-
return;
|
|
7489
|
+
return false;
|
|
7475
7490
|
}
|
|
7476
7491
|
if (!isLikelyImplementationPath2(chunk.filePath)) {
|
|
7477
|
-
return;
|
|
7492
|
+
return false;
|
|
7478
7493
|
}
|
|
7479
7494
|
const nameLower = (chunk.name ?? "").toLowerCase();
|
|
7480
7495
|
const exactName = nameLower === identifier || nameLower.replace(/_/g, "") === normalizedIdentifier;
|
|
@@ -7496,6 +7511,7 @@ function buildSymbolDefinitionLane(query, database, branchChunkIds, limit, fallb
|
|
|
7496
7511
|
}
|
|
7497
7512
|
});
|
|
7498
7513
|
}
|
|
7514
|
+
return true;
|
|
7499
7515
|
};
|
|
7500
7516
|
const normalizedHints = identifierHints.flatMap((hint) => [
|
|
7501
7517
|
hint,
|
|
@@ -7517,12 +7533,46 @@ function buildSymbolDefinitionLane(query, database, branchChunkIds, limit, fallb
|
|
|
7517
7533
|
dedupSymbols.set(symbol.id, symbol);
|
|
7518
7534
|
}
|
|
7519
7535
|
for (const symbol of dedupSymbols.values()) {
|
|
7536
|
+
if (branchSymbolIds && !branchSymbolIds.has(symbol.id)) {
|
|
7537
|
+
continue;
|
|
7538
|
+
}
|
|
7539
|
+
if (filePathHint && !pathMatchesHint(symbol.filePath, filePathHint)) {
|
|
7540
|
+
continue;
|
|
7541
|
+
}
|
|
7520
7542
|
const chunks = database.getChunksByFile(symbol.filePath);
|
|
7543
|
+
let foundCoveringChunk = false;
|
|
7521
7544
|
for (const chunk of chunks) {
|
|
7522
7545
|
if (chunk.startLine > symbol.startLine || chunk.endLine < symbol.endLine) {
|
|
7523
7546
|
continue;
|
|
7524
7547
|
}
|
|
7525
|
-
|
|
7548
|
+
const chunkName = (chunk.name ?? "").toLowerCase();
|
|
7549
|
+
const symbolName2 = symbol.name.toLowerCase();
|
|
7550
|
+
if (chunkName !== symbolName2 && chunkName.replace(/_/g, "") !== symbolName2.replace(/_/g, "")) {
|
|
7551
|
+
continue;
|
|
7552
|
+
}
|
|
7553
|
+
foundCoveringChunk = upsertChunkCandidate(chunk, identifier, normalizedIdentifier) || foundCoveringChunk;
|
|
7554
|
+
}
|
|
7555
|
+
if (foundCoveringChunk || !isLikelyImplementationPath2(symbol.filePath)) {
|
|
7556
|
+
continue;
|
|
7557
|
+
}
|
|
7558
|
+
const symbolName = symbol.name.toLowerCase();
|
|
7559
|
+
const exactName = symbolName === identifier || symbolName.replace(/_/g, "") === normalizedIdentifier;
|
|
7560
|
+
const score = exactName ? 0.99 : 0.88;
|
|
7561
|
+
const existing = symbolCandidates.get(symbol.id);
|
|
7562
|
+
if (!existing || score > existing.score) {
|
|
7563
|
+
symbolCandidates.set(symbol.id, {
|
|
7564
|
+
id: symbol.id,
|
|
7565
|
+
score,
|
|
7566
|
+
metadata: {
|
|
7567
|
+
filePath: symbol.filePath,
|
|
7568
|
+
startLine: symbol.startLine,
|
|
7569
|
+
endLine: symbol.endLine,
|
|
7570
|
+
chunkType: symbol.kind,
|
|
7571
|
+
name: symbol.name,
|
|
7572
|
+
language: symbol.language,
|
|
7573
|
+
hash: symbol.id
|
|
7574
|
+
}
|
|
7575
|
+
});
|
|
7526
7576
|
}
|
|
7527
7577
|
}
|
|
7528
7578
|
const dedupChunksByName = /* @__PURE__ */ new Map();
|
|
@@ -7530,6 +7580,9 @@ function buildSymbolDefinitionLane(query, database, branchChunkIds, limit, fallb
|
|
|
7530
7580
|
dedupChunksByName.set(chunk.chunkId, chunk);
|
|
7531
7581
|
}
|
|
7532
7582
|
for (const chunk of dedupChunksByName.values()) {
|
|
7583
|
+
if (filePathHint && !pathMatchesHint(chunk.filePath, filePathHint)) {
|
|
7584
|
+
continue;
|
|
7585
|
+
}
|
|
7533
7586
|
upsertChunkCandidate(chunk, identifier, normalizedIdentifier);
|
|
7534
7587
|
}
|
|
7535
7588
|
}
|
|
@@ -8071,6 +8124,10 @@ var Indexer = class _Indexer {
|
|
|
8071
8124
|
const projectHash = hashContent(path14.resolve(this.projectRoot)).slice(0, 16);
|
|
8072
8125
|
return `${key}.${projectHash}`;
|
|
8073
8126
|
}
|
|
8127
|
+
getSymbolExtractorVersionMetadataKey(catalogIdentity = this.getBranchCatalogIdentity()) {
|
|
8128
|
+
const branchKey = this.getBranchCatalogKeyFor(catalogIdentity);
|
|
8129
|
+
return `index.symbolExtractorVersion.${hashContent(branchKey).slice(0, 24)}`;
|
|
8130
|
+
}
|
|
8074
8131
|
hasProjectForceReembedPending() {
|
|
8075
8132
|
return this.config.scope === "global" && this.database?.getMetadata(this.getProjectForceReembedMetadataKey()) === "true";
|
|
8076
8133
|
}
|
|
@@ -9414,7 +9471,8 @@ var Indexer = class _Indexer {
|
|
|
9414
9471
|
}
|
|
9415
9472
|
const branchKey = this.getBranchCatalogKey();
|
|
9416
9473
|
const alreadyIndexed = database.getBranchChunkIds(branchKey).length > 0 && database.getBranchSymbolIds(branchKey).length > 0;
|
|
9417
|
-
|
|
9474
|
+
const symbolsCurrent = database.getMetadata(this.getSymbolExtractorVersionMetadataKey()) === SYMBOL_EXTRACTOR_VERSION;
|
|
9475
|
+
if (alreadyIndexed && symbolsCurrent && this.getStoredBranchCommit(database) === normalizedCommit) {
|
|
9418
9476
|
return { prepared: false };
|
|
9419
9477
|
}
|
|
9420
9478
|
const stats = await this.indexUnlocked(onProgress, [], true);
|
|
@@ -9473,6 +9531,8 @@ var Indexer = class _Indexer {
|
|
|
9473
9531
|
const reparseCachedSwiftFiles = database.getMetadata(swiftParserMetadataKey) !== SWIFT_PARSER_VERSION;
|
|
9474
9532
|
const metalParserMetadataKey = this.getMetalParserVersionMetadataKey();
|
|
9475
9533
|
const reparseCachedMetalFiles = database.getMetadata(metalParserMetadataKey) !== METAL_PARSER_VERSION;
|
|
9534
|
+
const symbolExtractorMetadataKey = this.getSymbolExtractorVersionMetadataKey();
|
|
9535
|
+
const refreshCachedSymbols = database.getMetadata(symbolExtractorMetadataKey) !== SYMBOL_EXTRACTOR_VERSION;
|
|
9476
9536
|
if (reparseCachedSwiftFiles && Array.from(this.fileHashCache.keys()).some(
|
|
9477
9537
|
(filePath) => path14.extname(filePath).toLowerCase() === ".swift"
|
|
9478
9538
|
)) {
|
|
@@ -9516,7 +9576,7 @@ var Indexer = class _Indexer {
|
|
|
9516
9576
|
);
|
|
9517
9577
|
const requiresSwiftParserUpgrade = reparseCachedSwiftFiles && path14.extname(canonicalPath).toLowerCase() === ".swift";
|
|
9518
9578
|
const requiresMetalParserUpgrade = reparseCachedMetalFiles && path14.extname(canonicalPath).toLowerCase() === ".metal";
|
|
9519
|
-
if (cachedHashMatches && !needsCallGraphRefresh && !requiresSwiftParserUpgrade && !requiresMetalParserUpgrade) {
|
|
9579
|
+
if (cachedHashMatches && !needsCallGraphRefresh && !requiresSwiftParserUpgrade && !requiresMetalParserUpgrade && !refreshCachedSymbols) {
|
|
9520
9580
|
unchangedFilePaths.add(canonicalPath);
|
|
9521
9581
|
this.logger.recordCacheHit();
|
|
9522
9582
|
} else {
|
|
@@ -9727,37 +9787,27 @@ var Indexer = class _Indexer {
|
|
|
9727
9787
|
const parsed = parsedFiles[i];
|
|
9728
9788
|
const changedFile = changedFiles[i];
|
|
9729
9789
|
const fileSymbols = [];
|
|
9730
|
-
for (const
|
|
9731
|
-
if (!
|
|
9732
|
-
const existingMetalSymbol = chunk.language === "metal" ? fileSymbols.find(
|
|
9733
|
-
(symbol2) => symbol2.name === chunk.name && symbol2.kind === chunk.chunkType && symbol2.startLine <= chunk.endLine && chunk.startLine <= symbol2.endLine
|
|
9734
|
-
) : void 0;
|
|
9735
|
-
if (existingMetalSymbol) {
|
|
9736
|
-
existingMetalSymbol.startLine = Math.min(existingMetalSymbol.startLine, chunk.startLine);
|
|
9737
|
-
existingMetalSymbol.endLine = Math.max(existingMetalSymbol.endLine, chunk.endLine);
|
|
9738
|
-
existingMetalSymbol.startCol = Math.min(existingMetalSymbol.startCol, chunk.startCol ?? 0);
|
|
9739
|
-
existingMetalSymbol.endCol = Math.max(existingMetalSymbol.endCol, chunk.endCol ?? 0);
|
|
9740
|
-
continue;
|
|
9741
|
-
}
|
|
9790
|
+
for (const parsedSymbol of parsed.symbols) {
|
|
9791
|
+
if (!CALL_GRAPH_SYMBOL_CHUNK_TYPES.has(parsedSymbol.kind)) continue;
|
|
9742
9792
|
const preparedNamespace = this.getPreparedBranchNamespace();
|
|
9743
9793
|
const symbolId = `sym_${hashContent(
|
|
9744
|
-
(preparedNamespace ? `${preparedNamespace}:` : "") + parsed.path + ":" +
|
|
9794
|
+
(preparedNamespace ? `${preparedNamespace}:` : "") + parsed.path + ":" + parsedSymbol.name + ":" + parsedSymbol.kind + ":" + parsedSymbol.startLine + ":" + parsedSymbol.startCol + ":" + changedFile.hash
|
|
9745
9795
|
).slice(0, 16)}`;
|
|
9746
9796
|
const symbol = {
|
|
9747
9797
|
id: symbolId,
|
|
9748
9798
|
filePath: parsed.path,
|
|
9749
|
-
name:
|
|
9750
|
-
kind:
|
|
9751
|
-
startLine:
|
|
9752
|
-
startCol:
|
|
9753
|
-
endLine:
|
|
9754
|
-
endCol:
|
|
9755
|
-
language:
|
|
9799
|
+
name: parsedSymbol.name,
|
|
9800
|
+
kind: parsedSymbol.kind,
|
|
9801
|
+
startLine: parsedSymbol.startLine,
|
|
9802
|
+
startCol: parsedSymbol.startCol,
|
|
9803
|
+
endLine: parsedSymbol.endLine,
|
|
9804
|
+
endCol: parsedSymbol.endCol,
|
|
9805
|
+
language: parsedSymbol.language
|
|
9756
9806
|
};
|
|
9757
9807
|
fileSymbols.push(symbol);
|
|
9758
9808
|
allSymbolIds.add(symbolId);
|
|
9759
9809
|
}
|
|
9760
|
-
const fileLanguage = parsed.chunks[0]?.language;
|
|
9810
|
+
const fileLanguage = parsed.symbols[0]?.language ?? parsed.chunks[0]?.language;
|
|
9761
9811
|
const isCaseInsensitiveLanguage = !!fileLanguage && CASE_INSENSITIVE_LANGUAGES.has(fileLanguage);
|
|
9762
9812
|
const normalizeSymbolKey = (name) => isCaseInsensitiveLanguage ? name.toLowerCase() : name;
|
|
9763
9813
|
const symbolsByName = /* @__PURE__ */ new Map();
|
|
@@ -9873,6 +9923,7 @@ var Indexer = class _Indexer {
|
|
|
9873
9923
|
}
|
|
9874
9924
|
database.setMetadata(swiftParserMetadataKey, SWIFT_PARSER_VERSION);
|
|
9875
9925
|
database.setMetadata(metalParserMetadataKey, METAL_PARSER_VERSION);
|
|
9926
|
+
database.setMetadata(symbolExtractorMetadataKey, SYMBOL_EXTRACTOR_VERSION);
|
|
9876
9927
|
this.saveBranchCommit(database, indexedCommit);
|
|
9877
9928
|
this.saveIndexMetadata(configuredProviderInfo);
|
|
9878
9929
|
this.indexCompatibility = { compatible: true };
|
|
@@ -9909,6 +9960,7 @@ var Indexer = class _Indexer {
|
|
|
9909
9960
|
}
|
|
9910
9961
|
database.setMetadata(swiftParserMetadataKey, SWIFT_PARSER_VERSION);
|
|
9911
9962
|
database.setMetadata(metalParserMetadataKey, METAL_PARSER_VERSION);
|
|
9963
|
+
database.setMetadata(symbolExtractorMetadataKey, SYMBOL_EXTRACTOR_VERSION);
|
|
9912
9964
|
this.saveBranchCommit(database, indexedCommit);
|
|
9913
9965
|
this.saveIndexMetadata(configuredProviderInfo);
|
|
9914
9966
|
this.indexCompatibility = { compatible: true };
|
|
@@ -10188,6 +10240,7 @@ var Indexer = class _Indexer {
|
|
|
10188
10240
|
}
|
|
10189
10241
|
database.setMetadata(swiftParserMetadataKey, SWIFT_PARSER_VERSION);
|
|
10190
10242
|
database.setMetadata(metalParserMetadataKey, METAL_PARSER_VERSION);
|
|
10243
|
+
database.setMetadata(symbolExtractorMetadataKey, SYMBOL_EXTRACTOR_VERSION);
|
|
10191
10244
|
this.saveBranchCommit(database, indexedCommit);
|
|
10192
10245
|
this.saveIndexMetadata(configuredProviderInfo);
|
|
10193
10246
|
this.indexCompatibility = { compatible: true };
|
|
@@ -10326,10 +10379,11 @@ var Indexer = class _Indexer {
|
|
|
10326
10379
|
const keywordResults = await this.keywordSearch(query, maxResults * 4, store, invertedIndex);
|
|
10327
10380
|
const keywordMs = import_perf_hooks.performance.now() - keywordStartTime;
|
|
10328
10381
|
let branchChunkIds = null;
|
|
10382
|
+
let branchSymbolIds = null;
|
|
10329
10383
|
if (filterByBranch && (this.config.scope === "global" || this.currentBranch !== "default")) {
|
|
10330
|
-
|
|
10331
|
-
|
|
10332
|
-
);
|
|
10384
|
+
const branchCatalogKeys = this.getBranchCatalogKeys();
|
|
10385
|
+
branchChunkIds = new Set(branchCatalogKeys.flatMap((branchKey) => database.getBranchChunkIds(branchKey)));
|
|
10386
|
+
branchSymbolIds = new Set(branchCatalogKeys.flatMap((branchKey) => database.getBranchSymbolIds(branchKey)));
|
|
10333
10387
|
}
|
|
10334
10388
|
const prefilterStartTime = import_perf_hooks.performance.now();
|
|
10335
10389
|
const shouldPrefilterByBranch = branchChunkIds !== null && (this.config.scope === "global" || branchChunkIds.size > 0);
|
|
@@ -10401,6 +10455,7 @@ var Indexer = class _Indexer {
|
|
|
10401
10455
|
query,
|
|
10402
10456
|
database,
|
|
10403
10457
|
branchChunkIds,
|
|
10458
|
+
branchSymbolIds,
|
|
10404
10459
|
maxResults,
|
|
10405
10460
|
union,
|
|
10406
10461
|
sourceIntent
|
|
@@ -10414,7 +10469,7 @@ var Indexer = class _Indexer {
|
|
|
10414
10469
|
(r) => isLikelyImplementationPath2(r.metadata.filePath) && isImplementationChunkType(r.metadata.chunkType)
|
|
10415
10470
|
);
|
|
10416
10471
|
const filtered = (sourceIntent && hasCodeHints && implementationOnly.length > 0 ? implementationOnly : baseFiltered).slice(0, maxResults);
|
|
10417
|
-
const identifierFallback = !options?.definitionIntent && filtered.length === 0 && identifierHints.length > 0 ? buildSymbolDefinitionLane(query, database, branchChunkIds, maxResults, union, true).filter((r) => matchesSearchFilters(r, options, this.config.search.minScore)).slice(0, maxResults) : [];
|
|
10472
|
+
const identifierFallback = !options?.definitionIntent && filtered.length === 0 && identifierHints.length > 0 ? buildSymbolDefinitionLane(query, database, branchChunkIds, branchSymbolIds, maxResults, union, true).filter((r) => matchesSearchFilters(r, options, this.config.search.minScore)).slice(0, maxResults) : [];
|
|
10418
10473
|
const finalResults = filtered.length > 0 ? filtered : identifierFallback;
|
|
10419
10474
|
const totalSearchMs = import_perf_hooks.performance.now() - searchStartTime;
|
|
10420
10475
|
this.logger.recordSearch(totalSearchMs, {
|
|
@@ -10571,7 +10626,7 @@ var Indexer = class _Indexer {
|
|
|
10571
10626
|
const extension = path14.extname(filePath).toLowerCase();
|
|
10572
10627
|
return extension === ".php" || extension === ".c" || extension === ".cc" || extension === ".cpp" || extension === ".cxx";
|
|
10573
10628
|
});
|
|
10574
|
-
if (hasSwiftFiles && database.getMetadata(this.getSwiftParserVersionMetadataKey()) !== SWIFT_PARSER_VERSION || hasMetalFiles && database.getMetadata(this.getMetalParserVersionMetadataKey()) !== METAL_PARSER_VERSION || hasCallGraphMigrationFiles && database.getMetadata(this.getCallGraphResolutionMetadataKey()) !== CALL_GRAPH_RESOLUTION_VERSION) {
|
|
10629
|
+
if (hasSwiftFiles && database.getMetadata(this.getSwiftParserVersionMetadataKey()) !== SWIFT_PARSER_VERSION || hasMetalFiles && database.getMetadata(this.getMetalParserVersionMetadataKey()) !== METAL_PARSER_VERSION || database.getMetadata(this.getSymbolExtractorVersionMetadataKey()) !== SYMBOL_EXTRACTOR_VERSION || hasCallGraphMigrationFiles && database.getMetadata(this.getCallGraphResolutionMetadataKey()) !== CALL_GRAPH_RESOLUTION_VERSION) {
|
|
10575
10630
|
return { readable: true, current: false, reason: "migration-required" };
|
|
10576
10631
|
}
|
|
10577
10632
|
if (isGitRepo(this.materializedProjectRoot)) {
|
|
@@ -11279,7 +11334,10 @@ var Indexer = class _Indexer {
|
|
|
11279
11334
|
const requestedRef = opts.pr !== void 0 ? expectedCommit : headRefName ?? resolvedBranch;
|
|
11280
11335
|
const storedCommit = this.getStoredBranchCommit(database, catalogIdentity);
|
|
11281
11336
|
const catalogIdentityMatches = storedCommit === expectedCommit;
|
|
11282
|
-
|
|
11337
|
+
const symbolsCurrent = database.getMetadata(
|
|
11338
|
+
this.getSymbolExtractorVersionMetadataKey(catalogIdentity)
|
|
11339
|
+
) === SYMBOL_EXTRACTOR_VERSION;
|
|
11340
|
+
if (branchSymbols.length === 0 || !catalogIdentityMatches || !symbolsCurrent) {
|
|
11283
11341
|
if (!resolvedBranch || resolvedBranch === "default") {
|
|
11284
11342
|
throw new Error("Run index_codebase first to build the call graph and symbol index for this project.");
|
|
11285
11343
|
}
|
|
@@ -11621,8 +11679,17 @@ function fitTextToContextBudget(text, tokenBudget) {
|
|
|
11621
11679
|
function normalizedLineRange(result) {
|
|
11622
11680
|
return result.startLine <= result.endLine ? { start: result.startLine, end: result.endLine } : { start: result.endLine, end: result.startLine };
|
|
11623
11681
|
}
|
|
11624
|
-
function rankContextCandidates(results) {
|
|
11625
|
-
return results.map((result, originalIndex) => ({ result, originalIndex })).sort((left, right) =>
|
|
11682
|
+
function rankContextCandidates(results, preferImplementationPaths) {
|
|
11683
|
+
return results.map((result, originalIndex) => ({ result, originalIndex })).sort((left, right) => {
|
|
11684
|
+
if (preferImplementationPaths) {
|
|
11685
|
+
const leftIsImplementation = isLikelyImplementationPath(left.result.filePath);
|
|
11686
|
+
const rightIsImplementation = isLikelyImplementationPath(right.result.filePath);
|
|
11687
|
+
if (leftIsImplementation !== rightIsImplementation) {
|
|
11688
|
+
return leftIsImplementation ? -1 : 1;
|
|
11689
|
+
}
|
|
11690
|
+
}
|
|
11691
|
+
return right.result.score - left.result.score || left.originalIndex - right.originalIndex;
|
|
11692
|
+
});
|
|
11626
11693
|
}
|
|
11627
11694
|
function deduplicateContextCandidates(candidates) {
|
|
11628
11695
|
const acceptedByFile = /* @__PURE__ */ new Map();
|
|
@@ -11711,7 +11778,12 @@ function buildContextPack(results, options = {}) {
|
|
|
11711
11778
|
const maxResults = Math.max(0, Math.floor(options.maxResults ?? results.length));
|
|
11712
11779
|
const includeExactSearchHandoff = options.includeExactSearchHandoff ?? false;
|
|
11713
11780
|
const candidateCount = results.length;
|
|
11714
|
-
const deduplicated = deduplicateContextCandidates(
|
|
11781
|
+
const deduplicated = deduplicateContextCandidates(
|
|
11782
|
+
rankContextCandidates(
|
|
11783
|
+
results,
|
|
11784
|
+
options.preferImplementationPaths ?? false
|
|
11785
|
+
)
|
|
11786
|
+
);
|
|
11715
11787
|
const diversified = diversifyContextCandidates(deduplicated);
|
|
11716
11788
|
const duplicateCount = candidateCount - deduplicated.length;
|
|
11717
11789
|
const selectable = diversified.slice(0, maxResults);
|
|
@@ -12083,7 +12155,7 @@ ${truncateContent(r.content)}
|
|
|
12083
12155
|
}
|
|
12084
12156
|
|
|
12085
12157
|
// src/utils/effectiveness-metrics.ts
|
|
12086
|
-
var EFFECTIVENESS_METRICS_SCHEMA_VERSION =
|
|
12158
|
+
var EFFECTIVENESS_METRICS_SCHEMA_VERSION = 3;
|
|
12087
12159
|
var MAX_EFFECTIVENESS_COUNTER = 1e9;
|
|
12088
12160
|
var EFFECTIVENESS_TOOL_ROUTES = [
|
|
12089
12161
|
"context-conceptual",
|
|
@@ -12129,6 +12201,9 @@ var EFFECTIVENESS_SCOPE_RELAXATION_BUCKETS = ["none", "directory", "file-type",
|
|
|
12129
12201
|
function emptyCounterMap(values) {
|
|
12130
12202
|
return Object.fromEntries(values.map((value) => [value, 0]));
|
|
12131
12203
|
}
|
|
12204
|
+
function emptyRouteCounterMap(routes, values) {
|
|
12205
|
+
return Object.fromEntries(routes.map((route) => [route, emptyCounterMap(values)]));
|
|
12206
|
+
}
|
|
12132
12207
|
function boundedNumber(value) {
|
|
12133
12208
|
if (value === void 0 || !Number.isFinite(value)) return 0;
|
|
12134
12209
|
return Math.max(0, Math.floor(value));
|
|
@@ -12177,6 +12252,11 @@ function allowedValue(value, allowed, fallback) {
|
|
|
12177
12252
|
function cloneCounterMap(counters) {
|
|
12178
12253
|
return { ...counters };
|
|
12179
12254
|
}
|
|
12255
|
+
function cloneRouteCounterMap(counters) {
|
|
12256
|
+
return Object.fromEntries(
|
|
12257
|
+
EFFECTIVENESS_TOOL_ROUTES.map((route) => [route, cloneCounterMap(counters[route])])
|
|
12258
|
+
);
|
|
12259
|
+
}
|
|
12180
12260
|
var EffectivenessMetrics = class {
|
|
12181
12261
|
constructor(counterCap = MAX_EFFECTIVENESS_COUNTER) {
|
|
12182
12262
|
this.counterCap = counterCap;
|
|
@@ -12192,7 +12272,7 @@ var EffectivenessMetrics = class {
|
|
|
12192
12272
|
lifetime: "process",
|
|
12193
12273
|
reset: "index_metrics-reset-or-process-exit",
|
|
12194
12274
|
maxCounterValue: this.counterCap,
|
|
12195
|
-
dimensions: "bounded-
|
|
12275
|
+
dimensions: "bounded-route-and-bucketed-performance-only"
|
|
12196
12276
|
},
|
|
12197
12277
|
totalCalls: 0,
|
|
12198
12278
|
toolRoute: emptyCounterMap(EFFECTIVENESS_TOOL_ROUTES),
|
|
@@ -12204,7 +12284,14 @@ var EffectivenessMetrics = class {
|
|
|
12204
12284
|
tokenBudget: emptyCounterMap(EFFECTIVENESS_TOKEN_BUDGET_BUCKETS),
|
|
12205
12285
|
returnedTokenEstimate: emptyCounterMap(EFFECTIVENESS_RETURNED_TOKEN_BUCKETS),
|
|
12206
12286
|
exactHandoffEmitted: emptyCounterMap(EFFECTIVENESS_BOOLEAN_BUCKETS),
|
|
12207
|
-
scopeRelaxation: emptyCounterMap(EFFECTIVENESS_SCOPE_RELAXATION_BUCKETS)
|
|
12287
|
+
scopeRelaxation: emptyCounterMap(EFFECTIVENESS_SCOPE_RELAXATION_BUCKETS),
|
|
12288
|
+
routeOutcome: emptyRouteCounterMap(EFFECTIVENESS_TOOL_ROUTES, EFFECTIVENESS_OUTCOMES),
|
|
12289
|
+
routeLatency: emptyRouteCounterMap(EFFECTIVENESS_TOOL_ROUTES, EFFECTIVENESS_LATENCY_BUCKETS),
|
|
12290
|
+
routeResultCount: emptyRouteCounterMap(EFFECTIVENESS_TOOL_ROUTES, EFFECTIVENESS_RESULT_COUNT_BUCKETS),
|
|
12291
|
+
routeReturnedTokenEstimate: emptyRouteCounterMap(
|
|
12292
|
+
EFFECTIVENESS_TOOL_ROUTES,
|
|
12293
|
+
EFFECTIVENESS_RETURNED_TOKEN_BUCKETS
|
|
12294
|
+
)
|
|
12208
12295
|
};
|
|
12209
12296
|
}
|
|
12210
12297
|
increment(counters, key) {
|
|
@@ -12226,12 +12313,19 @@ var EffectivenessMetrics = class {
|
|
|
12226
12313
|
this.increment(this.snapshot.hostMode, host);
|
|
12227
12314
|
this.increment(this.snapshot.outcome, outcome);
|
|
12228
12315
|
this.increment(this.snapshot.recoveryUsed, recoveryUsed);
|
|
12229
|
-
|
|
12230
|
-
|
|
12316
|
+
const resultCountBucketValue = resultCountBucket(event.resultCount);
|
|
12317
|
+
const latencyBucketValue = latencyBucket(event.latencyMs);
|
|
12318
|
+
const returnedTokenBucketValue = returnedTokenBucket(event.returnedTokenEstimate);
|
|
12319
|
+
this.increment(this.snapshot.resultCount, resultCountBucketValue);
|
|
12320
|
+
this.increment(this.snapshot.latency, latencyBucketValue);
|
|
12231
12321
|
this.increment(this.snapshot.tokenBudget, tokenBudgetBucket(event.tokenBudget));
|
|
12232
|
-
this.increment(this.snapshot.returnedTokenEstimate,
|
|
12322
|
+
this.increment(this.snapshot.returnedTokenEstimate, returnedTokenBucketValue);
|
|
12233
12323
|
this.increment(this.snapshot.exactHandoffEmitted, exactHandoffEmitted);
|
|
12234
12324
|
this.increment(this.snapshot.scopeRelaxation, scopeRelaxation);
|
|
12325
|
+
this.increment(this.snapshot.routeOutcome[route], outcome);
|
|
12326
|
+
this.increment(this.snapshot.routeLatency[route], latencyBucketValue);
|
|
12327
|
+
this.increment(this.snapshot.routeResultCount[route], resultCountBucketValue);
|
|
12328
|
+
this.increment(this.snapshot.routeReturnedTokenEstimate[route], returnedTokenBucketValue);
|
|
12235
12329
|
}
|
|
12236
12330
|
getSnapshot() {
|
|
12237
12331
|
return {
|
|
@@ -12246,7 +12340,11 @@ var EffectivenessMetrics = class {
|
|
|
12246
12340
|
tokenBudget: cloneCounterMap(this.snapshot.tokenBudget),
|
|
12247
12341
|
returnedTokenEstimate: cloneCounterMap(this.snapshot.returnedTokenEstimate),
|
|
12248
12342
|
exactHandoffEmitted: cloneCounterMap(this.snapshot.exactHandoffEmitted),
|
|
12249
|
-
scopeRelaxation: cloneCounterMap(this.snapshot.scopeRelaxation)
|
|
12343
|
+
scopeRelaxation: cloneCounterMap(this.snapshot.scopeRelaxation),
|
|
12344
|
+
routeOutcome: cloneRouteCounterMap(this.snapshot.routeOutcome),
|
|
12345
|
+
routeLatency: cloneRouteCounterMap(this.snapshot.routeLatency),
|
|
12346
|
+
routeResultCount: cloneRouteCounterMap(this.snapshot.routeResultCount),
|
|
12347
|
+
routeReturnedTokenEstimate: cloneRouteCounterMap(this.snapshot.routeReturnedTokenEstimate)
|
|
12250
12348
|
};
|
|
12251
12349
|
}
|
|
12252
12350
|
reset() {
|
|
@@ -12265,6 +12363,7 @@ function resetProcessEffectivenessMetrics() {
|
|
|
12265
12363
|
}
|
|
12266
12364
|
function formatEffectivenessMetrics(snapshot) {
|
|
12267
12365
|
const formatCounters = (counters) => Object.entries(counters).map(([bucket, count]) => `${bucket}=${count}`).join(", ");
|
|
12366
|
+
const formatRouteCounters = (counters) => EFFECTIVENESS_TOOL_ROUTES.map((route) => `${route} => ${formatCounters(counters[route])}`).join("; ");
|
|
12268
12367
|
const lines = [
|
|
12269
12368
|
`Privacy-safe effectiveness (schema v${snapshot.schemaVersion}):`,
|
|
12270
12369
|
` Retention: ${snapshot.retention.storage}, ${snapshot.retention.lifetime}-lifetime; reset with index_metrics(reset=true) or process exit`,
|
|
@@ -12279,6 +12378,10 @@ function formatEffectivenessMetrics(snapshot) {
|
|
|
12279
12378
|
` Latency bucket: ${formatCounters(snapshot.latency)}`,
|
|
12280
12379
|
` Token-budget bucket: ${formatCounters(snapshot.tokenBudget)}`,
|
|
12281
12380
|
` Returned-token estimate: ${formatCounters(snapshot.returnedTokenEstimate)}`,
|
|
12381
|
+
` Route outcome buckets: ${formatRouteCounters(snapshot.routeOutcome)}`,
|
|
12382
|
+
` Route latency buckets: ${formatRouteCounters(snapshot.routeLatency)}`,
|
|
12383
|
+
` Route result-count buckets: ${formatRouteCounters(snapshot.routeResultCount)}`,
|
|
12384
|
+
` Route returned-token buckets: ${formatRouteCounters(snapshot.routeReturnedTokenEstimate)}`,
|
|
12282
12385
|
` Exact handoff emitted: ${formatCounters(snapshot.exactHandoffEmitted)}`,
|
|
12283
12386
|
` Scope relaxation: ${formatCounters(snapshot.scopeRelaxation)}`,
|
|
12284
12387
|
" Privacy: no queries, response text, source, symbols, paths, repository names, user identity, or stable identifiers are retained."
|
|
@@ -12290,6 +12393,103 @@ function formatEffectivenessMetrics(snapshot) {
|
|
|
12290
12393
|
var import_fs11 = require("fs");
|
|
12291
12394
|
var os6 = __toESM(require("os"), 1);
|
|
12292
12395
|
var path16 = __toESM(require("path"), 1);
|
|
12396
|
+
|
|
12397
|
+
// src/utils/power-source.ts
|
|
12398
|
+
var childProcess = __toESM(require("child_process"), 1);
|
|
12399
|
+
var POWER_SOURCE_RECHECK_DELAY_MS = 6e4;
|
|
12400
|
+
var PMSET_TIMEOUT_MS = 5e3;
|
|
12401
|
+
function getErrorMessage4(error) {
|
|
12402
|
+
return error instanceof Error ? error.message : String(error);
|
|
12403
|
+
}
|
|
12404
|
+
function runCommand(file, args, options) {
|
|
12405
|
+
return new Promise((resolve14, reject) => {
|
|
12406
|
+
childProcess.execFile(
|
|
12407
|
+
file,
|
|
12408
|
+
args,
|
|
12409
|
+
{ encoding: "utf8", timeout: options.timeoutMs },
|
|
12410
|
+
(error, stdout) => {
|
|
12411
|
+
if (error) {
|
|
12412
|
+
reject(error);
|
|
12413
|
+
return;
|
|
12414
|
+
}
|
|
12415
|
+
resolve14(stdout);
|
|
12416
|
+
}
|
|
12417
|
+
);
|
|
12418
|
+
});
|
|
12419
|
+
}
|
|
12420
|
+
function parseMacOsPowerSource(output) {
|
|
12421
|
+
const match = output.match(/Now drawing from '([^']+)'/i);
|
|
12422
|
+
if (!match) {
|
|
12423
|
+
return "unknown";
|
|
12424
|
+
}
|
|
12425
|
+
const source = match[1].toLowerCase();
|
|
12426
|
+
if (source === "battery power") {
|
|
12427
|
+
return "battery";
|
|
12428
|
+
}
|
|
12429
|
+
if (source === "ac power") {
|
|
12430
|
+
return "ac";
|
|
12431
|
+
}
|
|
12432
|
+
return "unknown";
|
|
12433
|
+
}
|
|
12434
|
+
async function readMacOsPowerSource(commandRunner = runCommand) {
|
|
12435
|
+
const output = await commandRunner(
|
|
12436
|
+
"/usr/bin/pmset",
|
|
12437
|
+
["-g", "batt"],
|
|
12438
|
+
{ timeoutMs: PMSET_TIMEOUT_MS }
|
|
12439
|
+
);
|
|
12440
|
+
return parseMacOsPowerSource(output);
|
|
12441
|
+
}
|
|
12442
|
+
var MacOsBackgroundIndexingPolicy = class {
|
|
12443
|
+
constructor(readPowerSource, recheckDelayMs) {
|
|
12444
|
+
this.readPowerSource = readPowerSource;
|
|
12445
|
+
this.recheckDelayMs = recheckDelayMs;
|
|
12446
|
+
}
|
|
12447
|
+
readPowerSource;
|
|
12448
|
+
recheckDelayMs;
|
|
12449
|
+
lastPaused = null;
|
|
12450
|
+
reportedFailure = false;
|
|
12451
|
+
isPaused() {
|
|
12452
|
+
return this.checkPowerSource();
|
|
12453
|
+
}
|
|
12454
|
+
async checkPowerSource() {
|
|
12455
|
+
try {
|
|
12456
|
+
const source = await this.readPowerSource();
|
|
12457
|
+
if (source === "unknown") {
|
|
12458
|
+
throw new Error("pmset returned an unrecognized power source");
|
|
12459
|
+
}
|
|
12460
|
+
this.reportedFailure = false;
|
|
12461
|
+
const paused = source === "battery";
|
|
12462
|
+
if (paused && this.lastPaused !== true) {
|
|
12463
|
+
console.warn("[codebase-index] Background indexing paused while macOS is using battery power.");
|
|
12464
|
+
} else if (!paused && this.lastPaused === true) {
|
|
12465
|
+
console.warn("[codebase-index] AC power detected; resuming pending background indexing.");
|
|
12466
|
+
}
|
|
12467
|
+
this.lastPaused = paused;
|
|
12468
|
+
return paused;
|
|
12469
|
+
} catch (error) {
|
|
12470
|
+
if (!this.reportedFailure) {
|
|
12471
|
+
console.error(
|
|
12472
|
+
`[codebase-index] Failed to determine the macOS power source; background indexing will continue: ${getErrorMessage4(error)}`
|
|
12473
|
+
);
|
|
12474
|
+
this.reportedFailure = true;
|
|
12475
|
+
}
|
|
12476
|
+
this.lastPaused = false;
|
|
12477
|
+
return false;
|
|
12478
|
+
}
|
|
12479
|
+
}
|
|
12480
|
+
};
|
|
12481
|
+
function createBackgroundIndexingPolicy(pauseOnBattery, options = {}) {
|
|
12482
|
+
const platform2 = options.platform ?? process.platform;
|
|
12483
|
+
if (!pauseOnBattery || platform2 !== "darwin") {
|
|
12484
|
+
return null;
|
|
12485
|
+
}
|
|
12486
|
+
return new MacOsBackgroundIndexingPolicy(
|
|
12487
|
+
options.readPowerSource ?? readMacOsPowerSource,
|
|
12488
|
+
options.recheckDelayMs ?? POWER_SOURCE_RECHECK_DELAY_MS
|
|
12489
|
+
);
|
|
12490
|
+
}
|
|
12491
|
+
|
|
12492
|
+
// src/utils/auto-index.ts
|
|
12293
12493
|
var MAX_RETRY_DELAY_MS = 1e4;
|
|
12294
12494
|
var SHUTDOWN_WAIT_MS = 2e3;
|
|
12295
12495
|
var coordinators = /* @__PURE__ */ new Map();
|
|
@@ -12406,7 +12606,13 @@ var AutoIndexCoordinator = class {
|
|
|
12406
12606
|
activation = Promise.resolve();
|
|
12407
12607
|
inFlight = null;
|
|
12408
12608
|
activeRequest = null;
|
|
12609
|
+
batteryCheck = null;
|
|
12610
|
+
batteryIndexJob = null;
|
|
12611
|
+
batteryDeferredRequest = null;
|
|
12612
|
+
batteryRetryTimer = null;
|
|
12613
|
+
resolveBatteryRetry = null;
|
|
12409
12614
|
pendingRequest = null;
|
|
12615
|
+
pendingFollowUp = null;
|
|
12410
12616
|
abortController = null;
|
|
12411
12617
|
stopped = false;
|
|
12412
12618
|
constructor(registration) {
|
|
@@ -12419,6 +12625,7 @@ var AutoIndexCoordinator = class {
|
|
|
12419
12625
|
};
|
|
12420
12626
|
}
|
|
12421
12627
|
update(registration) {
|
|
12628
|
+
const pauseOnBatteryChanged = registration.config.indexing.pauseBackgroundIndexingOnBattery !== this.registration.config.indexing.pauseBackgroundIndexingOnBattery;
|
|
12422
12629
|
this.registration = registration;
|
|
12423
12630
|
this.status.enabled = registration.config.indexing.autoIndex;
|
|
12424
12631
|
this.status.blockedReason = registration.blockedReason;
|
|
@@ -12434,6 +12641,9 @@ var AutoIndexCoordinator = class {
|
|
|
12434
12641
|
this.setState("idle", { source: void 0 });
|
|
12435
12642
|
}
|
|
12436
12643
|
}
|
|
12644
|
+
if (pauseOnBatteryChanged) {
|
|
12645
|
+
this.cancelBatteryRetry();
|
|
12646
|
+
}
|
|
12437
12647
|
}
|
|
12438
12648
|
activateAfter(activation) {
|
|
12439
12649
|
this.activation = activation;
|
|
@@ -12455,7 +12665,26 @@ var AutoIndexCoordinator = class {
|
|
|
12455
12665
|
if (this.stopped) {
|
|
12456
12666
|
return Promise.resolve({ outcome: "stopped" });
|
|
12457
12667
|
}
|
|
12458
|
-
return this.activation.then(() => this.
|
|
12668
|
+
return this.activation.then(() => this.enqueueBatteryAwareRequest(request));
|
|
12669
|
+
}
|
|
12670
|
+
enqueueBatteryAwareRequest(request) {
|
|
12671
|
+
if (!this.shouldDeferForBattery(request)) {
|
|
12672
|
+
return this.enqueueRequest(request);
|
|
12673
|
+
}
|
|
12674
|
+
if (this.batteryCheck && this.batteryIndexJob !== null && this.batteryIndexJob === this.inFlight) {
|
|
12675
|
+
return this.enqueueRequest(request);
|
|
12676
|
+
}
|
|
12677
|
+
this.batteryDeferredRequest = mergeRequests(this.batteryDeferredRequest, request);
|
|
12678
|
+
if (this.batteryCheck) {
|
|
12679
|
+
return this.batteryCheck;
|
|
12680
|
+
}
|
|
12681
|
+
const batteryCheck = this.waitForACPower();
|
|
12682
|
+
this.batteryCheck = batteryCheck;
|
|
12683
|
+
void batteryCheck.then(
|
|
12684
|
+
() => this.finishBatteryCheck(batteryCheck),
|
|
12685
|
+
() => this.finishBatteryCheck(batteryCheck)
|
|
12686
|
+
);
|
|
12687
|
+
return batteryCheck;
|
|
12459
12688
|
}
|
|
12460
12689
|
enqueueRequest(request) {
|
|
12461
12690
|
if (this.stopped || !this.canRun(request)) {
|
|
@@ -12473,6 +12702,11 @@ var AutoIndexCoordinator = class {
|
|
|
12473
12702
|
}
|
|
12474
12703
|
if (request.source === "watcher") {
|
|
12475
12704
|
this.pendingRequest = mergeRequests(this.pendingRequest, request);
|
|
12705
|
+
const active = this.inFlight;
|
|
12706
|
+
return active.then(() => {
|
|
12707
|
+
if (this.stopped) return { outcome: "stopped" };
|
|
12708
|
+
return this.pendingFollowUp ?? { outcome: "stopped" };
|
|
12709
|
+
});
|
|
12476
12710
|
}
|
|
12477
12711
|
return this.inFlight;
|
|
12478
12712
|
}
|
|
@@ -12489,6 +12723,8 @@ var AutoIndexCoordinator = class {
|
|
|
12489
12723
|
}
|
|
12490
12724
|
async stop(waitForCompletion = false) {
|
|
12491
12725
|
this.stopped = true;
|
|
12726
|
+
this.batteryDeferredRequest = null;
|
|
12727
|
+
this.cancelBatteryRetry();
|
|
12492
12728
|
this.pendingRequest = null;
|
|
12493
12729
|
this.abortController?.abort();
|
|
12494
12730
|
this.setState("stopped", {
|
|
@@ -12518,10 +12754,20 @@ var AutoIndexCoordinator = class {
|
|
|
12518
12754
|
this.inFlight = null;
|
|
12519
12755
|
this.activeRequest = null;
|
|
12520
12756
|
this.abortController = null;
|
|
12757
|
+
if (this.batteryIndexJob === job) {
|
|
12758
|
+
this.batteryIndexJob = null;
|
|
12759
|
+
this.batteryCheck = null;
|
|
12760
|
+
}
|
|
12521
12761
|
const pending = this.pendingRequest;
|
|
12522
12762
|
this.pendingRequest = null;
|
|
12523
12763
|
if (pending && !this.stopped) {
|
|
12524
|
-
this.
|
|
12764
|
+
const followUp = this.request(pending);
|
|
12765
|
+
this.pendingFollowUp = followUp;
|
|
12766
|
+
void followUp.then(() => {
|
|
12767
|
+
if (this.pendingFollowUp === followUp) {
|
|
12768
|
+
this.pendingFollowUp = null;
|
|
12769
|
+
}
|
|
12770
|
+
});
|
|
12525
12771
|
}
|
|
12526
12772
|
});
|
|
12527
12773
|
return job;
|
|
@@ -12685,6 +12931,68 @@ var AutoIndexCoordinator = class {
|
|
|
12685
12931
|
}
|
|
12686
12932
|
return this.registration.safeToRun && this.registration.config.indexing.autoIndex;
|
|
12687
12933
|
}
|
|
12934
|
+
shouldDeferForBattery(request) {
|
|
12935
|
+
return this.registration.backgroundIndexingPolicy !== null && (request.source === "startup" || request.source === "watcher");
|
|
12936
|
+
}
|
|
12937
|
+
async waitForACPower() {
|
|
12938
|
+
while (!this.stopped) {
|
|
12939
|
+
const policy = this.registration.backgroundIndexingPolicy;
|
|
12940
|
+
if (!policy || !await this.isBatteryPauseActive(policy)) {
|
|
12941
|
+
const request = this.batteryDeferredRequest;
|
|
12942
|
+
this.batteryDeferredRequest = null;
|
|
12943
|
+
if (!request) return { outcome: "stopped" };
|
|
12944
|
+
const job = this.enqueueRequest(request);
|
|
12945
|
+
if (this.inFlight === job) {
|
|
12946
|
+
this.batteryIndexJob = job;
|
|
12947
|
+
}
|
|
12948
|
+
return job;
|
|
12949
|
+
}
|
|
12950
|
+
await this.waitForBatteryRetry(policy.recheckDelayMs);
|
|
12951
|
+
}
|
|
12952
|
+
return { outcome: "stopped" };
|
|
12953
|
+
}
|
|
12954
|
+
async isBatteryPauseActive(policy) {
|
|
12955
|
+
try {
|
|
12956
|
+
return await policy.isPaused();
|
|
12957
|
+
} catch (error) {
|
|
12958
|
+
console.error(
|
|
12959
|
+
`[codebase-index] Failed to apply the background indexing power policy; background indexing will continue: ${safeFailureMessage(error)}`
|
|
12960
|
+
);
|
|
12961
|
+
return false;
|
|
12962
|
+
}
|
|
12963
|
+
}
|
|
12964
|
+
waitForBatteryRetry(delayMs) {
|
|
12965
|
+
return new Promise((resolve14) => {
|
|
12966
|
+
const timer = setTimeout(() => {
|
|
12967
|
+
if (this.batteryRetryTimer === timer) {
|
|
12968
|
+
this.batteryRetryTimer = null;
|
|
12969
|
+
this.resolveBatteryRetry = null;
|
|
12970
|
+
}
|
|
12971
|
+
resolve14();
|
|
12972
|
+
}, delayMs);
|
|
12973
|
+
timer.unref?.();
|
|
12974
|
+
this.batteryRetryTimer = timer;
|
|
12975
|
+
this.resolveBatteryRetry = resolve14;
|
|
12976
|
+
});
|
|
12977
|
+
}
|
|
12978
|
+
cancelBatteryRetry() {
|
|
12979
|
+
if (this.batteryRetryTimer) {
|
|
12980
|
+
clearTimeout(this.batteryRetryTimer);
|
|
12981
|
+
this.batteryRetryTimer = null;
|
|
12982
|
+
}
|
|
12983
|
+
const resolve14 = this.resolveBatteryRetry;
|
|
12984
|
+
this.resolveBatteryRetry = null;
|
|
12985
|
+
resolve14?.();
|
|
12986
|
+
}
|
|
12987
|
+
finishBatteryCheck(batteryCheck) {
|
|
12988
|
+
if (this.batteryCheck !== batteryCheck) return;
|
|
12989
|
+
this.batteryCheck = null;
|
|
12990
|
+
const deferredRequest = this.batteryDeferredRequest;
|
|
12991
|
+
this.batteryDeferredRequest = null;
|
|
12992
|
+
if (deferredRequest && !this.stopped) {
|
|
12993
|
+
void this.request(deferredRequest);
|
|
12994
|
+
}
|
|
12995
|
+
}
|
|
12688
12996
|
};
|
|
12689
12997
|
function getCoordinator(projectRoot, host) {
|
|
12690
12998
|
const key = coordinatorKeysByProject.get(projectLookupKey(projectRoot, host));
|
|
@@ -12694,6 +13002,9 @@ function configureAutoIndex(projectRoot, host, config, getIndexer) {
|
|
|
12694
13002
|
const projectKey = projectLookupKey(projectRoot, host);
|
|
12695
13003
|
const safety = getProjectSafety(projectRoot, config);
|
|
12696
13004
|
const registration = {
|
|
13005
|
+
backgroundIndexingPolicy: createBackgroundIndexingPolicy(
|
|
13006
|
+
config.indexing.pauseBackgroundIndexingOnBattery
|
|
13007
|
+
),
|
|
12697
13008
|
config,
|
|
12698
13009
|
getIndexer,
|
|
12699
13010
|
projectRoot,
|
|
@@ -15445,7 +15756,10 @@ function createWatcherWithIndexer(getIndexer, projectRoot, config, host = "openc
|
|
|
15445
15756
|
if (isGitRepo(projectRoot)) {
|
|
15446
15757
|
gitWatcher = new GitHeadWatcher(projectRoot);
|
|
15447
15758
|
gitWatcher.start(async (oldBranch, newBranch) => {
|
|
15448
|
-
|
|
15759
|
+
getIndexer().getLogger().branch("info", "Branch changed", {
|
|
15760
|
+
oldBranch,
|
|
15761
|
+
newBranch
|
|
15762
|
+
});
|
|
15449
15763
|
requestReindex();
|
|
15450
15764
|
});
|
|
15451
15765
|
}
|
|
@@ -15997,6 +16311,7 @@ Explicit symbol lookup only; conceptual search was not attempted.`
|
|
|
15997
16311
|
const results = await tryConceptualSearch(attempt.queryText, attempt.scope, attempt.relaxed);
|
|
15998
16312
|
if (results.length > 0) {
|
|
15999
16313
|
const heading = buildPackHeading("conceptual", decisions);
|
|
16314
|
+
const intent = analyzeQueryIntent(attempt.queryText);
|
|
16000
16315
|
return toResult(
|
|
16001
16316
|
"conceptual",
|
|
16002
16317
|
attempt.queryText,
|
|
@@ -16004,7 +16319,8 @@ Explicit symbol lookup only; conceptual search was not attempted.`
|
|
|
16004
16319
|
tokenBudget,
|
|
16005
16320
|
maxResults: limit,
|
|
16006
16321
|
heading,
|
|
16007
|
-
includeExactSearchHandoff: true
|
|
16322
|
+
includeExactSearchHandoff: true,
|
|
16323
|
+
preferImplementationPaths: intent.preferSourcePaths || intent.primary !== "docs" && intent.primary !== "test"
|
|
16008
16324
|
})
|
|
16009
16325
|
);
|
|
16010
16326
|
}
|
|
@@ -17294,6 +17610,21 @@ var CONCEPTUAL_DISCOVERY_HINTS = [
|
|
|
17294
17610
|
"pattern",
|
|
17295
17611
|
"code that"
|
|
17296
17612
|
];
|
|
17613
|
+
var BROAD_LOCAL_TASK_HINTS = [
|
|
17614
|
+
"fix the bug",
|
|
17615
|
+
"fix this",
|
|
17616
|
+
"fix issue",
|
|
17617
|
+
"implement ",
|
|
17618
|
+
"add support",
|
|
17619
|
+
"investigate ",
|
|
17620
|
+
"debug ",
|
|
17621
|
+
"refactor ",
|
|
17622
|
+
"review this",
|
|
17623
|
+
"review codebase",
|
|
17624
|
+
"review the codebase",
|
|
17625
|
+
"audit this",
|
|
17626
|
+
"audit the codebase"
|
|
17627
|
+
];
|
|
17297
17628
|
var DEFINITION_HINTS = [
|
|
17298
17629
|
"defined",
|
|
17299
17630
|
"definition",
|
|
@@ -17340,6 +17671,9 @@ function isExternalLookup(text) {
|
|
|
17340
17671
|
function hasConceptualDiscoveryHint(text) {
|
|
17341
17672
|
return includesHint(text, CONCEPTUAL_DISCOVERY_HINTS);
|
|
17342
17673
|
}
|
|
17674
|
+
function hasBroadLocalTaskHint(text) {
|
|
17675
|
+
return includesHint(text, BROAD_LOCAL_TASK_HINTS);
|
|
17676
|
+
}
|
|
17343
17677
|
function hasDefinitionHint(text) {
|
|
17344
17678
|
return includesHint(text, DEFINITION_HINTS);
|
|
17345
17679
|
}
|
|
@@ -17397,10 +17731,11 @@ function assessRoutingIntent(text) {
|
|
|
17397
17731
|
const matchedDefinitionHint = hasDefinitionHint(lowered);
|
|
17398
17732
|
const matchedExactMatchHint = hasExactMatchHint(lowered);
|
|
17399
17733
|
const matchedNonDiscoveryHint = hasNonDiscoveryHint(lowered);
|
|
17734
|
+
const matchedBroadLocalTask = hasBroadLocalTaskHint(lowered);
|
|
17400
17735
|
const hasIdentifier = hasIdentifierShape(normalizedText);
|
|
17401
17736
|
const hasQuotedIdentifier = containsQuotedIdentifier(normalizedText);
|
|
17402
17737
|
const shortQuery = countWords(lowered) <= 10;
|
|
17403
|
-
if (matchedNonDiscoveryHint && !matchedConceptualHint) {
|
|
17738
|
+
if (matchedNonDiscoveryHint && !matchedConceptualHint && !matchedBroadLocalTask) {
|
|
17404
17739
|
return {
|
|
17405
17740
|
intent: "other",
|
|
17406
17741
|
text: normalizedText,
|
|
@@ -17421,6 +17756,13 @@ function assessRoutingIntent(text) {
|
|
|
17421
17756
|
reason: "definition_lookup_request"
|
|
17422
17757
|
};
|
|
17423
17758
|
}
|
|
17759
|
+
if (matchedBroadLocalTask) {
|
|
17760
|
+
return {
|
|
17761
|
+
intent: "local_broad_task",
|
|
17762
|
+
text: normalizedText,
|
|
17763
|
+
reason: "broad_local_code_task"
|
|
17764
|
+
};
|
|
17765
|
+
}
|
|
17424
17766
|
if ((matchedExactMatchHint || hasQuotedIdentifier || hasIdentifier) && !matchedConceptualHint && shortQuery) {
|
|
17425
17767
|
return {
|
|
17426
17768
|
intent: "exact_identifier",
|
|
@@ -17448,15 +17790,15 @@ function buildRoutingHint(assessment, status, includeGraphHandoff = false) {
|
|
|
17448
17790
|
}
|
|
17449
17791
|
return "For this turn, prefer `implementation_lookup` to find the authoritative definition site. Use `codebase_search` only if no definition is found, and use `grep` for exhaustive literal matches.";
|
|
17450
17792
|
}
|
|
17451
|
-
if (assessment.intent !== "local_conceptual") {
|
|
17793
|
+
if (assessment.intent !== "local_conceptual" && assessment.intent !== "local_broad_task") {
|
|
17452
17794
|
return null;
|
|
17453
17795
|
}
|
|
17454
17796
|
if (!status || !status.indexed || status.compatibility?.compatible === false) {
|
|
17455
17797
|
const graphHandoff2 = includeGraphHandoff ? " Use graph tools after semantic discovery identifies relevant symbols." : "";
|
|
17456
|
-
return `For this turn, if local code discovery by behavior is needed, check \`index_status\` first and run \`index_codebase\` if the index is missing or incompatible.${graphHandoff2} Use \`grep\` for exact identifiers or exhaustive matches.`;
|
|
17798
|
+
return `For this turn, if local code discovery by behavior is needed, check \`index_status\` first and run \`index_codebase\` if the index is missing or incompatible.${graphHandoff2} Then use \`codebase_context\` as the first local repository lookup. Use \`grep\` for exact identifiers or exhaustive matches.`;
|
|
17457
17799
|
}
|
|
17458
17800
|
const graphHandoff = includeGraphHandoff ? " before graph tools such as `call_graph`, `call_graph_path`, `pr_impact`, or OMO CodeGraph" : "";
|
|
17459
|
-
return `For this turn, prefer \`
|
|
17801
|
+
return `For this turn, prefer \`codebase_context\` for local code discovery, then use \`codebase_peek\` for metadata and \`codebase_search\` when you need implementation content${graphHandoff}. Use \`grep\` for exact identifiers or exhaustive matches.`;
|
|
17460
17802
|
}
|
|
17461
17803
|
var RoutingHintController = class {
|
|
17462
17804
|
constructor(getStatus, maxSessions = 200, includeGraphHandoff = false) {
|
|
@@ -17473,7 +17815,7 @@ var RoutingHintController = class {
|
|
|
17473
17815
|
this.compactSessions();
|
|
17474
17816
|
this.sessionState.set(sessionID, {
|
|
17475
17817
|
assessment,
|
|
17476
|
-
pendingHint: assessment.intent === "local_conceptual" || assessment.intent === "definition_lookup",
|
|
17818
|
+
pendingHint: assessment.intent === "local_conceptual" || assessment.intent === "local_broad_task" || assessment.intent === "definition_lookup",
|
|
17477
17819
|
updatedAt: Date.now()
|
|
17478
17820
|
});
|
|
17479
17821
|
return assessment;
|
|
@@ -17488,6 +17830,9 @@ var RoutingHintController = class {
|
|
|
17488
17830
|
}
|
|
17489
17831
|
const status = await this.safeGetStatus();
|
|
17490
17832
|
const hint = buildRoutingHint(state.assessment, status, this.includeGraphHandoff);
|
|
17833
|
+
state.pendingHint = false;
|
|
17834
|
+
state.updatedAt = Date.now();
|
|
17835
|
+
this.sessionState.set(sessionID, state);
|
|
17491
17836
|
return hint ? [hint] : [];
|
|
17492
17837
|
}
|
|
17493
17838
|
markToolUsed(sessionID, toolName) {
|
|
@@ -17495,7 +17840,7 @@ var RoutingHintController = class {
|
|
|
17495
17840
|
if (!state || !state.pendingHint) {
|
|
17496
17841
|
return;
|
|
17497
17842
|
}
|
|
17498
|
-
if (toolName === "codebase_peek" || toolName === "codebase_search" || toolName === "implementation_lookup" || toolName === "index_status" || toolName === "index_codebase") {
|
|
17843
|
+
if (toolName === "codebase_context" || toolName === "codebase_peek" || toolName === "codebase_search" || toolName === "implementation_lookup" || toolName === "index_status" || toolName === "index_codebase") {
|
|
17499
17844
|
state.pendingHint = false;
|
|
17500
17845
|
state.updatedAt = Date.now();
|
|
17501
17846
|
this.sessionState.set(sessionID, state);
|