open-codebase-index 0.22.3 → 0.22.4
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 +647 -94
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +647 -94
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +421 -55
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +421 -55
- package/dist/index.js.map +1 -1
- package/dist/pi-extension.cjs +401 -48
- package/dist/pi-extension.cjs.map +1 -1
- package/dist/pi-extension.js +401 -48
- package/dist/pi-extension.js.map +1 -1
- package/native/codebase-index-native.darwin-arm64.node +0 -0
- package/native/codebase-index-native.darwin-x64.node +0 -0
- package/native/codebase-index-native.linux-arm64-gnu.node +0 -0
- package/native/codebase-index-native.linux-x64-gnu.node +0 -0
- package/native/codebase-index-native.win32-x64-msvc.node +0 -0
- package/package.json +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";
|
|
@@ -9029,9 +9051,9 @@ function normalizeFilePathForHintMatch(filePath) {
|
|
|
9029
9051
|
return filePath.replace(/\\/g, "/").toLowerCase().replace(/^\.\//, "");
|
|
9030
9052
|
}
|
|
9031
9053
|
function pathMatchesHint(filePath, hint) {
|
|
9032
|
-
const
|
|
9054
|
+
const normalizedPath2 = normalizeFilePathForHintMatch(filePath);
|
|
9033
9055
|
const normalizedHint = normalizeFilePathForHintMatch(hint);
|
|
9034
|
-
return
|
|
9056
|
+
return normalizedPath2.endsWith(normalizedHint) || normalizedPath2.includes(`/${normalizedHint}`) || normalizedPath2.includes(normalizedHint);
|
|
9035
9057
|
}
|
|
9036
9058
|
function extractFilePathHint(query) {
|
|
9037
9059
|
const match = query.match(FILE_PATH_HINT_SUFFIX_REGEX);
|
|
@@ -12904,6 +12926,20 @@ var Indexer = class _Indexer {
|
|
|
12904
12926
|
requestedLimit = nextLimit;
|
|
12905
12927
|
}
|
|
12906
12928
|
}
|
|
12929
|
+
buildCandidateSnapshot(candidate) {
|
|
12930
|
+
return {
|
|
12931
|
+
id: candidate.id,
|
|
12932
|
+
filePath: candidate.metadata.filePath,
|
|
12933
|
+
startLine: candidate.metadata.startLine,
|
|
12934
|
+
endLine: candidate.metadata.endLine,
|
|
12935
|
+
score: candidate.score,
|
|
12936
|
+
chunkType: candidate.metadata.chunkType,
|
|
12937
|
+
name: candidate.metadata.name
|
|
12938
|
+
};
|
|
12939
|
+
}
|
|
12940
|
+
buildCandidateSnapshotList(candidates) {
|
|
12941
|
+
return candidates.map((candidate) => this.buildCandidateSnapshot(candidate));
|
|
12942
|
+
}
|
|
12907
12943
|
searchSemanticCandidates(store, embedding, initialLimit, branchChunkIds, shouldPrefilterByBranch) {
|
|
12908
12944
|
return this.searchCandidatesWithBranchPrefilter(
|
|
12909
12945
|
initialLimit,
|
|
@@ -13095,6 +13131,16 @@ var Indexer = class _Indexer {
|
|
|
13095
13131
|
prefilterMs: Math.round(prefilterMs * 100) / 100,
|
|
13096
13132
|
fusionMs: Math.round(fusionMs * 100) / 100
|
|
13097
13133
|
});
|
|
13134
|
+
if (options?.trace) {
|
|
13135
|
+
options.trace({
|
|
13136
|
+
semanticCandidates: this.buildCandidateSnapshotList(scopedSemanticCandidates),
|
|
13137
|
+
keywordCandidates: this.buildCandidateSnapshotList(scopedKeywordCandidates),
|
|
13138
|
+
hybridCandidates: this.buildCandidateSnapshotList(combined),
|
|
13139
|
+
postExternalRerankCandidates: this.buildCandidateSnapshotList(rerankedCombined),
|
|
13140
|
+
tieredCandidates: this.buildCandidateSnapshotList(tiered),
|
|
13141
|
+
finalCandidates: this.buildCandidateSnapshotList(finalResults)
|
|
13142
|
+
});
|
|
13143
|
+
}
|
|
13098
13144
|
const metadataOnly = options?.metadataOnly ?? false;
|
|
13099
13145
|
return Promise.all(
|
|
13100
13146
|
finalResults.map(async (r) => {
|
|
@@ -14355,7 +14401,8 @@ async function searchCodebase(projectRoot3, host, query, options = {}) {
|
|
|
14355
14401
|
definitionIntent: options.definitionIntent,
|
|
14356
14402
|
blameAuthor: options.blameAuthor,
|
|
14357
14403
|
blameSha: options.blameSha,
|
|
14358
|
-
blameSince: options.blameSince
|
|
14404
|
+
blameSince: options.blameSince,
|
|
14405
|
+
trace: options.trace
|
|
14359
14406
|
});
|
|
14360
14407
|
}
|
|
14361
14408
|
async function searchCodebaseWithEffectiveness(projectRoot3, host, route, query, options, render) {
|
|
@@ -14409,15 +14456,19 @@ async function implementationLookup(projectRoot3, host, query, options = {}) {
|
|
|
14409
14456
|
return indexer.search(query, options.limit, {
|
|
14410
14457
|
fileType: options.fileType,
|
|
14411
14458
|
directory: options.directory,
|
|
14412
|
-
definitionIntent: true
|
|
14459
|
+
definitionIntent: true,
|
|
14460
|
+
trace: options.trace
|
|
14413
14461
|
});
|
|
14414
14462
|
}
|
|
14415
14463
|
async function getCallGraphData(projectRoot3, host, params) {
|
|
14416
14464
|
await ensureAutoIndexReadyForRetrieval(projectRoot3, host);
|
|
14417
14465
|
const root = getProjectRoot(projectRoot3, host);
|
|
14418
14466
|
const indexer = getIndexerForProject(root, host);
|
|
14467
|
+
return getCallGraphDataForIndexer(indexer, root, params);
|
|
14468
|
+
}
|
|
14469
|
+
async function getCallGraphDataForIndexer(indexer, projectRoot3, params) {
|
|
14419
14470
|
const symbols = await indexer.getCallGraphSymbols();
|
|
14420
|
-
const resolution = resolveCallGraphSymbol(symbols,
|
|
14471
|
+
const resolution = resolveCallGraphSymbol(symbols, projectRoot3, params.name, params.filePath, params.symbolId);
|
|
14421
14472
|
const direction = params.direction === "callees" ? "callees" : "callers";
|
|
14422
14473
|
if (resolution.status !== "resolved") {
|
|
14423
14474
|
return { direction, resolution, callers: [], callees: [], relationshipType: params.relationshipType };
|
|
@@ -14645,17 +14696,17 @@ async function getIndexLogs(projectRoot3, host, args) {
|
|
|
14645
14696
|
function addKnowledgeBase(projectRoot3, host, knowledgeBasePath) {
|
|
14646
14697
|
const root = getProjectRoot(projectRoot3, host);
|
|
14647
14698
|
const inputPath = knowledgeBasePath.trim();
|
|
14648
|
-
const
|
|
14699
|
+
const normalizedPath2 = path20.resolve(
|
|
14649
14700
|
path20.isAbsolute(inputPath) ? inputPath : resolveKnowledgeBasePath(inputPath, root)
|
|
14650
14701
|
);
|
|
14651
|
-
if (!existsSync12(
|
|
14652
|
-
return `Error: Directory does not exist: ${
|
|
14702
|
+
if (!existsSync12(normalizedPath2)) {
|
|
14703
|
+
return `Error: Directory does not exist: ${normalizedPath2}`;
|
|
14653
14704
|
}
|
|
14654
14705
|
let realPath;
|
|
14655
14706
|
try {
|
|
14656
|
-
realPath = realpathSync5(
|
|
14707
|
+
realPath = realpathSync5(normalizedPath2);
|
|
14657
14708
|
} catch {
|
|
14658
|
-
return `Error: Cannot resolve path: ${
|
|
14709
|
+
return `Error: Cannot resolve path: ${normalizedPath2}`;
|
|
14659
14710
|
}
|
|
14660
14711
|
const blockedPrefixes = [
|
|
14661
14712
|
"/etc",
|
|
@@ -14678,34 +14729,34 @@ function addKnowledgeBase(projectRoot3, host, knowledgeBasePath) {
|
|
|
14678
14729
|
];
|
|
14679
14730
|
for (const prefix of blockedPrefixes) {
|
|
14680
14731
|
if (realPath === prefix || realPath.startsWith(`${prefix}/`)) {
|
|
14681
|
-
return `Error: Adding sensitive directory as knowledge base is not allowed: ${
|
|
14732
|
+
return `Error: Adding sensitive directory as knowledge base is not allowed: ${normalizedPath2}`;
|
|
14682
14733
|
}
|
|
14683
14734
|
}
|
|
14684
14735
|
for (const dotDir of sensitiveDotDirs) {
|
|
14685
14736
|
const sensitiveDir = path20.join(homeDir, dotDir);
|
|
14686
14737
|
if (sensitiveDir && (realPath === sensitiveDir || realPath.startsWith(`${sensitiveDir}/`))) {
|
|
14687
|
-
return `Error: Adding sensitive directory as knowledge base is not allowed: ${
|
|
14738
|
+
return `Error: Adding sensitive directory as knowledge base is not allowed: ${normalizedPath2}`;
|
|
14688
14739
|
}
|
|
14689
14740
|
}
|
|
14690
14741
|
try {
|
|
14691
|
-
const stat = statSync5(
|
|
14742
|
+
const stat = statSync5(normalizedPath2);
|
|
14692
14743
|
if (!stat.isDirectory()) {
|
|
14693
|
-
return `Error: Path is not a directory: ${
|
|
14744
|
+
return `Error: Path is not a directory: ${normalizedPath2}`;
|
|
14694
14745
|
}
|
|
14695
14746
|
} catch (error) {
|
|
14696
|
-
return `Error: Cannot access directory: ${
|
|
14747
|
+
return `Error: Cannot access directory: ${normalizedPath2} - ${error instanceof Error ? error.message : String(error)}`;
|
|
14697
14748
|
}
|
|
14698
14749
|
const config = loadEditableConfig(root, host);
|
|
14699
14750
|
const knowledgeBases = Array.isArray(config.knowledgeBases) ? config.knowledgeBases : [];
|
|
14700
|
-
const alreadyExists = hasMatchingKnowledgeBasePath(knowledgeBases,
|
|
14751
|
+
const alreadyExists = hasMatchingKnowledgeBasePath(knowledgeBases, normalizedPath2, root);
|
|
14701
14752
|
if (alreadyExists) {
|
|
14702
|
-
return `Knowledge base already configured: ${
|
|
14753
|
+
return `Knowledge base already configured: ${normalizedPath2}`;
|
|
14703
14754
|
}
|
|
14704
|
-
knowledgeBases.push(
|
|
14755
|
+
knowledgeBases.push(normalizedPath2);
|
|
14705
14756
|
config.knowledgeBases = knowledgeBases;
|
|
14706
14757
|
saveConfig(root, config, host);
|
|
14707
14758
|
refreshIndexerForDirectory(root, host);
|
|
14708
|
-
let result = `${
|
|
14759
|
+
let result = `${normalizedPath2}
|
|
14709
14760
|
`;
|
|
14710
14761
|
result += `Total knowledge bases: ${knowledgeBases.length}
|
|
14711
14762
|
`;
|
|
@@ -14880,6 +14931,27 @@ function buildRecoveryDetails(attempts, successIndex) {
|
|
|
14880
14931
|
successfulAttemptIndex: successIndex
|
|
14881
14932
|
};
|
|
14882
14933
|
}
|
|
14934
|
+
function serializeAttempts(attempts) {
|
|
14935
|
+
return attempts.map((attempt) => ({
|
|
14936
|
+
kind: attempt.kind,
|
|
14937
|
+
scope: attempt.scope,
|
|
14938
|
+
resultCount: attempt.resultCount,
|
|
14939
|
+
relaxedFields: attempt.relaxedFields
|
|
14940
|
+
}));
|
|
14941
|
+
}
|
|
14942
|
+
function buildSearchDiagnostic(attempt) {
|
|
14943
|
+
if (!attempt) {
|
|
14944
|
+
return void 0;
|
|
14945
|
+
}
|
|
14946
|
+
return {
|
|
14947
|
+
route: attempt.kind,
|
|
14948
|
+
routedQuery: attempt.query,
|
|
14949
|
+
searchQuery: attempt.query,
|
|
14950
|
+
searchScope: attempt.scopeFilter,
|
|
14951
|
+
searchTrace: attempt.searchTrace,
|
|
14952
|
+
contextPackTrace: attempt.contextPackTrace
|
|
14953
|
+
};
|
|
14954
|
+
}
|
|
14883
14955
|
function trimOrUndefined2(value) {
|
|
14884
14956
|
const normalized = value?.trim();
|
|
14885
14957
|
if (!normalized) {
|
|
@@ -14919,6 +14991,7 @@ async function resolveSearchContext(input, operations) {
|
|
|
14919
14991
|
const hasFilters = Boolean(fileType || directory);
|
|
14920
14992
|
const relaxedFields = relaxedHintFields(fileType, directory);
|
|
14921
14993
|
const attempts = [];
|
|
14994
|
+
const attemptStates = [];
|
|
14922
14995
|
const decisions = {
|
|
14923
14996
|
inferredDefinitionMiss: false,
|
|
14924
14997
|
fallbackFromOriginalConceptualToInferred: false,
|
|
@@ -14947,8 +15020,20 @@ async function resolveSearchContext(input, operations) {
|
|
|
14947
15020
|
if (seenAttempts.has(key)) {
|
|
14948
15021
|
return [];
|
|
14949
15022
|
}
|
|
14950
|
-
const
|
|
15023
|
+
const attemptState = {
|
|
15024
|
+
kind,
|
|
15025
|
+
scope: describeScope(scope.fileType, scope.directory),
|
|
15026
|
+
resultCount: 0,
|
|
15027
|
+
relaxedFields: [...relaxedFieldsForAttempt],
|
|
15028
|
+
query: attemptQuery,
|
|
15029
|
+
scopeFilter: scope
|
|
15030
|
+
};
|
|
15031
|
+
const results = await runAttempt((trace) => {
|
|
15032
|
+
attemptState.searchTrace = trace;
|
|
15033
|
+
});
|
|
15034
|
+
attemptState.resultCount = results.length;
|
|
14951
15035
|
seenAttempts.add(key);
|
|
15036
|
+
attemptStates.push(attemptState);
|
|
14952
15037
|
attempts.push({
|
|
14953
15038
|
kind,
|
|
14954
15039
|
scope: describeScope(scope.fileType, scope.directory),
|
|
@@ -14968,7 +15053,7 @@ async function resolveSearchContext(input, operations) {
|
|
|
14968
15053
|
symbol,
|
|
14969
15054
|
scope,
|
|
14970
15055
|
relaxedFieldsForAttempt,
|
|
14971
|
-
() => operations.lookup(symbol, MAX_CONTEXT_RESULT_LIMIT, scope)
|
|
15056
|
+
(trace) => operations.lookup(symbol, MAX_CONTEXT_RESULT_LIMIT, scope, input.diagnostic ? trace : void 0)
|
|
14972
15057
|
);
|
|
14973
15058
|
};
|
|
14974
15059
|
const tryConceptualSearch = async (searchQuery, scope, relaxedFieldsForAttempt) => {
|
|
@@ -14977,13 +15062,23 @@ async function resolveSearchContext(input, operations) {
|
|
|
14977
15062
|
searchQuery,
|
|
14978
15063
|
scope,
|
|
14979
15064
|
relaxedFieldsForAttempt,
|
|
14980
|
-
() => operations.search(searchQuery, MAX_CONTEXT_RESULT_LIMIT, scope)
|
|
15065
|
+
(trace) => operations.search(searchQuery, MAX_CONTEXT_RESULT_LIMIT, scope, input.diagnostic ? trace : void 0)
|
|
14981
15066
|
);
|
|
14982
15067
|
};
|
|
14983
|
-
const
|
|
15068
|
+
const findSuccessfulAttemptState = (route) => {
|
|
15069
|
+
for (let index = attemptStates.length - 1; index >= 0; index -= 1) {
|
|
15070
|
+
const attempt = attemptStates[index];
|
|
15071
|
+
if (attempt.kind === route && attempt.resultCount > 0) {
|
|
15072
|
+
return attempt;
|
|
15073
|
+
}
|
|
15074
|
+
}
|
|
15075
|
+
return void 0;
|
|
15076
|
+
};
|
|
15077
|
+
const toResult = (route, routedQuery, pack, successfulAttempt) => {
|
|
14984
15078
|
const base = packedResult(route, routedQuery, pack);
|
|
14985
15079
|
const baseDetails = base.details;
|
|
14986
15080
|
const successIndex = findSuccessfulAttemptIndex(route, attempts);
|
|
15081
|
+
const successState = successfulAttempt ?? findSuccessfulAttemptState(route);
|
|
14987
15082
|
return {
|
|
14988
15083
|
text: base.text,
|
|
14989
15084
|
details: {
|
|
@@ -14991,7 +15086,10 @@ async function resolveSearchContext(input, operations) {
|
|
|
14991
15086
|
tokenBudget: baseDetails.tokenBudget,
|
|
14992
15087
|
tokenEstimate: baseDetails.tokenEstimate,
|
|
14993
15088
|
truncated: false,
|
|
14994
|
-
recovery: buildRecoveryDetails(
|
|
15089
|
+
recovery: buildRecoveryDetails(serializeAttempts(attemptStates), successIndex),
|
|
15090
|
+
...input.diagnostic && {
|
|
15091
|
+
diagnostic: buildSearchDiagnostic(successState)
|
|
15092
|
+
}
|
|
14995
15093
|
}
|
|
14996
15094
|
};
|
|
14997
15095
|
};
|
|
@@ -15005,8 +15103,18 @@ async function resolveSearchContext(input, operations) {
|
|
|
15005
15103
|
buildContextPack(scopedDefinitionResults, {
|
|
15006
15104
|
tokenBudget,
|
|
15007
15105
|
maxResults: limit,
|
|
15008
|
-
heading
|
|
15009
|
-
|
|
15106
|
+
heading,
|
|
15107
|
+
preserveInputOrder: true,
|
|
15108
|
+
...input.diagnostic ? {
|
|
15109
|
+
trace: (trace) => {
|
|
15110
|
+
const attemptState = findSuccessfulAttemptState("definition");
|
|
15111
|
+
if (attemptState) {
|
|
15112
|
+
attemptState.contextPackTrace = trace;
|
|
15113
|
+
}
|
|
15114
|
+
}
|
|
15115
|
+
} : void 0
|
|
15116
|
+
}),
|
|
15117
|
+
findSuccessfulAttemptState("definition")
|
|
15010
15118
|
);
|
|
15011
15119
|
}
|
|
15012
15120
|
if (explicitSymbol) {
|
|
@@ -15024,8 +15132,18 @@ async function resolveSearchContext(input, operations) {
|
|
|
15024
15132
|
buildContextPack(unscopedDefinitionResults, {
|
|
15025
15133
|
tokenBudget,
|
|
15026
15134
|
maxResults: limit,
|
|
15027
|
-
heading: heading2
|
|
15028
|
-
|
|
15135
|
+
heading: heading2,
|
|
15136
|
+
preserveInputOrder: true,
|
|
15137
|
+
...input.diagnostic ? {
|
|
15138
|
+
trace: (trace) => {
|
|
15139
|
+
const attemptState = findSuccessfulAttemptState("definition");
|
|
15140
|
+
if (attemptState) {
|
|
15141
|
+
attemptState.contextPackTrace = trace;
|
|
15142
|
+
}
|
|
15143
|
+
}
|
|
15144
|
+
} : void 0
|
|
15145
|
+
}),
|
|
15146
|
+
findSuccessfulAttemptState("definition")
|
|
15029
15147
|
);
|
|
15030
15148
|
}
|
|
15031
15149
|
}
|
|
@@ -15044,7 +15162,10 @@ Explicit symbol lookup only; conceptual search was not attempted.`
|
|
|
15044
15162
|
tokenBudget: heading.tokenBudget,
|
|
15045
15163
|
tokenEstimate: heading.tokenEstimate,
|
|
15046
15164
|
truncated: heading.truncated,
|
|
15047
|
-
recovery: buildRecoveryDetails(
|
|
15165
|
+
recovery: buildRecoveryDetails(serializeAttempts(attemptStates), null),
|
|
15166
|
+
...input.diagnostic && {
|
|
15167
|
+
diagnostic: buildSearchDiagnostic(attemptStates[attemptStates.length - 1])
|
|
15168
|
+
}
|
|
15048
15169
|
}
|
|
15049
15170
|
};
|
|
15050
15171
|
}
|
|
@@ -15084,8 +15205,17 @@ Explicit symbol lookup only; conceptual search was not attempted.`
|
|
|
15084
15205
|
maxResults: limit,
|
|
15085
15206
|
heading,
|
|
15086
15207
|
includeExactSearchHandoff: true,
|
|
15087
|
-
preferImplementationPaths: intent.preferSourcePaths || intent.primary !== "docs" && intent.primary !== "test"
|
|
15088
|
-
|
|
15208
|
+
preferImplementationPaths: intent.preferSourcePaths || intent.primary !== "docs" && intent.primary !== "test",
|
|
15209
|
+
...input.diagnostic ? {
|
|
15210
|
+
trace: (trace) => {
|
|
15211
|
+
const attemptState = findSuccessfulAttemptState("conceptual");
|
|
15212
|
+
if (attemptState) {
|
|
15213
|
+
attemptState.contextPackTrace = trace;
|
|
15214
|
+
}
|
|
15215
|
+
}
|
|
15216
|
+
} : void 0
|
|
15217
|
+
}),
|
|
15218
|
+
findSuccessfulAttemptState("conceptual")
|
|
15089
15219
|
);
|
|
15090
15220
|
}
|
|
15091
15221
|
}
|
|
@@ -15101,7 +15231,10 @@ Explicit symbol lookup only; conceptual search was not attempted.`
|
|
|
15101
15231
|
tokenBudget: fallbackText.tokenBudget,
|
|
15102
15232
|
tokenEstimate: fallbackText.tokenEstimate,
|
|
15103
15233
|
truncated: fallbackText.truncated,
|
|
15104
|
-
recovery: buildRecoveryDetails(
|
|
15234
|
+
recovery: buildRecoveryDetails(serializeAttempts(attemptStates), null),
|
|
15235
|
+
...input.diagnostic && {
|
|
15236
|
+
diagnostic: buildSearchDiagnostic(attemptStates[attemptStates.length - 1])
|
|
15237
|
+
}
|
|
15105
15238
|
}
|
|
15106
15239
|
};
|
|
15107
15240
|
}
|
|
@@ -15182,17 +15315,27 @@ async function resolveCodebaseContextUnmeasured(projectRoot3, host, input) {
|
|
|
15182
15315
|
details: fittedDetails("path", fitted, 0)
|
|
15183
15316
|
};
|
|
15184
15317
|
}
|
|
15185
|
-
return resolveSearchContext({
|
|
15186
|
-
|
|
15318
|
+
return resolveSearchContext({
|
|
15319
|
+
query: input.query,
|
|
15320
|
+
symbol,
|
|
15321
|
+
limit,
|
|
15322
|
+
tokenBudget,
|
|
15323
|
+
fileType,
|
|
15324
|
+
directory,
|
|
15325
|
+
diagnostic: input.diagnostic
|
|
15326
|
+
}, {
|
|
15327
|
+
lookup: (lookupSymbol, retrievalLimit, scope, trace) => implementationLookup(projectRoot3, host, lookupSymbol, {
|
|
15187
15328
|
limit: retrievalLimit,
|
|
15188
15329
|
fileType: scope.fileType,
|
|
15189
|
-
directory: scope.directory
|
|
15330
|
+
directory: scope.directory,
|
|
15331
|
+
trace
|
|
15190
15332
|
}),
|
|
15191
|
-
search: (queryText, retrievalLimit, scope) => searchCodebase(projectRoot3, host, queryText, {
|
|
15333
|
+
search: (queryText, retrievalLimit, scope, trace) => searchCodebase(projectRoot3, host, queryText, {
|
|
15192
15334
|
limit: retrievalLimit,
|
|
15193
15335
|
fileType: scope.fileType,
|
|
15194
15336
|
directory: scope.directory,
|
|
15195
|
-
metadataOnly: true
|
|
15337
|
+
metadataOnly: true,
|
|
15338
|
+
trace
|
|
15196
15339
|
})
|
|
15197
15340
|
});
|
|
15198
15341
|
}
|
|
@@ -15257,12 +15400,188 @@ async function resolveCodebaseContext(projectRoot3, host, input) {
|
|
|
15257
15400
|
}
|
|
15258
15401
|
}
|
|
15259
15402
|
|
|
15403
|
+
// src/tools/edit-context.ts
|
|
15404
|
+
function edgeLimit(value) {
|
|
15405
|
+
if (value === null || value === void 0 || !Number.isFinite(value)) {
|
|
15406
|
+
return DEFAULT_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT;
|
|
15407
|
+
}
|
|
15408
|
+
return Math.min(
|
|
15409
|
+
MAX_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT,
|
|
15410
|
+
Math.max(MIN_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT, Math.floor(value))
|
|
15411
|
+
);
|
|
15412
|
+
}
|
|
15413
|
+
function normalizedPath(value) {
|
|
15414
|
+
return value.replaceAll("\\", "/").replace(/^\.\//, "");
|
|
15415
|
+
}
|
|
15416
|
+
function pathsMatch(left, right) {
|
|
15417
|
+
const normalizedLeft = normalizedPath(left);
|
|
15418
|
+
const normalizedRight = normalizedPath(right);
|
|
15419
|
+
return normalizedLeft === normalizedRight || normalizedLeft.endsWith(`/${normalizedRight}`) || normalizedRight.endsWith(`/${normalizedLeft}`);
|
|
15420
|
+
}
|
|
15421
|
+
function targetSource(results, resolution) {
|
|
15422
|
+
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);
|
|
15423
|
+
}
|
|
15424
|
+
function formatSource(result) {
|
|
15425
|
+
const name = result.name ? ` ${result.name}` : "";
|
|
15426
|
+
return [
|
|
15427
|
+
"## Target implementation",
|
|
15428
|
+
`${result.filePath}:${result.startLine}-${result.endLine} (${result.chunkType}${name})`,
|
|
15429
|
+
"```",
|
|
15430
|
+
result.content,
|
|
15431
|
+
"```"
|
|
15432
|
+
].join("\n");
|
|
15433
|
+
}
|
|
15434
|
+
function formatCallers(edges) {
|
|
15435
|
+
if (edges.length === 0) return "## Direct callers\nNone found.";
|
|
15436
|
+
return [
|
|
15437
|
+
"## Direct callers",
|
|
15438
|
+
...edges.map((edge) => `- ${edge.fromSymbolName ?? "<unknown>"} at ${edge.fromSymbolFilePath ?? "<unknown file>"}:${edge.line} (${edge.callType}, ${edge.isResolved ? "resolved" : "unresolved"})`)
|
|
15439
|
+
].join("\n");
|
|
15440
|
+
}
|
|
15441
|
+
function formatCallees(edges, sourceFilePath) {
|
|
15442
|
+
if (edges.length === 0) return "## Direct callees\nNone found.";
|
|
15443
|
+
return [
|
|
15444
|
+
"## Direct callees",
|
|
15445
|
+
...edges.map((edge) => `- ${edge.targetName} from ${sourceFilePath}:${edge.line} (${edge.callType}, ${edge.isResolved ? "resolved" : "unresolved"})`)
|
|
15446
|
+
].join("\n");
|
|
15447
|
+
}
|
|
15448
|
+
function formatResolutionRisk(resolution) {
|
|
15449
|
+
if (resolution.status === "ambiguous") {
|
|
15450
|
+
const candidates = resolution.candidates.map((candidate) => `${candidate.filePath}:${candidate.startLine}`).join(", ");
|
|
15451
|
+
return `Risk: symbol "${resolution.name}" is ambiguous. Pass filePath to select a target.${candidates ? ` Candidates: ${candidates}.` : ""}`;
|
|
15452
|
+
}
|
|
15453
|
+
if (resolution.filePath && resolution.totalCandidates > 0) {
|
|
15454
|
+
return `Risk: symbol "${resolution.name}" did not resolve at filePath="${resolution.filePath}". Review the conceptual evidence before editing.`;
|
|
15455
|
+
}
|
|
15456
|
+
return `Risk: symbol "${resolution.name}" could not be resolved. Review the conceptual evidence before editing.`;
|
|
15457
|
+
}
|
|
15458
|
+
async function fallbackPack(dependencies, query, risk, resolution, tokenBudget, candidateSource = []) {
|
|
15459
|
+
const conceptual = await dependencies.searchCodebase(query, { limit: 5 });
|
|
15460
|
+
const pack = buildContextPack([...candidateSource, ...conceptual], {
|
|
15461
|
+
tokenBudget: tokenBudget ?? void 0,
|
|
15462
|
+
heading: "## Conceptual evidence",
|
|
15463
|
+
maxResults: 5,
|
|
15464
|
+
includeExactSearchHandoff: false,
|
|
15465
|
+
preferImplementationPaths: true
|
|
15466
|
+
});
|
|
15467
|
+
const fitted = fitTextToContextBudget(`${risk}
|
|
15468
|
+
|
|
15469
|
+
${pack.text}`, tokenBudget ?? void 0);
|
|
15470
|
+
return {
|
|
15471
|
+
text: fitted.text,
|
|
15472
|
+
details: {
|
|
15473
|
+
resolution,
|
|
15474
|
+
tokenBudget: fitted.tokenBudget,
|
|
15475
|
+
tokenEstimate: fitted.tokenEstimate,
|
|
15476
|
+
truncated: fitted.truncated,
|
|
15477
|
+
sourceIncluded: candidateSource.length > 0,
|
|
15478
|
+
callerCount: 0,
|
|
15479
|
+
calleeCount: 0
|
|
15480
|
+
}
|
|
15481
|
+
};
|
|
15482
|
+
}
|
|
15483
|
+
async function resolveCodebaseEditContextWithDependencies(input, dependencies) {
|
|
15484
|
+
const symbol = input.symbol?.trim();
|
|
15485
|
+
if (!symbol) {
|
|
15486
|
+
return fallbackPack(
|
|
15487
|
+
dependencies,
|
|
15488
|
+
input.query,
|
|
15489
|
+
"Risk: no authoritative symbol was supplied. Review the conceptual evidence before editing.",
|
|
15490
|
+
"not_requested",
|
|
15491
|
+
input.tokenBudget
|
|
15492
|
+
);
|
|
15493
|
+
}
|
|
15494
|
+
let callersResult;
|
|
15495
|
+
try {
|
|
15496
|
+
callersResult = await dependencies.getCallGraphData({
|
|
15497
|
+
name: symbol,
|
|
15498
|
+
filePath: input.filePath ?? void 0,
|
|
15499
|
+
direction: "callers"
|
|
15500
|
+
});
|
|
15501
|
+
} catch (error) {
|
|
15502
|
+
const candidates = await dependencies.implementationLookup(symbol, { limit: 5 });
|
|
15503
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
15504
|
+
return fallbackPack(
|
|
15505
|
+
dependencies,
|
|
15506
|
+
input.query,
|
|
15507
|
+
`Risk: graph data is unavailable (${message}). Target and dependencies are not graph-verified.`,
|
|
15508
|
+
"graph_unavailable",
|
|
15509
|
+
input.tokenBudget,
|
|
15510
|
+
candidates
|
|
15511
|
+
);
|
|
15512
|
+
}
|
|
15513
|
+
if (callersResult.resolution.status !== "resolved") {
|
|
15514
|
+
return fallbackPack(
|
|
15515
|
+
dependencies,
|
|
15516
|
+
input.query,
|
|
15517
|
+
formatResolutionRisk(callersResult.resolution),
|
|
15518
|
+
callersResult.resolution.status,
|
|
15519
|
+
input.tokenBudget
|
|
15520
|
+
);
|
|
15521
|
+
}
|
|
15522
|
+
const resolution = callersResult.resolution;
|
|
15523
|
+
const [definitionsResult, calleesResult] = await Promise.allSettled([
|
|
15524
|
+
dependencies.implementationLookup(symbol, { limit: 10 }),
|
|
15525
|
+
dependencies.getCallGraphData({
|
|
15526
|
+
name: symbol,
|
|
15527
|
+
filePath: input.filePath ?? resolution.filePath,
|
|
15528
|
+
direction: "callees"
|
|
15529
|
+
})
|
|
15530
|
+
]);
|
|
15531
|
+
if (definitionsResult.status === "rejected") throw definitionsResult.reason;
|
|
15532
|
+
let graphRisk;
|
|
15533
|
+
let callees = [];
|
|
15534
|
+
if (calleesResult.status === "rejected") {
|
|
15535
|
+
const message = calleesResult.reason instanceof Error ? calleesResult.reason.message : String(calleesResult.reason);
|
|
15536
|
+
graphRisk = `Risk: callee graph data is unavailable (${message}). Dependency evidence is incomplete.`;
|
|
15537
|
+
} else if (calleesResult.value.resolution.status !== "resolved") {
|
|
15538
|
+
graphRisk = "Risk: the target resolved for callers but not callees. Dependency evidence is incomplete.";
|
|
15539
|
+
} else {
|
|
15540
|
+
callees = calleesResult.value.callees.slice(0, edgeLimit(input.calleeLimit));
|
|
15541
|
+
}
|
|
15542
|
+
const source = targetSource(definitionsResult.value, resolution);
|
|
15543
|
+
const callers = callersResult.callers.slice(0, edgeLimit(input.callerLimit));
|
|
15544
|
+
const sourceBudget = Math.max(
|
|
15545
|
+
MIN_CONTEXT_PACK_TOKEN_BUDGET,
|
|
15546
|
+
Math.floor((input.tokenBudget ?? DEFAULT_CONTEXT_PACK_TOKEN_BUDGET) * 0.6)
|
|
15547
|
+
);
|
|
15548
|
+
const sourceText = source ? fitTextToContextBudget(formatSource(source), sourceBudget).text : `## Target implementation
|
|
15549
|
+
Risk: no implementation source matched the resolved target at ${resolution.filePath}:${resolution.startLine}.`;
|
|
15550
|
+
const fitted = fitTextToContextBudget([
|
|
15551
|
+
`# Pre-edit context for ${resolution.name}`,
|
|
15552
|
+
graphRisk,
|
|
15553
|
+
sourceText,
|
|
15554
|
+
formatCallers(callers),
|
|
15555
|
+
formatCallees(callees, resolution.filePath)
|
|
15556
|
+
].filter((section) => section !== void 0).join("\n\n"), input.tokenBudget ?? void 0);
|
|
15557
|
+
return {
|
|
15558
|
+
text: fitted.text,
|
|
15559
|
+
details: {
|
|
15560
|
+
resolution: "resolved",
|
|
15561
|
+
tokenBudget: fitted.tokenBudget,
|
|
15562
|
+
tokenEstimate: fitted.tokenEstimate,
|
|
15563
|
+
truncated: fitted.truncated,
|
|
15564
|
+
sourceIncluded: source !== void 0,
|
|
15565
|
+
callerCount: callers.length,
|
|
15566
|
+
calleeCount: callees.length
|
|
15567
|
+
}
|
|
15568
|
+
};
|
|
15569
|
+
}
|
|
15570
|
+
async function resolveCodebaseEditContext(projectRoot3, host, input) {
|
|
15571
|
+
return resolveCodebaseEditContextWithDependencies(input, {
|
|
15572
|
+
searchCodebase: (query, options) => searchCodebase(projectRoot3, host, query, options),
|
|
15573
|
+
implementationLookup: (query, options) => implementationLookup(projectRoot3, host, query, options),
|
|
15574
|
+
getCallGraphData: (params) => getCallGraphData(projectRoot3, host, params)
|
|
15575
|
+
});
|
|
15576
|
+
}
|
|
15577
|
+
|
|
15260
15578
|
// src/adapters/pi/call-graph.ts
|
|
15261
15579
|
import { Type } from "typebox";
|
|
15262
15580
|
|
|
15263
15581
|
// src/tools/tool-names.ts
|
|
15264
15582
|
var TOOL_NAME = {
|
|
15265
15583
|
CODEBASE_CONTEXT: "codebase_context",
|
|
15584
|
+
CODEBASE_EDIT_CONTEXT: "codebase_edit_context",
|
|
15266
15585
|
CODEBASE_SEARCH: "codebase_search",
|
|
15267
15586
|
CODEBASE_PEEK: "codebase_peek",
|
|
15268
15587
|
FIND_SIMILAR: "find_similar",
|
|
@@ -15286,6 +15605,7 @@ var TOOL_NAME = {
|
|
|
15286
15605
|
};
|
|
15287
15606
|
var PORTABLE_TOOL_NAMES = [
|
|
15288
15607
|
TOOL_NAME.CODEBASE_CONTEXT,
|
|
15608
|
+
TOOL_NAME.CODEBASE_EDIT_CONTEXT,
|
|
15289
15609
|
TOOL_NAME.CODEBASE_SEARCH,
|
|
15290
15610
|
TOOL_NAME.CODEBASE_PEEK,
|
|
15291
15611
|
TOOL_NAME.INDEX_CODEBASE,
|
|
@@ -15302,6 +15622,7 @@ var PORTABLE_TOOL_NAMES = [
|
|
|
15302
15622
|
];
|
|
15303
15623
|
var OPENCODE_TOOL_NAMES = [
|
|
15304
15624
|
TOOL_NAME.CODEBASE_CONTEXT,
|
|
15625
|
+
TOOL_NAME.CODEBASE_EDIT_CONTEXT,
|
|
15305
15626
|
TOOL_NAME.CODEBASE_SEARCH,
|
|
15306
15627
|
TOOL_NAME.CODEBASE_PEEK,
|
|
15307
15628
|
TOOL_NAME.INDEX_CODEBASE,
|
|
@@ -15322,6 +15643,7 @@ var OPENCODE_TOOL_NAMES = [
|
|
|
15322
15643
|
];
|
|
15323
15644
|
var PI_TOOL_NAMES = [
|
|
15324
15645
|
TOOL_NAME.CODEBASE_CONTEXT,
|
|
15646
|
+
TOOL_NAME.CODEBASE_EDIT_CONTEXT,
|
|
15325
15647
|
TOOL_NAME.CODEBASE_SEARCH,
|
|
15326
15648
|
TOOL_NAME.CODEBASE_PEEK,
|
|
15327
15649
|
TOOL_NAME.FIND_SIMILAR,
|
|
@@ -15436,6 +15758,7 @@ function codebaseIndexPiExtension(pi) {
|
|
|
15436
15758
|
Type2.Integer({ minimum: MIN_CONTEXT_PATH_DEPTH, maximum: MAX_CONTEXT_PATH_DEPTH }),
|
|
15437
15759
|
Type2.Null()
|
|
15438
15760
|
], { default: 10, description: `Maximum call-graph traversal depth (${MIN_CONTEXT_PATH_DEPTH}-${MAX_CONTEXT_PATH_DEPTH})` })),
|
|
15761
|
+
diagnostic: Type2.Optional(Type2.Union([Type2.Boolean(), Type2.Null()], { description: "Collect diagnostic routing and search traces without changing normal output." })),
|
|
15439
15762
|
fileType: Type2.Optional(Type2.Union([Type2.String(), Type2.Null()], { description: "Filter by file extension, e.g., ts, py, rs" })),
|
|
15440
15763
|
directory: Type2.Optional(Type2.Union([Type2.String(), Type2.Null()], { description: "Filter by directory path" })),
|
|
15441
15764
|
tokenBudget: Type2.Optional(Type2.Union([
|
|
@@ -15447,10 +15770,40 @@ function codebaseIndexPiExtension(pi) {
|
|
|
15447
15770
|
}))
|
|
15448
15771
|
}),
|
|
15449
15772
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
15450
|
-
const
|
|
15773
|
+
const normalizedParams = {
|
|
15774
|
+
...params,
|
|
15775
|
+
diagnostic: params.diagnostic ?? void 0
|
|
15776
|
+
};
|
|
15777
|
+
const result = await resolveCodebaseContext(projectRoot2(ctx), HOST2, normalizedParams);
|
|
15451
15778
|
return text2(result.text, result.details);
|
|
15452
15779
|
}
|
|
15453
15780
|
});
|
|
15781
|
+
pi.registerTool({
|
|
15782
|
+
name: TOOL_NAME.CODEBASE_EDIT_CONTEXT,
|
|
15783
|
+
label: "Codebase Edit Context",
|
|
15784
|
+
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.",
|
|
15785
|
+
parameters: Type2.Object({
|
|
15786
|
+
query: Type2.String({ description: "The requested change or target behavior" }),
|
|
15787
|
+
symbol: Type2.Optional(Type2.Union([Type2.String(), Type2.Null()])),
|
|
15788
|
+
filePath: Type2.Optional(Type2.Union([Type2.String(), Type2.Null()])),
|
|
15789
|
+
callerLimit: Type2.Optional(Type2.Union([
|
|
15790
|
+
Type2.Integer({ minimum: MIN_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT, maximum: MAX_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT }),
|
|
15791
|
+
Type2.Null()
|
|
15792
|
+
], { default: DEFAULT_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT })),
|
|
15793
|
+
calleeLimit: Type2.Optional(Type2.Union([
|
|
15794
|
+
Type2.Integer({ minimum: MIN_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT, maximum: MAX_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT }),
|
|
15795
|
+
Type2.Null()
|
|
15796
|
+
], { default: DEFAULT_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT })),
|
|
15797
|
+
tokenBudget: Type2.Optional(Type2.Union([
|
|
15798
|
+
Type2.Integer({ minimum: MIN_CONTEXT_PACK_TOKEN_BUDGET, maximum: MAX_CONTEXT_PACK_TOKEN_BUDGET }),
|
|
15799
|
+
Type2.Null()
|
|
15800
|
+
], { default: DEFAULT_CONTEXT_PACK_TOKEN_BUDGET }))
|
|
15801
|
+
}),
|
|
15802
|
+
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
15803
|
+
const result = await resolveCodebaseEditContext(projectRoot2(ctx), HOST2, params);
|
|
15804
|
+
return text2(result.text);
|
|
15805
|
+
}
|
|
15806
|
+
});
|
|
15454
15807
|
pi.registerTool({
|
|
15455
15808
|
name: TOOL_NAME.CODEBASE_SEARCH,
|
|
15456
15809
|
label: "Codebase Search",
|