opencode-codebase-index 0.19.0 → 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 +766 -127
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +766 -127
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +408 -59
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +408 -59
- package/dist/index.js.map +1 -1
- package/dist/pi-extension.cjs +362 -51
- package/dist/pi-extension.cjs.map +1 -1
- package/dist/pi-extension.js +362 -51
- 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,
|
|
@@ -3496,9 +3498,7 @@ var PROJECT_MARKERS = [
|
|
|
3496
3498
|
"pom.xml",
|
|
3497
3499
|
"build.gradle",
|
|
3498
3500
|
"CMakeLists.txt",
|
|
3499
|
-
"Makefile"
|
|
3500
|
-
".opencode",
|
|
3501
|
-
".codebase-index"
|
|
3501
|
+
"Makefile"
|
|
3502
3502
|
];
|
|
3503
3503
|
function hasProjectMarker(projectRoot) {
|
|
3504
3504
|
for (const marker of PROJECT_MARKERS) {
|
|
@@ -4190,9 +4190,21 @@ function parseFiles(files) {
|
|
|
4190
4190
|
return result.map((f) => ({
|
|
4191
4191
|
path: f.path,
|
|
4192
4192
|
chunks: f.chunks.map(mapChunk),
|
|
4193
|
+
symbols: (f.symbols ?? []).map(mapParsedSymbol),
|
|
4193
4194
|
hash: f.hash
|
|
4194
4195
|
}));
|
|
4195
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
|
+
}
|
|
4196
4208
|
function mapChunk(c) {
|
|
4197
4209
|
return {
|
|
4198
4210
|
content: c.content,
|
|
@@ -6709,6 +6721,7 @@ var INDEX_METADATA_VERSION = "1";
|
|
|
6709
6721
|
var EMBEDDING_STRATEGY_VERSION = "2";
|
|
6710
6722
|
var SWIFT_PARSER_VERSION = "1";
|
|
6711
6723
|
var METAL_PARSER_VERSION = "1";
|
|
6724
|
+
var SYMBOL_EXTRACTOR_VERSION = "1";
|
|
6712
6725
|
var RANKING_TOKEN_CACHE_LIMIT = 4096;
|
|
6713
6726
|
var RANK_HYBRID_CACHE_LIMIT = 256;
|
|
6714
6727
|
function createPendingChunkStorageText(texts) {
|
|
@@ -7010,7 +7023,7 @@ function classifyQueryIntentRaw(query) {
|
|
|
7010
7023
|
return "neutral";
|
|
7011
7024
|
}
|
|
7012
7025
|
function isImplementationChunkType(chunkType) {
|
|
7013
|
-
return [
|
|
7026
|
+
return CALL_GRAPH_SYMBOL_CHUNK_TYPES.has(chunkType) || [
|
|
7014
7027
|
"export_statement",
|
|
7015
7028
|
"function",
|
|
7016
7029
|
"function_declaration",
|
|
@@ -7455,7 +7468,7 @@ function promoteIdentifierMatches(query, combined, semanticCandidates, keywordCa
|
|
|
7455
7468
|
const remainder = combined.filter((candidate) => !promotedIds.has(candidate.id));
|
|
7456
7469
|
return [...promoted, ...remainder];
|
|
7457
7470
|
}
|
|
7458
|
-
function buildSymbolDefinitionLane(query, database, branchChunkIds, limit, fallbackCandidates, prioritizeSourcePaths = classifyQueryIntentRaw(query) === "source") {
|
|
7471
|
+
function buildSymbolDefinitionLane(query, database, branchChunkIds, branchSymbolIds, limit, fallbackCandidates, prioritizeSourcePaths = classifyQueryIntentRaw(query) === "source") {
|
|
7459
7472
|
if (!prioritizeSourcePaths) {
|
|
7460
7473
|
return [];
|
|
7461
7474
|
}
|
|
@@ -7469,14 +7482,14 @@ function buildSymbolDefinitionLane(query, database, branchChunkIds, limit, fallb
|
|
|
7469
7482
|
const primaryHint = extractPrimaryIdentifierQueryHint(query);
|
|
7470
7483
|
const upsertChunkCandidate = (chunk, identifier, normalizedIdentifier, baseScore) => {
|
|
7471
7484
|
if (branchChunkIds && !branchChunkIds.has(chunk.chunkId)) {
|
|
7472
|
-
return;
|
|
7485
|
+
return false;
|
|
7473
7486
|
}
|
|
7474
7487
|
const chunkType = chunk.nodeType ?? "other";
|
|
7475
7488
|
if (!isImplementationChunkType(chunkType)) {
|
|
7476
|
-
return;
|
|
7489
|
+
return false;
|
|
7477
7490
|
}
|
|
7478
7491
|
if (!isLikelyImplementationPath2(chunk.filePath)) {
|
|
7479
|
-
return;
|
|
7492
|
+
return false;
|
|
7480
7493
|
}
|
|
7481
7494
|
const nameLower = (chunk.name ?? "").toLowerCase();
|
|
7482
7495
|
const exactName = nameLower === identifier || nameLower.replace(/_/g, "") === normalizedIdentifier;
|
|
@@ -7498,6 +7511,7 @@ function buildSymbolDefinitionLane(query, database, branchChunkIds, limit, fallb
|
|
|
7498
7511
|
}
|
|
7499
7512
|
});
|
|
7500
7513
|
}
|
|
7514
|
+
return true;
|
|
7501
7515
|
};
|
|
7502
7516
|
const normalizedHints = identifierHints.flatMap((hint) => [
|
|
7503
7517
|
hint,
|
|
@@ -7519,12 +7533,46 @@ function buildSymbolDefinitionLane(query, database, branchChunkIds, limit, fallb
|
|
|
7519
7533
|
dedupSymbols.set(symbol.id, symbol);
|
|
7520
7534
|
}
|
|
7521
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
|
+
}
|
|
7522
7542
|
const chunks = database.getChunksByFile(symbol.filePath);
|
|
7543
|
+
let foundCoveringChunk = false;
|
|
7523
7544
|
for (const chunk of chunks) {
|
|
7524
7545
|
if (chunk.startLine > symbol.startLine || chunk.endLine < symbol.endLine) {
|
|
7525
7546
|
continue;
|
|
7526
7547
|
}
|
|
7527
|
-
|
|
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
|
+
});
|
|
7528
7576
|
}
|
|
7529
7577
|
}
|
|
7530
7578
|
const dedupChunksByName = /* @__PURE__ */ new Map();
|
|
@@ -7532,6 +7580,9 @@ function buildSymbolDefinitionLane(query, database, branchChunkIds, limit, fallb
|
|
|
7532
7580
|
dedupChunksByName.set(chunk.chunkId, chunk);
|
|
7533
7581
|
}
|
|
7534
7582
|
for (const chunk of dedupChunksByName.values()) {
|
|
7583
|
+
if (filePathHint && !pathMatchesHint(chunk.filePath, filePathHint)) {
|
|
7584
|
+
continue;
|
|
7585
|
+
}
|
|
7535
7586
|
upsertChunkCandidate(chunk, identifier, normalizedIdentifier);
|
|
7536
7587
|
}
|
|
7537
7588
|
}
|
|
@@ -8073,6 +8124,10 @@ var Indexer = class _Indexer {
|
|
|
8073
8124
|
const projectHash = hashContent(path14.resolve(this.projectRoot)).slice(0, 16);
|
|
8074
8125
|
return `${key}.${projectHash}`;
|
|
8075
8126
|
}
|
|
8127
|
+
getSymbolExtractorVersionMetadataKey(catalogIdentity = this.getBranchCatalogIdentity()) {
|
|
8128
|
+
const branchKey = this.getBranchCatalogKeyFor(catalogIdentity);
|
|
8129
|
+
return `index.symbolExtractorVersion.${hashContent(branchKey).slice(0, 24)}`;
|
|
8130
|
+
}
|
|
8076
8131
|
hasProjectForceReembedPending() {
|
|
8077
8132
|
return this.config.scope === "global" && this.database?.getMetadata(this.getProjectForceReembedMetadataKey()) === "true";
|
|
8078
8133
|
}
|
|
@@ -9416,7 +9471,8 @@ var Indexer = class _Indexer {
|
|
|
9416
9471
|
}
|
|
9417
9472
|
const branchKey = this.getBranchCatalogKey();
|
|
9418
9473
|
const alreadyIndexed = database.getBranchChunkIds(branchKey).length > 0 && database.getBranchSymbolIds(branchKey).length > 0;
|
|
9419
|
-
|
|
9474
|
+
const symbolsCurrent = database.getMetadata(this.getSymbolExtractorVersionMetadataKey()) === SYMBOL_EXTRACTOR_VERSION;
|
|
9475
|
+
if (alreadyIndexed && symbolsCurrent && this.getStoredBranchCommit(database) === normalizedCommit) {
|
|
9420
9476
|
return { prepared: false };
|
|
9421
9477
|
}
|
|
9422
9478
|
const stats = await this.indexUnlocked(onProgress, [], true);
|
|
@@ -9475,6 +9531,8 @@ var Indexer = class _Indexer {
|
|
|
9475
9531
|
const reparseCachedSwiftFiles = database.getMetadata(swiftParserMetadataKey) !== SWIFT_PARSER_VERSION;
|
|
9476
9532
|
const metalParserMetadataKey = this.getMetalParserVersionMetadataKey();
|
|
9477
9533
|
const reparseCachedMetalFiles = database.getMetadata(metalParserMetadataKey) !== METAL_PARSER_VERSION;
|
|
9534
|
+
const symbolExtractorMetadataKey = this.getSymbolExtractorVersionMetadataKey();
|
|
9535
|
+
const refreshCachedSymbols = database.getMetadata(symbolExtractorMetadataKey) !== SYMBOL_EXTRACTOR_VERSION;
|
|
9478
9536
|
if (reparseCachedSwiftFiles && Array.from(this.fileHashCache.keys()).some(
|
|
9479
9537
|
(filePath) => path14.extname(filePath).toLowerCase() === ".swift"
|
|
9480
9538
|
)) {
|
|
@@ -9518,7 +9576,7 @@ var Indexer = class _Indexer {
|
|
|
9518
9576
|
);
|
|
9519
9577
|
const requiresSwiftParserUpgrade = reparseCachedSwiftFiles && path14.extname(canonicalPath).toLowerCase() === ".swift";
|
|
9520
9578
|
const requiresMetalParserUpgrade = reparseCachedMetalFiles && path14.extname(canonicalPath).toLowerCase() === ".metal";
|
|
9521
|
-
if (cachedHashMatches && !needsCallGraphRefresh && !requiresSwiftParserUpgrade && !requiresMetalParserUpgrade) {
|
|
9579
|
+
if (cachedHashMatches && !needsCallGraphRefresh && !requiresSwiftParserUpgrade && !requiresMetalParserUpgrade && !refreshCachedSymbols) {
|
|
9522
9580
|
unchangedFilePaths.add(canonicalPath);
|
|
9523
9581
|
this.logger.recordCacheHit();
|
|
9524
9582
|
} else {
|
|
@@ -9729,37 +9787,27 @@ var Indexer = class _Indexer {
|
|
|
9729
9787
|
const parsed = parsedFiles[i];
|
|
9730
9788
|
const changedFile = changedFiles[i];
|
|
9731
9789
|
const fileSymbols = [];
|
|
9732
|
-
for (const
|
|
9733
|
-
if (!
|
|
9734
|
-
const existingMetalSymbol = chunk.language === "metal" ? fileSymbols.find(
|
|
9735
|
-
(symbol2) => symbol2.name === chunk.name && symbol2.kind === chunk.chunkType && symbol2.startLine <= chunk.endLine && chunk.startLine <= symbol2.endLine
|
|
9736
|
-
) : void 0;
|
|
9737
|
-
if (existingMetalSymbol) {
|
|
9738
|
-
existingMetalSymbol.startLine = Math.min(existingMetalSymbol.startLine, chunk.startLine);
|
|
9739
|
-
existingMetalSymbol.endLine = Math.max(existingMetalSymbol.endLine, chunk.endLine);
|
|
9740
|
-
existingMetalSymbol.startCol = Math.min(existingMetalSymbol.startCol, chunk.startCol ?? 0);
|
|
9741
|
-
existingMetalSymbol.endCol = Math.max(existingMetalSymbol.endCol, chunk.endCol ?? 0);
|
|
9742
|
-
continue;
|
|
9743
|
-
}
|
|
9790
|
+
for (const parsedSymbol of parsed.symbols) {
|
|
9791
|
+
if (!CALL_GRAPH_SYMBOL_CHUNK_TYPES.has(parsedSymbol.kind)) continue;
|
|
9744
9792
|
const preparedNamespace = this.getPreparedBranchNamespace();
|
|
9745
9793
|
const symbolId = `sym_${hashContent(
|
|
9746
|
-
(preparedNamespace ? `${preparedNamespace}:` : "") + parsed.path + ":" +
|
|
9794
|
+
(preparedNamespace ? `${preparedNamespace}:` : "") + parsed.path + ":" + parsedSymbol.name + ":" + parsedSymbol.kind + ":" + parsedSymbol.startLine + ":" + parsedSymbol.startCol + ":" + changedFile.hash
|
|
9747
9795
|
).slice(0, 16)}`;
|
|
9748
9796
|
const symbol = {
|
|
9749
9797
|
id: symbolId,
|
|
9750
9798
|
filePath: parsed.path,
|
|
9751
|
-
name:
|
|
9752
|
-
kind:
|
|
9753
|
-
startLine:
|
|
9754
|
-
startCol:
|
|
9755
|
-
endLine:
|
|
9756
|
-
endCol:
|
|
9757
|
-
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
|
|
9758
9806
|
};
|
|
9759
9807
|
fileSymbols.push(symbol);
|
|
9760
9808
|
allSymbolIds.add(symbolId);
|
|
9761
9809
|
}
|
|
9762
|
-
const fileLanguage = parsed.chunks[0]?.language;
|
|
9810
|
+
const fileLanguage = parsed.symbols[0]?.language ?? parsed.chunks[0]?.language;
|
|
9763
9811
|
const isCaseInsensitiveLanguage = !!fileLanguage && CASE_INSENSITIVE_LANGUAGES.has(fileLanguage);
|
|
9764
9812
|
const normalizeSymbolKey = (name) => isCaseInsensitiveLanguage ? name.toLowerCase() : name;
|
|
9765
9813
|
const symbolsByName = /* @__PURE__ */ new Map();
|
|
@@ -9875,6 +9923,7 @@ var Indexer = class _Indexer {
|
|
|
9875
9923
|
}
|
|
9876
9924
|
database.setMetadata(swiftParserMetadataKey, SWIFT_PARSER_VERSION);
|
|
9877
9925
|
database.setMetadata(metalParserMetadataKey, METAL_PARSER_VERSION);
|
|
9926
|
+
database.setMetadata(symbolExtractorMetadataKey, SYMBOL_EXTRACTOR_VERSION);
|
|
9878
9927
|
this.saveBranchCommit(database, indexedCommit);
|
|
9879
9928
|
this.saveIndexMetadata(configuredProviderInfo);
|
|
9880
9929
|
this.indexCompatibility = { compatible: true };
|
|
@@ -9911,6 +9960,7 @@ var Indexer = class _Indexer {
|
|
|
9911
9960
|
}
|
|
9912
9961
|
database.setMetadata(swiftParserMetadataKey, SWIFT_PARSER_VERSION);
|
|
9913
9962
|
database.setMetadata(metalParserMetadataKey, METAL_PARSER_VERSION);
|
|
9963
|
+
database.setMetadata(symbolExtractorMetadataKey, SYMBOL_EXTRACTOR_VERSION);
|
|
9914
9964
|
this.saveBranchCommit(database, indexedCommit);
|
|
9915
9965
|
this.saveIndexMetadata(configuredProviderInfo);
|
|
9916
9966
|
this.indexCompatibility = { compatible: true };
|
|
@@ -10190,6 +10240,7 @@ var Indexer = class _Indexer {
|
|
|
10190
10240
|
}
|
|
10191
10241
|
database.setMetadata(swiftParserMetadataKey, SWIFT_PARSER_VERSION);
|
|
10192
10242
|
database.setMetadata(metalParserMetadataKey, METAL_PARSER_VERSION);
|
|
10243
|
+
database.setMetadata(symbolExtractorMetadataKey, SYMBOL_EXTRACTOR_VERSION);
|
|
10193
10244
|
this.saveBranchCommit(database, indexedCommit);
|
|
10194
10245
|
this.saveIndexMetadata(configuredProviderInfo);
|
|
10195
10246
|
this.indexCompatibility = { compatible: true };
|
|
@@ -10328,10 +10379,11 @@ var Indexer = class _Indexer {
|
|
|
10328
10379
|
const keywordResults = await this.keywordSearch(query, maxResults * 4, store, invertedIndex);
|
|
10329
10380
|
const keywordMs = import_perf_hooks.performance.now() - keywordStartTime;
|
|
10330
10381
|
let branchChunkIds = null;
|
|
10382
|
+
let branchSymbolIds = null;
|
|
10331
10383
|
if (filterByBranch && (this.config.scope === "global" || this.currentBranch !== "default")) {
|
|
10332
|
-
|
|
10333
|
-
|
|
10334
|
-
);
|
|
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)));
|
|
10335
10387
|
}
|
|
10336
10388
|
const prefilterStartTime = import_perf_hooks.performance.now();
|
|
10337
10389
|
const shouldPrefilterByBranch = branchChunkIds !== null && (this.config.scope === "global" || branchChunkIds.size > 0);
|
|
@@ -10403,6 +10455,7 @@ var Indexer = class _Indexer {
|
|
|
10403
10455
|
query,
|
|
10404
10456
|
database,
|
|
10405
10457
|
branchChunkIds,
|
|
10458
|
+
branchSymbolIds,
|
|
10406
10459
|
maxResults,
|
|
10407
10460
|
union,
|
|
10408
10461
|
sourceIntent
|
|
@@ -10416,7 +10469,7 @@ var Indexer = class _Indexer {
|
|
|
10416
10469
|
(r) => isLikelyImplementationPath2(r.metadata.filePath) && isImplementationChunkType(r.metadata.chunkType)
|
|
10417
10470
|
);
|
|
10418
10471
|
const filtered = (sourceIntent && hasCodeHints && implementationOnly.length > 0 ? implementationOnly : baseFiltered).slice(0, maxResults);
|
|
10419
|
-
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) : [];
|
|
10420
10473
|
const finalResults = filtered.length > 0 ? filtered : identifierFallback;
|
|
10421
10474
|
const totalSearchMs = import_perf_hooks.performance.now() - searchStartTime;
|
|
10422
10475
|
this.logger.recordSearch(totalSearchMs, {
|
|
@@ -10573,7 +10626,7 @@ var Indexer = class _Indexer {
|
|
|
10573
10626
|
const extension = path14.extname(filePath).toLowerCase();
|
|
10574
10627
|
return extension === ".php" || extension === ".c" || extension === ".cc" || extension === ".cpp" || extension === ".cxx";
|
|
10575
10628
|
});
|
|
10576
|
-
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) {
|
|
10577
10630
|
return { readable: true, current: false, reason: "migration-required" };
|
|
10578
10631
|
}
|
|
10579
10632
|
if (isGitRepo(this.materializedProjectRoot)) {
|
|
@@ -11281,7 +11334,10 @@ var Indexer = class _Indexer {
|
|
|
11281
11334
|
const requestedRef = opts.pr !== void 0 ? expectedCommit : headRefName ?? resolvedBranch;
|
|
11282
11335
|
const storedCommit = this.getStoredBranchCommit(database, catalogIdentity);
|
|
11283
11336
|
const catalogIdentityMatches = storedCommit === expectedCommit;
|
|
11284
|
-
|
|
11337
|
+
const symbolsCurrent = database.getMetadata(
|
|
11338
|
+
this.getSymbolExtractorVersionMetadataKey(catalogIdentity)
|
|
11339
|
+
) === SYMBOL_EXTRACTOR_VERSION;
|
|
11340
|
+
if (branchSymbols.length === 0 || !catalogIdentityMatches || !symbolsCurrent) {
|
|
11285
11341
|
if (!resolvedBranch || resolvedBranch === "default") {
|
|
11286
11342
|
throw new Error("Run index_codebase first to build the call graph and symbol index for this project.");
|
|
11287
11343
|
}
|
|
@@ -11623,8 +11679,17 @@ function fitTextToContextBudget(text, tokenBudget) {
|
|
|
11623
11679
|
function normalizedLineRange(result) {
|
|
11624
11680
|
return result.startLine <= result.endLine ? { start: result.startLine, end: result.endLine } : { start: result.endLine, end: result.startLine };
|
|
11625
11681
|
}
|
|
11626
|
-
function rankContextCandidates(results) {
|
|
11627
|
-
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
|
+
});
|
|
11628
11693
|
}
|
|
11629
11694
|
function deduplicateContextCandidates(candidates) {
|
|
11630
11695
|
const acceptedByFile = /* @__PURE__ */ new Map();
|
|
@@ -11713,7 +11778,12 @@ function buildContextPack(results, options = {}) {
|
|
|
11713
11778
|
const maxResults = Math.max(0, Math.floor(options.maxResults ?? results.length));
|
|
11714
11779
|
const includeExactSearchHandoff = options.includeExactSearchHandoff ?? false;
|
|
11715
11780
|
const candidateCount = results.length;
|
|
11716
|
-
const deduplicated = deduplicateContextCandidates(
|
|
11781
|
+
const deduplicated = deduplicateContextCandidates(
|
|
11782
|
+
rankContextCandidates(
|
|
11783
|
+
results,
|
|
11784
|
+
options.preferImplementationPaths ?? false
|
|
11785
|
+
)
|
|
11786
|
+
);
|
|
11717
11787
|
const diversified = diversifyContextCandidates(deduplicated);
|
|
11718
11788
|
const duplicateCount = candidateCount - deduplicated.length;
|
|
11719
11789
|
const selectable = diversified.slice(0, maxResults);
|
|
@@ -12085,7 +12155,7 @@ ${truncateContent(r.content)}
|
|
|
12085
12155
|
}
|
|
12086
12156
|
|
|
12087
12157
|
// src/utils/effectiveness-metrics.ts
|
|
12088
|
-
var EFFECTIVENESS_METRICS_SCHEMA_VERSION =
|
|
12158
|
+
var EFFECTIVENESS_METRICS_SCHEMA_VERSION = 3;
|
|
12089
12159
|
var MAX_EFFECTIVENESS_COUNTER = 1e9;
|
|
12090
12160
|
var EFFECTIVENESS_TOOL_ROUTES = [
|
|
12091
12161
|
"context-conceptual",
|
|
@@ -12131,6 +12201,9 @@ var EFFECTIVENESS_SCOPE_RELAXATION_BUCKETS = ["none", "directory", "file-type",
|
|
|
12131
12201
|
function emptyCounterMap(values) {
|
|
12132
12202
|
return Object.fromEntries(values.map((value) => [value, 0]));
|
|
12133
12203
|
}
|
|
12204
|
+
function emptyRouteCounterMap(routes, values) {
|
|
12205
|
+
return Object.fromEntries(routes.map((route) => [route, emptyCounterMap(values)]));
|
|
12206
|
+
}
|
|
12134
12207
|
function boundedNumber(value) {
|
|
12135
12208
|
if (value === void 0 || !Number.isFinite(value)) return 0;
|
|
12136
12209
|
return Math.max(0, Math.floor(value));
|
|
@@ -12179,6 +12252,11 @@ function allowedValue(value, allowed, fallback) {
|
|
|
12179
12252
|
function cloneCounterMap(counters) {
|
|
12180
12253
|
return { ...counters };
|
|
12181
12254
|
}
|
|
12255
|
+
function cloneRouteCounterMap(counters) {
|
|
12256
|
+
return Object.fromEntries(
|
|
12257
|
+
EFFECTIVENESS_TOOL_ROUTES.map((route) => [route, cloneCounterMap(counters[route])])
|
|
12258
|
+
);
|
|
12259
|
+
}
|
|
12182
12260
|
var EffectivenessMetrics = class {
|
|
12183
12261
|
constructor(counterCap = MAX_EFFECTIVENESS_COUNTER) {
|
|
12184
12262
|
this.counterCap = counterCap;
|
|
@@ -12194,7 +12272,7 @@ var EffectivenessMetrics = class {
|
|
|
12194
12272
|
lifetime: "process",
|
|
12195
12273
|
reset: "index_metrics-reset-or-process-exit",
|
|
12196
12274
|
maxCounterValue: this.counterCap,
|
|
12197
|
-
dimensions: "bounded-
|
|
12275
|
+
dimensions: "bounded-route-and-bucketed-performance-only"
|
|
12198
12276
|
},
|
|
12199
12277
|
totalCalls: 0,
|
|
12200
12278
|
toolRoute: emptyCounterMap(EFFECTIVENESS_TOOL_ROUTES),
|
|
@@ -12206,7 +12284,14 @@ var EffectivenessMetrics = class {
|
|
|
12206
12284
|
tokenBudget: emptyCounterMap(EFFECTIVENESS_TOKEN_BUDGET_BUCKETS),
|
|
12207
12285
|
returnedTokenEstimate: emptyCounterMap(EFFECTIVENESS_RETURNED_TOKEN_BUCKETS),
|
|
12208
12286
|
exactHandoffEmitted: emptyCounterMap(EFFECTIVENESS_BOOLEAN_BUCKETS),
|
|
12209
|
-
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
|
+
)
|
|
12210
12295
|
};
|
|
12211
12296
|
}
|
|
12212
12297
|
increment(counters, key) {
|
|
@@ -12228,12 +12313,19 @@ var EffectivenessMetrics = class {
|
|
|
12228
12313
|
this.increment(this.snapshot.hostMode, host);
|
|
12229
12314
|
this.increment(this.snapshot.outcome, outcome);
|
|
12230
12315
|
this.increment(this.snapshot.recoveryUsed, recoveryUsed);
|
|
12231
|
-
|
|
12232
|
-
|
|
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);
|
|
12233
12321
|
this.increment(this.snapshot.tokenBudget, tokenBudgetBucket(event.tokenBudget));
|
|
12234
|
-
this.increment(this.snapshot.returnedTokenEstimate,
|
|
12322
|
+
this.increment(this.snapshot.returnedTokenEstimate, returnedTokenBucketValue);
|
|
12235
12323
|
this.increment(this.snapshot.exactHandoffEmitted, exactHandoffEmitted);
|
|
12236
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);
|
|
12237
12329
|
}
|
|
12238
12330
|
getSnapshot() {
|
|
12239
12331
|
return {
|
|
@@ -12248,7 +12340,11 @@ var EffectivenessMetrics = class {
|
|
|
12248
12340
|
tokenBudget: cloneCounterMap(this.snapshot.tokenBudget),
|
|
12249
12341
|
returnedTokenEstimate: cloneCounterMap(this.snapshot.returnedTokenEstimate),
|
|
12250
12342
|
exactHandoffEmitted: cloneCounterMap(this.snapshot.exactHandoffEmitted),
|
|
12251
|
-
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)
|
|
12252
12348
|
};
|
|
12253
12349
|
}
|
|
12254
12350
|
reset() {
|
|
@@ -12267,6 +12363,7 @@ function resetProcessEffectivenessMetrics() {
|
|
|
12267
12363
|
}
|
|
12268
12364
|
function formatEffectivenessMetrics(snapshot) {
|
|
12269
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("; ");
|
|
12270
12367
|
const lines = [
|
|
12271
12368
|
`Privacy-safe effectiveness (schema v${snapshot.schemaVersion}):`,
|
|
12272
12369
|
` Retention: ${snapshot.retention.storage}, ${snapshot.retention.lifetime}-lifetime; reset with index_metrics(reset=true) or process exit`,
|
|
@@ -12281,6 +12378,10 @@ function formatEffectivenessMetrics(snapshot) {
|
|
|
12281
12378
|
` Latency bucket: ${formatCounters(snapshot.latency)}`,
|
|
12282
12379
|
` Token-budget bucket: ${formatCounters(snapshot.tokenBudget)}`,
|
|
12283
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)}`,
|
|
12284
12385
|
` Exact handoff emitted: ${formatCounters(snapshot.exactHandoffEmitted)}`,
|
|
12285
12386
|
` Scope relaxation: ${formatCounters(snapshot.scopeRelaxation)}`,
|
|
12286
12387
|
" Privacy: no queries, response text, source, symbols, paths, repository names, user identity, or stable identifiers are retained."
|
|
@@ -12292,6 +12393,103 @@ function formatEffectivenessMetrics(snapshot) {
|
|
|
12292
12393
|
var import_fs11 = require("fs");
|
|
12293
12394
|
var os6 = __toESM(require("os"), 1);
|
|
12294
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
|
|
12295
12493
|
var MAX_RETRY_DELAY_MS = 1e4;
|
|
12296
12494
|
var SHUTDOWN_WAIT_MS = 2e3;
|
|
12297
12495
|
var coordinators = /* @__PURE__ */ new Map();
|
|
@@ -12408,7 +12606,13 @@ var AutoIndexCoordinator = class {
|
|
|
12408
12606
|
activation = Promise.resolve();
|
|
12409
12607
|
inFlight = null;
|
|
12410
12608
|
activeRequest = null;
|
|
12609
|
+
batteryCheck = null;
|
|
12610
|
+
batteryIndexJob = null;
|
|
12611
|
+
batteryDeferredRequest = null;
|
|
12612
|
+
batteryRetryTimer = null;
|
|
12613
|
+
resolveBatteryRetry = null;
|
|
12411
12614
|
pendingRequest = null;
|
|
12615
|
+
pendingFollowUp = null;
|
|
12412
12616
|
abortController = null;
|
|
12413
12617
|
stopped = false;
|
|
12414
12618
|
constructor(registration) {
|
|
@@ -12421,6 +12625,7 @@ var AutoIndexCoordinator = class {
|
|
|
12421
12625
|
};
|
|
12422
12626
|
}
|
|
12423
12627
|
update(registration) {
|
|
12628
|
+
const pauseOnBatteryChanged = registration.config.indexing.pauseBackgroundIndexingOnBattery !== this.registration.config.indexing.pauseBackgroundIndexingOnBattery;
|
|
12424
12629
|
this.registration = registration;
|
|
12425
12630
|
this.status.enabled = registration.config.indexing.autoIndex;
|
|
12426
12631
|
this.status.blockedReason = registration.blockedReason;
|
|
@@ -12436,6 +12641,9 @@ var AutoIndexCoordinator = class {
|
|
|
12436
12641
|
this.setState("idle", { source: void 0 });
|
|
12437
12642
|
}
|
|
12438
12643
|
}
|
|
12644
|
+
if (pauseOnBatteryChanged) {
|
|
12645
|
+
this.cancelBatteryRetry();
|
|
12646
|
+
}
|
|
12439
12647
|
}
|
|
12440
12648
|
activateAfter(activation) {
|
|
12441
12649
|
this.activation = activation;
|
|
@@ -12457,7 +12665,26 @@ var AutoIndexCoordinator = class {
|
|
|
12457
12665
|
if (this.stopped) {
|
|
12458
12666
|
return Promise.resolve({ outcome: "stopped" });
|
|
12459
12667
|
}
|
|
12460
|
-
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;
|
|
12461
12688
|
}
|
|
12462
12689
|
enqueueRequest(request) {
|
|
12463
12690
|
if (this.stopped || !this.canRun(request)) {
|
|
@@ -12475,6 +12702,11 @@ var AutoIndexCoordinator = class {
|
|
|
12475
12702
|
}
|
|
12476
12703
|
if (request.source === "watcher") {
|
|
12477
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
|
+
});
|
|
12478
12710
|
}
|
|
12479
12711
|
return this.inFlight;
|
|
12480
12712
|
}
|
|
@@ -12491,6 +12723,8 @@ var AutoIndexCoordinator = class {
|
|
|
12491
12723
|
}
|
|
12492
12724
|
async stop(waitForCompletion = false) {
|
|
12493
12725
|
this.stopped = true;
|
|
12726
|
+
this.batteryDeferredRequest = null;
|
|
12727
|
+
this.cancelBatteryRetry();
|
|
12494
12728
|
this.pendingRequest = null;
|
|
12495
12729
|
this.abortController?.abort();
|
|
12496
12730
|
this.setState("stopped", {
|
|
@@ -12520,10 +12754,20 @@ var AutoIndexCoordinator = class {
|
|
|
12520
12754
|
this.inFlight = null;
|
|
12521
12755
|
this.activeRequest = null;
|
|
12522
12756
|
this.abortController = null;
|
|
12757
|
+
if (this.batteryIndexJob === job) {
|
|
12758
|
+
this.batteryIndexJob = null;
|
|
12759
|
+
this.batteryCheck = null;
|
|
12760
|
+
}
|
|
12523
12761
|
const pending = this.pendingRequest;
|
|
12524
12762
|
this.pendingRequest = null;
|
|
12525
12763
|
if (pending && !this.stopped) {
|
|
12526
|
-
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
|
+
});
|
|
12527
12771
|
}
|
|
12528
12772
|
});
|
|
12529
12773
|
return job;
|
|
@@ -12687,6 +12931,68 @@ var AutoIndexCoordinator = class {
|
|
|
12687
12931
|
}
|
|
12688
12932
|
return this.registration.safeToRun && this.registration.config.indexing.autoIndex;
|
|
12689
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
|
+
}
|
|
12690
12996
|
};
|
|
12691
12997
|
function getCoordinator(projectRoot, host) {
|
|
12692
12998
|
const key = coordinatorKeysByProject.get(projectLookupKey(projectRoot, host));
|
|
@@ -12696,6 +13002,9 @@ function configureAutoIndex(projectRoot, host, config, getIndexer) {
|
|
|
12696
13002
|
const projectKey = projectLookupKey(projectRoot, host);
|
|
12697
13003
|
const safety = getProjectSafety(projectRoot, config);
|
|
12698
13004
|
const registration = {
|
|
13005
|
+
backgroundIndexingPolicy: createBackgroundIndexingPolicy(
|
|
13006
|
+
config.indexing.pauseBackgroundIndexingOnBattery
|
|
13007
|
+
),
|
|
12699
13008
|
config,
|
|
12700
13009
|
getIndexer,
|
|
12701
13010
|
projectRoot,
|
|
@@ -15447,7 +15756,10 @@ function createWatcherWithIndexer(getIndexer, projectRoot, config, host = "openc
|
|
|
15447
15756
|
if (isGitRepo(projectRoot)) {
|
|
15448
15757
|
gitWatcher = new GitHeadWatcher(projectRoot);
|
|
15449
15758
|
gitWatcher.start(async (oldBranch, newBranch) => {
|
|
15450
|
-
|
|
15759
|
+
getIndexer().getLogger().branch("info", "Branch changed", {
|
|
15760
|
+
oldBranch,
|
|
15761
|
+
newBranch
|
|
15762
|
+
});
|
|
15451
15763
|
requestReindex();
|
|
15452
15764
|
});
|
|
15453
15765
|
}
|
|
@@ -15999,6 +16311,7 @@ Explicit symbol lookup only; conceptual search was not attempted.`
|
|
|
15999
16311
|
const results = await tryConceptualSearch(attempt.queryText, attempt.scope, attempt.relaxed);
|
|
16000
16312
|
if (results.length > 0) {
|
|
16001
16313
|
const heading = buildPackHeading("conceptual", decisions);
|
|
16314
|
+
const intent = analyzeQueryIntent(attempt.queryText);
|
|
16002
16315
|
return toResult(
|
|
16003
16316
|
"conceptual",
|
|
16004
16317
|
attempt.queryText,
|
|
@@ -16006,7 +16319,8 @@ Explicit symbol lookup only; conceptual search was not attempted.`
|
|
|
16006
16319
|
tokenBudget,
|
|
16007
16320
|
maxResults: limit,
|
|
16008
16321
|
heading,
|
|
16009
|
-
includeExactSearchHandoff: true
|
|
16322
|
+
includeExactSearchHandoff: true,
|
|
16323
|
+
preferImplementationPaths: intent.preferSourcePaths || intent.primary !== "docs" && intent.primary !== "test"
|
|
16010
16324
|
})
|
|
16011
16325
|
);
|
|
16012
16326
|
}
|
|
@@ -17296,6 +17610,21 @@ var CONCEPTUAL_DISCOVERY_HINTS = [
|
|
|
17296
17610
|
"pattern",
|
|
17297
17611
|
"code that"
|
|
17298
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
|
+
];
|
|
17299
17628
|
var DEFINITION_HINTS = [
|
|
17300
17629
|
"defined",
|
|
17301
17630
|
"definition",
|
|
@@ -17342,6 +17671,9 @@ function isExternalLookup(text) {
|
|
|
17342
17671
|
function hasConceptualDiscoveryHint(text) {
|
|
17343
17672
|
return includesHint(text, CONCEPTUAL_DISCOVERY_HINTS);
|
|
17344
17673
|
}
|
|
17674
|
+
function hasBroadLocalTaskHint(text) {
|
|
17675
|
+
return includesHint(text, BROAD_LOCAL_TASK_HINTS);
|
|
17676
|
+
}
|
|
17345
17677
|
function hasDefinitionHint(text) {
|
|
17346
17678
|
return includesHint(text, DEFINITION_HINTS);
|
|
17347
17679
|
}
|
|
@@ -17399,10 +17731,11 @@ function assessRoutingIntent(text) {
|
|
|
17399
17731
|
const matchedDefinitionHint = hasDefinitionHint(lowered);
|
|
17400
17732
|
const matchedExactMatchHint = hasExactMatchHint(lowered);
|
|
17401
17733
|
const matchedNonDiscoveryHint = hasNonDiscoveryHint(lowered);
|
|
17734
|
+
const matchedBroadLocalTask = hasBroadLocalTaskHint(lowered);
|
|
17402
17735
|
const hasIdentifier = hasIdentifierShape(normalizedText);
|
|
17403
17736
|
const hasQuotedIdentifier = containsQuotedIdentifier(normalizedText);
|
|
17404
17737
|
const shortQuery = countWords(lowered) <= 10;
|
|
17405
|
-
if (matchedNonDiscoveryHint && !matchedConceptualHint) {
|
|
17738
|
+
if (matchedNonDiscoveryHint && !matchedConceptualHint && !matchedBroadLocalTask) {
|
|
17406
17739
|
return {
|
|
17407
17740
|
intent: "other",
|
|
17408
17741
|
text: normalizedText,
|
|
@@ -17423,6 +17756,13 @@ function assessRoutingIntent(text) {
|
|
|
17423
17756
|
reason: "definition_lookup_request"
|
|
17424
17757
|
};
|
|
17425
17758
|
}
|
|
17759
|
+
if (matchedBroadLocalTask) {
|
|
17760
|
+
return {
|
|
17761
|
+
intent: "local_broad_task",
|
|
17762
|
+
text: normalizedText,
|
|
17763
|
+
reason: "broad_local_code_task"
|
|
17764
|
+
};
|
|
17765
|
+
}
|
|
17426
17766
|
if ((matchedExactMatchHint || hasQuotedIdentifier || hasIdentifier) && !matchedConceptualHint && shortQuery) {
|
|
17427
17767
|
return {
|
|
17428
17768
|
intent: "exact_identifier",
|
|
@@ -17450,15 +17790,15 @@ function buildRoutingHint(assessment, status, includeGraphHandoff = false) {
|
|
|
17450
17790
|
}
|
|
17451
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.";
|
|
17452
17792
|
}
|
|
17453
|
-
if (assessment.intent !== "local_conceptual") {
|
|
17793
|
+
if (assessment.intent !== "local_conceptual" && assessment.intent !== "local_broad_task") {
|
|
17454
17794
|
return null;
|
|
17455
17795
|
}
|
|
17456
17796
|
if (!status || !status.indexed || status.compatibility?.compatible === false) {
|
|
17457
17797
|
const graphHandoff2 = includeGraphHandoff ? " Use graph tools after semantic discovery identifies relevant symbols." : "";
|
|
17458
|
-
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.`;
|
|
17459
17799
|
}
|
|
17460
17800
|
const graphHandoff = includeGraphHandoff ? " before graph tools such as `call_graph`, `call_graph_path`, `pr_impact`, or OMO CodeGraph" : "";
|
|
17461
|
-
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.`;
|
|
17462
17802
|
}
|
|
17463
17803
|
var RoutingHintController = class {
|
|
17464
17804
|
constructor(getStatus, maxSessions = 200, includeGraphHandoff = false) {
|
|
@@ -17475,7 +17815,7 @@ var RoutingHintController = class {
|
|
|
17475
17815
|
this.compactSessions();
|
|
17476
17816
|
this.sessionState.set(sessionID, {
|
|
17477
17817
|
assessment,
|
|
17478
|
-
pendingHint: assessment.intent === "local_conceptual" || assessment.intent === "definition_lookup",
|
|
17818
|
+
pendingHint: assessment.intent === "local_conceptual" || assessment.intent === "local_broad_task" || assessment.intent === "definition_lookup",
|
|
17479
17819
|
updatedAt: Date.now()
|
|
17480
17820
|
});
|
|
17481
17821
|
return assessment;
|
|
@@ -17490,6 +17830,9 @@ var RoutingHintController = class {
|
|
|
17490
17830
|
}
|
|
17491
17831
|
const status = await this.safeGetStatus();
|
|
17492
17832
|
const hint = buildRoutingHint(state.assessment, status, this.includeGraphHandoff);
|
|
17833
|
+
state.pendingHint = false;
|
|
17834
|
+
state.updatedAt = Date.now();
|
|
17835
|
+
this.sessionState.set(sessionID, state);
|
|
17493
17836
|
return hint ? [hint] : [];
|
|
17494
17837
|
}
|
|
17495
17838
|
markToolUsed(sessionID, toolName) {
|
|
@@ -17497,7 +17840,7 @@ var RoutingHintController = class {
|
|
|
17497
17840
|
if (!state || !state.pendingHint) {
|
|
17498
17841
|
return;
|
|
17499
17842
|
}
|
|
17500
|
-
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") {
|
|
17501
17844
|
state.pendingHint = false;
|
|
17502
17845
|
state.updatedAt = Date.now();
|
|
17503
17846
|
this.sessionState.set(sessionID, state);
|
|
@@ -17554,9 +17897,15 @@ function appendRoutingHints(output, hints, preferredRole) {
|
|
|
17554
17897
|
output.system.push(...hints);
|
|
17555
17898
|
}
|
|
17556
17899
|
}
|
|
17900
|
+
function resolveProjectRoot(directory, worktree) {
|
|
17901
|
+
if (worktree && isGitRepo(worktree)) {
|
|
17902
|
+
return worktree;
|
|
17903
|
+
}
|
|
17904
|
+
return directory;
|
|
17905
|
+
}
|
|
17557
17906
|
var plugin = async ({ directory, worktree }) => {
|
|
17558
17907
|
try {
|
|
17559
|
-
const projectRoot = worktree
|
|
17908
|
+
const projectRoot = resolveProjectRoot(directory, worktree);
|
|
17560
17909
|
const rawConfig = loadMergedConfig(projectRoot);
|
|
17561
17910
|
const config = parseConfig(rawConfig);
|
|
17562
17911
|
initializeTools2(projectRoot, config);
|