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/index.cjs
CHANGED
|
@@ -1925,6 +1925,9 @@ var RELATIONSHIP_TYPES = [
|
|
|
1925
1925
|
];
|
|
1926
1926
|
var INDEX_LOG_CATEGORIES = ["search", "embedding", "cache", "gc", "branch", "general"];
|
|
1927
1927
|
var INDEX_LOG_LEVELS = ["error", "warn", "info", "debug"];
|
|
1928
|
+
var MIN_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT = 1;
|
|
1929
|
+
var MAX_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT = 20;
|
|
1930
|
+
var DEFAULT_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT = 5;
|
|
1928
1931
|
var CODE_COMMUNITIES_MIN_SIZE = 1;
|
|
1929
1932
|
var CODE_COMMUNITIES_DEFAULT_LIMIT = 20;
|
|
1930
1933
|
var CODE_COMMUNITIES_MAX_LIMIT = 100;
|
|
@@ -2548,6 +2551,16 @@ function compactEvidenceValue(value, maxChars) {
|
|
|
2548
2551
|
}
|
|
2549
2552
|
var MAX_EXACT_SEARCH_HANDOFF_NAMES = 3;
|
|
2550
2553
|
var MAX_EXACT_SEARCH_HANDOFF_NAME_CHARS = 64;
|
|
2554
|
+
function toContextPackTraceCandidate(result) {
|
|
2555
|
+
return {
|
|
2556
|
+
filePath: result.filePath,
|
|
2557
|
+
startLine: result.startLine,
|
|
2558
|
+
endLine: result.endLine,
|
|
2559
|
+
score: result.score,
|
|
2560
|
+
chunkType: result.chunkType,
|
|
2561
|
+
name: result.name
|
|
2562
|
+
};
|
|
2563
|
+
}
|
|
2551
2564
|
function formatExactSearchHandoff(results) {
|
|
2552
2565
|
const suggestedNames = [];
|
|
2553
2566
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -2596,13 +2609,13 @@ function buildContextPack(results, options = {}) {
|
|
|
2596
2609
|
const maxResults = Math.max(0, Math.floor(options.maxResults ?? results.length));
|
|
2597
2610
|
const includeExactSearchHandoff = options.includeExactSearchHandoff ?? false;
|
|
2598
2611
|
const candidateCount = results.length;
|
|
2599
|
-
const
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
);
|
|
2605
|
-
const
|
|
2612
|
+
const preserveInputOrder = options.preserveInputOrder ?? false;
|
|
2613
|
+
const ranked = preserveInputOrder ? results.map((result, originalIndex) => ({ result, originalIndex })) : rankContextCandidates(results, options.preferImplementationPaths ?? false);
|
|
2614
|
+
const rankedCandidates = ranked.map((entry) => toContextPackTraceCandidate(entry.result));
|
|
2615
|
+
const deduplicated = deduplicateContextCandidates(ranked);
|
|
2616
|
+
const deduplicatedCandidates = deduplicated.map((result) => toContextPackTraceCandidate(result));
|
|
2617
|
+
const diversified = preserveInputOrder ? deduplicated : diversifyContextCandidates(deduplicated);
|
|
2618
|
+
const diversifiedCandidates = diversified.map((result) => toContextPackTraceCandidate(result));
|
|
2606
2619
|
const duplicateCount = candidateCount - deduplicated.length;
|
|
2607
2620
|
const selectable = diversified.slice(0, maxResults);
|
|
2608
2621
|
const limitOmittedCount = deduplicated.length - selectable.length;
|
|
@@ -2635,6 +2648,15 @@ function buildContextPack(results, options = {}) {
|
|
|
2635
2648
|
const fitted = fitTextToContextBudget(text, tokenBudget);
|
|
2636
2649
|
const budgetOmittedCount = selectable.length - selected.length;
|
|
2637
2650
|
const omittedCount = candidateCount - selected.length;
|
|
2651
|
+
if (options.trace) {
|
|
2652
|
+
options.trace({
|
|
2653
|
+
inputCandidates: results.map(toContextPackTraceCandidate),
|
|
2654
|
+
rankedCandidates,
|
|
2655
|
+
deduplicatedCandidates,
|
|
2656
|
+
diversifiedCandidates,
|
|
2657
|
+
selectedCandidates: selected.map(toContextPackTraceCandidate)
|
|
2658
|
+
});
|
|
2659
|
+
}
|
|
2638
2660
|
return {
|
|
2639
2661
|
requestedTokenBudget,
|
|
2640
2662
|
tokenBudget,
|
|
@@ -8613,12 +8635,12 @@ function diversifyGroupBySymbol(entries, getCandidate) {
|
|
|
8613
8635
|
return [...primary, ...remainder];
|
|
8614
8636
|
}
|
|
8615
8637
|
function buildDiversityKey(metadata) {
|
|
8616
|
-
const
|
|
8638
|
+
const normalizedPath2 = metadata.filePath.toLowerCase();
|
|
8617
8639
|
const normalizedName = (metadata.name ?? "").trim().toLowerCase();
|
|
8618
8640
|
if (normalizedName.length > 0) {
|
|
8619
|
-
return `${
|
|
8641
|
+
return `${normalizedPath2}#${normalizedName}`;
|
|
8620
8642
|
}
|
|
8621
|
-
return
|
|
8643
|
+
return normalizedPath2;
|
|
8622
8644
|
}
|
|
8623
8645
|
function rankHybridResults(query, semanticResults, keywordResults, options) {
|
|
8624
8646
|
const prioritizeSourcePaths = options.prioritizeSourcePaths ?? classifyQueryIntentRaw(query) === "source";
|
|
@@ -9024,6 +9046,29 @@ function extractPrimaryIdentifierQueryHint(query) {
|
|
|
9024
9046
|
const best = codeTerms.find((term) => term.length >= 6);
|
|
9025
9047
|
return best ?? null;
|
|
9026
9048
|
}
|
|
9049
|
+
function pathSegmentsForAffinityMatch(filePath) {
|
|
9050
|
+
const normalizedPath2 = normalizeRankingText(filePath).replace(/\\/g, "/");
|
|
9051
|
+
const segments = normalizedPath2.split("/").filter((segment) => segment.length > 0);
|
|
9052
|
+
if (segments.length === 0) {
|
|
9053
|
+
return [];
|
|
9054
|
+
}
|
|
9055
|
+
const basename9 = segments[segments.length - 1] ?? "";
|
|
9056
|
+
const basenameWithoutExt = basename9.replace(/\.[^/.]+$/u, "");
|
|
9057
|
+
const normalizedSegments = segments.map((segment) => segment.toLowerCase());
|
|
9058
|
+
return Array.from(/* @__PURE__ */ new Set([
|
|
9059
|
+
...normalizedSegments,
|
|
9060
|
+
basenameWithoutExt.toLowerCase()
|
|
9061
|
+
]));
|
|
9062
|
+
}
|
|
9063
|
+
function hasModuleAffinity(filePath, exactIdentifierVariants) {
|
|
9064
|
+
const haystack = pathSegmentsForAffinityMatch(filePath);
|
|
9065
|
+
return exactIdentifierVariants.some((variant) => {
|
|
9066
|
+
if (!variant || variant.length < 2) {
|
|
9067
|
+
return false;
|
|
9068
|
+
}
|
|
9069
|
+
return haystack.includes(variant);
|
|
9070
|
+
});
|
|
9071
|
+
}
|
|
9027
9072
|
var FILE_PATH_HINT_EXTENSIONS = [
|
|
9028
9073
|
"ts",
|
|
9029
9074
|
"tsx",
|
|
@@ -9067,9 +9112,9 @@ function normalizeFilePathForHintMatch(filePath) {
|
|
|
9067
9112
|
return filePath.replace(/\\/g, "/").toLowerCase().replace(/^\.\//, "");
|
|
9068
9113
|
}
|
|
9069
9114
|
function pathMatchesHint(filePath, hint) {
|
|
9070
|
-
const
|
|
9115
|
+
const normalizedPath2 = normalizeFilePathForHintMatch(filePath);
|
|
9071
9116
|
const normalizedHint = normalizeFilePathForHintMatch(hint);
|
|
9072
|
-
return
|
|
9117
|
+
return normalizedPath2.endsWith(normalizedHint) || normalizedPath2.includes(`/${normalizedHint}`) || normalizedPath2.includes(normalizedHint);
|
|
9073
9118
|
}
|
|
9074
9119
|
function extractFilePathHint(query) {
|
|
9075
9120
|
const match = query.match(FILE_PATH_HINT_SUFFIX_REGEX);
|
|
@@ -9099,10 +9144,13 @@ function buildDeterministicIdentifierPass(query, candidates, limit, prioritizeSo
|
|
|
9099
9144
|
).map((candidate) => {
|
|
9100
9145
|
const nameLower = (candidate.metadata.name ?? "").toLowerCase();
|
|
9101
9146
|
const pathLower = candidate.metadata.filePath.toLowerCase();
|
|
9102
|
-
|
|
9103
|
-
const
|
|
9147
|
+
const exactIdentifierVariants = primaryVariants.filter((value) => value.length >= 2);
|
|
9148
|
+
const exactMatch = exactIdentifierVariants.some(
|
|
9104
9149
|
(variant) => nameLower === variant || nameLower.replace(/[^a-z0-9]/g, "") === variant.replace(/[^a-z0-9]/g, "")
|
|
9105
9150
|
);
|
|
9151
|
+
let maxMatch = 0;
|
|
9152
|
+
const nameMatchesPrimary = exactMatch;
|
|
9153
|
+
const pathAffinity = exactMatch ? hasModuleAffinity(candidate.metadata.filePath, exactIdentifierVariants) : false;
|
|
9106
9154
|
const pathMatchesFileHint = filePathHint ? pathMatchesHint(candidate.metadata.filePath, filePathHint) : false;
|
|
9107
9155
|
for (const hint of hints) {
|
|
9108
9156
|
const variants = normalizeIdentifierVariants(hint);
|
|
@@ -9123,12 +9171,17 @@ function buildDeterministicIdentifierPass(query, candidates, limit, prioritizeSo
|
|
|
9123
9171
|
candidate,
|
|
9124
9172
|
maxMatch,
|
|
9125
9173
|
pathMatchesFileHint,
|
|
9126
|
-
nameMatchesPrimary
|
|
9174
|
+
nameMatchesPrimary,
|
|
9175
|
+
pathAffinity
|
|
9127
9176
|
};
|
|
9128
9177
|
}).filter((entry) => entry.maxMatch >= 0.7).sort((a, b) => {
|
|
9129
9178
|
const aAnchored = a.pathMatchesFileHint && a.nameMatchesPrimary ? 1 : 0;
|
|
9130
9179
|
const bAnchored = b.pathMatchesFileHint && b.nameMatchesPrimary ? 1 : 0;
|
|
9131
9180
|
if (aAnchored !== bAnchored) return bAnchored - aAnchored;
|
|
9181
|
+
if (a.nameMatchesPrimary !== b.nameMatchesPrimary) {
|
|
9182
|
+
return b.nameMatchesPrimary ? 1 : -1;
|
|
9183
|
+
}
|
|
9184
|
+
if (a.pathAffinity !== b.pathAffinity) return b.pathAffinity ? 1 : -1;
|
|
9132
9185
|
if (b.maxMatch !== a.maxMatch) return b.maxMatch - a.maxMatch;
|
|
9133
9186
|
if (b.candidate.score !== a.candidate.score) return b.candidate.score - a.candidate.score;
|
|
9134
9187
|
return a.candidate.id.localeCompare(b.candidate.id);
|
|
@@ -12942,6 +12995,20 @@ var Indexer = class _Indexer {
|
|
|
12942
12995
|
requestedLimit = nextLimit;
|
|
12943
12996
|
}
|
|
12944
12997
|
}
|
|
12998
|
+
buildCandidateSnapshot(candidate) {
|
|
12999
|
+
return {
|
|
13000
|
+
id: candidate.id,
|
|
13001
|
+
filePath: candidate.metadata.filePath,
|
|
13002
|
+
startLine: candidate.metadata.startLine,
|
|
13003
|
+
endLine: candidate.metadata.endLine,
|
|
13004
|
+
score: candidate.score,
|
|
13005
|
+
chunkType: candidate.metadata.chunkType,
|
|
13006
|
+
name: candidate.metadata.name
|
|
13007
|
+
};
|
|
13008
|
+
}
|
|
13009
|
+
buildCandidateSnapshotList(candidates) {
|
|
13010
|
+
return candidates.map((candidate) => this.buildCandidateSnapshot(candidate));
|
|
13011
|
+
}
|
|
12945
13012
|
searchSemanticCandidates(store, embedding, initialLimit, branchChunkIds, shouldPrefilterByBranch) {
|
|
12946
13013
|
return this.searchCandidatesWithBranchPrefilter(
|
|
12947
13014
|
initialLimit,
|
|
@@ -13133,6 +13200,16 @@ var Indexer = class _Indexer {
|
|
|
13133
13200
|
prefilterMs: Math.round(prefilterMs * 100) / 100,
|
|
13134
13201
|
fusionMs: Math.round(fusionMs * 100) / 100
|
|
13135
13202
|
});
|
|
13203
|
+
if (options?.trace) {
|
|
13204
|
+
options.trace({
|
|
13205
|
+
semanticCandidates: this.buildCandidateSnapshotList(scopedSemanticCandidates),
|
|
13206
|
+
keywordCandidates: this.buildCandidateSnapshotList(scopedKeywordCandidates),
|
|
13207
|
+
hybridCandidates: this.buildCandidateSnapshotList(combined),
|
|
13208
|
+
postExternalRerankCandidates: this.buildCandidateSnapshotList(rerankedCombined),
|
|
13209
|
+
tieredCandidates: this.buildCandidateSnapshotList(tiered),
|
|
13210
|
+
finalCandidates: this.buildCandidateSnapshotList(finalResults)
|
|
13211
|
+
});
|
|
13212
|
+
}
|
|
13136
13213
|
const metadataOnly = options?.metadataOnly ?? false;
|
|
13137
13214
|
return Promise.all(
|
|
13138
13215
|
finalResults.map(async (r) => {
|
|
@@ -14400,7 +14477,8 @@ async function searchCodebase(projectRoot, host, query, options = {}) {
|
|
|
14400
14477
|
definitionIntent: options.definitionIntent,
|
|
14401
14478
|
blameAuthor: options.blameAuthor,
|
|
14402
14479
|
blameSha: options.blameSha,
|
|
14403
|
-
blameSince: options.blameSince
|
|
14480
|
+
blameSince: options.blameSince,
|
|
14481
|
+
trace: options.trace
|
|
14404
14482
|
});
|
|
14405
14483
|
}
|
|
14406
14484
|
async function searchCodebaseWithEffectiveness(projectRoot, host, route, query, options, render) {
|
|
@@ -14454,15 +14532,19 @@ async function implementationLookup(projectRoot, host, query, options = {}) {
|
|
|
14454
14532
|
return indexer.search(query, options.limit, {
|
|
14455
14533
|
fileType: options.fileType,
|
|
14456
14534
|
directory: options.directory,
|
|
14457
|
-
definitionIntent: true
|
|
14535
|
+
definitionIntent: true,
|
|
14536
|
+
trace: options.trace
|
|
14458
14537
|
});
|
|
14459
14538
|
}
|
|
14460
14539
|
async function getCallGraphData(projectRoot, host, params) {
|
|
14461
14540
|
await ensureAutoIndexReadyForRetrieval(projectRoot, host);
|
|
14462
14541
|
const root = getProjectRoot(projectRoot, host);
|
|
14463
14542
|
const indexer = getIndexerForProject(root, host);
|
|
14543
|
+
return getCallGraphDataForIndexer(indexer, root, params);
|
|
14544
|
+
}
|
|
14545
|
+
async function getCallGraphDataForIndexer(indexer, projectRoot, params) {
|
|
14464
14546
|
const symbols = await indexer.getCallGraphSymbols();
|
|
14465
|
-
const resolution = resolveCallGraphSymbol(symbols,
|
|
14547
|
+
const resolution = resolveCallGraphSymbol(symbols, projectRoot, params.name, params.filePath, params.symbolId);
|
|
14466
14548
|
const direction = params.direction === "callees" ? "callees" : "callers";
|
|
14467
14549
|
if (resolution.status !== "resolved") {
|
|
14468
14550
|
return { direction, resolution, callers: [], callees: [], relationshipType: params.relationshipType };
|
|
@@ -14678,17 +14760,17 @@ async function getIndexLogs(projectRoot, host, args) {
|
|
|
14678
14760
|
function addKnowledgeBase(projectRoot, host, knowledgeBasePath) {
|
|
14679
14761
|
const root = getProjectRoot(projectRoot, host);
|
|
14680
14762
|
const inputPath = knowledgeBasePath.trim();
|
|
14681
|
-
const
|
|
14763
|
+
const normalizedPath2 = path20.resolve(
|
|
14682
14764
|
path20.isAbsolute(inputPath) ? inputPath : resolveKnowledgeBasePath(inputPath, root)
|
|
14683
14765
|
);
|
|
14684
|
-
if (!(0, import_fs13.existsSync)(
|
|
14685
|
-
return `Error: Directory does not exist: ${
|
|
14766
|
+
if (!(0, import_fs13.existsSync)(normalizedPath2)) {
|
|
14767
|
+
return `Error: Directory does not exist: ${normalizedPath2}`;
|
|
14686
14768
|
}
|
|
14687
14769
|
let realPath;
|
|
14688
14770
|
try {
|
|
14689
|
-
realPath = (0, import_fs13.realpathSync)(
|
|
14771
|
+
realPath = (0, import_fs13.realpathSync)(normalizedPath2);
|
|
14690
14772
|
} catch {
|
|
14691
|
-
return `Error: Cannot resolve path: ${
|
|
14773
|
+
return `Error: Cannot resolve path: ${normalizedPath2}`;
|
|
14692
14774
|
}
|
|
14693
14775
|
const blockedPrefixes = [
|
|
14694
14776
|
"/etc",
|
|
@@ -14711,34 +14793,34 @@ function addKnowledgeBase(projectRoot, host, knowledgeBasePath) {
|
|
|
14711
14793
|
];
|
|
14712
14794
|
for (const prefix of blockedPrefixes) {
|
|
14713
14795
|
if (realPath === prefix || realPath.startsWith(`${prefix}/`)) {
|
|
14714
|
-
return `Error: Adding sensitive directory as knowledge base is not allowed: ${
|
|
14796
|
+
return `Error: Adding sensitive directory as knowledge base is not allowed: ${normalizedPath2}`;
|
|
14715
14797
|
}
|
|
14716
14798
|
}
|
|
14717
14799
|
for (const dotDir of sensitiveDotDirs) {
|
|
14718
14800
|
const sensitiveDir = path20.join(homeDir, dotDir);
|
|
14719
14801
|
if (sensitiveDir && (realPath === sensitiveDir || realPath.startsWith(`${sensitiveDir}/`))) {
|
|
14720
|
-
return `Error: Adding sensitive directory as knowledge base is not allowed: ${
|
|
14802
|
+
return `Error: Adding sensitive directory as knowledge base is not allowed: ${normalizedPath2}`;
|
|
14721
14803
|
}
|
|
14722
14804
|
}
|
|
14723
14805
|
try {
|
|
14724
|
-
const stat4 = (0, import_fs13.statSync)(
|
|
14806
|
+
const stat4 = (0, import_fs13.statSync)(normalizedPath2);
|
|
14725
14807
|
if (!stat4.isDirectory()) {
|
|
14726
|
-
return `Error: Path is not a directory: ${
|
|
14808
|
+
return `Error: Path is not a directory: ${normalizedPath2}`;
|
|
14727
14809
|
}
|
|
14728
14810
|
} catch (error) {
|
|
14729
|
-
return `Error: Cannot access directory: ${
|
|
14811
|
+
return `Error: Cannot access directory: ${normalizedPath2} - ${error instanceof Error ? error.message : String(error)}`;
|
|
14730
14812
|
}
|
|
14731
14813
|
const config = loadEditableConfig(root, host);
|
|
14732
14814
|
const knowledgeBases = Array.isArray(config.knowledgeBases) ? config.knowledgeBases : [];
|
|
14733
|
-
const alreadyExists = hasMatchingKnowledgeBasePath(knowledgeBases,
|
|
14815
|
+
const alreadyExists = hasMatchingKnowledgeBasePath(knowledgeBases, normalizedPath2, root);
|
|
14734
14816
|
if (alreadyExists) {
|
|
14735
|
-
return `Knowledge base already configured: ${
|
|
14817
|
+
return `Knowledge base already configured: ${normalizedPath2}`;
|
|
14736
14818
|
}
|
|
14737
|
-
knowledgeBases.push(
|
|
14819
|
+
knowledgeBases.push(normalizedPath2);
|
|
14738
14820
|
config.knowledgeBases = knowledgeBases;
|
|
14739
14821
|
saveConfig(root, config, host);
|
|
14740
14822
|
refreshIndexerForDirectory(root, host);
|
|
14741
|
-
let result = `${
|
|
14823
|
+
let result = `${normalizedPath2}
|
|
14742
14824
|
`;
|
|
14743
14825
|
result += `Total knowledge bases: ${knowledgeBases.length}
|
|
14744
14826
|
`;
|
|
@@ -17051,6 +17133,181 @@ var pr_impact = tool({
|
|
|
17051
17133
|
}
|
|
17052
17134
|
});
|
|
17053
17135
|
|
|
17136
|
+
// src/tools/edit-context.ts
|
|
17137
|
+
function edgeLimit(value) {
|
|
17138
|
+
if (value === null || value === void 0 || !Number.isFinite(value)) {
|
|
17139
|
+
return DEFAULT_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT;
|
|
17140
|
+
}
|
|
17141
|
+
return Math.min(
|
|
17142
|
+
MAX_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT,
|
|
17143
|
+
Math.max(MIN_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT, Math.floor(value))
|
|
17144
|
+
);
|
|
17145
|
+
}
|
|
17146
|
+
function normalizedPath(value) {
|
|
17147
|
+
return value.replaceAll("\\", "/").replace(/^\.\//, "");
|
|
17148
|
+
}
|
|
17149
|
+
function pathsMatch(left, right) {
|
|
17150
|
+
const normalizedLeft = normalizedPath(left);
|
|
17151
|
+
const normalizedRight = normalizedPath(right);
|
|
17152
|
+
return normalizedLeft === normalizedRight || normalizedLeft.endsWith(`/${normalizedRight}`) || normalizedRight.endsWith(`/${normalizedLeft}`);
|
|
17153
|
+
}
|
|
17154
|
+
function targetSource(results, resolution) {
|
|
17155
|
+
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);
|
|
17156
|
+
}
|
|
17157
|
+
function formatSource(result) {
|
|
17158
|
+
const name = result.name ? ` ${result.name}` : "";
|
|
17159
|
+
return [
|
|
17160
|
+
"## Target implementation",
|
|
17161
|
+
`${result.filePath}:${result.startLine}-${result.endLine} (${result.chunkType}${name})`,
|
|
17162
|
+
"```",
|
|
17163
|
+
result.content,
|
|
17164
|
+
"```"
|
|
17165
|
+
].join("\n");
|
|
17166
|
+
}
|
|
17167
|
+
function formatCallers(edges) {
|
|
17168
|
+
if (edges.length === 0) return "## Direct callers\nNone found.";
|
|
17169
|
+
return [
|
|
17170
|
+
"## Direct callers",
|
|
17171
|
+
...edges.map((edge) => `- ${edge.fromSymbolName ?? "<unknown>"} at ${edge.fromSymbolFilePath ?? "<unknown file>"}:${edge.line} (${edge.callType}, ${edge.isResolved ? "resolved" : "unresolved"})`)
|
|
17172
|
+
].join("\n");
|
|
17173
|
+
}
|
|
17174
|
+
function formatCallees(edges, sourceFilePath) {
|
|
17175
|
+
if (edges.length === 0) return "## Direct callees\nNone found.";
|
|
17176
|
+
return [
|
|
17177
|
+
"## Direct callees",
|
|
17178
|
+
...edges.map((edge) => `- ${edge.targetName} from ${sourceFilePath}:${edge.line} (${edge.callType}, ${edge.isResolved ? "resolved" : "unresolved"})`)
|
|
17179
|
+
].join("\n");
|
|
17180
|
+
}
|
|
17181
|
+
function formatResolutionRisk(resolution) {
|
|
17182
|
+
if (resolution.status === "ambiguous") {
|
|
17183
|
+
const candidates = resolution.candidates.map((candidate) => `${candidate.filePath}:${candidate.startLine}`).join(", ");
|
|
17184
|
+
return `Risk: symbol "${resolution.name}" is ambiguous. Pass filePath to select a target.${candidates ? ` Candidates: ${candidates}.` : ""}`;
|
|
17185
|
+
}
|
|
17186
|
+
if (resolution.filePath && resolution.totalCandidates > 0) {
|
|
17187
|
+
return `Risk: symbol "${resolution.name}" did not resolve at filePath="${resolution.filePath}". Review the conceptual evidence before editing.`;
|
|
17188
|
+
}
|
|
17189
|
+
return `Risk: symbol "${resolution.name}" could not be resolved. Review the conceptual evidence before editing.`;
|
|
17190
|
+
}
|
|
17191
|
+
async function fallbackPack(dependencies, query, risk, resolution, tokenBudget, candidateSource = []) {
|
|
17192
|
+
const conceptual = await dependencies.searchCodebase(query, { limit: 5 });
|
|
17193
|
+
const pack = buildContextPack([...candidateSource, ...conceptual], {
|
|
17194
|
+
tokenBudget: tokenBudget ?? void 0,
|
|
17195
|
+
heading: "## Conceptual evidence",
|
|
17196
|
+
maxResults: 5,
|
|
17197
|
+
includeExactSearchHandoff: false,
|
|
17198
|
+
preferImplementationPaths: true
|
|
17199
|
+
});
|
|
17200
|
+
const fitted = fitTextToContextBudget(`${risk}
|
|
17201
|
+
|
|
17202
|
+
${pack.text}`, tokenBudget ?? void 0);
|
|
17203
|
+
return {
|
|
17204
|
+
text: fitted.text,
|
|
17205
|
+
details: {
|
|
17206
|
+
resolution,
|
|
17207
|
+
tokenBudget: fitted.tokenBudget,
|
|
17208
|
+
tokenEstimate: fitted.tokenEstimate,
|
|
17209
|
+
truncated: fitted.truncated,
|
|
17210
|
+
sourceIncluded: candidateSource.length > 0,
|
|
17211
|
+
callerCount: 0,
|
|
17212
|
+
calleeCount: 0
|
|
17213
|
+
}
|
|
17214
|
+
};
|
|
17215
|
+
}
|
|
17216
|
+
async function resolveCodebaseEditContextWithDependencies(input, dependencies) {
|
|
17217
|
+
const symbol = input.symbol?.trim();
|
|
17218
|
+
if (!symbol) {
|
|
17219
|
+
return fallbackPack(
|
|
17220
|
+
dependencies,
|
|
17221
|
+
input.query,
|
|
17222
|
+
"Risk: no authoritative symbol was supplied. Review the conceptual evidence before editing.",
|
|
17223
|
+
"not_requested",
|
|
17224
|
+
input.tokenBudget
|
|
17225
|
+
);
|
|
17226
|
+
}
|
|
17227
|
+
let callersResult;
|
|
17228
|
+
try {
|
|
17229
|
+
callersResult = await dependencies.getCallGraphData({
|
|
17230
|
+
name: symbol,
|
|
17231
|
+
filePath: input.filePath ?? void 0,
|
|
17232
|
+
direction: "callers"
|
|
17233
|
+
});
|
|
17234
|
+
} catch (error) {
|
|
17235
|
+
const candidates = await dependencies.implementationLookup(symbol, { limit: 5 });
|
|
17236
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
17237
|
+
return fallbackPack(
|
|
17238
|
+
dependencies,
|
|
17239
|
+
input.query,
|
|
17240
|
+
`Risk: graph data is unavailable (${message}). Target and dependencies are not graph-verified.`,
|
|
17241
|
+
"graph_unavailable",
|
|
17242
|
+
input.tokenBudget,
|
|
17243
|
+
candidates
|
|
17244
|
+
);
|
|
17245
|
+
}
|
|
17246
|
+
if (callersResult.resolution.status !== "resolved") {
|
|
17247
|
+
return fallbackPack(
|
|
17248
|
+
dependencies,
|
|
17249
|
+
input.query,
|
|
17250
|
+
formatResolutionRisk(callersResult.resolution),
|
|
17251
|
+
callersResult.resolution.status,
|
|
17252
|
+
input.tokenBudget
|
|
17253
|
+
);
|
|
17254
|
+
}
|
|
17255
|
+
const resolution = callersResult.resolution;
|
|
17256
|
+
const [definitionsResult, calleesResult] = await Promise.allSettled([
|
|
17257
|
+
dependencies.implementationLookup(symbol, { limit: 10 }),
|
|
17258
|
+
dependencies.getCallGraphData({
|
|
17259
|
+
name: symbol,
|
|
17260
|
+
filePath: input.filePath ?? resolution.filePath,
|
|
17261
|
+
direction: "callees"
|
|
17262
|
+
})
|
|
17263
|
+
]);
|
|
17264
|
+
if (definitionsResult.status === "rejected") throw definitionsResult.reason;
|
|
17265
|
+
let graphRisk;
|
|
17266
|
+
let callees = [];
|
|
17267
|
+
if (calleesResult.status === "rejected") {
|
|
17268
|
+
const message = calleesResult.reason instanceof Error ? calleesResult.reason.message : String(calleesResult.reason);
|
|
17269
|
+
graphRisk = `Risk: callee graph data is unavailable (${message}). Dependency evidence is incomplete.`;
|
|
17270
|
+
} else if (calleesResult.value.resolution.status !== "resolved") {
|
|
17271
|
+
graphRisk = "Risk: the target resolved for callers but not callees. Dependency evidence is incomplete.";
|
|
17272
|
+
} else {
|
|
17273
|
+
callees = calleesResult.value.callees.slice(0, edgeLimit(input.calleeLimit));
|
|
17274
|
+
}
|
|
17275
|
+
const source = targetSource(definitionsResult.value, resolution);
|
|
17276
|
+
const callers = callersResult.callers.slice(0, edgeLimit(input.callerLimit));
|
|
17277
|
+
const sourceBudget = Math.max(
|
|
17278
|
+
MIN_CONTEXT_PACK_TOKEN_BUDGET,
|
|
17279
|
+
Math.floor((input.tokenBudget ?? DEFAULT_CONTEXT_PACK_TOKEN_BUDGET) * 0.6)
|
|
17280
|
+
);
|
|
17281
|
+
const sourceText = source ? fitTextToContextBudget(formatSource(source), sourceBudget).text : `## Target implementation
|
|
17282
|
+
Risk: no implementation source matched the resolved target at ${resolution.filePath}:${resolution.startLine}.`;
|
|
17283
|
+
const fitted = fitTextToContextBudget([
|
|
17284
|
+
`# Pre-edit context for ${resolution.name}`,
|
|
17285
|
+
graphRisk,
|
|
17286
|
+
sourceText,
|
|
17287
|
+
formatCallers(callers),
|
|
17288
|
+
formatCallees(callees, resolution.filePath)
|
|
17289
|
+
].filter((section) => section !== void 0).join("\n\n"), input.tokenBudget ?? void 0);
|
|
17290
|
+
return {
|
|
17291
|
+
text: fitted.text,
|
|
17292
|
+
details: {
|
|
17293
|
+
resolution: "resolved",
|
|
17294
|
+
tokenBudget: fitted.tokenBudget,
|
|
17295
|
+
tokenEstimate: fitted.tokenEstimate,
|
|
17296
|
+
truncated: fitted.truncated,
|
|
17297
|
+
sourceIncluded: source !== void 0,
|
|
17298
|
+
callerCount: callers.length,
|
|
17299
|
+
calleeCount: callees.length
|
|
17300
|
+
}
|
|
17301
|
+
};
|
|
17302
|
+
}
|
|
17303
|
+
async function resolveCodebaseEditContext(projectRoot, host, input) {
|
|
17304
|
+
return resolveCodebaseEditContextWithDependencies(input, {
|
|
17305
|
+
searchCodebase: (query, options) => searchCodebase(projectRoot, host, query, options),
|
|
17306
|
+
implementationLookup: (query, options) => implementationLookup(projectRoot, host, query, options),
|
|
17307
|
+
getCallGraphData: (params) => getCallGraphData(projectRoot, host, params)
|
|
17308
|
+
});
|
|
17309
|
+
}
|
|
17310
|
+
|
|
17054
17311
|
// src/tools/context-search.ts
|
|
17055
17312
|
var MIN_CONTEXT_RESULT_LIMIT = 1;
|
|
17056
17313
|
var MAX_CONTEXT_RESULT_LIMIT = 100;
|
|
@@ -17153,6 +17410,27 @@ function buildRecoveryDetails(attempts, successIndex) {
|
|
|
17153
17410
|
successfulAttemptIndex: successIndex
|
|
17154
17411
|
};
|
|
17155
17412
|
}
|
|
17413
|
+
function serializeAttempts(attempts) {
|
|
17414
|
+
return attempts.map((attempt) => ({
|
|
17415
|
+
kind: attempt.kind,
|
|
17416
|
+
scope: attempt.scope,
|
|
17417
|
+
resultCount: attempt.resultCount,
|
|
17418
|
+
relaxedFields: attempt.relaxedFields
|
|
17419
|
+
}));
|
|
17420
|
+
}
|
|
17421
|
+
function buildSearchDiagnostic(attempt) {
|
|
17422
|
+
if (!attempt) {
|
|
17423
|
+
return void 0;
|
|
17424
|
+
}
|
|
17425
|
+
return {
|
|
17426
|
+
route: attempt.kind,
|
|
17427
|
+
routedQuery: attempt.query,
|
|
17428
|
+
searchQuery: attempt.query,
|
|
17429
|
+
searchScope: attempt.scopeFilter,
|
|
17430
|
+
searchTrace: attempt.searchTrace,
|
|
17431
|
+
contextPackTrace: attempt.contextPackTrace
|
|
17432
|
+
};
|
|
17433
|
+
}
|
|
17156
17434
|
function trimOrUndefined2(value) {
|
|
17157
17435
|
const normalized = value?.trim();
|
|
17158
17436
|
if (!normalized) {
|
|
@@ -17192,6 +17470,7 @@ async function resolveSearchContext(input, operations) {
|
|
|
17192
17470
|
const hasFilters = Boolean(fileType || directory);
|
|
17193
17471
|
const relaxedFields = relaxedHintFields(fileType, directory);
|
|
17194
17472
|
const attempts = [];
|
|
17473
|
+
const attemptStates = [];
|
|
17195
17474
|
const decisions = {
|
|
17196
17475
|
inferredDefinitionMiss: false,
|
|
17197
17476
|
fallbackFromOriginalConceptualToInferred: false,
|
|
@@ -17220,8 +17499,20 @@ async function resolveSearchContext(input, operations) {
|
|
|
17220
17499
|
if (seenAttempts.has(key)) {
|
|
17221
17500
|
return [];
|
|
17222
17501
|
}
|
|
17223
|
-
const
|
|
17502
|
+
const attemptState = {
|
|
17503
|
+
kind,
|
|
17504
|
+
scope: describeScope(scope.fileType, scope.directory),
|
|
17505
|
+
resultCount: 0,
|
|
17506
|
+
relaxedFields: [...relaxedFieldsForAttempt],
|
|
17507
|
+
query: attemptQuery,
|
|
17508
|
+
scopeFilter: scope
|
|
17509
|
+
};
|
|
17510
|
+
const results = await runAttempt((trace) => {
|
|
17511
|
+
attemptState.searchTrace = trace;
|
|
17512
|
+
});
|
|
17513
|
+
attemptState.resultCount = results.length;
|
|
17224
17514
|
seenAttempts.add(key);
|
|
17515
|
+
attemptStates.push(attemptState);
|
|
17225
17516
|
attempts.push({
|
|
17226
17517
|
kind,
|
|
17227
17518
|
scope: describeScope(scope.fileType, scope.directory),
|
|
@@ -17241,7 +17532,7 @@ async function resolveSearchContext(input, operations) {
|
|
|
17241
17532
|
symbol,
|
|
17242
17533
|
scope,
|
|
17243
17534
|
relaxedFieldsForAttempt,
|
|
17244
|
-
() => operations.lookup(symbol, MAX_CONTEXT_RESULT_LIMIT, scope)
|
|
17535
|
+
(trace) => operations.lookup(symbol, MAX_CONTEXT_RESULT_LIMIT, scope, input.diagnostic ? trace : void 0)
|
|
17245
17536
|
);
|
|
17246
17537
|
};
|
|
17247
17538
|
const tryConceptualSearch = async (searchQuery, scope, relaxedFieldsForAttempt) => {
|
|
@@ -17250,13 +17541,23 @@ async function resolveSearchContext(input, operations) {
|
|
|
17250
17541
|
searchQuery,
|
|
17251
17542
|
scope,
|
|
17252
17543
|
relaxedFieldsForAttempt,
|
|
17253
|
-
() => operations.search(searchQuery, MAX_CONTEXT_RESULT_LIMIT, scope)
|
|
17544
|
+
(trace) => operations.search(searchQuery, MAX_CONTEXT_RESULT_LIMIT, scope, input.diagnostic ? trace : void 0)
|
|
17254
17545
|
);
|
|
17255
17546
|
};
|
|
17256
|
-
const
|
|
17547
|
+
const findSuccessfulAttemptState = (route) => {
|
|
17548
|
+
for (let index = attemptStates.length - 1; index >= 0; index -= 1) {
|
|
17549
|
+
const attempt = attemptStates[index];
|
|
17550
|
+
if (attempt.kind === route && attempt.resultCount > 0) {
|
|
17551
|
+
return attempt;
|
|
17552
|
+
}
|
|
17553
|
+
}
|
|
17554
|
+
return void 0;
|
|
17555
|
+
};
|
|
17556
|
+
const toResult = (route, routedQuery, pack, successfulAttempt) => {
|
|
17257
17557
|
const base = packedResult(route, routedQuery, pack);
|
|
17258
17558
|
const baseDetails = base.details;
|
|
17259
17559
|
const successIndex = findSuccessfulAttemptIndex(route, attempts);
|
|
17560
|
+
const successState = successfulAttempt ?? findSuccessfulAttemptState(route);
|
|
17260
17561
|
return {
|
|
17261
17562
|
text: base.text,
|
|
17262
17563
|
details: {
|
|
@@ -17264,7 +17565,10 @@ async function resolveSearchContext(input, operations) {
|
|
|
17264
17565
|
tokenBudget: baseDetails.tokenBudget,
|
|
17265
17566
|
tokenEstimate: baseDetails.tokenEstimate,
|
|
17266
17567
|
truncated: false,
|
|
17267
|
-
recovery: buildRecoveryDetails(
|
|
17568
|
+
recovery: buildRecoveryDetails(serializeAttempts(attemptStates), successIndex),
|
|
17569
|
+
...input.diagnostic && {
|
|
17570
|
+
diagnostic: buildSearchDiagnostic(successState)
|
|
17571
|
+
}
|
|
17268
17572
|
}
|
|
17269
17573
|
};
|
|
17270
17574
|
};
|
|
@@ -17278,8 +17582,18 @@ async function resolveSearchContext(input, operations) {
|
|
|
17278
17582
|
buildContextPack(scopedDefinitionResults, {
|
|
17279
17583
|
tokenBudget,
|
|
17280
17584
|
maxResults: limit,
|
|
17281
|
-
heading
|
|
17282
|
-
|
|
17585
|
+
heading,
|
|
17586
|
+
preserveInputOrder: true,
|
|
17587
|
+
...input.diagnostic ? {
|
|
17588
|
+
trace: (trace) => {
|
|
17589
|
+
const attemptState = findSuccessfulAttemptState("definition");
|
|
17590
|
+
if (attemptState) {
|
|
17591
|
+
attemptState.contextPackTrace = trace;
|
|
17592
|
+
}
|
|
17593
|
+
}
|
|
17594
|
+
} : void 0
|
|
17595
|
+
}),
|
|
17596
|
+
findSuccessfulAttemptState("definition")
|
|
17283
17597
|
);
|
|
17284
17598
|
}
|
|
17285
17599
|
if (explicitSymbol) {
|
|
@@ -17297,8 +17611,18 @@ async function resolveSearchContext(input, operations) {
|
|
|
17297
17611
|
buildContextPack(unscopedDefinitionResults, {
|
|
17298
17612
|
tokenBudget,
|
|
17299
17613
|
maxResults: limit,
|
|
17300
|
-
heading: heading2
|
|
17301
|
-
|
|
17614
|
+
heading: heading2,
|
|
17615
|
+
preserveInputOrder: true,
|
|
17616
|
+
...input.diagnostic ? {
|
|
17617
|
+
trace: (trace) => {
|
|
17618
|
+
const attemptState = findSuccessfulAttemptState("definition");
|
|
17619
|
+
if (attemptState) {
|
|
17620
|
+
attemptState.contextPackTrace = trace;
|
|
17621
|
+
}
|
|
17622
|
+
}
|
|
17623
|
+
} : void 0
|
|
17624
|
+
}),
|
|
17625
|
+
findSuccessfulAttemptState("definition")
|
|
17302
17626
|
);
|
|
17303
17627
|
}
|
|
17304
17628
|
}
|
|
@@ -17317,7 +17641,10 @@ Explicit symbol lookup only; conceptual search was not attempted.`
|
|
|
17317
17641
|
tokenBudget: heading.tokenBudget,
|
|
17318
17642
|
tokenEstimate: heading.tokenEstimate,
|
|
17319
17643
|
truncated: heading.truncated,
|
|
17320
|
-
recovery: buildRecoveryDetails(
|
|
17644
|
+
recovery: buildRecoveryDetails(serializeAttempts(attemptStates), null),
|
|
17645
|
+
...input.diagnostic && {
|
|
17646
|
+
diagnostic: buildSearchDiagnostic(attemptStates[attemptStates.length - 1])
|
|
17647
|
+
}
|
|
17321
17648
|
}
|
|
17322
17649
|
};
|
|
17323
17650
|
}
|
|
@@ -17357,8 +17684,17 @@ Explicit symbol lookup only; conceptual search was not attempted.`
|
|
|
17357
17684
|
maxResults: limit,
|
|
17358
17685
|
heading,
|
|
17359
17686
|
includeExactSearchHandoff: true,
|
|
17360
|
-
preferImplementationPaths: intent.preferSourcePaths || intent.primary !== "docs" && intent.primary !== "test"
|
|
17361
|
-
|
|
17687
|
+
preferImplementationPaths: intent.preferSourcePaths || intent.primary !== "docs" && intent.primary !== "test",
|
|
17688
|
+
...input.diagnostic ? {
|
|
17689
|
+
trace: (trace) => {
|
|
17690
|
+
const attemptState = findSuccessfulAttemptState("conceptual");
|
|
17691
|
+
if (attemptState) {
|
|
17692
|
+
attemptState.contextPackTrace = trace;
|
|
17693
|
+
}
|
|
17694
|
+
}
|
|
17695
|
+
} : void 0
|
|
17696
|
+
}),
|
|
17697
|
+
findSuccessfulAttemptState("conceptual")
|
|
17362
17698
|
);
|
|
17363
17699
|
}
|
|
17364
17700
|
}
|
|
@@ -17374,7 +17710,10 @@ Explicit symbol lookup only; conceptual search was not attempted.`
|
|
|
17374
17710
|
tokenBudget: fallbackText.tokenBudget,
|
|
17375
17711
|
tokenEstimate: fallbackText.tokenEstimate,
|
|
17376
17712
|
truncated: fallbackText.truncated,
|
|
17377
|
-
recovery: buildRecoveryDetails(
|
|
17713
|
+
recovery: buildRecoveryDetails(serializeAttempts(attemptStates), null),
|
|
17714
|
+
...input.diagnostic && {
|
|
17715
|
+
diagnostic: buildSearchDiagnostic(attemptStates[attemptStates.length - 1])
|
|
17716
|
+
}
|
|
17378
17717
|
}
|
|
17379
17718
|
};
|
|
17380
17719
|
}
|
|
@@ -17455,17 +17794,27 @@ async function resolveCodebaseContextUnmeasured(projectRoot, host, input) {
|
|
|
17455
17794
|
details: fittedDetails("path", fitted, 0)
|
|
17456
17795
|
};
|
|
17457
17796
|
}
|
|
17458
|
-
return resolveSearchContext({
|
|
17459
|
-
|
|
17797
|
+
return resolveSearchContext({
|
|
17798
|
+
query: input.query,
|
|
17799
|
+
symbol,
|
|
17800
|
+
limit,
|
|
17801
|
+
tokenBudget,
|
|
17802
|
+
fileType,
|
|
17803
|
+
directory,
|
|
17804
|
+
diagnostic: input.diagnostic
|
|
17805
|
+
}, {
|
|
17806
|
+
lookup: (lookupSymbol, retrievalLimit, scope, trace) => implementationLookup(projectRoot, host, lookupSymbol, {
|
|
17460
17807
|
limit: retrievalLimit,
|
|
17461
17808
|
fileType: scope.fileType,
|
|
17462
|
-
directory: scope.directory
|
|
17809
|
+
directory: scope.directory,
|
|
17810
|
+
trace
|
|
17463
17811
|
}),
|
|
17464
|
-
search: (queryText, retrievalLimit, scope) => searchCodebase(projectRoot, host, queryText, {
|
|
17812
|
+
search: (queryText, retrievalLimit, scope, trace) => searchCodebase(projectRoot, host, queryText, {
|
|
17465
17813
|
limit: retrievalLimit,
|
|
17466
17814
|
fileType: scope.fileType,
|
|
17467
17815
|
directory: scope.directory,
|
|
17468
|
-
metadataOnly: true
|
|
17816
|
+
metadataOnly: true,
|
|
17817
|
+
trace
|
|
17469
17818
|
})
|
|
17470
17819
|
});
|
|
17471
17820
|
}
|
|
@@ -17532,7 +17881,11 @@ async function resolveCodebaseContext(projectRoot, host, input) {
|
|
|
17532
17881
|
|
|
17533
17882
|
// src/tools/execute-common.ts
|
|
17534
17883
|
async function executeCodebaseContext(projectRoot, host, args) {
|
|
17535
|
-
|
|
17884
|
+
const result = await resolveCodebaseContext(projectRoot, host, args);
|
|
17885
|
+
return { text: result.text, details: result.details };
|
|
17886
|
+
}
|
|
17887
|
+
async function executeCodebaseEditContext(projectRoot, host, args) {
|
|
17888
|
+
return { text: (await resolveCodebaseEditContext(projectRoot, host, args)).text };
|
|
17536
17889
|
}
|
|
17537
17890
|
async function executeIndexCodebase(projectRoot, host, args, onProgress) {
|
|
17538
17891
|
const result = await runIndexCodebase(projectRoot, host, args, onProgress);
|
|
@@ -17635,9 +17988,9 @@ function parseGitActivity(output) {
|
|
|
17635
17988
|
if (!filePath || addedRaw === "-" || deletedRaw === "-") continue;
|
|
17636
17989
|
const churn = Number(addedRaw) + Number(deletedRaw);
|
|
17637
17990
|
if (!Number.isFinite(churn) || churn <= 0) continue;
|
|
17638
|
-
const
|
|
17639
|
-
const previous = activity.get(
|
|
17640
|
-
activity.set(
|
|
17991
|
+
const normalizedPath2 = normalizePath3(filePath);
|
|
17992
|
+
const previous = activity.get(normalizedPath2);
|
|
17993
|
+
activity.set(normalizedPath2, {
|
|
17641
17994
|
churn: (previous?.churn ?? 0) + churn,
|
|
17642
17995
|
commits: (previous?.commits ?? 0) + 1,
|
|
17643
17996
|
latestDate: previous?.latestDate ?? latestDate,
|
|
@@ -18227,8 +18580,8 @@ function transformForVisualization(symbols, edges, options = {}) {
|
|
|
18227
18580
|
const normalizedAbsoluteSuffix = `/${normalizedDirWithSlash}`;
|
|
18228
18581
|
filteredSymbols = symbols.filter(
|
|
18229
18582
|
(s) => {
|
|
18230
|
-
const
|
|
18231
|
-
return
|
|
18583
|
+
const normalizedPath2 = s.filePath.replace(/\\/g, "/");
|
|
18584
|
+
return normalizedPath2 === normalizedDir || normalizedPath2.startsWith(normalizedDirWithSlash) || normalizedPath2.endsWith(`/${normalizedDir}`) || normalizedPath2.includes(normalizedAbsoluteSuffix);
|
|
18232
18585
|
}
|
|
18233
18586
|
);
|
|
18234
18587
|
}
|
|
@@ -18302,6 +18655,26 @@ var z3 = tool.schema;
|
|
|
18302
18655
|
var DEFAULT_HOST = "opencode";
|
|
18303
18656
|
var CHUNK_TYPE_VALUES = CHUNK_TYPES;
|
|
18304
18657
|
var RELATIONSHIP_TYPE_VALUES = RELATIONSHIP_TYPES;
|
|
18658
|
+
function stableSortedDiagnosticValue(value) {
|
|
18659
|
+
if (Array.isArray(value)) {
|
|
18660
|
+
return value.map((item) => stableSortedDiagnosticValue(item));
|
|
18661
|
+
}
|
|
18662
|
+
if (value === null || typeof value !== "object") {
|
|
18663
|
+
return value;
|
|
18664
|
+
}
|
|
18665
|
+
const entries = Object.entries(value).sort(([left], [right]) => left.localeCompare(right));
|
|
18666
|
+
const sorted = {};
|
|
18667
|
+
for (const [key, item] of entries) {
|
|
18668
|
+
sorted[key] = stableSortedDiagnosticValue(item);
|
|
18669
|
+
}
|
|
18670
|
+
return sorted;
|
|
18671
|
+
}
|
|
18672
|
+
function formatCodebaseContextDiagnostic(details) {
|
|
18673
|
+
const sorted = stableSortedDiagnosticValue(details);
|
|
18674
|
+
return `
|
|
18675
|
+
Diagnostics:
|
|
18676
|
+
${JSON.stringify(sorted, null, 2)}`;
|
|
18677
|
+
}
|
|
18305
18678
|
function initializeTools2(projectRoot, config) {
|
|
18306
18679
|
initializeTools(projectRoot, config, DEFAULT_HOST);
|
|
18307
18680
|
}
|
|
@@ -18321,10 +18694,29 @@ var codebase_context = tool({
|
|
|
18321
18694
|
maxDepth: z3.number().int().min(MIN_CONTEXT_PATH_DEPTH).max(MAX_CONTEXT_PATH_DEPTH).nullable().optional().default(10).describe(`Maximum call-path traversal depth (${MIN_CONTEXT_PATH_DEPTH}-${MAX_CONTEXT_PATH_DEPTH})`),
|
|
18322
18695
|
fileType: z3.string().nullable().optional().describe("Filter by file extension"),
|
|
18323
18696
|
directory: z3.string().nullable().optional().describe("Filter by directory path"),
|
|
18324
|
-
tokenBudget: z3.number().int().min(MIN_CONTEXT_PACK_TOKEN_BUDGET).max(MAX_CONTEXT_PACK_TOKEN_BUDGET).nullable().optional().default(DEFAULT_CONTEXT_PACK_TOKEN_BUDGET).describe(`Maximum response tokens (${MIN_CONTEXT_PACK_TOKEN_BUDGET}-${MAX_CONTEXT_PACK_TOKEN_BUDGET})`)
|
|
18697
|
+
tokenBudget: z3.number().int().min(MIN_CONTEXT_PACK_TOKEN_BUDGET).max(MAX_CONTEXT_PACK_TOKEN_BUDGET).nullable().optional().default(DEFAULT_CONTEXT_PACK_TOKEN_BUDGET).describe(`Maximum response tokens (${MIN_CONTEXT_PACK_TOKEN_BUDGET}-${MAX_CONTEXT_PACK_TOKEN_BUDGET})`),
|
|
18698
|
+
diagnostic: z3.boolean().optional().describe("Collect diagnostic routing and search traces without changing normal text output.")
|
|
18699
|
+
},
|
|
18700
|
+
async execute(args, context) {
|
|
18701
|
+
const result = await executeCodebaseContext(context?.worktree, DEFAULT_HOST, args);
|
|
18702
|
+
if (!args.diagnostic || !result.details?.diagnostic) {
|
|
18703
|
+
return result.text;
|
|
18704
|
+
}
|
|
18705
|
+
return `${result.text}${formatCodebaseContextDiagnostic(result.details.diagnostic)}`;
|
|
18706
|
+
}
|
|
18707
|
+
});
|
|
18708
|
+
var codebase_edit_context = tool({
|
|
18709
|
+
description: "PRE-EDIT TOOL for a known or suspected symbol. Returns token-bounded target source, direct callers and callees, or a risk-marked conceptual fallback when the target cannot be resolved.",
|
|
18710
|
+
args: {
|
|
18711
|
+
query: z3.string().describe("The requested change or target behavior"),
|
|
18712
|
+
symbol: z3.string().nullable().optional().describe("Authoritative target symbol when known"),
|
|
18713
|
+
filePath: z3.string().nullable().optional().describe("Optional file path used to disambiguate duplicate symbol names"),
|
|
18714
|
+
callerLimit: z3.number().int().min(MIN_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT).max(MAX_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT).nullable().optional().default(DEFAULT_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT),
|
|
18715
|
+
calleeLimit: z3.number().int().min(MIN_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT).max(MAX_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT).nullable().optional().default(DEFAULT_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT),
|
|
18716
|
+
tokenBudget: z3.number().int().min(MIN_CONTEXT_PACK_TOKEN_BUDGET).max(MAX_CONTEXT_PACK_TOKEN_BUDGET).nullable().optional().default(DEFAULT_CONTEXT_PACK_TOKEN_BUDGET)
|
|
18325
18717
|
},
|
|
18326
18718
|
async execute(args, context) {
|
|
18327
|
-
return (await
|
|
18719
|
+
return (await executeCodebaseEditContext(context?.worktree, DEFAULT_HOST, args)).text;
|
|
18328
18720
|
}
|
|
18329
18721
|
});
|
|
18330
18722
|
var codebase_peek = tool({
|
|
@@ -18581,6 +18973,7 @@ var index_visualize = tool({
|
|
|
18581
18973
|
// src/tools/tool-names.ts
|
|
18582
18974
|
var TOOL_NAME = {
|
|
18583
18975
|
CODEBASE_CONTEXT: "codebase_context",
|
|
18976
|
+
CODEBASE_EDIT_CONTEXT: "codebase_edit_context",
|
|
18584
18977
|
CODEBASE_SEARCH: "codebase_search",
|
|
18585
18978
|
CODEBASE_PEEK: "codebase_peek",
|
|
18586
18979
|
FIND_SIMILAR: "find_similar",
|
|
@@ -18604,6 +18997,7 @@ var TOOL_NAME = {
|
|
|
18604
18997
|
};
|
|
18605
18998
|
var PORTABLE_TOOL_NAMES = [
|
|
18606
18999
|
TOOL_NAME.CODEBASE_CONTEXT,
|
|
19000
|
+
TOOL_NAME.CODEBASE_EDIT_CONTEXT,
|
|
18607
19001
|
TOOL_NAME.CODEBASE_SEARCH,
|
|
18608
19002
|
TOOL_NAME.CODEBASE_PEEK,
|
|
18609
19003
|
TOOL_NAME.INDEX_CODEBASE,
|
|
@@ -18620,6 +19014,7 @@ var PORTABLE_TOOL_NAMES = [
|
|
|
18620
19014
|
];
|
|
18621
19015
|
var OPENCODE_TOOL_NAMES = [
|
|
18622
19016
|
TOOL_NAME.CODEBASE_CONTEXT,
|
|
19017
|
+
TOOL_NAME.CODEBASE_EDIT_CONTEXT,
|
|
18623
19018
|
TOOL_NAME.CODEBASE_SEARCH,
|
|
18624
19019
|
TOOL_NAME.CODEBASE_PEEK,
|
|
18625
19020
|
TOOL_NAME.INDEX_CODEBASE,
|
|
@@ -18640,6 +19035,7 @@ var OPENCODE_TOOL_NAMES = [
|
|
|
18640
19035
|
];
|
|
18641
19036
|
var PI_TOOL_NAMES = [
|
|
18642
19037
|
TOOL_NAME.CODEBASE_CONTEXT,
|
|
19038
|
+
TOOL_NAME.CODEBASE_EDIT_CONTEXT,
|
|
18643
19039
|
TOOL_NAME.CODEBASE_SEARCH,
|
|
18644
19040
|
TOOL_NAME.CODEBASE_PEEK,
|
|
18645
19041
|
TOOL_NAME.FIND_SIMILAR,
|
|
@@ -19094,6 +19490,7 @@ var plugin = async ({ directory, worktree }) => {
|
|
|
19094
19490
|
return {
|
|
19095
19491
|
tool: {
|
|
19096
19492
|
[TOOL_NAME.CODEBASE_CONTEXT]: codebase_context,
|
|
19493
|
+
[TOOL_NAME.CODEBASE_EDIT_CONTEXT]: codebase_edit_context,
|
|
19097
19494
|
[TOOL_NAME.CODEBASE_SEARCH]: codebase_search,
|
|
19098
19495
|
[TOOL_NAME.CODEBASE_PEEK]: codebase_peek,
|
|
19099
19496
|
[TOOL_NAME.INDEX_CODEBASE]: index_codebase,
|