open-codebase-index 0.22.2 → 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 +668 -96
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +668 -96
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +442 -57
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +442 -57
- package/dist/index.js.map +1 -1
- package/dist/pi-extension.cjs +402 -49
- package/dist/pi-extension.cjs.map +1 -1
- package/dist/pi-extension.js +402 -49
- 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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//
|
|
1
|
+
// open-codebase-index - Semantic codebase indexing and search
|
|
2
2
|
"use strict";
|
|
3
3
|
var __create = Object.create;
|
|
4
4
|
var __defProp = Object.defineProperty;
|
|
@@ -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";
|
|
@@ -9067,9 +9089,9 @@ function normalizeFilePathForHintMatch(filePath) {
|
|
|
9067
9089
|
return filePath.replace(/\\/g, "/").toLowerCase().replace(/^\.\//, "");
|
|
9068
9090
|
}
|
|
9069
9091
|
function pathMatchesHint(filePath, hint) {
|
|
9070
|
-
const
|
|
9092
|
+
const normalizedPath2 = normalizeFilePathForHintMatch(filePath);
|
|
9071
9093
|
const normalizedHint = normalizeFilePathForHintMatch(hint);
|
|
9072
|
-
return
|
|
9094
|
+
return normalizedPath2.endsWith(normalizedHint) || normalizedPath2.includes(`/${normalizedHint}`) || normalizedPath2.includes(normalizedHint);
|
|
9073
9095
|
}
|
|
9074
9096
|
function extractFilePathHint(query) {
|
|
9075
9097
|
const match = query.match(FILE_PATH_HINT_SUFFIX_REGEX);
|
|
@@ -12942,6 +12964,20 @@ var Indexer = class _Indexer {
|
|
|
12942
12964
|
requestedLimit = nextLimit;
|
|
12943
12965
|
}
|
|
12944
12966
|
}
|
|
12967
|
+
buildCandidateSnapshot(candidate) {
|
|
12968
|
+
return {
|
|
12969
|
+
id: candidate.id,
|
|
12970
|
+
filePath: candidate.metadata.filePath,
|
|
12971
|
+
startLine: candidate.metadata.startLine,
|
|
12972
|
+
endLine: candidate.metadata.endLine,
|
|
12973
|
+
score: candidate.score,
|
|
12974
|
+
chunkType: candidate.metadata.chunkType,
|
|
12975
|
+
name: candidate.metadata.name
|
|
12976
|
+
};
|
|
12977
|
+
}
|
|
12978
|
+
buildCandidateSnapshotList(candidates) {
|
|
12979
|
+
return candidates.map((candidate) => this.buildCandidateSnapshot(candidate));
|
|
12980
|
+
}
|
|
12945
12981
|
searchSemanticCandidates(store, embedding, initialLimit, branchChunkIds, shouldPrefilterByBranch) {
|
|
12946
12982
|
return this.searchCandidatesWithBranchPrefilter(
|
|
12947
12983
|
initialLimit,
|
|
@@ -13133,6 +13169,16 @@ var Indexer = class _Indexer {
|
|
|
13133
13169
|
prefilterMs: Math.round(prefilterMs * 100) / 100,
|
|
13134
13170
|
fusionMs: Math.round(fusionMs * 100) / 100
|
|
13135
13171
|
});
|
|
13172
|
+
if (options?.trace) {
|
|
13173
|
+
options.trace({
|
|
13174
|
+
semanticCandidates: this.buildCandidateSnapshotList(scopedSemanticCandidates),
|
|
13175
|
+
keywordCandidates: this.buildCandidateSnapshotList(scopedKeywordCandidates),
|
|
13176
|
+
hybridCandidates: this.buildCandidateSnapshotList(combined),
|
|
13177
|
+
postExternalRerankCandidates: this.buildCandidateSnapshotList(rerankedCombined),
|
|
13178
|
+
tieredCandidates: this.buildCandidateSnapshotList(tiered),
|
|
13179
|
+
finalCandidates: this.buildCandidateSnapshotList(finalResults)
|
|
13180
|
+
});
|
|
13181
|
+
}
|
|
13136
13182
|
const metadataOnly = options?.metadataOnly ?? false;
|
|
13137
13183
|
return Promise.all(
|
|
13138
13184
|
finalResults.map(async (r) => {
|
|
@@ -14400,7 +14446,8 @@ async function searchCodebase(projectRoot, host, query, options = {}) {
|
|
|
14400
14446
|
definitionIntent: options.definitionIntent,
|
|
14401
14447
|
blameAuthor: options.blameAuthor,
|
|
14402
14448
|
blameSha: options.blameSha,
|
|
14403
|
-
blameSince: options.blameSince
|
|
14449
|
+
blameSince: options.blameSince,
|
|
14450
|
+
trace: options.trace
|
|
14404
14451
|
});
|
|
14405
14452
|
}
|
|
14406
14453
|
async function searchCodebaseWithEffectiveness(projectRoot, host, route, query, options, render) {
|
|
@@ -14454,15 +14501,19 @@ async function implementationLookup(projectRoot, host, query, options = {}) {
|
|
|
14454
14501
|
return indexer.search(query, options.limit, {
|
|
14455
14502
|
fileType: options.fileType,
|
|
14456
14503
|
directory: options.directory,
|
|
14457
|
-
definitionIntent: true
|
|
14504
|
+
definitionIntent: true,
|
|
14505
|
+
trace: options.trace
|
|
14458
14506
|
});
|
|
14459
14507
|
}
|
|
14460
14508
|
async function getCallGraphData(projectRoot, host, params) {
|
|
14461
14509
|
await ensureAutoIndexReadyForRetrieval(projectRoot, host);
|
|
14462
14510
|
const root = getProjectRoot(projectRoot, host);
|
|
14463
14511
|
const indexer = getIndexerForProject(root, host);
|
|
14512
|
+
return getCallGraphDataForIndexer(indexer, root, params);
|
|
14513
|
+
}
|
|
14514
|
+
async function getCallGraphDataForIndexer(indexer, projectRoot, params) {
|
|
14464
14515
|
const symbols = await indexer.getCallGraphSymbols();
|
|
14465
|
-
const resolution = resolveCallGraphSymbol(symbols,
|
|
14516
|
+
const resolution = resolveCallGraphSymbol(symbols, projectRoot, params.name, params.filePath, params.symbolId);
|
|
14466
14517
|
const direction = params.direction === "callees" ? "callees" : "callers";
|
|
14467
14518
|
if (resolution.status !== "resolved") {
|
|
14468
14519
|
return { direction, resolution, callers: [], callees: [], relationshipType: params.relationshipType };
|
|
@@ -14678,17 +14729,17 @@ async function getIndexLogs(projectRoot, host, args) {
|
|
|
14678
14729
|
function addKnowledgeBase(projectRoot, host, knowledgeBasePath) {
|
|
14679
14730
|
const root = getProjectRoot(projectRoot, host);
|
|
14680
14731
|
const inputPath = knowledgeBasePath.trim();
|
|
14681
|
-
const
|
|
14732
|
+
const normalizedPath2 = path20.resolve(
|
|
14682
14733
|
path20.isAbsolute(inputPath) ? inputPath : resolveKnowledgeBasePath(inputPath, root)
|
|
14683
14734
|
);
|
|
14684
|
-
if (!(0, import_fs13.existsSync)(
|
|
14685
|
-
return `Error: Directory does not exist: ${
|
|
14735
|
+
if (!(0, import_fs13.existsSync)(normalizedPath2)) {
|
|
14736
|
+
return `Error: Directory does not exist: ${normalizedPath2}`;
|
|
14686
14737
|
}
|
|
14687
14738
|
let realPath;
|
|
14688
14739
|
try {
|
|
14689
|
-
realPath = (0, import_fs13.realpathSync)(
|
|
14740
|
+
realPath = (0, import_fs13.realpathSync)(normalizedPath2);
|
|
14690
14741
|
} catch {
|
|
14691
|
-
return `Error: Cannot resolve path: ${
|
|
14742
|
+
return `Error: Cannot resolve path: ${normalizedPath2}`;
|
|
14692
14743
|
}
|
|
14693
14744
|
const blockedPrefixes = [
|
|
14694
14745
|
"/etc",
|
|
@@ -14711,34 +14762,34 @@ function addKnowledgeBase(projectRoot, host, knowledgeBasePath) {
|
|
|
14711
14762
|
];
|
|
14712
14763
|
for (const prefix of blockedPrefixes) {
|
|
14713
14764
|
if (realPath === prefix || realPath.startsWith(`${prefix}/`)) {
|
|
14714
|
-
return `Error: Adding sensitive directory as knowledge base is not allowed: ${
|
|
14765
|
+
return `Error: Adding sensitive directory as knowledge base is not allowed: ${normalizedPath2}`;
|
|
14715
14766
|
}
|
|
14716
14767
|
}
|
|
14717
14768
|
for (const dotDir of sensitiveDotDirs) {
|
|
14718
14769
|
const sensitiveDir = path20.join(homeDir, dotDir);
|
|
14719
14770
|
if (sensitiveDir && (realPath === sensitiveDir || realPath.startsWith(`${sensitiveDir}/`))) {
|
|
14720
|
-
return `Error: Adding sensitive directory as knowledge base is not allowed: ${
|
|
14771
|
+
return `Error: Adding sensitive directory as knowledge base is not allowed: ${normalizedPath2}`;
|
|
14721
14772
|
}
|
|
14722
14773
|
}
|
|
14723
14774
|
try {
|
|
14724
|
-
const stat4 = (0, import_fs13.statSync)(
|
|
14775
|
+
const stat4 = (0, import_fs13.statSync)(normalizedPath2);
|
|
14725
14776
|
if (!stat4.isDirectory()) {
|
|
14726
|
-
return `Error: Path is not a directory: ${
|
|
14777
|
+
return `Error: Path is not a directory: ${normalizedPath2}`;
|
|
14727
14778
|
}
|
|
14728
14779
|
} catch (error) {
|
|
14729
|
-
return `Error: Cannot access directory: ${
|
|
14780
|
+
return `Error: Cannot access directory: ${normalizedPath2} - ${error instanceof Error ? error.message : String(error)}`;
|
|
14730
14781
|
}
|
|
14731
14782
|
const config = loadEditableConfig(root, host);
|
|
14732
14783
|
const knowledgeBases = Array.isArray(config.knowledgeBases) ? config.knowledgeBases : [];
|
|
14733
|
-
const alreadyExists = hasMatchingKnowledgeBasePath(knowledgeBases,
|
|
14784
|
+
const alreadyExists = hasMatchingKnowledgeBasePath(knowledgeBases, normalizedPath2, root);
|
|
14734
14785
|
if (alreadyExists) {
|
|
14735
|
-
return `Knowledge base already configured: ${
|
|
14786
|
+
return `Knowledge base already configured: ${normalizedPath2}`;
|
|
14736
14787
|
}
|
|
14737
|
-
knowledgeBases.push(
|
|
14788
|
+
knowledgeBases.push(normalizedPath2);
|
|
14738
14789
|
config.knowledgeBases = knowledgeBases;
|
|
14739
14790
|
saveConfig(root, config, host);
|
|
14740
14791
|
refreshIndexerForDirectory(root, host);
|
|
14741
|
-
let result = `${
|
|
14792
|
+
let result = `${normalizedPath2}
|
|
14742
14793
|
`;
|
|
14743
14794
|
result += `Total knowledge bases: ${knowledgeBases.length}
|
|
14744
14795
|
`;
|
|
@@ -16783,6 +16834,8 @@ var GitHeadWatcher = class {
|
|
|
16783
16834
|
debounceTimer = null;
|
|
16784
16835
|
debounceMs = 100;
|
|
16785
16836
|
// Short debounce for git operations
|
|
16837
|
+
readyPromise = Promise.resolve();
|
|
16838
|
+
resolveReady = null;
|
|
16786
16839
|
constructor(projectRoot) {
|
|
16787
16840
|
this.projectRoot = projectRoot;
|
|
16788
16841
|
}
|
|
@@ -16791,8 +16844,12 @@ var GitHeadWatcher = class {
|
|
|
16791
16844
|
return;
|
|
16792
16845
|
}
|
|
16793
16846
|
if (!isGitRepo(this.projectRoot)) {
|
|
16847
|
+
this.readyPromise = Promise.resolve();
|
|
16794
16848
|
return;
|
|
16795
16849
|
}
|
|
16850
|
+
this.readyPromise = new Promise((resolve15) => {
|
|
16851
|
+
this.resolveReady = resolve15;
|
|
16852
|
+
});
|
|
16796
16853
|
this.onBranchChange = handler;
|
|
16797
16854
|
this.currentBranch = getCurrentBranch(this.projectRoot);
|
|
16798
16855
|
const headPath = getHeadPath(this.projectRoot);
|
|
@@ -16807,6 +16864,10 @@ var GitHeadWatcher = class {
|
|
|
16807
16864
|
});
|
|
16808
16865
|
this.watcher.on("change", () => this.handleHeadChange());
|
|
16809
16866
|
this.watcher.on("add", () => this.handleHeadChange());
|
|
16867
|
+
this.watcher.once("ready", () => {
|
|
16868
|
+
this.resolveReady?.();
|
|
16869
|
+
this.resolveReady = null;
|
|
16870
|
+
});
|
|
16810
16871
|
}
|
|
16811
16872
|
handleHeadChange() {
|
|
16812
16873
|
if (this.debounceTimer) {
|
|
@@ -16844,10 +16905,16 @@ var GitHeadWatcher = class {
|
|
|
16844
16905
|
await watcher.close();
|
|
16845
16906
|
}
|
|
16846
16907
|
this.onBranchChange = null;
|
|
16908
|
+
this.resolveReady?.();
|
|
16909
|
+
this.resolveReady = null;
|
|
16910
|
+
this.readyPromise = Promise.resolve();
|
|
16847
16911
|
}
|
|
16848
16912
|
isRunning() {
|
|
16849
16913
|
return this.watcher !== null;
|
|
16850
16914
|
}
|
|
16915
|
+
async waitUntilReady() {
|
|
16916
|
+
await this.readyPromise;
|
|
16917
|
+
}
|
|
16851
16918
|
};
|
|
16852
16919
|
|
|
16853
16920
|
// src/watcher/index.ts
|
|
@@ -16897,7 +16964,10 @@ function createWatcherWithIndexer(getIndexer, projectRoot, config, host, options
|
|
|
16897
16964
|
fileWatcher,
|
|
16898
16965
|
gitWatcher,
|
|
16899
16966
|
whenReady() {
|
|
16900
|
-
return
|
|
16967
|
+
return Promise.all([
|
|
16968
|
+
fileWatcher.waitUntilReady(),
|
|
16969
|
+
gitWatcher?.waitUntilReady()
|
|
16970
|
+
]).then(() => void 0);
|
|
16901
16971
|
},
|
|
16902
16972
|
async stop() {
|
|
16903
16973
|
stopped = true;
|
|
@@ -17032,6 +17102,181 @@ var pr_impact = tool({
|
|
|
17032
17102
|
}
|
|
17033
17103
|
});
|
|
17034
17104
|
|
|
17105
|
+
// src/tools/edit-context.ts
|
|
17106
|
+
function edgeLimit(value) {
|
|
17107
|
+
if (value === null || value === void 0 || !Number.isFinite(value)) {
|
|
17108
|
+
return DEFAULT_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT;
|
|
17109
|
+
}
|
|
17110
|
+
return Math.min(
|
|
17111
|
+
MAX_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT,
|
|
17112
|
+
Math.max(MIN_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT, Math.floor(value))
|
|
17113
|
+
);
|
|
17114
|
+
}
|
|
17115
|
+
function normalizedPath(value) {
|
|
17116
|
+
return value.replaceAll("\\", "/").replace(/^\.\//, "");
|
|
17117
|
+
}
|
|
17118
|
+
function pathsMatch(left, right) {
|
|
17119
|
+
const normalizedLeft = normalizedPath(left);
|
|
17120
|
+
const normalizedRight = normalizedPath(right);
|
|
17121
|
+
return normalizedLeft === normalizedRight || normalizedLeft.endsWith(`/${normalizedRight}`) || normalizedRight.endsWith(`/${normalizedLeft}`);
|
|
17122
|
+
}
|
|
17123
|
+
function targetSource(results, resolution) {
|
|
17124
|
+
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);
|
|
17125
|
+
}
|
|
17126
|
+
function formatSource(result) {
|
|
17127
|
+
const name = result.name ? ` ${result.name}` : "";
|
|
17128
|
+
return [
|
|
17129
|
+
"## Target implementation",
|
|
17130
|
+
`${result.filePath}:${result.startLine}-${result.endLine} (${result.chunkType}${name})`,
|
|
17131
|
+
"```",
|
|
17132
|
+
result.content,
|
|
17133
|
+
"```"
|
|
17134
|
+
].join("\n");
|
|
17135
|
+
}
|
|
17136
|
+
function formatCallers(edges) {
|
|
17137
|
+
if (edges.length === 0) return "## Direct callers\nNone found.";
|
|
17138
|
+
return [
|
|
17139
|
+
"## Direct callers",
|
|
17140
|
+
...edges.map((edge) => `- ${edge.fromSymbolName ?? "<unknown>"} at ${edge.fromSymbolFilePath ?? "<unknown file>"}:${edge.line} (${edge.callType}, ${edge.isResolved ? "resolved" : "unresolved"})`)
|
|
17141
|
+
].join("\n");
|
|
17142
|
+
}
|
|
17143
|
+
function formatCallees(edges, sourceFilePath) {
|
|
17144
|
+
if (edges.length === 0) return "## Direct callees\nNone found.";
|
|
17145
|
+
return [
|
|
17146
|
+
"## Direct callees",
|
|
17147
|
+
...edges.map((edge) => `- ${edge.targetName} from ${sourceFilePath}:${edge.line} (${edge.callType}, ${edge.isResolved ? "resolved" : "unresolved"})`)
|
|
17148
|
+
].join("\n");
|
|
17149
|
+
}
|
|
17150
|
+
function formatResolutionRisk(resolution) {
|
|
17151
|
+
if (resolution.status === "ambiguous") {
|
|
17152
|
+
const candidates = resolution.candidates.map((candidate) => `${candidate.filePath}:${candidate.startLine}`).join(", ");
|
|
17153
|
+
return `Risk: symbol "${resolution.name}" is ambiguous. Pass filePath to select a target.${candidates ? ` Candidates: ${candidates}.` : ""}`;
|
|
17154
|
+
}
|
|
17155
|
+
if (resolution.filePath && resolution.totalCandidates > 0) {
|
|
17156
|
+
return `Risk: symbol "${resolution.name}" did not resolve at filePath="${resolution.filePath}". Review the conceptual evidence before editing.`;
|
|
17157
|
+
}
|
|
17158
|
+
return `Risk: symbol "${resolution.name}" could not be resolved. Review the conceptual evidence before editing.`;
|
|
17159
|
+
}
|
|
17160
|
+
async function fallbackPack(dependencies, query, risk, resolution, tokenBudget, candidateSource = []) {
|
|
17161
|
+
const conceptual = await dependencies.searchCodebase(query, { limit: 5 });
|
|
17162
|
+
const pack = buildContextPack([...candidateSource, ...conceptual], {
|
|
17163
|
+
tokenBudget: tokenBudget ?? void 0,
|
|
17164
|
+
heading: "## Conceptual evidence",
|
|
17165
|
+
maxResults: 5,
|
|
17166
|
+
includeExactSearchHandoff: false,
|
|
17167
|
+
preferImplementationPaths: true
|
|
17168
|
+
});
|
|
17169
|
+
const fitted = fitTextToContextBudget(`${risk}
|
|
17170
|
+
|
|
17171
|
+
${pack.text}`, tokenBudget ?? void 0);
|
|
17172
|
+
return {
|
|
17173
|
+
text: fitted.text,
|
|
17174
|
+
details: {
|
|
17175
|
+
resolution,
|
|
17176
|
+
tokenBudget: fitted.tokenBudget,
|
|
17177
|
+
tokenEstimate: fitted.tokenEstimate,
|
|
17178
|
+
truncated: fitted.truncated,
|
|
17179
|
+
sourceIncluded: candidateSource.length > 0,
|
|
17180
|
+
callerCount: 0,
|
|
17181
|
+
calleeCount: 0
|
|
17182
|
+
}
|
|
17183
|
+
};
|
|
17184
|
+
}
|
|
17185
|
+
async function resolveCodebaseEditContextWithDependencies(input, dependencies) {
|
|
17186
|
+
const symbol = input.symbol?.trim();
|
|
17187
|
+
if (!symbol) {
|
|
17188
|
+
return fallbackPack(
|
|
17189
|
+
dependencies,
|
|
17190
|
+
input.query,
|
|
17191
|
+
"Risk: no authoritative symbol was supplied. Review the conceptual evidence before editing.",
|
|
17192
|
+
"not_requested",
|
|
17193
|
+
input.tokenBudget
|
|
17194
|
+
);
|
|
17195
|
+
}
|
|
17196
|
+
let callersResult;
|
|
17197
|
+
try {
|
|
17198
|
+
callersResult = await dependencies.getCallGraphData({
|
|
17199
|
+
name: symbol,
|
|
17200
|
+
filePath: input.filePath ?? void 0,
|
|
17201
|
+
direction: "callers"
|
|
17202
|
+
});
|
|
17203
|
+
} catch (error) {
|
|
17204
|
+
const candidates = await dependencies.implementationLookup(symbol, { limit: 5 });
|
|
17205
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
17206
|
+
return fallbackPack(
|
|
17207
|
+
dependencies,
|
|
17208
|
+
input.query,
|
|
17209
|
+
`Risk: graph data is unavailable (${message}). Target and dependencies are not graph-verified.`,
|
|
17210
|
+
"graph_unavailable",
|
|
17211
|
+
input.tokenBudget,
|
|
17212
|
+
candidates
|
|
17213
|
+
);
|
|
17214
|
+
}
|
|
17215
|
+
if (callersResult.resolution.status !== "resolved") {
|
|
17216
|
+
return fallbackPack(
|
|
17217
|
+
dependencies,
|
|
17218
|
+
input.query,
|
|
17219
|
+
formatResolutionRisk(callersResult.resolution),
|
|
17220
|
+
callersResult.resolution.status,
|
|
17221
|
+
input.tokenBudget
|
|
17222
|
+
);
|
|
17223
|
+
}
|
|
17224
|
+
const resolution = callersResult.resolution;
|
|
17225
|
+
const [definitionsResult, calleesResult] = await Promise.allSettled([
|
|
17226
|
+
dependencies.implementationLookup(symbol, { limit: 10 }),
|
|
17227
|
+
dependencies.getCallGraphData({
|
|
17228
|
+
name: symbol,
|
|
17229
|
+
filePath: input.filePath ?? resolution.filePath,
|
|
17230
|
+
direction: "callees"
|
|
17231
|
+
})
|
|
17232
|
+
]);
|
|
17233
|
+
if (definitionsResult.status === "rejected") throw definitionsResult.reason;
|
|
17234
|
+
let graphRisk;
|
|
17235
|
+
let callees = [];
|
|
17236
|
+
if (calleesResult.status === "rejected") {
|
|
17237
|
+
const message = calleesResult.reason instanceof Error ? calleesResult.reason.message : String(calleesResult.reason);
|
|
17238
|
+
graphRisk = `Risk: callee graph data is unavailable (${message}). Dependency evidence is incomplete.`;
|
|
17239
|
+
} else if (calleesResult.value.resolution.status !== "resolved") {
|
|
17240
|
+
graphRisk = "Risk: the target resolved for callers but not callees. Dependency evidence is incomplete.";
|
|
17241
|
+
} else {
|
|
17242
|
+
callees = calleesResult.value.callees.slice(0, edgeLimit(input.calleeLimit));
|
|
17243
|
+
}
|
|
17244
|
+
const source = targetSource(definitionsResult.value, resolution);
|
|
17245
|
+
const callers = callersResult.callers.slice(0, edgeLimit(input.callerLimit));
|
|
17246
|
+
const sourceBudget = Math.max(
|
|
17247
|
+
MIN_CONTEXT_PACK_TOKEN_BUDGET,
|
|
17248
|
+
Math.floor((input.tokenBudget ?? DEFAULT_CONTEXT_PACK_TOKEN_BUDGET) * 0.6)
|
|
17249
|
+
);
|
|
17250
|
+
const sourceText = source ? fitTextToContextBudget(formatSource(source), sourceBudget).text : `## Target implementation
|
|
17251
|
+
Risk: no implementation source matched the resolved target at ${resolution.filePath}:${resolution.startLine}.`;
|
|
17252
|
+
const fitted = fitTextToContextBudget([
|
|
17253
|
+
`# Pre-edit context for ${resolution.name}`,
|
|
17254
|
+
graphRisk,
|
|
17255
|
+
sourceText,
|
|
17256
|
+
formatCallers(callers),
|
|
17257
|
+
formatCallees(callees, resolution.filePath)
|
|
17258
|
+
].filter((section) => section !== void 0).join("\n\n"), input.tokenBudget ?? void 0);
|
|
17259
|
+
return {
|
|
17260
|
+
text: fitted.text,
|
|
17261
|
+
details: {
|
|
17262
|
+
resolution: "resolved",
|
|
17263
|
+
tokenBudget: fitted.tokenBudget,
|
|
17264
|
+
tokenEstimate: fitted.tokenEstimate,
|
|
17265
|
+
truncated: fitted.truncated,
|
|
17266
|
+
sourceIncluded: source !== void 0,
|
|
17267
|
+
callerCount: callers.length,
|
|
17268
|
+
calleeCount: callees.length
|
|
17269
|
+
}
|
|
17270
|
+
};
|
|
17271
|
+
}
|
|
17272
|
+
async function resolveCodebaseEditContext(projectRoot, host, input) {
|
|
17273
|
+
return resolveCodebaseEditContextWithDependencies(input, {
|
|
17274
|
+
searchCodebase: (query, options) => searchCodebase(projectRoot, host, query, options),
|
|
17275
|
+
implementationLookup: (query, options) => implementationLookup(projectRoot, host, query, options),
|
|
17276
|
+
getCallGraphData: (params) => getCallGraphData(projectRoot, host, params)
|
|
17277
|
+
});
|
|
17278
|
+
}
|
|
17279
|
+
|
|
17035
17280
|
// src/tools/context-search.ts
|
|
17036
17281
|
var MIN_CONTEXT_RESULT_LIMIT = 1;
|
|
17037
17282
|
var MAX_CONTEXT_RESULT_LIMIT = 100;
|
|
@@ -17134,6 +17379,27 @@ function buildRecoveryDetails(attempts, successIndex) {
|
|
|
17134
17379
|
successfulAttemptIndex: successIndex
|
|
17135
17380
|
};
|
|
17136
17381
|
}
|
|
17382
|
+
function serializeAttempts(attempts) {
|
|
17383
|
+
return attempts.map((attempt) => ({
|
|
17384
|
+
kind: attempt.kind,
|
|
17385
|
+
scope: attempt.scope,
|
|
17386
|
+
resultCount: attempt.resultCount,
|
|
17387
|
+
relaxedFields: attempt.relaxedFields
|
|
17388
|
+
}));
|
|
17389
|
+
}
|
|
17390
|
+
function buildSearchDiagnostic(attempt) {
|
|
17391
|
+
if (!attempt) {
|
|
17392
|
+
return void 0;
|
|
17393
|
+
}
|
|
17394
|
+
return {
|
|
17395
|
+
route: attempt.kind,
|
|
17396
|
+
routedQuery: attempt.query,
|
|
17397
|
+
searchQuery: attempt.query,
|
|
17398
|
+
searchScope: attempt.scopeFilter,
|
|
17399
|
+
searchTrace: attempt.searchTrace,
|
|
17400
|
+
contextPackTrace: attempt.contextPackTrace
|
|
17401
|
+
};
|
|
17402
|
+
}
|
|
17137
17403
|
function trimOrUndefined2(value) {
|
|
17138
17404
|
const normalized = value?.trim();
|
|
17139
17405
|
if (!normalized) {
|
|
@@ -17173,6 +17439,7 @@ async function resolveSearchContext(input, operations) {
|
|
|
17173
17439
|
const hasFilters = Boolean(fileType || directory);
|
|
17174
17440
|
const relaxedFields = relaxedHintFields(fileType, directory);
|
|
17175
17441
|
const attempts = [];
|
|
17442
|
+
const attemptStates = [];
|
|
17176
17443
|
const decisions = {
|
|
17177
17444
|
inferredDefinitionMiss: false,
|
|
17178
17445
|
fallbackFromOriginalConceptualToInferred: false,
|
|
@@ -17201,8 +17468,20 @@ async function resolveSearchContext(input, operations) {
|
|
|
17201
17468
|
if (seenAttempts.has(key)) {
|
|
17202
17469
|
return [];
|
|
17203
17470
|
}
|
|
17204
|
-
const
|
|
17471
|
+
const attemptState = {
|
|
17472
|
+
kind,
|
|
17473
|
+
scope: describeScope(scope.fileType, scope.directory),
|
|
17474
|
+
resultCount: 0,
|
|
17475
|
+
relaxedFields: [...relaxedFieldsForAttempt],
|
|
17476
|
+
query: attemptQuery,
|
|
17477
|
+
scopeFilter: scope
|
|
17478
|
+
};
|
|
17479
|
+
const results = await runAttempt((trace) => {
|
|
17480
|
+
attemptState.searchTrace = trace;
|
|
17481
|
+
});
|
|
17482
|
+
attemptState.resultCount = results.length;
|
|
17205
17483
|
seenAttempts.add(key);
|
|
17484
|
+
attemptStates.push(attemptState);
|
|
17206
17485
|
attempts.push({
|
|
17207
17486
|
kind,
|
|
17208
17487
|
scope: describeScope(scope.fileType, scope.directory),
|
|
@@ -17222,7 +17501,7 @@ async function resolveSearchContext(input, operations) {
|
|
|
17222
17501
|
symbol,
|
|
17223
17502
|
scope,
|
|
17224
17503
|
relaxedFieldsForAttempt,
|
|
17225
|
-
() => operations.lookup(symbol, MAX_CONTEXT_RESULT_LIMIT, scope)
|
|
17504
|
+
(trace) => operations.lookup(symbol, MAX_CONTEXT_RESULT_LIMIT, scope, input.diagnostic ? trace : void 0)
|
|
17226
17505
|
);
|
|
17227
17506
|
};
|
|
17228
17507
|
const tryConceptualSearch = async (searchQuery, scope, relaxedFieldsForAttempt) => {
|
|
@@ -17231,13 +17510,23 @@ async function resolveSearchContext(input, operations) {
|
|
|
17231
17510
|
searchQuery,
|
|
17232
17511
|
scope,
|
|
17233
17512
|
relaxedFieldsForAttempt,
|
|
17234
|
-
() => operations.search(searchQuery, MAX_CONTEXT_RESULT_LIMIT, scope)
|
|
17513
|
+
(trace) => operations.search(searchQuery, MAX_CONTEXT_RESULT_LIMIT, scope, input.diagnostic ? trace : void 0)
|
|
17235
17514
|
);
|
|
17236
17515
|
};
|
|
17237
|
-
const
|
|
17516
|
+
const findSuccessfulAttemptState = (route) => {
|
|
17517
|
+
for (let index = attemptStates.length - 1; index >= 0; index -= 1) {
|
|
17518
|
+
const attempt = attemptStates[index];
|
|
17519
|
+
if (attempt.kind === route && attempt.resultCount > 0) {
|
|
17520
|
+
return attempt;
|
|
17521
|
+
}
|
|
17522
|
+
}
|
|
17523
|
+
return void 0;
|
|
17524
|
+
};
|
|
17525
|
+
const toResult = (route, routedQuery, pack, successfulAttempt) => {
|
|
17238
17526
|
const base = packedResult(route, routedQuery, pack);
|
|
17239
17527
|
const baseDetails = base.details;
|
|
17240
17528
|
const successIndex = findSuccessfulAttemptIndex(route, attempts);
|
|
17529
|
+
const successState = successfulAttempt ?? findSuccessfulAttemptState(route);
|
|
17241
17530
|
return {
|
|
17242
17531
|
text: base.text,
|
|
17243
17532
|
details: {
|
|
@@ -17245,7 +17534,10 @@ async function resolveSearchContext(input, operations) {
|
|
|
17245
17534
|
tokenBudget: baseDetails.tokenBudget,
|
|
17246
17535
|
tokenEstimate: baseDetails.tokenEstimate,
|
|
17247
17536
|
truncated: false,
|
|
17248
|
-
recovery: buildRecoveryDetails(
|
|
17537
|
+
recovery: buildRecoveryDetails(serializeAttempts(attemptStates), successIndex),
|
|
17538
|
+
...input.diagnostic && {
|
|
17539
|
+
diagnostic: buildSearchDiagnostic(successState)
|
|
17540
|
+
}
|
|
17249
17541
|
}
|
|
17250
17542
|
};
|
|
17251
17543
|
};
|
|
@@ -17259,8 +17551,18 @@ async function resolveSearchContext(input, operations) {
|
|
|
17259
17551
|
buildContextPack(scopedDefinitionResults, {
|
|
17260
17552
|
tokenBudget,
|
|
17261
17553
|
maxResults: limit,
|
|
17262
|
-
heading
|
|
17263
|
-
|
|
17554
|
+
heading,
|
|
17555
|
+
preserveInputOrder: true,
|
|
17556
|
+
...input.diagnostic ? {
|
|
17557
|
+
trace: (trace) => {
|
|
17558
|
+
const attemptState = findSuccessfulAttemptState("definition");
|
|
17559
|
+
if (attemptState) {
|
|
17560
|
+
attemptState.contextPackTrace = trace;
|
|
17561
|
+
}
|
|
17562
|
+
}
|
|
17563
|
+
} : void 0
|
|
17564
|
+
}),
|
|
17565
|
+
findSuccessfulAttemptState("definition")
|
|
17264
17566
|
);
|
|
17265
17567
|
}
|
|
17266
17568
|
if (explicitSymbol) {
|
|
@@ -17278,8 +17580,18 @@ async function resolveSearchContext(input, operations) {
|
|
|
17278
17580
|
buildContextPack(unscopedDefinitionResults, {
|
|
17279
17581
|
tokenBudget,
|
|
17280
17582
|
maxResults: limit,
|
|
17281
|
-
heading: heading2
|
|
17282
|
-
|
|
17583
|
+
heading: heading2,
|
|
17584
|
+
preserveInputOrder: true,
|
|
17585
|
+
...input.diagnostic ? {
|
|
17586
|
+
trace: (trace) => {
|
|
17587
|
+
const attemptState = findSuccessfulAttemptState("definition");
|
|
17588
|
+
if (attemptState) {
|
|
17589
|
+
attemptState.contextPackTrace = trace;
|
|
17590
|
+
}
|
|
17591
|
+
}
|
|
17592
|
+
} : void 0
|
|
17593
|
+
}),
|
|
17594
|
+
findSuccessfulAttemptState("definition")
|
|
17283
17595
|
);
|
|
17284
17596
|
}
|
|
17285
17597
|
}
|
|
@@ -17298,7 +17610,10 @@ Explicit symbol lookup only; conceptual search was not attempted.`
|
|
|
17298
17610
|
tokenBudget: heading.tokenBudget,
|
|
17299
17611
|
tokenEstimate: heading.tokenEstimate,
|
|
17300
17612
|
truncated: heading.truncated,
|
|
17301
|
-
recovery: buildRecoveryDetails(
|
|
17613
|
+
recovery: buildRecoveryDetails(serializeAttempts(attemptStates), null),
|
|
17614
|
+
...input.diagnostic && {
|
|
17615
|
+
diagnostic: buildSearchDiagnostic(attemptStates[attemptStates.length - 1])
|
|
17616
|
+
}
|
|
17302
17617
|
}
|
|
17303
17618
|
};
|
|
17304
17619
|
}
|
|
@@ -17338,8 +17653,17 @@ Explicit symbol lookup only; conceptual search was not attempted.`
|
|
|
17338
17653
|
maxResults: limit,
|
|
17339
17654
|
heading,
|
|
17340
17655
|
includeExactSearchHandoff: true,
|
|
17341
|
-
preferImplementationPaths: intent.preferSourcePaths || intent.primary !== "docs" && intent.primary !== "test"
|
|
17342
|
-
|
|
17656
|
+
preferImplementationPaths: intent.preferSourcePaths || intent.primary !== "docs" && intent.primary !== "test",
|
|
17657
|
+
...input.diagnostic ? {
|
|
17658
|
+
trace: (trace) => {
|
|
17659
|
+
const attemptState = findSuccessfulAttemptState("conceptual");
|
|
17660
|
+
if (attemptState) {
|
|
17661
|
+
attemptState.contextPackTrace = trace;
|
|
17662
|
+
}
|
|
17663
|
+
}
|
|
17664
|
+
} : void 0
|
|
17665
|
+
}),
|
|
17666
|
+
findSuccessfulAttemptState("conceptual")
|
|
17343
17667
|
);
|
|
17344
17668
|
}
|
|
17345
17669
|
}
|
|
@@ -17355,7 +17679,10 @@ Explicit symbol lookup only; conceptual search was not attempted.`
|
|
|
17355
17679
|
tokenBudget: fallbackText.tokenBudget,
|
|
17356
17680
|
tokenEstimate: fallbackText.tokenEstimate,
|
|
17357
17681
|
truncated: fallbackText.truncated,
|
|
17358
|
-
recovery: buildRecoveryDetails(
|
|
17682
|
+
recovery: buildRecoveryDetails(serializeAttempts(attemptStates), null),
|
|
17683
|
+
...input.diagnostic && {
|
|
17684
|
+
diagnostic: buildSearchDiagnostic(attemptStates[attemptStates.length - 1])
|
|
17685
|
+
}
|
|
17359
17686
|
}
|
|
17360
17687
|
};
|
|
17361
17688
|
}
|
|
@@ -17436,17 +17763,27 @@ async function resolveCodebaseContextUnmeasured(projectRoot, host, input) {
|
|
|
17436
17763
|
details: fittedDetails("path", fitted, 0)
|
|
17437
17764
|
};
|
|
17438
17765
|
}
|
|
17439
|
-
return resolveSearchContext({
|
|
17440
|
-
|
|
17766
|
+
return resolveSearchContext({
|
|
17767
|
+
query: input.query,
|
|
17768
|
+
symbol,
|
|
17769
|
+
limit,
|
|
17770
|
+
tokenBudget,
|
|
17771
|
+
fileType,
|
|
17772
|
+
directory,
|
|
17773
|
+
diagnostic: input.diagnostic
|
|
17774
|
+
}, {
|
|
17775
|
+
lookup: (lookupSymbol, retrievalLimit, scope, trace) => implementationLookup(projectRoot, host, lookupSymbol, {
|
|
17441
17776
|
limit: retrievalLimit,
|
|
17442
17777
|
fileType: scope.fileType,
|
|
17443
|
-
directory: scope.directory
|
|
17778
|
+
directory: scope.directory,
|
|
17779
|
+
trace
|
|
17444
17780
|
}),
|
|
17445
|
-
search: (queryText, retrievalLimit, scope) => searchCodebase(projectRoot, host, queryText, {
|
|
17781
|
+
search: (queryText, retrievalLimit, scope, trace) => searchCodebase(projectRoot, host, queryText, {
|
|
17446
17782
|
limit: retrievalLimit,
|
|
17447
17783
|
fileType: scope.fileType,
|
|
17448
17784
|
directory: scope.directory,
|
|
17449
|
-
metadataOnly: true
|
|
17785
|
+
metadataOnly: true,
|
|
17786
|
+
trace
|
|
17450
17787
|
})
|
|
17451
17788
|
});
|
|
17452
17789
|
}
|
|
@@ -17513,7 +17850,11 @@ async function resolveCodebaseContext(projectRoot, host, input) {
|
|
|
17513
17850
|
|
|
17514
17851
|
// src/tools/execute-common.ts
|
|
17515
17852
|
async function executeCodebaseContext(projectRoot, host, args) {
|
|
17516
|
-
|
|
17853
|
+
const result = await resolveCodebaseContext(projectRoot, host, args);
|
|
17854
|
+
return { text: result.text, details: result.details };
|
|
17855
|
+
}
|
|
17856
|
+
async function executeCodebaseEditContext(projectRoot, host, args) {
|
|
17857
|
+
return { text: (await resolveCodebaseEditContext(projectRoot, host, args)).text };
|
|
17517
17858
|
}
|
|
17518
17859
|
async function executeIndexCodebase(projectRoot, host, args, onProgress) {
|
|
17519
17860
|
const result = await runIndexCodebase(projectRoot, host, args, onProgress);
|
|
@@ -17616,9 +17957,9 @@ function parseGitActivity(output) {
|
|
|
17616
17957
|
if (!filePath || addedRaw === "-" || deletedRaw === "-") continue;
|
|
17617
17958
|
const churn = Number(addedRaw) + Number(deletedRaw);
|
|
17618
17959
|
if (!Number.isFinite(churn) || churn <= 0) continue;
|
|
17619
|
-
const
|
|
17620
|
-
const previous = activity.get(
|
|
17621
|
-
activity.set(
|
|
17960
|
+
const normalizedPath2 = normalizePath3(filePath);
|
|
17961
|
+
const previous = activity.get(normalizedPath2);
|
|
17962
|
+
activity.set(normalizedPath2, {
|
|
17622
17963
|
churn: (previous?.churn ?? 0) + churn,
|
|
17623
17964
|
commits: (previous?.commits ?? 0) + 1,
|
|
17624
17965
|
latestDate: previous?.latestDate ?? latestDate,
|
|
@@ -18208,8 +18549,8 @@ function transformForVisualization(symbols, edges, options = {}) {
|
|
|
18208
18549
|
const normalizedAbsoluteSuffix = `/${normalizedDirWithSlash}`;
|
|
18209
18550
|
filteredSymbols = symbols.filter(
|
|
18210
18551
|
(s) => {
|
|
18211
|
-
const
|
|
18212
|
-
return
|
|
18552
|
+
const normalizedPath2 = s.filePath.replace(/\\/g, "/");
|
|
18553
|
+
return normalizedPath2 === normalizedDir || normalizedPath2.startsWith(normalizedDirWithSlash) || normalizedPath2.endsWith(`/${normalizedDir}`) || normalizedPath2.includes(normalizedAbsoluteSuffix);
|
|
18213
18554
|
}
|
|
18214
18555
|
);
|
|
18215
18556
|
}
|
|
@@ -18283,6 +18624,26 @@ var z3 = tool.schema;
|
|
|
18283
18624
|
var DEFAULT_HOST = "opencode";
|
|
18284
18625
|
var CHUNK_TYPE_VALUES = CHUNK_TYPES;
|
|
18285
18626
|
var RELATIONSHIP_TYPE_VALUES = RELATIONSHIP_TYPES;
|
|
18627
|
+
function stableSortedDiagnosticValue(value) {
|
|
18628
|
+
if (Array.isArray(value)) {
|
|
18629
|
+
return value.map((item) => stableSortedDiagnosticValue(item));
|
|
18630
|
+
}
|
|
18631
|
+
if (value === null || typeof value !== "object") {
|
|
18632
|
+
return value;
|
|
18633
|
+
}
|
|
18634
|
+
const entries = Object.entries(value).sort(([left], [right]) => left.localeCompare(right));
|
|
18635
|
+
const sorted = {};
|
|
18636
|
+
for (const [key, item] of entries) {
|
|
18637
|
+
sorted[key] = stableSortedDiagnosticValue(item);
|
|
18638
|
+
}
|
|
18639
|
+
return sorted;
|
|
18640
|
+
}
|
|
18641
|
+
function formatCodebaseContextDiagnostic(details) {
|
|
18642
|
+
const sorted = stableSortedDiagnosticValue(details);
|
|
18643
|
+
return `
|
|
18644
|
+
Diagnostics:
|
|
18645
|
+
${JSON.stringify(sorted, null, 2)}`;
|
|
18646
|
+
}
|
|
18286
18647
|
function initializeTools2(projectRoot, config) {
|
|
18287
18648
|
initializeTools(projectRoot, config, DEFAULT_HOST);
|
|
18288
18649
|
}
|
|
@@ -18302,10 +18663,29 @@ var codebase_context = tool({
|
|
|
18302
18663
|
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})`),
|
|
18303
18664
|
fileType: z3.string().nullable().optional().describe("Filter by file extension"),
|
|
18304
18665
|
directory: z3.string().nullable().optional().describe("Filter by directory path"),
|
|
18305
|
-
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})`)
|
|
18666
|
+
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})`),
|
|
18667
|
+
diagnostic: z3.boolean().optional().describe("Collect diagnostic routing and search traces without changing normal text output.")
|
|
18668
|
+
},
|
|
18669
|
+
async execute(args, context) {
|
|
18670
|
+
const result = await executeCodebaseContext(context?.worktree, DEFAULT_HOST, args);
|
|
18671
|
+
if (!args.diagnostic || !result.details?.diagnostic) {
|
|
18672
|
+
return result.text;
|
|
18673
|
+
}
|
|
18674
|
+
return `${result.text}${formatCodebaseContextDiagnostic(result.details.diagnostic)}`;
|
|
18675
|
+
}
|
|
18676
|
+
});
|
|
18677
|
+
var codebase_edit_context = tool({
|
|
18678
|
+
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.",
|
|
18679
|
+
args: {
|
|
18680
|
+
query: z3.string().describe("The requested change or target behavior"),
|
|
18681
|
+
symbol: z3.string().nullable().optional().describe("Authoritative target symbol when known"),
|
|
18682
|
+
filePath: z3.string().nullable().optional().describe("Optional file path used to disambiguate duplicate symbol names"),
|
|
18683
|
+
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),
|
|
18684
|
+
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),
|
|
18685
|
+
tokenBudget: z3.number().int().min(MIN_CONTEXT_PACK_TOKEN_BUDGET).max(MAX_CONTEXT_PACK_TOKEN_BUDGET).nullable().optional().default(DEFAULT_CONTEXT_PACK_TOKEN_BUDGET)
|
|
18306
18686
|
},
|
|
18307
18687
|
async execute(args, context) {
|
|
18308
|
-
return (await
|
|
18688
|
+
return (await executeCodebaseEditContext(context?.worktree, DEFAULT_HOST, args)).text;
|
|
18309
18689
|
}
|
|
18310
18690
|
});
|
|
18311
18691
|
var codebase_peek = tool({
|
|
@@ -18562,6 +18942,7 @@ var index_visualize = tool({
|
|
|
18562
18942
|
// src/tools/tool-names.ts
|
|
18563
18943
|
var TOOL_NAME = {
|
|
18564
18944
|
CODEBASE_CONTEXT: "codebase_context",
|
|
18945
|
+
CODEBASE_EDIT_CONTEXT: "codebase_edit_context",
|
|
18565
18946
|
CODEBASE_SEARCH: "codebase_search",
|
|
18566
18947
|
CODEBASE_PEEK: "codebase_peek",
|
|
18567
18948
|
FIND_SIMILAR: "find_similar",
|
|
@@ -18585,6 +18966,7 @@ var TOOL_NAME = {
|
|
|
18585
18966
|
};
|
|
18586
18967
|
var PORTABLE_TOOL_NAMES = [
|
|
18587
18968
|
TOOL_NAME.CODEBASE_CONTEXT,
|
|
18969
|
+
TOOL_NAME.CODEBASE_EDIT_CONTEXT,
|
|
18588
18970
|
TOOL_NAME.CODEBASE_SEARCH,
|
|
18589
18971
|
TOOL_NAME.CODEBASE_PEEK,
|
|
18590
18972
|
TOOL_NAME.INDEX_CODEBASE,
|
|
@@ -18601,6 +18983,7 @@ var PORTABLE_TOOL_NAMES = [
|
|
|
18601
18983
|
];
|
|
18602
18984
|
var OPENCODE_TOOL_NAMES = [
|
|
18603
18985
|
TOOL_NAME.CODEBASE_CONTEXT,
|
|
18986
|
+
TOOL_NAME.CODEBASE_EDIT_CONTEXT,
|
|
18604
18987
|
TOOL_NAME.CODEBASE_SEARCH,
|
|
18605
18988
|
TOOL_NAME.CODEBASE_PEEK,
|
|
18606
18989
|
TOOL_NAME.INDEX_CODEBASE,
|
|
@@ -18621,6 +19004,7 @@ var OPENCODE_TOOL_NAMES = [
|
|
|
18621
19004
|
];
|
|
18622
19005
|
var PI_TOOL_NAMES = [
|
|
18623
19006
|
TOOL_NAME.CODEBASE_CONTEXT,
|
|
19007
|
+
TOOL_NAME.CODEBASE_EDIT_CONTEXT,
|
|
18624
19008
|
TOOL_NAME.CODEBASE_SEARCH,
|
|
18625
19009
|
TOOL_NAME.CODEBASE_PEEK,
|
|
18626
19010
|
TOOL_NAME.FIND_SIMILAR,
|
|
@@ -19075,6 +19459,7 @@ var plugin = async ({ directory, worktree }) => {
|
|
|
19075
19459
|
return {
|
|
19076
19460
|
tool: {
|
|
19077
19461
|
[TOOL_NAME.CODEBASE_CONTEXT]: codebase_context,
|
|
19462
|
+
[TOOL_NAME.CODEBASE_EDIT_CONTEXT]: codebase_edit_context,
|
|
19078
19463
|
[TOOL_NAME.CODEBASE_SEARCH]: codebase_search,
|
|
19079
19464
|
[TOOL_NAME.CODEBASE_PEEK]: codebase_peek,
|
|
19080
19465
|
[TOOL_NAME.INDEX_CODEBASE]: index_codebase,
|