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.js
CHANGED
|
@@ -1913,6 +1913,9 @@ var RELATIONSHIP_TYPES = [
|
|
|
1913
1913
|
];
|
|
1914
1914
|
var INDEX_LOG_CATEGORIES = ["search", "embedding", "cache", "gc", "branch", "general"];
|
|
1915
1915
|
var INDEX_LOG_LEVELS = ["error", "warn", "info", "debug"];
|
|
1916
|
+
var MIN_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT = 1;
|
|
1917
|
+
var MAX_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT = 20;
|
|
1918
|
+
var DEFAULT_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT = 5;
|
|
1916
1919
|
var CODE_COMMUNITIES_MIN_SIZE = 1;
|
|
1917
1920
|
var CODE_COMMUNITIES_DEFAULT_LIMIT = 20;
|
|
1918
1921
|
var CODE_COMMUNITIES_MAX_LIMIT = 100;
|
|
@@ -2536,6 +2539,16 @@ function compactEvidenceValue(value, maxChars) {
|
|
|
2536
2539
|
}
|
|
2537
2540
|
var MAX_EXACT_SEARCH_HANDOFF_NAMES = 3;
|
|
2538
2541
|
var MAX_EXACT_SEARCH_HANDOFF_NAME_CHARS = 64;
|
|
2542
|
+
function toContextPackTraceCandidate(result) {
|
|
2543
|
+
return {
|
|
2544
|
+
filePath: result.filePath,
|
|
2545
|
+
startLine: result.startLine,
|
|
2546
|
+
endLine: result.endLine,
|
|
2547
|
+
score: result.score,
|
|
2548
|
+
chunkType: result.chunkType,
|
|
2549
|
+
name: result.name
|
|
2550
|
+
};
|
|
2551
|
+
}
|
|
2539
2552
|
function formatExactSearchHandoff(results) {
|
|
2540
2553
|
const suggestedNames = [];
|
|
2541
2554
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -2584,13 +2597,13 @@ function buildContextPack(results, options = {}) {
|
|
|
2584
2597
|
const maxResults = Math.max(0, Math.floor(options.maxResults ?? results.length));
|
|
2585
2598
|
const includeExactSearchHandoff = options.includeExactSearchHandoff ?? false;
|
|
2586
2599
|
const candidateCount = results.length;
|
|
2587
|
-
const
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
);
|
|
2593
|
-
const
|
|
2600
|
+
const preserveInputOrder = options.preserveInputOrder ?? false;
|
|
2601
|
+
const ranked = preserveInputOrder ? results.map((result, originalIndex) => ({ result, originalIndex })) : rankContextCandidates(results, options.preferImplementationPaths ?? false);
|
|
2602
|
+
const rankedCandidates = ranked.map((entry) => toContextPackTraceCandidate(entry.result));
|
|
2603
|
+
const deduplicated = deduplicateContextCandidates(ranked);
|
|
2604
|
+
const deduplicatedCandidates = deduplicated.map((result) => toContextPackTraceCandidate(result));
|
|
2605
|
+
const diversified = preserveInputOrder ? deduplicated : diversifyContextCandidates(deduplicated);
|
|
2606
|
+
const diversifiedCandidates = diversified.map((result) => toContextPackTraceCandidate(result));
|
|
2594
2607
|
const duplicateCount = candidateCount - deduplicated.length;
|
|
2595
2608
|
const selectable = diversified.slice(0, maxResults);
|
|
2596
2609
|
const limitOmittedCount = deduplicated.length - selectable.length;
|
|
@@ -2623,6 +2636,15 @@ function buildContextPack(results, options = {}) {
|
|
|
2623
2636
|
const fitted = fitTextToContextBudget(text, tokenBudget);
|
|
2624
2637
|
const budgetOmittedCount = selectable.length - selected.length;
|
|
2625
2638
|
const omittedCount = candidateCount - selected.length;
|
|
2639
|
+
if (options.trace) {
|
|
2640
|
+
options.trace({
|
|
2641
|
+
inputCandidates: results.map(toContextPackTraceCandidate),
|
|
2642
|
+
rankedCandidates,
|
|
2643
|
+
deduplicatedCandidates,
|
|
2644
|
+
diversifiedCandidates,
|
|
2645
|
+
selectedCandidates: selected.map(toContextPackTraceCandidate)
|
|
2646
|
+
});
|
|
2647
|
+
}
|
|
2626
2648
|
return {
|
|
2627
2649
|
requestedTokenBudget,
|
|
2628
2650
|
tokenBudget,
|
|
@@ -8610,12 +8632,12 @@ function diversifyGroupBySymbol(entries, getCandidate) {
|
|
|
8610
8632
|
return [...primary, ...remainder];
|
|
8611
8633
|
}
|
|
8612
8634
|
function buildDiversityKey(metadata) {
|
|
8613
|
-
const
|
|
8635
|
+
const normalizedPath2 = metadata.filePath.toLowerCase();
|
|
8614
8636
|
const normalizedName = (metadata.name ?? "").trim().toLowerCase();
|
|
8615
8637
|
if (normalizedName.length > 0) {
|
|
8616
|
-
return `${
|
|
8638
|
+
return `${normalizedPath2}#${normalizedName}`;
|
|
8617
8639
|
}
|
|
8618
|
-
return
|
|
8640
|
+
return normalizedPath2;
|
|
8619
8641
|
}
|
|
8620
8642
|
function rankHybridResults(query, semanticResults, keywordResults, options) {
|
|
8621
8643
|
const prioritizeSourcePaths = options.prioritizeSourcePaths ?? classifyQueryIntentRaw(query) === "source";
|
|
@@ -9021,6 +9043,29 @@ function extractPrimaryIdentifierQueryHint(query) {
|
|
|
9021
9043
|
const best = codeTerms.find((term) => term.length >= 6);
|
|
9022
9044
|
return best ?? null;
|
|
9023
9045
|
}
|
|
9046
|
+
function pathSegmentsForAffinityMatch(filePath) {
|
|
9047
|
+
const normalizedPath2 = normalizeRankingText(filePath).replace(/\\/g, "/");
|
|
9048
|
+
const segments = normalizedPath2.split("/").filter((segment) => segment.length > 0);
|
|
9049
|
+
if (segments.length === 0) {
|
|
9050
|
+
return [];
|
|
9051
|
+
}
|
|
9052
|
+
const basename9 = segments[segments.length - 1] ?? "";
|
|
9053
|
+
const basenameWithoutExt = basename9.replace(/\.[^/.]+$/u, "");
|
|
9054
|
+
const normalizedSegments = segments.map((segment) => segment.toLowerCase());
|
|
9055
|
+
return Array.from(/* @__PURE__ */ new Set([
|
|
9056
|
+
...normalizedSegments,
|
|
9057
|
+
basenameWithoutExt.toLowerCase()
|
|
9058
|
+
]));
|
|
9059
|
+
}
|
|
9060
|
+
function hasModuleAffinity(filePath, exactIdentifierVariants) {
|
|
9061
|
+
const haystack = pathSegmentsForAffinityMatch(filePath);
|
|
9062
|
+
return exactIdentifierVariants.some((variant) => {
|
|
9063
|
+
if (!variant || variant.length < 2) {
|
|
9064
|
+
return false;
|
|
9065
|
+
}
|
|
9066
|
+
return haystack.includes(variant);
|
|
9067
|
+
});
|
|
9068
|
+
}
|
|
9024
9069
|
var FILE_PATH_HINT_EXTENSIONS = [
|
|
9025
9070
|
"ts",
|
|
9026
9071
|
"tsx",
|
|
@@ -9064,9 +9109,9 @@ function normalizeFilePathForHintMatch(filePath) {
|
|
|
9064
9109
|
return filePath.replace(/\\/g, "/").toLowerCase().replace(/^\.\//, "");
|
|
9065
9110
|
}
|
|
9066
9111
|
function pathMatchesHint(filePath, hint) {
|
|
9067
|
-
const
|
|
9112
|
+
const normalizedPath2 = normalizeFilePathForHintMatch(filePath);
|
|
9068
9113
|
const normalizedHint = normalizeFilePathForHintMatch(hint);
|
|
9069
|
-
return
|
|
9114
|
+
return normalizedPath2.endsWith(normalizedHint) || normalizedPath2.includes(`/${normalizedHint}`) || normalizedPath2.includes(normalizedHint);
|
|
9070
9115
|
}
|
|
9071
9116
|
function extractFilePathHint(query) {
|
|
9072
9117
|
const match = query.match(FILE_PATH_HINT_SUFFIX_REGEX);
|
|
@@ -9096,10 +9141,13 @@ function buildDeterministicIdentifierPass(query, candidates, limit, prioritizeSo
|
|
|
9096
9141
|
).map((candidate) => {
|
|
9097
9142
|
const nameLower = (candidate.metadata.name ?? "").toLowerCase();
|
|
9098
9143
|
const pathLower = candidate.metadata.filePath.toLowerCase();
|
|
9099
|
-
|
|
9100
|
-
const
|
|
9144
|
+
const exactIdentifierVariants = primaryVariants.filter((value) => value.length >= 2);
|
|
9145
|
+
const exactMatch = exactIdentifierVariants.some(
|
|
9101
9146
|
(variant) => nameLower === variant || nameLower.replace(/[^a-z0-9]/g, "") === variant.replace(/[^a-z0-9]/g, "")
|
|
9102
9147
|
);
|
|
9148
|
+
let maxMatch = 0;
|
|
9149
|
+
const nameMatchesPrimary = exactMatch;
|
|
9150
|
+
const pathAffinity = exactMatch ? hasModuleAffinity(candidate.metadata.filePath, exactIdentifierVariants) : false;
|
|
9103
9151
|
const pathMatchesFileHint = filePathHint ? pathMatchesHint(candidate.metadata.filePath, filePathHint) : false;
|
|
9104
9152
|
for (const hint of hints) {
|
|
9105
9153
|
const variants = normalizeIdentifierVariants(hint);
|
|
@@ -9120,12 +9168,17 @@ function buildDeterministicIdentifierPass(query, candidates, limit, prioritizeSo
|
|
|
9120
9168
|
candidate,
|
|
9121
9169
|
maxMatch,
|
|
9122
9170
|
pathMatchesFileHint,
|
|
9123
|
-
nameMatchesPrimary
|
|
9171
|
+
nameMatchesPrimary,
|
|
9172
|
+
pathAffinity
|
|
9124
9173
|
};
|
|
9125
9174
|
}).filter((entry) => entry.maxMatch >= 0.7).sort((a, b) => {
|
|
9126
9175
|
const aAnchored = a.pathMatchesFileHint && a.nameMatchesPrimary ? 1 : 0;
|
|
9127
9176
|
const bAnchored = b.pathMatchesFileHint && b.nameMatchesPrimary ? 1 : 0;
|
|
9128
9177
|
if (aAnchored !== bAnchored) return bAnchored - aAnchored;
|
|
9178
|
+
if (a.nameMatchesPrimary !== b.nameMatchesPrimary) {
|
|
9179
|
+
return b.nameMatchesPrimary ? 1 : -1;
|
|
9180
|
+
}
|
|
9181
|
+
if (a.pathAffinity !== b.pathAffinity) return b.pathAffinity ? 1 : -1;
|
|
9129
9182
|
if (b.maxMatch !== a.maxMatch) return b.maxMatch - a.maxMatch;
|
|
9130
9183
|
if (b.candidate.score !== a.candidate.score) return b.candidate.score - a.candidate.score;
|
|
9131
9184
|
return a.candidate.id.localeCompare(b.candidate.id);
|
|
@@ -12939,6 +12992,20 @@ var Indexer = class _Indexer {
|
|
|
12939
12992
|
requestedLimit = nextLimit;
|
|
12940
12993
|
}
|
|
12941
12994
|
}
|
|
12995
|
+
buildCandidateSnapshot(candidate) {
|
|
12996
|
+
return {
|
|
12997
|
+
id: candidate.id,
|
|
12998
|
+
filePath: candidate.metadata.filePath,
|
|
12999
|
+
startLine: candidate.metadata.startLine,
|
|
13000
|
+
endLine: candidate.metadata.endLine,
|
|
13001
|
+
score: candidate.score,
|
|
13002
|
+
chunkType: candidate.metadata.chunkType,
|
|
13003
|
+
name: candidate.metadata.name
|
|
13004
|
+
};
|
|
13005
|
+
}
|
|
13006
|
+
buildCandidateSnapshotList(candidates) {
|
|
13007
|
+
return candidates.map((candidate) => this.buildCandidateSnapshot(candidate));
|
|
13008
|
+
}
|
|
12942
13009
|
searchSemanticCandidates(store, embedding, initialLimit, branchChunkIds, shouldPrefilterByBranch) {
|
|
12943
13010
|
return this.searchCandidatesWithBranchPrefilter(
|
|
12944
13011
|
initialLimit,
|
|
@@ -13130,6 +13197,16 @@ var Indexer = class _Indexer {
|
|
|
13130
13197
|
prefilterMs: Math.round(prefilterMs * 100) / 100,
|
|
13131
13198
|
fusionMs: Math.round(fusionMs * 100) / 100
|
|
13132
13199
|
});
|
|
13200
|
+
if (options?.trace) {
|
|
13201
|
+
options.trace({
|
|
13202
|
+
semanticCandidates: this.buildCandidateSnapshotList(scopedSemanticCandidates),
|
|
13203
|
+
keywordCandidates: this.buildCandidateSnapshotList(scopedKeywordCandidates),
|
|
13204
|
+
hybridCandidates: this.buildCandidateSnapshotList(combined),
|
|
13205
|
+
postExternalRerankCandidates: this.buildCandidateSnapshotList(rerankedCombined),
|
|
13206
|
+
tieredCandidates: this.buildCandidateSnapshotList(tiered),
|
|
13207
|
+
finalCandidates: this.buildCandidateSnapshotList(finalResults)
|
|
13208
|
+
});
|
|
13209
|
+
}
|
|
13133
13210
|
const metadataOnly = options?.metadataOnly ?? false;
|
|
13134
13211
|
return Promise.all(
|
|
13135
13212
|
finalResults.map(async (r) => {
|
|
@@ -14397,7 +14474,8 @@ async function searchCodebase(projectRoot, host, query, options = {}) {
|
|
|
14397
14474
|
definitionIntent: options.definitionIntent,
|
|
14398
14475
|
blameAuthor: options.blameAuthor,
|
|
14399
14476
|
blameSha: options.blameSha,
|
|
14400
|
-
blameSince: options.blameSince
|
|
14477
|
+
blameSince: options.blameSince,
|
|
14478
|
+
trace: options.trace
|
|
14401
14479
|
});
|
|
14402
14480
|
}
|
|
14403
14481
|
async function searchCodebaseWithEffectiveness(projectRoot, host, route, query, options, render) {
|
|
@@ -14451,15 +14529,19 @@ async function implementationLookup(projectRoot, host, query, options = {}) {
|
|
|
14451
14529
|
return indexer.search(query, options.limit, {
|
|
14452
14530
|
fileType: options.fileType,
|
|
14453
14531
|
directory: options.directory,
|
|
14454
|
-
definitionIntent: true
|
|
14532
|
+
definitionIntent: true,
|
|
14533
|
+
trace: options.trace
|
|
14455
14534
|
});
|
|
14456
14535
|
}
|
|
14457
14536
|
async function getCallGraphData(projectRoot, host, params) {
|
|
14458
14537
|
await ensureAutoIndexReadyForRetrieval(projectRoot, host);
|
|
14459
14538
|
const root = getProjectRoot(projectRoot, host);
|
|
14460
14539
|
const indexer = getIndexerForProject(root, host);
|
|
14540
|
+
return getCallGraphDataForIndexer(indexer, root, params);
|
|
14541
|
+
}
|
|
14542
|
+
async function getCallGraphDataForIndexer(indexer, projectRoot, params) {
|
|
14461
14543
|
const symbols = await indexer.getCallGraphSymbols();
|
|
14462
|
-
const resolution = resolveCallGraphSymbol(symbols,
|
|
14544
|
+
const resolution = resolveCallGraphSymbol(symbols, projectRoot, params.name, params.filePath, params.symbolId);
|
|
14463
14545
|
const direction = params.direction === "callees" ? "callees" : "callers";
|
|
14464
14546
|
if (resolution.status !== "resolved") {
|
|
14465
14547
|
return { direction, resolution, callers: [], callees: [], relationshipType: params.relationshipType };
|
|
@@ -14675,17 +14757,17 @@ async function getIndexLogs(projectRoot, host, args) {
|
|
|
14675
14757
|
function addKnowledgeBase(projectRoot, host, knowledgeBasePath) {
|
|
14676
14758
|
const root = getProjectRoot(projectRoot, host);
|
|
14677
14759
|
const inputPath = knowledgeBasePath.trim();
|
|
14678
|
-
const
|
|
14760
|
+
const normalizedPath2 = path20.resolve(
|
|
14679
14761
|
path20.isAbsolute(inputPath) ? inputPath : resolveKnowledgeBasePath(inputPath, root)
|
|
14680
14762
|
);
|
|
14681
|
-
if (!existsSync12(
|
|
14682
|
-
return `Error: Directory does not exist: ${
|
|
14763
|
+
if (!existsSync12(normalizedPath2)) {
|
|
14764
|
+
return `Error: Directory does not exist: ${normalizedPath2}`;
|
|
14683
14765
|
}
|
|
14684
14766
|
let realPath;
|
|
14685
14767
|
try {
|
|
14686
|
-
realPath = realpathSync5(
|
|
14768
|
+
realPath = realpathSync5(normalizedPath2);
|
|
14687
14769
|
} catch {
|
|
14688
|
-
return `Error: Cannot resolve path: ${
|
|
14770
|
+
return `Error: Cannot resolve path: ${normalizedPath2}`;
|
|
14689
14771
|
}
|
|
14690
14772
|
const blockedPrefixes = [
|
|
14691
14773
|
"/etc",
|
|
@@ -14708,34 +14790,34 @@ function addKnowledgeBase(projectRoot, host, knowledgeBasePath) {
|
|
|
14708
14790
|
];
|
|
14709
14791
|
for (const prefix of blockedPrefixes) {
|
|
14710
14792
|
if (realPath === prefix || realPath.startsWith(`${prefix}/`)) {
|
|
14711
|
-
return `Error: Adding sensitive directory as knowledge base is not allowed: ${
|
|
14793
|
+
return `Error: Adding sensitive directory as knowledge base is not allowed: ${normalizedPath2}`;
|
|
14712
14794
|
}
|
|
14713
14795
|
}
|
|
14714
14796
|
for (const dotDir of sensitiveDotDirs) {
|
|
14715
14797
|
const sensitiveDir = path20.join(homeDir, dotDir);
|
|
14716
14798
|
if (sensitiveDir && (realPath === sensitiveDir || realPath.startsWith(`${sensitiveDir}/`))) {
|
|
14717
|
-
return `Error: Adding sensitive directory as knowledge base is not allowed: ${
|
|
14799
|
+
return `Error: Adding sensitive directory as knowledge base is not allowed: ${normalizedPath2}`;
|
|
14718
14800
|
}
|
|
14719
14801
|
}
|
|
14720
14802
|
try {
|
|
14721
|
-
const stat4 = statSync5(
|
|
14803
|
+
const stat4 = statSync5(normalizedPath2);
|
|
14722
14804
|
if (!stat4.isDirectory()) {
|
|
14723
|
-
return `Error: Path is not a directory: ${
|
|
14805
|
+
return `Error: Path is not a directory: ${normalizedPath2}`;
|
|
14724
14806
|
}
|
|
14725
14807
|
} catch (error) {
|
|
14726
|
-
return `Error: Cannot access directory: ${
|
|
14808
|
+
return `Error: Cannot access directory: ${normalizedPath2} - ${error instanceof Error ? error.message : String(error)}`;
|
|
14727
14809
|
}
|
|
14728
14810
|
const config = loadEditableConfig(root, host);
|
|
14729
14811
|
const knowledgeBases = Array.isArray(config.knowledgeBases) ? config.knowledgeBases : [];
|
|
14730
|
-
const alreadyExists = hasMatchingKnowledgeBasePath(knowledgeBases,
|
|
14812
|
+
const alreadyExists = hasMatchingKnowledgeBasePath(knowledgeBases, normalizedPath2, root);
|
|
14731
14813
|
if (alreadyExists) {
|
|
14732
|
-
return `Knowledge base already configured: ${
|
|
14814
|
+
return `Knowledge base already configured: ${normalizedPath2}`;
|
|
14733
14815
|
}
|
|
14734
|
-
knowledgeBases.push(
|
|
14816
|
+
knowledgeBases.push(normalizedPath2);
|
|
14735
14817
|
config.knowledgeBases = knowledgeBases;
|
|
14736
14818
|
saveConfig(root, config, host);
|
|
14737
14819
|
refreshIndexerForDirectory(root, host);
|
|
14738
|
-
let result = `${
|
|
14820
|
+
let result = `${normalizedPath2}
|
|
14739
14821
|
`;
|
|
14740
14822
|
result += `Total knowledge bases: ${knowledgeBases.length}
|
|
14741
14823
|
`;
|
|
@@ -17048,6 +17130,181 @@ var pr_impact = tool({
|
|
|
17048
17130
|
}
|
|
17049
17131
|
});
|
|
17050
17132
|
|
|
17133
|
+
// src/tools/edit-context.ts
|
|
17134
|
+
function edgeLimit(value) {
|
|
17135
|
+
if (value === null || value === void 0 || !Number.isFinite(value)) {
|
|
17136
|
+
return DEFAULT_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT;
|
|
17137
|
+
}
|
|
17138
|
+
return Math.min(
|
|
17139
|
+
MAX_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT,
|
|
17140
|
+
Math.max(MIN_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT, Math.floor(value))
|
|
17141
|
+
);
|
|
17142
|
+
}
|
|
17143
|
+
function normalizedPath(value) {
|
|
17144
|
+
return value.replaceAll("\\", "/").replace(/^\.\//, "");
|
|
17145
|
+
}
|
|
17146
|
+
function pathsMatch(left, right) {
|
|
17147
|
+
const normalizedLeft = normalizedPath(left);
|
|
17148
|
+
const normalizedRight = normalizedPath(right);
|
|
17149
|
+
return normalizedLeft === normalizedRight || normalizedLeft.endsWith(`/${normalizedRight}`) || normalizedRight.endsWith(`/${normalizedLeft}`);
|
|
17150
|
+
}
|
|
17151
|
+
function targetSource(results, resolution) {
|
|
17152
|
+
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);
|
|
17153
|
+
}
|
|
17154
|
+
function formatSource(result) {
|
|
17155
|
+
const name = result.name ? ` ${result.name}` : "";
|
|
17156
|
+
return [
|
|
17157
|
+
"## Target implementation",
|
|
17158
|
+
`${result.filePath}:${result.startLine}-${result.endLine} (${result.chunkType}${name})`,
|
|
17159
|
+
"```",
|
|
17160
|
+
result.content,
|
|
17161
|
+
"```"
|
|
17162
|
+
].join("\n");
|
|
17163
|
+
}
|
|
17164
|
+
function formatCallers(edges) {
|
|
17165
|
+
if (edges.length === 0) return "## Direct callers\nNone found.";
|
|
17166
|
+
return [
|
|
17167
|
+
"## Direct callers",
|
|
17168
|
+
...edges.map((edge) => `- ${edge.fromSymbolName ?? "<unknown>"} at ${edge.fromSymbolFilePath ?? "<unknown file>"}:${edge.line} (${edge.callType}, ${edge.isResolved ? "resolved" : "unresolved"})`)
|
|
17169
|
+
].join("\n");
|
|
17170
|
+
}
|
|
17171
|
+
function formatCallees(edges, sourceFilePath) {
|
|
17172
|
+
if (edges.length === 0) return "## Direct callees\nNone found.";
|
|
17173
|
+
return [
|
|
17174
|
+
"## Direct callees",
|
|
17175
|
+
...edges.map((edge) => `- ${edge.targetName} from ${sourceFilePath}:${edge.line} (${edge.callType}, ${edge.isResolved ? "resolved" : "unresolved"})`)
|
|
17176
|
+
].join("\n");
|
|
17177
|
+
}
|
|
17178
|
+
function formatResolutionRisk(resolution) {
|
|
17179
|
+
if (resolution.status === "ambiguous") {
|
|
17180
|
+
const candidates = resolution.candidates.map((candidate) => `${candidate.filePath}:${candidate.startLine}`).join(", ");
|
|
17181
|
+
return `Risk: symbol "${resolution.name}" is ambiguous. Pass filePath to select a target.${candidates ? ` Candidates: ${candidates}.` : ""}`;
|
|
17182
|
+
}
|
|
17183
|
+
if (resolution.filePath && resolution.totalCandidates > 0) {
|
|
17184
|
+
return `Risk: symbol "${resolution.name}" did not resolve at filePath="${resolution.filePath}". Review the conceptual evidence before editing.`;
|
|
17185
|
+
}
|
|
17186
|
+
return `Risk: symbol "${resolution.name}" could not be resolved. Review the conceptual evidence before editing.`;
|
|
17187
|
+
}
|
|
17188
|
+
async function fallbackPack(dependencies, query, risk, resolution, tokenBudget, candidateSource = []) {
|
|
17189
|
+
const conceptual = await dependencies.searchCodebase(query, { limit: 5 });
|
|
17190
|
+
const pack = buildContextPack([...candidateSource, ...conceptual], {
|
|
17191
|
+
tokenBudget: tokenBudget ?? void 0,
|
|
17192
|
+
heading: "## Conceptual evidence",
|
|
17193
|
+
maxResults: 5,
|
|
17194
|
+
includeExactSearchHandoff: false,
|
|
17195
|
+
preferImplementationPaths: true
|
|
17196
|
+
});
|
|
17197
|
+
const fitted = fitTextToContextBudget(`${risk}
|
|
17198
|
+
|
|
17199
|
+
${pack.text}`, tokenBudget ?? void 0);
|
|
17200
|
+
return {
|
|
17201
|
+
text: fitted.text,
|
|
17202
|
+
details: {
|
|
17203
|
+
resolution,
|
|
17204
|
+
tokenBudget: fitted.tokenBudget,
|
|
17205
|
+
tokenEstimate: fitted.tokenEstimate,
|
|
17206
|
+
truncated: fitted.truncated,
|
|
17207
|
+
sourceIncluded: candidateSource.length > 0,
|
|
17208
|
+
callerCount: 0,
|
|
17209
|
+
calleeCount: 0
|
|
17210
|
+
}
|
|
17211
|
+
};
|
|
17212
|
+
}
|
|
17213
|
+
async function resolveCodebaseEditContextWithDependencies(input, dependencies) {
|
|
17214
|
+
const symbol = input.symbol?.trim();
|
|
17215
|
+
if (!symbol) {
|
|
17216
|
+
return fallbackPack(
|
|
17217
|
+
dependencies,
|
|
17218
|
+
input.query,
|
|
17219
|
+
"Risk: no authoritative symbol was supplied. Review the conceptual evidence before editing.",
|
|
17220
|
+
"not_requested",
|
|
17221
|
+
input.tokenBudget
|
|
17222
|
+
);
|
|
17223
|
+
}
|
|
17224
|
+
let callersResult;
|
|
17225
|
+
try {
|
|
17226
|
+
callersResult = await dependencies.getCallGraphData({
|
|
17227
|
+
name: symbol,
|
|
17228
|
+
filePath: input.filePath ?? void 0,
|
|
17229
|
+
direction: "callers"
|
|
17230
|
+
});
|
|
17231
|
+
} catch (error) {
|
|
17232
|
+
const candidates = await dependencies.implementationLookup(symbol, { limit: 5 });
|
|
17233
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
17234
|
+
return fallbackPack(
|
|
17235
|
+
dependencies,
|
|
17236
|
+
input.query,
|
|
17237
|
+
`Risk: graph data is unavailable (${message}). Target and dependencies are not graph-verified.`,
|
|
17238
|
+
"graph_unavailable",
|
|
17239
|
+
input.tokenBudget,
|
|
17240
|
+
candidates
|
|
17241
|
+
);
|
|
17242
|
+
}
|
|
17243
|
+
if (callersResult.resolution.status !== "resolved") {
|
|
17244
|
+
return fallbackPack(
|
|
17245
|
+
dependencies,
|
|
17246
|
+
input.query,
|
|
17247
|
+
formatResolutionRisk(callersResult.resolution),
|
|
17248
|
+
callersResult.resolution.status,
|
|
17249
|
+
input.tokenBudget
|
|
17250
|
+
);
|
|
17251
|
+
}
|
|
17252
|
+
const resolution = callersResult.resolution;
|
|
17253
|
+
const [definitionsResult, calleesResult] = await Promise.allSettled([
|
|
17254
|
+
dependencies.implementationLookup(symbol, { limit: 10 }),
|
|
17255
|
+
dependencies.getCallGraphData({
|
|
17256
|
+
name: symbol,
|
|
17257
|
+
filePath: input.filePath ?? resolution.filePath,
|
|
17258
|
+
direction: "callees"
|
|
17259
|
+
})
|
|
17260
|
+
]);
|
|
17261
|
+
if (definitionsResult.status === "rejected") throw definitionsResult.reason;
|
|
17262
|
+
let graphRisk;
|
|
17263
|
+
let callees = [];
|
|
17264
|
+
if (calleesResult.status === "rejected") {
|
|
17265
|
+
const message = calleesResult.reason instanceof Error ? calleesResult.reason.message : String(calleesResult.reason);
|
|
17266
|
+
graphRisk = `Risk: callee graph data is unavailable (${message}). Dependency evidence is incomplete.`;
|
|
17267
|
+
} else if (calleesResult.value.resolution.status !== "resolved") {
|
|
17268
|
+
graphRisk = "Risk: the target resolved for callers but not callees. Dependency evidence is incomplete.";
|
|
17269
|
+
} else {
|
|
17270
|
+
callees = calleesResult.value.callees.slice(0, edgeLimit(input.calleeLimit));
|
|
17271
|
+
}
|
|
17272
|
+
const source = targetSource(definitionsResult.value, resolution);
|
|
17273
|
+
const callers = callersResult.callers.slice(0, edgeLimit(input.callerLimit));
|
|
17274
|
+
const sourceBudget = Math.max(
|
|
17275
|
+
MIN_CONTEXT_PACK_TOKEN_BUDGET,
|
|
17276
|
+
Math.floor((input.tokenBudget ?? DEFAULT_CONTEXT_PACK_TOKEN_BUDGET) * 0.6)
|
|
17277
|
+
);
|
|
17278
|
+
const sourceText = source ? fitTextToContextBudget(formatSource(source), sourceBudget).text : `## Target implementation
|
|
17279
|
+
Risk: no implementation source matched the resolved target at ${resolution.filePath}:${resolution.startLine}.`;
|
|
17280
|
+
const fitted = fitTextToContextBudget([
|
|
17281
|
+
`# Pre-edit context for ${resolution.name}`,
|
|
17282
|
+
graphRisk,
|
|
17283
|
+
sourceText,
|
|
17284
|
+
formatCallers(callers),
|
|
17285
|
+
formatCallees(callees, resolution.filePath)
|
|
17286
|
+
].filter((section) => section !== void 0).join("\n\n"), input.tokenBudget ?? void 0);
|
|
17287
|
+
return {
|
|
17288
|
+
text: fitted.text,
|
|
17289
|
+
details: {
|
|
17290
|
+
resolution: "resolved",
|
|
17291
|
+
tokenBudget: fitted.tokenBudget,
|
|
17292
|
+
tokenEstimate: fitted.tokenEstimate,
|
|
17293
|
+
truncated: fitted.truncated,
|
|
17294
|
+
sourceIncluded: source !== void 0,
|
|
17295
|
+
callerCount: callers.length,
|
|
17296
|
+
calleeCount: callees.length
|
|
17297
|
+
}
|
|
17298
|
+
};
|
|
17299
|
+
}
|
|
17300
|
+
async function resolveCodebaseEditContext(projectRoot, host, input) {
|
|
17301
|
+
return resolveCodebaseEditContextWithDependencies(input, {
|
|
17302
|
+
searchCodebase: (query, options) => searchCodebase(projectRoot, host, query, options),
|
|
17303
|
+
implementationLookup: (query, options) => implementationLookup(projectRoot, host, query, options),
|
|
17304
|
+
getCallGraphData: (params) => getCallGraphData(projectRoot, host, params)
|
|
17305
|
+
});
|
|
17306
|
+
}
|
|
17307
|
+
|
|
17051
17308
|
// src/tools/context-search.ts
|
|
17052
17309
|
var MIN_CONTEXT_RESULT_LIMIT = 1;
|
|
17053
17310
|
var MAX_CONTEXT_RESULT_LIMIT = 100;
|
|
@@ -17150,6 +17407,27 @@ function buildRecoveryDetails(attempts, successIndex) {
|
|
|
17150
17407
|
successfulAttemptIndex: successIndex
|
|
17151
17408
|
};
|
|
17152
17409
|
}
|
|
17410
|
+
function serializeAttempts(attempts) {
|
|
17411
|
+
return attempts.map((attempt) => ({
|
|
17412
|
+
kind: attempt.kind,
|
|
17413
|
+
scope: attempt.scope,
|
|
17414
|
+
resultCount: attempt.resultCount,
|
|
17415
|
+
relaxedFields: attempt.relaxedFields
|
|
17416
|
+
}));
|
|
17417
|
+
}
|
|
17418
|
+
function buildSearchDiagnostic(attempt) {
|
|
17419
|
+
if (!attempt) {
|
|
17420
|
+
return void 0;
|
|
17421
|
+
}
|
|
17422
|
+
return {
|
|
17423
|
+
route: attempt.kind,
|
|
17424
|
+
routedQuery: attempt.query,
|
|
17425
|
+
searchQuery: attempt.query,
|
|
17426
|
+
searchScope: attempt.scopeFilter,
|
|
17427
|
+
searchTrace: attempt.searchTrace,
|
|
17428
|
+
contextPackTrace: attempt.contextPackTrace
|
|
17429
|
+
};
|
|
17430
|
+
}
|
|
17153
17431
|
function trimOrUndefined2(value) {
|
|
17154
17432
|
const normalized = value?.trim();
|
|
17155
17433
|
if (!normalized) {
|
|
@@ -17189,6 +17467,7 @@ async function resolveSearchContext(input, operations) {
|
|
|
17189
17467
|
const hasFilters = Boolean(fileType || directory);
|
|
17190
17468
|
const relaxedFields = relaxedHintFields(fileType, directory);
|
|
17191
17469
|
const attempts = [];
|
|
17470
|
+
const attemptStates = [];
|
|
17192
17471
|
const decisions = {
|
|
17193
17472
|
inferredDefinitionMiss: false,
|
|
17194
17473
|
fallbackFromOriginalConceptualToInferred: false,
|
|
@@ -17217,8 +17496,20 @@ async function resolveSearchContext(input, operations) {
|
|
|
17217
17496
|
if (seenAttempts.has(key)) {
|
|
17218
17497
|
return [];
|
|
17219
17498
|
}
|
|
17220
|
-
const
|
|
17499
|
+
const attemptState = {
|
|
17500
|
+
kind,
|
|
17501
|
+
scope: describeScope(scope.fileType, scope.directory),
|
|
17502
|
+
resultCount: 0,
|
|
17503
|
+
relaxedFields: [...relaxedFieldsForAttempt],
|
|
17504
|
+
query: attemptQuery,
|
|
17505
|
+
scopeFilter: scope
|
|
17506
|
+
};
|
|
17507
|
+
const results = await runAttempt((trace) => {
|
|
17508
|
+
attemptState.searchTrace = trace;
|
|
17509
|
+
});
|
|
17510
|
+
attemptState.resultCount = results.length;
|
|
17221
17511
|
seenAttempts.add(key);
|
|
17512
|
+
attemptStates.push(attemptState);
|
|
17222
17513
|
attempts.push({
|
|
17223
17514
|
kind,
|
|
17224
17515
|
scope: describeScope(scope.fileType, scope.directory),
|
|
@@ -17238,7 +17529,7 @@ async function resolveSearchContext(input, operations) {
|
|
|
17238
17529
|
symbol,
|
|
17239
17530
|
scope,
|
|
17240
17531
|
relaxedFieldsForAttempt,
|
|
17241
|
-
() => operations.lookup(symbol, MAX_CONTEXT_RESULT_LIMIT, scope)
|
|
17532
|
+
(trace) => operations.lookup(symbol, MAX_CONTEXT_RESULT_LIMIT, scope, input.diagnostic ? trace : void 0)
|
|
17242
17533
|
);
|
|
17243
17534
|
};
|
|
17244
17535
|
const tryConceptualSearch = async (searchQuery, scope, relaxedFieldsForAttempt) => {
|
|
@@ -17247,13 +17538,23 @@ async function resolveSearchContext(input, operations) {
|
|
|
17247
17538
|
searchQuery,
|
|
17248
17539
|
scope,
|
|
17249
17540
|
relaxedFieldsForAttempt,
|
|
17250
|
-
() => operations.search(searchQuery, MAX_CONTEXT_RESULT_LIMIT, scope)
|
|
17541
|
+
(trace) => operations.search(searchQuery, MAX_CONTEXT_RESULT_LIMIT, scope, input.diagnostic ? trace : void 0)
|
|
17251
17542
|
);
|
|
17252
17543
|
};
|
|
17253
|
-
const
|
|
17544
|
+
const findSuccessfulAttemptState = (route) => {
|
|
17545
|
+
for (let index = attemptStates.length - 1; index >= 0; index -= 1) {
|
|
17546
|
+
const attempt = attemptStates[index];
|
|
17547
|
+
if (attempt.kind === route && attempt.resultCount > 0) {
|
|
17548
|
+
return attempt;
|
|
17549
|
+
}
|
|
17550
|
+
}
|
|
17551
|
+
return void 0;
|
|
17552
|
+
};
|
|
17553
|
+
const toResult = (route, routedQuery, pack, successfulAttempt) => {
|
|
17254
17554
|
const base = packedResult(route, routedQuery, pack);
|
|
17255
17555
|
const baseDetails = base.details;
|
|
17256
17556
|
const successIndex = findSuccessfulAttemptIndex(route, attempts);
|
|
17557
|
+
const successState = successfulAttempt ?? findSuccessfulAttemptState(route);
|
|
17257
17558
|
return {
|
|
17258
17559
|
text: base.text,
|
|
17259
17560
|
details: {
|
|
@@ -17261,7 +17562,10 @@ async function resolveSearchContext(input, operations) {
|
|
|
17261
17562
|
tokenBudget: baseDetails.tokenBudget,
|
|
17262
17563
|
tokenEstimate: baseDetails.tokenEstimate,
|
|
17263
17564
|
truncated: false,
|
|
17264
|
-
recovery: buildRecoveryDetails(
|
|
17565
|
+
recovery: buildRecoveryDetails(serializeAttempts(attemptStates), successIndex),
|
|
17566
|
+
...input.diagnostic && {
|
|
17567
|
+
diagnostic: buildSearchDiagnostic(successState)
|
|
17568
|
+
}
|
|
17265
17569
|
}
|
|
17266
17570
|
};
|
|
17267
17571
|
};
|
|
@@ -17275,8 +17579,18 @@ async function resolveSearchContext(input, operations) {
|
|
|
17275
17579
|
buildContextPack(scopedDefinitionResults, {
|
|
17276
17580
|
tokenBudget,
|
|
17277
17581
|
maxResults: limit,
|
|
17278
|
-
heading
|
|
17279
|
-
|
|
17582
|
+
heading,
|
|
17583
|
+
preserveInputOrder: true,
|
|
17584
|
+
...input.diagnostic ? {
|
|
17585
|
+
trace: (trace) => {
|
|
17586
|
+
const attemptState = findSuccessfulAttemptState("definition");
|
|
17587
|
+
if (attemptState) {
|
|
17588
|
+
attemptState.contextPackTrace = trace;
|
|
17589
|
+
}
|
|
17590
|
+
}
|
|
17591
|
+
} : void 0
|
|
17592
|
+
}),
|
|
17593
|
+
findSuccessfulAttemptState("definition")
|
|
17280
17594
|
);
|
|
17281
17595
|
}
|
|
17282
17596
|
if (explicitSymbol) {
|
|
@@ -17294,8 +17608,18 @@ async function resolveSearchContext(input, operations) {
|
|
|
17294
17608
|
buildContextPack(unscopedDefinitionResults, {
|
|
17295
17609
|
tokenBudget,
|
|
17296
17610
|
maxResults: limit,
|
|
17297
|
-
heading: heading2
|
|
17298
|
-
|
|
17611
|
+
heading: heading2,
|
|
17612
|
+
preserveInputOrder: true,
|
|
17613
|
+
...input.diagnostic ? {
|
|
17614
|
+
trace: (trace) => {
|
|
17615
|
+
const attemptState = findSuccessfulAttemptState("definition");
|
|
17616
|
+
if (attemptState) {
|
|
17617
|
+
attemptState.contextPackTrace = trace;
|
|
17618
|
+
}
|
|
17619
|
+
}
|
|
17620
|
+
} : void 0
|
|
17621
|
+
}),
|
|
17622
|
+
findSuccessfulAttemptState("definition")
|
|
17299
17623
|
);
|
|
17300
17624
|
}
|
|
17301
17625
|
}
|
|
@@ -17314,7 +17638,10 @@ Explicit symbol lookup only; conceptual search was not attempted.`
|
|
|
17314
17638
|
tokenBudget: heading.tokenBudget,
|
|
17315
17639
|
tokenEstimate: heading.tokenEstimate,
|
|
17316
17640
|
truncated: heading.truncated,
|
|
17317
|
-
recovery: buildRecoveryDetails(
|
|
17641
|
+
recovery: buildRecoveryDetails(serializeAttempts(attemptStates), null),
|
|
17642
|
+
...input.diagnostic && {
|
|
17643
|
+
diagnostic: buildSearchDiagnostic(attemptStates[attemptStates.length - 1])
|
|
17644
|
+
}
|
|
17318
17645
|
}
|
|
17319
17646
|
};
|
|
17320
17647
|
}
|
|
@@ -17354,8 +17681,17 @@ Explicit symbol lookup only; conceptual search was not attempted.`
|
|
|
17354
17681
|
maxResults: limit,
|
|
17355
17682
|
heading,
|
|
17356
17683
|
includeExactSearchHandoff: true,
|
|
17357
|
-
preferImplementationPaths: intent.preferSourcePaths || intent.primary !== "docs" && intent.primary !== "test"
|
|
17358
|
-
|
|
17684
|
+
preferImplementationPaths: intent.preferSourcePaths || intent.primary !== "docs" && intent.primary !== "test",
|
|
17685
|
+
...input.diagnostic ? {
|
|
17686
|
+
trace: (trace) => {
|
|
17687
|
+
const attemptState = findSuccessfulAttemptState("conceptual");
|
|
17688
|
+
if (attemptState) {
|
|
17689
|
+
attemptState.contextPackTrace = trace;
|
|
17690
|
+
}
|
|
17691
|
+
}
|
|
17692
|
+
} : void 0
|
|
17693
|
+
}),
|
|
17694
|
+
findSuccessfulAttemptState("conceptual")
|
|
17359
17695
|
);
|
|
17360
17696
|
}
|
|
17361
17697
|
}
|
|
@@ -17371,7 +17707,10 @@ Explicit symbol lookup only; conceptual search was not attempted.`
|
|
|
17371
17707
|
tokenBudget: fallbackText.tokenBudget,
|
|
17372
17708
|
tokenEstimate: fallbackText.tokenEstimate,
|
|
17373
17709
|
truncated: fallbackText.truncated,
|
|
17374
|
-
recovery: buildRecoveryDetails(
|
|
17710
|
+
recovery: buildRecoveryDetails(serializeAttempts(attemptStates), null),
|
|
17711
|
+
...input.diagnostic && {
|
|
17712
|
+
diagnostic: buildSearchDiagnostic(attemptStates[attemptStates.length - 1])
|
|
17713
|
+
}
|
|
17375
17714
|
}
|
|
17376
17715
|
};
|
|
17377
17716
|
}
|
|
@@ -17452,17 +17791,27 @@ async function resolveCodebaseContextUnmeasured(projectRoot, host, input) {
|
|
|
17452
17791
|
details: fittedDetails("path", fitted, 0)
|
|
17453
17792
|
};
|
|
17454
17793
|
}
|
|
17455
|
-
return resolveSearchContext({
|
|
17456
|
-
|
|
17794
|
+
return resolveSearchContext({
|
|
17795
|
+
query: input.query,
|
|
17796
|
+
symbol,
|
|
17797
|
+
limit,
|
|
17798
|
+
tokenBudget,
|
|
17799
|
+
fileType,
|
|
17800
|
+
directory,
|
|
17801
|
+
diagnostic: input.diagnostic
|
|
17802
|
+
}, {
|
|
17803
|
+
lookup: (lookupSymbol, retrievalLimit, scope, trace) => implementationLookup(projectRoot, host, lookupSymbol, {
|
|
17457
17804
|
limit: retrievalLimit,
|
|
17458
17805
|
fileType: scope.fileType,
|
|
17459
|
-
directory: scope.directory
|
|
17806
|
+
directory: scope.directory,
|
|
17807
|
+
trace
|
|
17460
17808
|
}),
|
|
17461
|
-
search: (queryText, retrievalLimit, scope) => searchCodebase(projectRoot, host, queryText, {
|
|
17809
|
+
search: (queryText, retrievalLimit, scope, trace) => searchCodebase(projectRoot, host, queryText, {
|
|
17462
17810
|
limit: retrievalLimit,
|
|
17463
17811
|
fileType: scope.fileType,
|
|
17464
17812
|
directory: scope.directory,
|
|
17465
|
-
metadataOnly: true
|
|
17813
|
+
metadataOnly: true,
|
|
17814
|
+
trace
|
|
17466
17815
|
})
|
|
17467
17816
|
});
|
|
17468
17817
|
}
|
|
@@ -17529,7 +17878,11 @@ async function resolveCodebaseContext(projectRoot, host, input) {
|
|
|
17529
17878
|
|
|
17530
17879
|
// src/tools/execute-common.ts
|
|
17531
17880
|
async function executeCodebaseContext(projectRoot, host, args) {
|
|
17532
|
-
|
|
17881
|
+
const result = await resolveCodebaseContext(projectRoot, host, args);
|
|
17882
|
+
return { text: result.text, details: result.details };
|
|
17883
|
+
}
|
|
17884
|
+
async function executeCodebaseEditContext(projectRoot, host, args) {
|
|
17885
|
+
return { text: (await resolveCodebaseEditContext(projectRoot, host, args)).text };
|
|
17533
17886
|
}
|
|
17534
17887
|
async function executeIndexCodebase(projectRoot, host, args, onProgress) {
|
|
17535
17888
|
const result = await runIndexCodebase(projectRoot, host, args, onProgress);
|
|
@@ -17632,9 +17985,9 @@ function parseGitActivity(output) {
|
|
|
17632
17985
|
if (!filePath || addedRaw === "-" || deletedRaw === "-") continue;
|
|
17633
17986
|
const churn = Number(addedRaw) + Number(deletedRaw);
|
|
17634
17987
|
if (!Number.isFinite(churn) || churn <= 0) continue;
|
|
17635
|
-
const
|
|
17636
|
-
const previous = activity.get(
|
|
17637
|
-
activity.set(
|
|
17988
|
+
const normalizedPath2 = normalizePath3(filePath);
|
|
17989
|
+
const previous = activity.get(normalizedPath2);
|
|
17990
|
+
activity.set(normalizedPath2, {
|
|
17638
17991
|
churn: (previous?.churn ?? 0) + churn,
|
|
17639
17992
|
commits: (previous?.commits ?? 0) + 1,
|
|
17640
17993
|
latestDate: previous?.latestDate ?? latestDate,
|
|
@@ -18224,8 +18577,8 @@ function transformForVisualization(symbols, edges, options = {}) {
|
|
|
18224
18577
|
const normalizedAbsoluteSuffix = `/${normalizedDirWithSlash}`;
|
|
18225
18578
|
filteredSymbols = symbols.filter(
|
|
18226
18579
|
(s) => {
|
|
18227
|
-
const
|
|
18228
|
-
return
|
|
18580
|
+
const normalizedPath2 = s.filePath.replace(/\\/g, "/");
|
|
18581
|
+
return normalizedPath2 === normalizedDir || normalizedPath2.startsWith(normalizedDirWithSlash) || normalizedPath2.endsWith(`/${normalizedDir}`) || normalizedPath2.includes(normalizedAbsoluteSuffix);
|
|
18229
18582
|
}
|
|
18230
18583
|
);
|
|
18231
18584
|
}
|
|
@@ -18299,6 +18652,26 @@ var z3 = tool.schema;
|
|
|
18299
18652
|
var DEFAULT_HOST = "opencode";
|
|
18300
18653
|
var CHUNK_TYPE_VALUES = CHUNK_TYPES;
|
|
18301
18654
|
var RELATIONSHIP_TYPE_VALUES = RELATIONSHIP_TYPES;
|
|
18655
|
+
function stableSortedDiagnosticValue(value) {
|
|
18656
|
+
if (Array.isArray(value)) {
|
|
18657
|
+
return value.map((item) => stableSortedDiagnosticValue(item));
|
|
18658
|
+
}
|
|
18659
|
+
if (value === null || typeof value !== "object") {
|
|
18660
|
+
return value;
|
|
18661
|
+
}
|
|
18662
|
+
const entries = Object.entries(value).sort(([left], [right]) => left.localeCompare(right));
|
|
18663
|
+
const sorted = {};
|
|
18664
|
+
for (const [key, item] of entries) {
|
|
18665
|
+
sorted[key] = stableSortedDiagnosticValue(item);
|
|
18666
|
+
}
|
|
18667
|
+
return sorted;
|
|
18668
|
+
}
|
|
18669
|
+
function formatCodebaseContextDiagnostic(details) {
|
|
18670
|
+
const sorted = stableSortedDiagnosticValue(details);
|
|
18671
|
+
return `
|
|
18672
|
+
Diagnostics:
|
|
18673
|
+
${JSON.stringify(sorted, null, 2)}`;
|
|
18674
|
+
}
|
|
18302
18675
|
function initializeTools2(projectRoot, config) {
|
|
18303
18676
|
initializeTools(projectRoot, config, DEFAULT_HOST);
|
|
18304
18677
|
}
|
|
@@ -18318,10 +18691,29 @@ var codebase_context = tool({
|
|
|
18318
18691
|
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})`),
|
|
18319
18692
|
fileType: z3.string().nullable().optional().describe("Filter by file extension"),
|
|
18320
18693
|
directory: z3.string().nullable().optional().describe("Filter by directory path"),
|
|
18321
|
-
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})`)
|
|
18694
|
+
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})`),
|
|
18695
|
+
diagnostic: z3.boolean().optional().describe("Collect diagnostic routing and search traces without changing normal text output.")
|
|
18696
|
+
},
|
|
18697
|
+
async execute(args, context) {
|
|
18698
|
+
const result = await executeCodebaseContext(context?.worktree, DEFAULT_HOST, args);
|
|
18699
|
+
if (!args.diagnostic || !result.details?.diagnostic) {
|
|
18700
|
+
return result.text;
|
|
18701
|
+
}
|
|
18702
|
+
return `${result.text}${formatCodebaseContextDiagnostic(result.details.diagnostic)}`;
|
|
18703
|
+
}
|
|
18704
|
+
});
|
|
18705
|
+
var codebase_edit_context = tool({
|
|
18706
|
+
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.",
|
|
18707
|
+
args: {
|
|
18708
|
+
query: z3.string().describe("The requested change or target behavior"),
|
|
18709
|
+
symbol: z3.string().nullable().optional().describe("Authoritative target symbol when known"),
|
|
18710
|
+
filePath: z3.string().nullable().optional().describe("Optional file path used to disambiguate duplicate symbol names"),
|
|
18711
|
+
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),
|
|
18712
|
+
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),
|
|
18713
|
+
tokenBudget: z3.number().int().min(MIN_CONTEXT_PACK_TOKEN_BUDGET).max(MAX_CONTEXT_PACK_TOKEN_BUDGET).nullable().optional().default(DEFAULT_CONTEXT_PACK_TOKEN_BUDGET)
|
|
18322
18714
|
},
|
|
18323
18715
|
async execute(args, context) {
|
|
18324
|
-
return (await
|
|
18716
|
+
return (await executeCodebaseEditContext(context?.worktree, DEFAULT_HOST, args)).text;
|
|
18325
18717
|
}
|
|
18326
18718
|
});
|
|
18327
18719
|
var codebase_peek = tool({
|
|
@@ -18578,6 +18970,7 @@ var index_visualize = tool({
|
|
|
18578
18970
|
// src/tools/tool-names.ts
|
|
18579
18971
|
var TOOL_NAME = {
|
|
18580
18972
|
CODEBASE_CONTEXT: "codebase_context",
|
|
18973
|
+
CODEBASE_EDIT_CONTEXT: "codebase_edit_context",
|
|
18581
18974
|
CODEBASE_SEARCH: "codebase_search",
|
|
18582
18975
|
CODEBASE_PEEK: "codebase_peek",
|
|
18583
18976
|
FIND_SIMILAR: "find_similar",
|
|
@@ -18601,6 +18994,7 @@ var TOOL_NAME = {
|
|
|
18601
18994
|
};
|
|
18602
18995
|
var PORTABLE_TOOL_NAMES = [
|
|
18603
18996
|
TOOL_NAME.CODEBASE_CONTEXT,
|
|
18997
|
+
TOOL_NAME.CODEBASE_EDIT_CONTEXT,
|
|
18604
18998
|
TOOL_NAME.CODEBASE_SEARCH,
|
|
18605
18999
|
TOOL_NAME.CODEBASE_PEEK,
|
|
18606
19000
|
TOOL_NAME.INDEX_CODEBASE,
|
|
@@ -18617,6 +19011,7 @@ var PORTABLE_TOOL_NAMES = [
|
|
|
18617
19011
|
];
|
|
18618
19012
|
var OPENCODE_TOOL_NAMES = [
|
|
18619
19013
|
TOOL_NAME.CODEBASE_CONTEXT,
|
|
19014
|
+
TOOL_NAME.CODEBASE_EDIT_CONTEXT,
|
|
18620
19015
|
TOOL_NAME.CODEBASE_SEARCH,
|
|
18621
19016
|
TOOL_NAME.CODEBASE_PEEK,
|
|
18622
19017
|
TOOL_NAME.INDEX_CODEBASE,
|
|
@@ -18637,6 +19032,7 @@ var OPENCODE_TOOL_NAMES = [
|
|
|
18637
19032
|
];
|
|
18638
19033
|
var PI_TOOL_NAMES = [
|
|
18639
19034
|
TOOL_NAME.CODEBASE_CONTEXT,
|
|
19035
|
+
TOOL_NAME.CODEBASE_EDIT_CONTEXT,
|
|
18640
19036
|
TOOL_NAME.CODEBASE_SEARCH,
|
|
18641
19037
|
TOOL_NAME.CODEBASE_PEEK,
|
|
18642
19038
|
TOOL_NAME.FIND_SIMILAR,
|
|
@@ -19090,6 +19486,7 @@ var plugin = async ({ directory, worktree }) => {
|
|
|
19090
19486
|
return {
|
|
19091
19487
|
tool: {
|
|
19092
19488
|
[TOOL_NAME.CODEBASE_CONTEXT]: codebase_context,
|
|
19489
|
+
[TOOL_NAME.CODEBASE_EDIT_CONTEXT]: codebase_edit_context,
|
|
19093
19490
|
[TOOL_NAME.CODEBASE_SEARCH]: codebase_search,
|
|
19094
19491
|
[TOOL_NAME.CODEBASE_PEEK]: codebase_peek,
|
|
19095
19492
|
[TOOL_NAME.INDEX_CODEBASE]: index_codebase,
|