opencode-codebase-index 0.22.3 → 0.22.5
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/dist/cli.cjs +681 -97
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +681 -97
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +455 -58
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +455 -58
- package/dist/index.js.map +1 -1
- package/dist/pi-extension.cjs +435 -51
- package/dist/pi-extension.cjs.map +1 -1
- package/dist/pi-extension.js +435 -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 +13 -9
package/dist/pi-extension.js
CHANGED
|
@@ -2041,6 +2041,9 @@ function findKnowledgeBasePathIndex(knowledgeBases, inputPath, projectRoot3) {
|
|
|
2041
2041
|
}
|
|
2042
2042
|
|
|
2043
2043
|
// src/tools/contracts.ts
|
|
2044
|
+
var MIN_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT = 1;
|
|
2045
|
+
var MAX_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT = 20;
|
|
2046
|
+
var DEFAULT_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT = 5;
|
|
2044
2047
|
var CODE_COMMUNITIES_MIN_SIZE = 1;
|
|
2045
2048
|
var CODE_COMMUNITIES_DEFAULT_LIMIT = 20;
|
|
2046
2049
|
var CODE_COMMUNITIES_MAX_LIMIT = 100;
|
|
@@ -2664,6 +2667,16 @@ function compactEvidenceValue(value, maxChars) {
|
|
|
2664
2667
|
}
|
|
2665
2668
|
var MAX_EXACT_SEARCH_HANDOFF_NAMES = 3;
|
|
2666
2669
|
var MAX_EXACT_SEARCH_HANDOFF_NAME_CHARS = 64;
|
|
2670
|
+
function toContextPackTraceCandidate(result) {
|
|
2671
|
+
return {
|
|
2672
|
+
filePath: result.filePath,
|
|
2673
|
+
startLine: result.startLine,
|
|
2674
|
+
endLine: result.endLine,
|
|
2675
|
+
score: result.score,
|
|
2676
|
+
chunkType: result.chunkType,
|
|
2677
|
+
name: result.name
|
|
2678
|
+
};
|
|
2679
|
+
}
|
|
2667
2680
|
function formatExactSearchHandoff(results) {
|
|
2668
2681
|
const suggestedNames = [];
|
|
2669
2682
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -2712,13 +2725,13 @@ function buildContextPack(results, options = {}) {
|
|
|
2712
2725
|
const maxResults = Math.max(0, Math.floor(options.maxResults ?? results.length));
|
|
2713
2726
|
const includeExactSearchHandoff = options.includeExactSearchHandoff ?? false;
|
|
2714
2727
|
const candidateCount = results.length;
|
|
2715
|
-
const
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
);
|
|
2721
|
-
const
|
|
2728
|
+
const preserveInputOrder = options.preserveInputOrder ?? false;
|
|
2729
|
+
const ranked = preserveInputOrder ? results.map((result, originalIndex) => ({ result, originalIndex })) : rankContextCandidates(results, options.preferImplementationPaths ?? false);
|
|
2730
|
+
const rankedCandidates = ranked.map((entry) => toContextPackTraceCandidate(entry.result));
|
|
2731
|
+
const deduplicated = deduplicateContextCandidates(ranked);
|
|
2732
|
+
const deduplicatedCandidates = deduplicated.map((result) => toContextPackTraceCandidate(result));
|
|
2733
|
+
const diversified = preserveInputOrder ? deduplicated : diversifyContextCandidates(deduplicated);
|
|
2734
|
+
const diversifiedCandidates = diversified.map((result) => toContextPackTraceCandidate(result));
|
|
2722
2735
|
const duplicateCount = candidateCount - deduplicated.length;
|
|
2723
2736
|
const selectable = diversified.slice(0, maxResults);
|
|
2724
2737
|
const limitOmittedCount = deduplicated.length - selectable.length;
|
|
@@ -2751,6 +2764,15 @@ function buildContextPack(results, options = {}) {
|
|
|
2751
2764
|
const fitted = fitTextToContextBudget(text3, tokenBudget);
|
|
2752
2765
|
const budgetOmittedCount = selectable.length - selected.length;
|
|
2753
2766
|
const omittedCount = candidateCount - selected.length;
|
|
2767
|
+
if (options.trace) {
|
|
2768
|
+
options.trace({
|
|
2769
|
+
inputCandidates: results.map(toContextPackTraceCandidate),
|
|
2770
|
+
rankedCandidates,
|
|
2771
|
+
deduplicatedCandidates,
|
|
2772
|
+
diversifiedCandidates,
|
|
2773
|
+
selectedCandidates: selected.map(toContextPackTraceCandidate)
|
|
2774
|
+
});
|
|
2775
|
+
}
|
|
2754
2776
|
return {
|
|
2755
2777
|
requestedTokenBudget,
|
|
2756
2778
|
tokenBudget,
|
|
@@ -8575,12 +8597,12 @@ function diversifyGroupBySymbol(entries, getCandidate) {
|
|
|
8575
8597
|
return [...primary, ...remainder];
|
|
8576
8598
|
}
|
|
8577
8599
|
function buildDiversityKey(metadata) {
|
|
8578
|
-
const
|
|
8600
|
+
const normalizedPath2 = metadata.filePath.toLowerCase();
|
|
8579
8601
|
const normalizedName = (metadata.name ?? "").trim().toLowerCase();
|
|
8580
8602
|
if (normalizedName.length > 0) {
|
|
8581
|
-
return `${
|
|
8603
|
+
return `${normalizedPath2}#${normalizedName}`;
|
|
8582
8604
|
}
|
|
8583
|
-
return
|
|
8605
|
+
return normalizedPath2;
|
|
8584
8606
|
}
|
|
8585
8607
|
function rankHybridResults(query, semanticResults, keywordResults, options) {
|
|
8586
8608
|
const prioritizeSourcePaths = options.prioritizeSourcePaths ?? classifyQueryIntentRaw(query) === "source";
|
|
@@ -8986,6 +9008,29 @@ function extractPrimaryIdentifierQueryHint(query) {
|
|
|
8986
9008
|
const best = codeTerms.find((term) => term.length >= 6);
|
|
8987
9009
|
return best ?? null;
|
|
8988
9010
|
}
|
|
9011
|
+
function pathSegmentsForAffinityMatch(filePath) {
|
|
9012
|
+
const normalizedPath2 = normalizeRankingText(filePath).replace(/\\/g, "/");
|
|
9013
|
+
const segments = normalizedPath2.split("/").filter((segment) => segment.length > 0);
|
|
9014
|
+
if (segments.length === 0) {
|
|
9015
|
+
return [];
|
|
9016
|
+
}
|
|
9017
|
+
const basename5 = segments[segments.length - 1] ?? "";
|
|
9018
|
+
const basenameWithoutExt = basename5.replace(/\.[^/.]+$/u, "");
|
|
9019
|
+
const normalizedSegments = segments.map((segment) => segment.toLowerCase());
|
|
9020
|
+
return Array.from(/* @__PURE__ */ new Set([
|
|
9021
|
+
...normalizedSegments,
|
|
9022
|
+
basenameWithoutExt.toLowerCase()
|
|
9023
|
+
]));
|
|
9024
|
+
}
|
|
9025
|
+
function hasModuleAffinity(filePath, exactIdentifierVariants) {
|
|
9026
|
+
const haystack = pathSegmentsForAffinityMatch(filePath);
|
|
9027
|
+
return exactIdentifierVariants.some((variant) => {
|
|
9028
|
+
if (!variant || variant.length < 2) {
|
|
9029
|
+
return false;
|
|
9030
|
+
}
|
|
9031
|
+
return haystack.includes(variant);
|
|
9032
|
+
});
|
|
9033
|
+
}
|
|
8989
9034
|
var FILE_PATH_HINT_EXTENSIONS = [
|
|
8990
9035
|
"ts",
|
|
8991
9036
|
"tsx",
|
|
@@ -9029,9 +9074,9 @@ function normalizeFilePathForHintMatch(filePath) {
|
|
|
9029
9074
|
return filePath.replace(/\\/g, "/").toLowerCase().replace(/^\.\//, "");
|
|
9030
9075
|
}
|
|
9031
9076
|
function pathMatchesHint(filePath, hint) {
|
|
9032
|
-
const
|
|
9077
|
+
const normalizedPath2 = normalizeFilePathForHintMatch(filePath);
|
|
9033
9078
|
const normalizedHint = normalizeFilePathForHintMatch(hint);
|
|
9034
|
-
return
|
|
9079
|
+
return normalizedPath2.endsWith(normalizedHint) || normalizedPath2.includes(`/${normalizedHint}`) || normalizedPath2.includes(normalizedHint);
|
|
9035
9080
|
}
|
|
9036
9081
|
function extractFilePathHint(query) {
|
|
9037
9082
|
const match = query.match(FILE_PATH_HINT_SUFFIX_REGEX);
|
|
@@ -9061,10 +9106,13 @@ function buildDeterministicIdentifierPass(query, candidates, limit, prioritizeSo
|
|
|
9061
9106
|
).map((candidate) => {
|
|
9062
9107
|
const nameLower = (candidate.metadata.name ?? "").toLowerCase();
|
|
9063
9108
|
const pathLower = candidate.metadata.filePath.toLowerCase();
|
|
9064
|
-
|
|
9065
|
-
const
|
|
9109
|
+
const exactIdentifierVariants = primaryVariants.filter((value) => value.length >= 2);
|
|
9110
|
+
const exactMatch = exactIdentifierVariants.some(
|
|
9066
9111
|
(variant) => nameLower === variant || nameLower.replace(/[^a-z0-9]/g, "") === variant.replace(/[^a-z0-9]/g, "")
|
|
9067
9112
|
);
|
|
9113
|
+
let maxMatch = 0;
|
|
9114
|
+
const nameMatchesPrimary = exactMatch;
|
|
9115
|
+
const pathAffinity = exactMatch ? hasModuleAffinity(candidate.metadata.filePath, exactIdentifierVariants) : false;
|
|
9068
9116
|
const pathMatchesFileHint = filePathHint ? pathMatchesHint(candidate.metadata.filePath, filePathHint) : false;
|
|
9069
9117
|
for (const hint of hints) {
|
|
9070
9118
|
const variants = normalizeIdentifierVariants(hint);
|
|
@@ -9085,12 +9133,17 @@ function buildDeterministicIdentifierPass(query, candidates, limit, prioritizeSo
|
|
|
9085
9133
|
candidate,
|
|
9086
9134
|
maxMatch,
|
|
9087
9135
|
pathMatchesFileHint,
|
|
9088
|
-
nameMatchesPrimary
|
|
9136
|
+
nameMatchesPrimary,
|
|
9137
|
+
pathAffinity
|
|
9089
9138
|
};
|
|
9090
9139
|
}).filter((entry) => entry.maxMatch >= 0.7).sort((a, b) => {
|
|
9091
9140
|
const aAnchored = a.pathMatchesFileHint && a.nameMatchesPrimary ? 1 : 0;
|
|
9092
9141
|
const bAnchored = b.pathMatchesFileHint && b.nameMatchesPrimary ? 1 : 0;
|
|
9093
9142
|
if (aAnchored !== bAnchored) return bAnchored - aAnchored;
|
|
9143
|
+
if (a.nameMatchesPrimary !== b.nameMatchesPrimary) {
|
|
9144
|
+
return b.nameMatchesPrimary ? 1 : -1;
|
|
9145
|
+
}
|
|
9146
|
+
if (a.pathAffinity !== b.pathAffinity) return b.pathAffinity ? 1 : -1;
|
|
9094
9147
|
if (b.maxMatch !== a.maxMatch) return b.maxMatch - a.maxMatch;
|
|
9095
9148
|
if (b.candidate.score !== a.candidate.score) return b.candidate.score - a.candidate.score;
|
|
9096
9149
|
return a.candidate.id.localeCompare(b.candidate.id);
|
|
@@ -12904,6 +12957,20 @@ var Indexer = class _Indexer {
|
|
|
12904
12957
|
requestedLimit = nextLimit;
|
|
12905
12958
|
}
|
|
12906
12959
|
}
|
|
12960
|
+
buildCandidateSnapshot(candidate) {
|
|
12961
|
+
return {
|
|
12962
|
+
id: candidate.id,
|
|
12963
|
+
filePath: candidate.metadata.filePath,
|
|
12964
|
+
startLine: candidate.metadata.startLine,
|
|
12965
|
+
endLine: candidate.metadata.endLine,
|
|
12966
|
+
score: candidate.score,
|
|
12967
|
+
chunkType: candidate.metadata.chunkType,
|
|
12968
|
+
name: candidate.metadata.name
|
|
12969
|
+
};
|
|
12970
|
+
}
|
|
12971
|
+
buildCandidateSnapshotList(candidates) {
|
|
12972
|
+
return candidates.map((candidate) => this.buildCandidateSnapshot(candidate));
|
|
12973
|
+
}
|
|
12907
12974
|
searchSemanticCandidates(store, embedding, initialLimit, branchChunkIds, shouldPrefilterByBranch) {
|
|
12908
12975
|
return this.searchCandidatesWithBranchPrefilter(
|
|
12909
12976
|
initialLimit,
|
|
@@ -13095,6 +13162,16 @@ var Indexer = class _Indexer {
|
|
|
13095
13162
|
prefilterMs: Math.round(prefilterMs * 100) / 100,
|
|
13096
13163
|
fusionMs: Math.round(fusionMs * 100) / 100
|
|
13097
13164
|
});
|
|
13165
|
+
if (options?.trace) {
|
|
13166
|
+
options.trace({
|
|
13167
|
+
semanticCandidates: this.buildCandidateSnapshotList(scopedSemanticCandidates),
|
|
13168
|
+
keywordCandidates: this.buildCandidateSnapshotList(scopedKeywordCandidates),
|
|
13169
|
+
hybridCandidates: this.buildCandidateSnapshotList(combined),
|
|
13170
|
+
postExternalRerankCandidates: this.buildCandidateSnapshotList(rerankedCombined),
|
|
13171
|
+
tieredCandidates: this.buildCandidateSnapshotList(tiered),
|
|
13172
|
+
finalCandidates: this.buildCandidateSnapshotList(finalResults)
|
|
13173
|
+
});
|
|
13174
|
+
}
|
|
13098
13175
|
const metadataOnly = options?.metadataOnly ?? false;
|
|
13099
13176
|
return Promise.all(
|
|
13100
13177
|
finalResults.map(async (r) => {
|
|
@@ -14355,7 +14432,8 @@ async function searchCodebase(projectRoot3, host, query, options = {}) {
|
|
|
14355
14432
|
definitionIntent: options.definitionIntent,
|
|
14356
14433
|
blameAuthor: options.blameAuthor,
|
|
14357
14434
|
blameSha: options.blameSha,
|
|
14358
|
-
blameSince: options.blameSince
|
|
14435
|
+
blameSince: options.blameSince,
|
|
14436
|
+
trace: options.trace
|
|
14359
14437
|
});
|
|
14360
14438
|
}
|
|
14361
14439
|
async function searchCodebaseWithEffectiveness(projectRoot3, host, route, query, options, render) {
|
|
@@ -14409,15 +14487,19 @@ async function implementationLookup(projectRoot3, host, query, options = {}) {
|
|
|
14409
14487
|
return indexer.search(query, options.limit, {
|
|
14410
14488
|
fileType: options.fileType,
|
|
14411
14489
|
directory: options.directory,
|
|
14412
|
-
definitionIntent: true
|
|
14490
|
+
definitionIntent: true,
|
|
14491
|
+
trace: options.trace
|
|
14413
14492
|
});
|
|
14414
14493
|
}
|
|
14415
14494
|
async function getCallGraphData(projectRoot3, host, params) {
|
|
14416
14495
|
await ensureAutoIndexReadyForRetrieval(projectRoot3, host);
|
|
14417
14496
|
const root = getProjectRoot(projectRoot3, host);
|
|
14418
14497
|
const indexer = getIndexerForProject(root, host);
|
|
14498
|
+
return getCallGraphDataForIndexer(indexer, root, params);
|
|
14499
|
+
}
|
|
14500
|
+
async function getCallGraphDataForIndexer(indexer, projectRoot3, params) {
|
|
14419
14501
|
const symbols = await indexer.getCallGraphSymbols();
|
|
14420
|
-
const resolution = resolveCallGraphSymbol(symbols,
|
|
14502
|
+
const resolution = resolveCallGraphSymbol(symbols, projectRoot3, params.name, params.filePath, params.symbolId);
|
|
14421
14503
|
const direction = params.direction === "callees" ? "callees" : "callers";
|
|
14422
14504
|
if (resolution.status !== "resolved") {
|
|
14423
14505
|
return { direction, resolution, callers: [], callees: [], relationshipType: params.relationshipType };
|
|
@@ -14645,17 +14727,17 @@ async function getIndexLogs(projectRoot3, host, args) {
|
|
|
14645
14727
|
function addKnowledgeBase(projectRoot3, host, knowledgeBasePath) {
|
|
14646
14728
|
const root = getProjectRoot(projectRoot3, host);
|
|
14647
14729
|
const inputPath = knowledgeBasePath.trim();
|
|
14648
|
-
const
|
|
14730
|
+
const normalizedPath2 = path20.resolve(
|
|
14649
14731
|
path20.isAbsolute(inputPath) ? inputPath : resolveKnowledgeBasePath(inputPath, root)
|
|
14650
14732
|
);
|
|
14651
|
-
if (!existsSync12(
|
|
14652
|
-
return `Error: Directory does not exist: ${
|
|
14733
|
+
if (!existsSync12(normalizedPath2)) {
|
|
14734
|
+
return `Error: Directory does not exist: ${normalizedPath2}`;
|
|
14653
14735
|
}
|
|
14654
14736
|
let realPath;
|
|
14655
14737
|
try {
|
|
14656
|
-
realPath = realpathSync5(
|
|
14738
|
+
realPath = realpathSync5(normalizedPath2);
|
|
14657
14739
|
} catch {
|
|
14658
|
-
return `Error: Cannot resolve path: ${
|
|
14740
|
+
return `Error: Cannot resolve path: ${normalizedPath2}`;
|
|
14659
14741
|
}
|
|
14660
14742
|
const blockedPrefixes = [
|
|
14661
14743
|
"/etc",
|
|
@@ -14678,34 +14760,34 @@ function addKnowledgeBase(projectRoot3, host, knowledgeBasePath) {
|
|
|
14678
14760
|
];
|
|
14679
14761
|
for (const prefix of blockedPrefixes) {
|
|
14680
14762
|
if (realPath === prefix || realPath.startsWith(`${prefix}/`)) {
|
|
14681
|
-
return `Error: Adding sensitive directory as knowledge base is not allowed: ${
|
|
14763
|
+
return `Error: Adding sensitive directory as knowledge base is not allowed: ${normalizedPath2}`;
|
|
14682
14764
|
}
|
|
14683
14765
|
}
|
|
14684
14766
|
for (const dotDir of sensitiveDotDirs) {
|
|
14685
14767
|
const sensitiveDir = path20.join(homeDir, dotDir);
|
|
14686
14768
|
if (sensitiveDir && (realPath === sensitiveDir || realPath.startsWith(`${sensitiveDir}/`))) {
|
|
14687
|
-
return `Error: Adding sensitive directory as knowledge base is not allowed: ${
|
|
14769
|
+
return `Error: Adding sensitive directory as knowledge base is not allowed: ${normalizedPath2}`;
|
|
14688
14770
|
}
|
|
14689
14771
|
}
|
|
14690
14772
|
try {
|
|
14691
|
-
const stat = statSync5(
|
|
14773
|
+
const stat = statSync5(normalizedPath2);
|
|
14692
14774
|
if (!stat.isDirectory()) {
|
|
14693
|
-
return `Error: Path is not a directory: ${
|
|
14775
|
+
return `Error: Path is not a directory: ${normalizedPath2}`;
|
|
14694
14776
|
}
|
|
14695
14777
|
} catch (error) {
|
|
14696
|
-
return `Error: Cannot access directory: ${
|
|
14778
|
+
return `Error: Cannot access directory: ${normalizedPath2} - ${error instanceof Error ? error.message : String(error)}`;
|
|
14697
14779
|
}
|
|
14698
14780
|
const config = loadEditableConfig(root, host);
|
|
14699
14781
|
const knowledgeBases = Array.isArray(config.knowledgeBases) ? config.knowledgeBases : [];
|
|
14700
|
-
const alreadyExists = hasMatchingKnowledgeBasePath(knowledgeBases,
|
|
14782
|
+
const alreadyExists = hasMatchingKnowledgeBasePath(knowledgeBases, normalizedPath2, root);
|
|
14701
14783
|
if (alreadyExists) {
|
|
14702
|
-
return `Knowledge base already configured: ${
|
|
14784
|
+
return `Knowledge base already configured: ${normalizedPath2}`;
|
|
14703
14785
|
}
|
|
14704
|
-
knowledgeBases.push(
|
|
14786
|
+
knowledgeBases.push(normalizedPath2);
|
|
14705
14787
|
config.knowledgeBases = knowledgeBases;
|
|
14706
14788
|
saveConfig(root, config, host);
|
|
14707
14789
|
refreshIndexerForDirectory(root, host);
|
|
14708
|
-
let result = `${
|
|
14790
|
+
let result = `${normalizedPath2}
|
|
14709
14791
|
`;
|
|
14710
14792
|
result += `Total knowledge bases: ${knowledgeBases.length}
|
|
14711
14793
|
`;
|
|
@@ -14880,6 +14962,27 @@ function buildRecoveryDetails(attempts, successIndex) {
|
|
|
14880
14962
|
successfulAttemptIndex: successIndex
|
|
14881
14963
|
};
|
|
14882
14964
|
}
|
|
14965
|
+
function serializeAttempts(attempts) {
|
|
14966
|
+
return attempts.map((attempt) => ({
|
|
14967
|
+
kind: attempt.kind,
|
|
14968
|
+
scope: attempt.scope,
|
|
14969
|
+
resultCount: attempt.resultCount,
|
|
14970
|
+
relaxedFields: attempt.relaxedFields
|
|
14971
|
+
}));
|
|
14972
|
+
}
|
|
14973
|
+
function buildSearchDiagnostic(attempt) {
|
|
14974
|
+
if (!attempt) {
|
|
14975
|
+
return void 0;
|
|
14976
|
+
}
|
|
14977
|
+
return {
|
|
14978
|
+
route: attempt.kind,
|
|
14979
|
+
routedQuery: attempt.query,
|
|
14980
|
+
searchQuery: attempt.query,
|
|
14981
|
+
searchScope: attempt.scopeFilter,
|
|
14982
|
+
searchTrace: attempt.searchTrace,
|
|
14983
|
+
contextPackTrace: attempt.contextPackTrace
|
|
14984
|
+
};
|
|
14985
|
+
}
|
|
14883
14986
|
function trimOrUndefined2(value) {
|
|
14884
14987
|
const normalized = value?.trim();
|
|
14885
14988
|
if (!normalized) {
|
|
@@ -14919,6 +15022,7 @@ async function resolveSearchContext(input, operations) {
|
|
|
14919
15022
|
const hasFilters = Boolean(fileType || directory);
|
|
14920
15023
|
const relaxedFields = relaxedHintFields(fileType, directory);
|
|
14921
15024
|
const attempts = [];
|
|
15025
|
+
const attemptStates = [];
|
|
14922
15026
|
const decisions = {
|
|
14923
15027
|
inferredDefinitionMiss: false,
|
|
14924
15028
|
fallbackFromOriginalConceptualToInferred: false,
|
|
@@ -14947,8 +15051,20 @@ async function resolveSearchContext(input, operations) {
|
|
|
14947
15051
|
if (seenAttempts.has(key)) {
|
|
14948
15052
|
return [];
|
|
14949
15053
|
}
|
|
14950
|
-
const
|
|
15054
|
+
const attemptState = {
|
|
15055
|
+
kind,
|
|
15056
|
+
scope: describeScope(scope.fileType, scope.directory),
|
|
15057
|
+
resultCount: 0,
|
|
15058
|
+
relaxedFields: [...relaxedFieldsForAttempt],
|
|
15059
|
+
query: attemptQuery,
|
|
15060
|
+
scopeFilter: scope
|
|
15061
|
+
};
|
|
15062
|
+
const results = await runAttempt((trace) => {
|
|
15063
|
+
attemptState.searchTrace = trace;
|
|
15064
|
+
});
|
|
15065
|
+
attemptState.resultCount = results.length;
|
|
14951
15066
|
seenAttempts.add(key);
|
|
15067
|
+
attemptStates.push(attemptState);
|
|
14952
15068
|
attempts.push({
|
|
14953
15069
|
kind,
|
|
14954
15070
|
scope: describeScope(scope.fileType, scope.directory),
|
|
@@ -14968,7 +15084,7 @@ async function resolveSearchContext(input, operations) {
|
|
|
14968
15084
|
symbol,
|
|
14969
15085
|
scope,
|
|
14970
15086
|
relaxedFieldsForAttempt,
|
|
14971
|
-
() => operations.lookup(symbol, MAX_CONTEXT_RESULT_LIMIT, scope)
|
|
15087
|
+
(trace) => operations.lookup(symbol, MAX_CONTEXT_RESULT_LIMIT, scope, input.diagnostic ? trace : void 0)
|
|
14972
15088
|
);
|
|
14973
15089
|
};
|
|
14974
15090
|
const tryConceptualSearch = async (searchQuery, scope, relaxedFieldsForAttempt) => {
|
|
@@ -14977,13 +15093,23 @@ async function resolveSearchContext(input, operations) {
|
|
|
14977
15093
|
searchQuery,
|
|
14978
15094
|
scope,
|
|
14979
15095
|
relaxedFieldsForAttempt,
|
|
14980
|
-
() => operations.search(searchQuery, MAX_CONTEXT_RESULT_LIMIT, scope)
|
|
15096
|
+
(trace) => operations.search(searchQuery, MAX_CONTEXT_RESULT_LIMIT, scope, input.diagnostic ? trace : void 0)
|
|
14981
15097
|
);
|
|
14982
15098
|
};
|
|
14983
|
-
const
|
|
15099
|
+
const findSuccessfulAttemptState = (route) => {
|
|
15100
|
+
for (let index = attemptStates.length - 1; index >= 0; index -= 1) {
|
|
15101
|
+
const attempt = attemptStates[index];
|
|
15102
|
+
if (attempt.kind === route && attempt.resultCount > 0) {
|
|
15103
|
+
return attempt;
|
|
15104
|
+
}
|
|
15105
|
+
}
|
|
15106
|
+
return void 0;
|
|
15107
|
+
};
|
|
15108
|
+
const toResult = (route, routedQuery, pack, successfulAttempt) => {
|
|
14984
15109
|
const base = packedResult(route, routedQuery, pack);
|
|
14985
15110
|
const baseDetails = base.details;
|
|
14986
15111
|
const successIndex = findSuccessfulAttemptIndex(route, attempts);
|
|
15112
|
+
const successState = successfulAttempt ?? findSuccessfulAttemptState(route);
|
|
14987
15113
|
return {
|
|
14988
15114
|
text: base.text,
|
|
14989
15115
|
details: {
|
|
@@ -14991,7 +15117,10 @@ async function resolveSearchContext(input, operations) {
|
|
|
14991
15117
|
tokenBudget: baseDetails.tokenBudget,
|
|
14992
15118
|
tokenEstimate: baseDetails.tokenEstimate,
|
|
14993
15119
|
truncated: false,
|
|
14994
|
-
recovery: buildRecoveryDetails(
|
|
15120
|
+
recovery: buildRecoveryDetails(serializeAttempts(attemptStates), successIndex),
|
|
15121
|
+
...input.diagnostic && {
|
|
15122
|
+
diagnostic: buildSearchDiagnostic(successState)
|
|
15123
|
+
}
|
|
14995
15124
|
}
|
|
14996
15125
|
};
|
|
14997
15126
|
};
|
|
@@ -15005,8 +15134,18 @@ async function resolveSearchContext(input, operations) {
|
|
|
15005
15134
|
buildContextPack(scopedDefinitionResults, {
|
|
15006
15135
|
tokenBudget,
|
|
15007
15136
|
maxResults: limit,
|
|
15008
|
-
heading
|
|
15009
|
-
|
|
15137
|
+
heading,
|
|
15138
|
+
preserveInputOrder: true,
|
|
15139
|
+
...input.diagnostic ? {
|
|
15140
|
+
trace: (trace) => {
|
|
15141
|
+
const attemptState = findSuccessfulAttemptState("definition");
|
|
15142
|
+
if (attemptState) {
|
|
15143
|
+
attemptState.contextPackTrace = trace;
|
|
15144
|
+
}
|
|
15145
|
+
}
|
|
15146
|
+
} : void 0
|
|
15147
|
+
}),
|
|
15148
|
+
findSuccessfulAttemptState("definition")
|
|
15010
15149
|
);
|
|
15011
15150
|
}
|
|
15012
15151
|
if (explicitSymbol) {
|
|
@@ -15024,8 +15163,18 @@ async function resolveSearchContext(input, operations) {
|
|
|
15024
15163
|
buildContextPack(unscopedDefinitionResults, {
|
|
15025
15164
|
tokenBudget,
|
|
15026
15165
|
maxResults: limit,
|
|
15027
|
-
heading: heading2
|
|
15028
|
-
|
|
15166
|
+
heading: heading2,
|
|
15167
|
+
preserveInputOrder: true,
|
|
15168
|
+
...input.diagnostic ? {
|
|
15169
|
+
trace: (trace) => {
|
|
15170
|
+
const attemptState = findSuccessfulAttemptState("definition");
|
|
15171
|
+
if (attemptState) {
|
|
15172
|
+
attemptState.contextPackTrace = trace;
|
|
15173
|
+
}
|
|
15174
|
+
}
|
|
15175
|
+
} : void 0
|
|
15176
|
+
}),
|
|
15177
|
+
findSuccessfulAttemptState("definition")
|
|
15029
15178
|
);
|
|
15030
15179
|
}
|
|
15031
15180
|
}
|
|
@@ -15044,7 +15193,10 @@ Explicit symbol lookup only; conceptual search was not attempted.`
|
|
|
15044
15193
|
tokenBudget: heading.tokenBudget,
|
|
15045
15194
|
tokenEstimate: heading.tokenEstimate,
|
|
15046
15195
|
truncated: heading.truncated,
|
|
15047
|
-
recovery: buildRecoveryDetails(
|
|
15196
|
+
recovery: buildRecoveryDetails(serializeAttempts(attemptStates), null),
|
|
15197
|
+
...input.diagnostic && {
|
|
15198
|
+
diagnostic: buildSearchDiagnostic(attemptStates[attemptStates.length - 1])
|
|
15199
|
+
}
|
|
15048
15200
|
}
|
|
15049
15201
|
};
|
|
15050
15202
|
}
|
|
@@ -15084,8 +15236,17 @@ Explicit symbol lookup only; conceptual search was not attempted.`
|
|
|
15084
15236
|
maxResults: limit,
|
|
15085
15237
|
heading,
|
|
15086
15238
|
includeExactSearchHandoff: true,
|
|
15087
|
-
preferImplementationPaths: intent.preferSourcePaths || intent.primary !== "docs" && intent.primary !== "test"
|
|
15088
|
-
|
|
15239
|
+
preferImplementationPaths: intent.preferSourcePaths || intent.primary !== "docs" && intent.primary !== "test",
|
|
15240
|
+
...input.diagnostic ? {
|
|
15241
|
+
trace: (trace) => {
|
|
15242
|
+
const attemptState = findSuccessfulAttemptState("conceptual");
|
|
15243
|
+
if (attemptState) {
|
|
15244
|
+
attemptState.contextPackTrace = trace;
|
|
15245
|
+
}
|
|
15246
|
+
}
|
|
15247
|
+
} : void 0
|
|
15248
|
+
}),
|
|
15249
|
+
findSuccessfulAttemptState("conceptual")
|
|
15089
15250
|
);
|
|
15090
15251
|
}
|
|
15091
15252
|
}
|
|
@@ -15101,7 +15262,10 @@ Explicit symbol lookup only; conceptual search was not attempted.`
|
|
|
15101
15262
|
tokenBudget: fallbackText.tokenBudget,
|
|
15102
15263
|
tokenEstimate: fallbackText.tokenEstimate,
|
|
15103
15264
|
truncated: fallbackText.truncated,
|
|
15104
|
-
recovery: buildRecoveryDetails(
|
|
15265
|
+
recovery: buildRecoveryDetails(serializeAttempts(attemptStates), null),
|
|
15266
|
+
...input.diagnostic && {
|
|
15267
|
+
diagnostic: buildSearchDiagnostic(attemptStates[attemptStates.length - 1])
|
|
15268
|
+
}
|
|
15105
15269
|
}
|
|
15106
15270
|
};
|
|
15107
15271
|
}
|
|
@@ -15182,17 +15346,27 @@ async function resolveCodebaseContextUnmeasured(projectRoot3, host, input) {
|
|
|
15182
15346
|
details: fittedDetails("path", fitted, 0)
|
|
15183
15347
|
};
|
|
15184
15348
|
}
|
|
15185
|
-
return resolveSearchContext({
|
|
15186
|
-
|
|
15349
|
+
return resolveSearchContext({
|
|
15350
|
+
query: input.query,
|
|
15351
|
+
symbol,
|
|
15352
|
+
limit,
|
|
15353
|
+
tokenBudget,
|
|
15354
|
+
fileType,
|
|
15355
|
+
directory,
|
|
15356
|
+
diagnostic: input.diagnostic
|
|
15357
|
+
}, {
|
|
15358
|
+
lookup: (lookupSymbol, retrievalLimit, scope, trace) => implementationLookup(projectRoot3, host, lookupSymbol, {
|
|
15187
15359
|
limit: retrievalLimit,
|
|
15188
15360
|
fileType: scope.fileType,
|
|
15189
|
-
directory: scope.directory
|
|
15361
|
+
directory: scope.directory,
|
|
15362
|
+
trace
|
|
15190
15363
|
}),
|
|
15191
|
-
search: (queryText, retrievalLimit, scope) => searchCodebase(projectRoot3, host, queryText, {
|
|
15364
|
+
search: (queryText, retrievalLimit, scope, trace) => searchCodebase(projectRoot3, host, queryText, {
|
|
15192
15365
|
limit: retrievalLimit,
|
|
15193
15366
|
fileType: scope.fileType,
|
|
15194
15367
|
directory: scope.directory,
|
|
15195
|
-
metadataOnly: true
|
|
15368
|
+
metadataOnly: true,
|
|
15369
|
+
trace
|
|
15196
15370
|
})
|
|
15197
15371
|
});
|
|
15198
15372
|
}
|
|
@@ -15257,12 +15431,188 @@ async function resolveCodebaseContext(projectRoot3, host, input) {
|
|
|
15257
15431
|
}
|
|
15258
15432
|
}
|
|
15259
15433
|
|
|
15434
|
+
// src/tools/edit-context.ts
|
|
15435
|
+
function edgeLimit(value) {
|
|
15436
|
+
if (value === null || value === void 0 || !Number.isFinite(value)) {
|
|
15437
|
+
return DEFAULT_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT;
|
|
15438
|
+
}
|
|
15439
|
+
return Math.min(
|
|
15440
|
+
MAX_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT,
|
|
15441
|
+
Math.max(MIN_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT, Math.floor(value))
|
|
15442
|
+
);
|
|
15443
|
+
}
|
|
15444
|
+
function normalizedPath(value) {
|
|
15445
|
+
return value.replaceAll("\\", "/").replace(/^\.\//, "");
|
|
15446
|
+
}
|
|
15447
|
+
function pathsMatch(left, right) {
|
|
15448
|
+
const normalizedLeft = normalizedPath(left);
|
|
15449
|
+
const normalizedRight = normalizedPath(right);
|
|
15450
|
+
return normalizedLeft === normalizedRight || normalizedLeft.endsWith(`/${normalizedRight}`) || normalizedRight.endsWith(`/${normalizedLeft}`);
|
|
15451
|
+
}
|
|
15452
|
+
function targetSource(results, resolution) {
|
|
15453
|
+
return results.find((result) => pathsMatch(result.filePath, resolution.filePath) && result.startLine <= resolution.startLine && result.endLine >= resolution.startLine) ?? results.find((result) => pathsMatch(result.filePath, resolution.filePath) && result.name === resolution.name);
|
|
15454
|
+
}
|
|
15455
|
+
function formatSource(result) {
|
|
15456
|
+
const name = result.name ? ` ${result.name}` : "";
|
|
15457
|
+
return [
|
|
15458
|
+
"## Target implementation",
|
|
15459
|
+
`${result.filePath}:${result.startLine}-${result.endLine} (${result.chunkType}${name})`,
|
|
15460
|
+
"```",
|
|
15461
|
+
result.content,
|
|
15462
|
+
"```"
|
|
15463
|
+
].join("\n");
|
|
15464
|
+
}
|
|
15465
|
+
function formatCallers(edges) {
|
|
15466
|
+
if (edges.length === 0) return "## Direct callers\nNone found.";
|
|
15467
|
+
return [
|
|
15468
|
+
"## Direct callers",
|
|
15469
|
+
...edges.map((edge) => `- ${edge.fromSymbolName ?? "<unknown>"} at ${edge.fromSymbolFilePath ?? "<unknown file>"}:${edge.line} (${edge.callType}, ${edge.isResolved ? "resolved" : "unresolved"})`)
|
|
15470
|
+
].join("\n");
|
|
15471
|
+
}
|
|
15472
|
+
function formatCallees(edges, sourceFilePath) {
|
|
15473
|
+
if (edges.length === 0) return "## Direct callees\nNone found.";
|
|
15474
|
+
return [
|
|
15475
|
+
"## Direct callees",
|
|
15476
|
+
...edges.map((edge) => `- ${edge.targetName} from ${sourceFilePath}:${edge.line} (${edge.callType}, ${edge.isResolved ? "resolved" : "unresolved"})`)
|
|
15477
|
+
].join("\n");
|
|
15478
|
+
}
|
|
15479
|
+
function formatResolutionRisk(resolution) {
|
|
15480
|
+
if (resolution.status === "ambiguous") {
|
|
15481
|
+
const candidates = resolution.candidates.map((candidate) => `${candidate.filePath}:${candidate.startLine}`).join(", ");
|
|
15482
|
+
return `Risk: symbol "${resolution.name}" is ambiguous. Pass filePath to select a target.${candidates ? ` Candidates: ${candidates}.` : ""}`;
|
|
15483
|
+
}
|
|
15484
|
+
if (resolution.filePath && resolution.totalCandidates > 0) {
|
|
15485
|
+
return `Risk: symbol "${resolution.name}" did not resolve at filePath="${resolution.filePath}". Review the conceptual evidence before editing.`;
|
|
15486
|
+
}
|
|
15487
|
+
return `Risk: symbol "${resolution.name}" could not be resolved. Review the conceptual evidence before editing.`;
|
|
15488
|
+
}
|
|
15489
|
+
async function fallbackPack(dependencies, query, risk, resolution, tokenBudget, candidateSource = []) {
|
|
15490
|
+
const conceptual = await dependencies.searchCodebase(query, { limit: 5 });
|
|
15491
|
+
const pack = buildContextPack([...candidateSource, ...conceptual], {
|
|
15492
|
+
tokenBudget: tokenBudget ?? void 0,
|
|
15493
|
+
heading: "## Conceptual evidence",
|
|
15494
|
+
maxResults: 5,
|
|
15495
|
+
includeExactSearchHandoff: false,
|
|
15496
|
+
preferImplementationPaths: true
|
|
15497
|
+
});
|
|
15498
|
+
const fitted = fitTextToContextBudget(`${risk}
|
|
15499
|
+
|
|
15500
|
+
${pack.text}`, tokenBudget ?? void 0);
|
|
15501
|
+
return {
|
|
15502
|
+
text: fitted.text,
|
|
15503
|
+
details: {
|
|
15504
|
+
resolution,
|
|
15505
|
+
tokenBudget: fitted.tokenBudget,
|
|
15506
|
+
tokenEstimate: fitted.tokenEstimate,
|
|
15507
|
+
truncated: fitted.truncated,
|
|
15508
|
+
sourceIncluded: candidateSource.length > 0,
|
|
15509
|
+
callerCount: 0,
|
|
15510
|
+
calleeCount: 0
|
|
15511
|
+
}
|
|
15512
|
+
};
|
|
15513
|
+
}
|
|
15514
|
+
async function resolveCodebaseEditContextWithDependencies(input, dependencies) {
|
|
15515
|
+
const symbol = input.symbol?.trim();
|
|
15516
|
+
if (!symbol) {
|
|
15517
|
+
return fallbackPack(
|
|
15518
|
+
dependencies,
|
|
15519
|
+
input.query,
|
|
15520
|
+
"Risk: no authoritative symbol was supplied. Review the conceptual evidence before editing.",
|
|
15521
|
+
"not_requested",
|
|
15522
|
+
input.tokenBudget
|
|
15523
|
+
);
|
|
15524
|
+
}
|
|
15525
|
+
let callersResult;
|
|
15526
|
+
try {
|
|
15527
|
+
callersResult = await dependencies.getCallGraphData({
|
|
15528
|
+
name: symbol,
|
|
15529
|
+
filePath: input.filePath ?? void 0,
|
|
15530
|
+
direction: "callers"
|
|
15531
|
+
});
|
|
15532
|
+
} catch (error) {
|
|
15533
|
+
const candidates = await dependencies.implementationLookup(symbol, { limit: 5 });
|
|
15534
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
15535
|
+
return fallbackPack(
|
|
15536
|
+
dependencies,
|
|
15537
|
+
input.query,
|
|
15538
|
+
`Risk: graph data is unavailable (${message}). Target and dependencies are not graph-verified.`,
|
|
15539
|
+
"graph_unavailable",
|
|
15540
|
+
input.tokenBudget,
|
|
15541
|
+
candidates
|
|
15542
|
+
);
|
|
15543
|
+
}
|
|
15544
|
+
if (callersResult.resolution.status !== "resolved") {
|
|
15545
|
+
return fallbackPack(
|
|
15546
|
+
dependencies,
|
|
15547
|
+
input.query,
|
|
15548
|
+
formatResolutionRisk(callersResult.resolution),
|
|
15549
|
+
callersResult.resolution.status,
|
|
15550
|
+
input.tokenBudget
|
|
15551
|
+
);
|
|
15552
|
+
}
|
|
15553
|
+
const resolution = callersResult.resolution;
|
|
15554
|
+
const [definitionsResult, calleesResult] = await Promise.allSettled([
|
|
15555
|
+
dependencies.implementationLookup(symbol, { limit: 10 }),
|
|
15556
|
+
dependencies.getCallGraphData({
|
|
15557
|
+
name: symbol,
|
|
15558
|
+
filePath: input.filePath ?? resolution.filePath,
|
|
15559
|
+
direction: "callees"
|
|
15560
|
+
})
|
|
15561
|
+
]);
|
|
15562
|
+
if (definitionsResult.status === "rejected") throw definitionsResult.reason;
|
|
15563
|
+
let graphRisk;
|
|
15564
|
+
let callees = [];
|
|
15565
|
+
if (calleesResult.status === "rejected") {
|
|
15566
|
+
const message = calleesResult.reason instanceof Error ? calleesResult.reason.message : String(calleesResult.reason);
|
|
15567
|
+
graphRisk = `Risk: callee graph data is unavailable (${message}). Dependency evidence is incomplete.`;
|
|
15568
|
+
} else if (calleesResult.value.resolution.status !== "resolved") {
|
|
15569
|
+
graphRisk = "Risk: the target resolved for callers but not callees. Dependency evidence is incomplete.";
|
|
15570
|
+
} else {
|
|
15571
|
+
callees = calleesResult.value.callees.slice(0, edgeLimit(input.calleeLimit));
|
|
15572
|
+
}
|
|
15573
|
+
const source = targetSource(definitionsResult.value, resolution);
|
|
15574
|
+
const callers = callersResult.callers.slice(0, edgeLimit(input.callerLimit));
|
|
15575
|
+
const sourceBudget = Math.max(
|
|
15576
|
+
MIN_CONTEXT_PACK_TOKEN_BUDGET,
|
|
15577
|
+
Math.floor((input.tokenBudget ?? DEFAULT_CONTEXT_PACK_TOKEN_BUDGET) * 0.6)
|
|
15578
|
+
);
|
|
15579
|
+
const sourceText = source ? fitTextToContextBudget(formatSource(source), sourceBudget).text : `## Target implementation
|
|
15580
|
+
Risk: no implementation source matched the resolved target at ${resolution.filePath}:${resolution.startLine}.`;
|
|
15581
|
+
const fitted = fitTextToContextBudget([
|
|
15582
|
+
`# Pre-edit context for ${resolution.name}`,
|
|
15583
|
+
graphRisk,
|
|
15584
|
+
sourceText,
|
|
15585
|
+
formatCallers(callers),
|
|
15586
|
+
formatCallees(callees, resolution.filePath)
|
|
15587
|
+
].filter((section) => section !== void 0).join("\n\n"), input.tokenBudget ?? void 0);
|
|
15588
|
+
return {
|
|
15589
|
+
text: fitted.text,
|
|
15590
|
+
details: {
|
|
15591
|
+
resolution: "resolved",
|
|
15592
|
+
tokenBudget: fitted.tokenBudget,
|
|
15593
|
+
tokenEstimate: fitted.tokenEstimate,
|
|
15594
|
+
truncated: fitted.truncated,
|
|
15595
|
+
sourceIncluded: source !== void 0,
|
|
15596
|
+
callerCount: callers.length,
|
|
15597
|
+
calleeCount: callees.length
|
|
15598
|
+
}
|
|
15599
|
+
};
|
|
15600
|
+
}
|
|
15601
|
+
async function resolveCodebaseEditContext(projectRoot3, host, input) {
|
|
15602
|
+
return resolveCodebaseEditContextWithDependencies(input, {
|
|
15603
|
+
searchCodebase: (query, options) => searchCodebase(projectRoot3, host, query, options),
|
|
15604
|
+
implementationLookup: (query, options) => implementationLookup(projectRoot3, host, query, options),
|
|
15605
|
+
getCallGraphData: (params) => getCallGraphData(projectRoot3, host, params)
|
|
15606
|
+
});
|
|
15607
|
+
}
|
|
15608
|
+
|
|
15260
15609
|
// src/adapters/pi/call-graph.ts
|
|
15261
15610
|
import { Type } from "typebox";
|
|
15262
15611
|
|
|
15263
15612
|
// src/tools/tool-names.ts
|
|
15264
15613
|
var TOOL_NAME = {
|
|
15265
15614
|
CODEBASE_CONTEXT: "codebase_context",
|
|
15615
|
+
CODEBASE_EDIT_CONTEXT: "codebase_edit_context",
|
|
15266
15616
|
CODEBASE_SEARCH: "codebase_search",
|
|
15267
15617
|
CODEBASE_PEEK: "codebase_peek",
|
|
15268
15618
|
FIND_SIMILAR: "find_similar",
|
|
@@ -15286,6 +15636,7 @@ var TOOL_NAME = {
|
|
|
15286
15636
|
};
|
|
15287
15637
|
var PORTABLE_TOOL_NAMES = [
|
|
15288
15638
|
TOOL_NAME.CODEBASE_CONTEXT,
|
|
15639
|
+
TOOL_NAME.CODEBASE_EDIT_CONTEXT,
|
|
15289
15640
|
TOOL_NAME.CODEBASE_SEARCH,
|
|
15290
15641
|
TOOL_NAME.CODEBASE_PEEK,
|
|
15291
15642
|
TOOL_NAME.INDEX_CODEBASE,
|
|
@@ -15302,6 +15653,7 @@ var PORTABLE_TOOL_NAMES = [
|
|
|
15302
15653
|
];
|
|
15303
15654
|
var OPENCODE_TOOL_NAMES = [
|
|
15304
15655
|
TOOL_NAME.CODEBASE_CONTEXT,
|
|
15656
|
+
TOOL_NAME.CODEBASE_EDIT_CONTEXT,
|
|
15305
15657
|
TOOL_NAME.CODEBASE_SEARCH,
|
|
15306
15658
|
TOOL_NAME.CODEBASE_PEEK,
|
|
15307
15659
|
TOOL_NAME.INDEX_CODEBASE,
|
|
@@ -15322,6 +15674,7 @@ var OPENCODE_TOOL_NAMES = [
|
|
|
15322
15674
|
];
|
|
15323
15675
|
var PI_TOOL_NAMES = [
|
|
15324
15676
|
TOOL_NAME.CODEBASE_CONTEXT,
|
|
15677
|
+
TOOL_NAME.CODEBASE_EDIT_CONTEXT,
|
|
15325
15678
|
TOOL_NAME.CODEBASE_SEARCH,
|
|
15326
15679
|
TOOL_NAME.CODEBASE_PEEK,
|
|
15327
15680
|
TOOL_NAME.FIND_SIMILAR,
|
|
@@ -15436,6 +15789,7 @@ function codebaseIndexPiExtension(pi) {
|
|
|
15436
15789
|
Type2.Integer({ minimum: MIN_CONTEXT_PATH_DEPTH, maximum: MAX_CONTEXT_PATH_DEPTH }),
|
|
15437
15790
|
Type2.Null()
|
|
15438
15791
|
], { default: 10, description: `Maximum call-graph traversal depth (${MIN_CONTEXT_PATH_DEPTH}-${MAX_CONTEXT_PATH_DEPTH})` })),
|
|
15792
|
+
diagnostic: Type2.Optional(Type2.Union([Type2.Boolean(), Type2.Null()], { description: "Collect diagnostic routing and search traces without changing normal output." })),
|
|
15439
15793
|
fileType: Type2.Optional(Type2.Union([Type2.String(), Type2.Null()], { description: "Filter by file extension, e.g., ts, py, rs" })),
|
|
15440
15794
|
directory: Type2.Optional(Type2.Union([Type2.String(), Type2.Null()], { description: "Filter by directory path" })),
|
|
15441
15795
|
tokenBudget: Type2.Optional(Type2.Union([
|
|
@@ -15447,10 +15801,40 @@ function codebaseIndexPiExtension(pi) {
|
|
|
15447
15801
|
}))
|
|
15448
15802
|
}),
|
|
15449
15803
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
15450
|
-
const
|
|
15804
|
+
const normalizedParams = {
|
|
15805
|
+
...params,
|
|
15806
|
+
diagnostic: params.diagnostic ?? void 0
|
|
15807
|
+
};
|
|
15808
|
+
const result = await resolveCodebaseContext(projectRoot2(ctx), HOST2, normalizedParams);
|
|
15451
15809
|
return text2(result.text, result.details);
|
|
15452
15810
|
}
|
|
15453
15811
|
});
|
|
15812
|
+
pi.registerTool({
|
|
15813
|
+
name: TOOL_NAME.CODEBASE_EDIT_CONTEXT,
|
|
15814
|
+
label: "Codebase Edit Context",
|
|
15815
|
+
description: "PRE-EDIT TOOL for a known or suspected symbol. Returns bounded target source and direct graph evidence, with a risk-marked fallback when unresolved.",
|
|
15816
|
+
parameters: Type2.Object({
|
|
15817
|
+
query: Type2.String({ description: "The requested change or target behavior" }),
|
|
15818
|
+
symbol: Type2.Optional(Type2.Union([Type2.String(), Type2.Null()])),
|
|
15819
|
+
filePath: Type2.Optional(Type2.Union([Type2.String(), Type2.Null()])),
|
|
15820
|
+
callerLimit: Type2.Optional(Type2.Union([
|
|
15821
|
+
Type2.Integer({ minimum: MIN_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT, maximum: MAX_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT }),
|
|
15822
|
+
Type2.Null()
|
|
15823
|
+
], { default: DEFAULT_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT })),
|
|
15824
|
+
calleeLimit: Type2.Optional(Type2.Union([
|
|
15825
|
+
Type2.Integer({ minimum: MIN_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT, maximum: MAX_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT }),
|
|
15826
|
+
Type2.Null()
|
|
15827
|
+
], { default: DEFAULT_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT })),
|
|
15828
|
+
tokenBudget: Type2.Optional(Type2.Union([
|
|
15829
|
+
Type2.Integer({ minimum: MIN_CONTEXT_PACK_TOKEN_BUDGET, maximum: MAX_CONTEXT_PACK_TOKEN_BUDGET }),
|
|
15830
|
+
Type2.Null()
|
|
15831
|
+
], { default: DEFAULT_CONTEXT_PACK_TOKEN_BUDGET }))
|
|
15832
|
+
}),
|
|
15833
|
+
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
15834
|
+
const result = await resolveCodebaseEditContext(projectRoot2(ctx), HOST2, params);
|
|
15835
|
+
return text2(result.text);
|
|
15836
|
+
}
|
|
15837
|
+
});
|
|
15454
15838
|
pi.registerTool({
|
|
15455
15839
|
name: TOOL_NAME.CODEBASE_SEARCH,
|
|
15456
15840
|
label: "Codebase Search",
|