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