opencode-codebase-index 0.22.3 → 0.22.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/dist/cli.cjs +647 -94
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +647 -94
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +421 -55
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +421 -55
- package/dist/index.js.map +1 -1
- package/dist/pi-extension.cjs +401 -48
- package/dist/pi-extension.cjs.map +1 -1
- package/dist/pi-extension.js +401 -48
- package/dist/pi-extension.js.map +1 -1
- package/native/codebase-index-native.darwin-arm64.node +0 -0
- package/native/codebase-index-native.darwin-x64.node +0 -0
- package/native/codebase-index-native.linux-arm64-gnu.node +0 -0
- package/native/codebase-index-native.linux-x64-gnu.node +0 -0
- package/native/codebase-index-native.win32-x64-msvc.node +0 -0
- package/package.json +13 -9
package/dist/cli.js
CHANGED
|
@@ -1277,6 +1277,7 @@ function createSummaryMarkdown(summary, comparison, gate, sweep) {
|
|
|
1277
1277
|
lines.push(`| Hit@10 | ${formatPct(summary.metrics.hitAt10)} |`);
|
|
1278
1278
|
lines.push(`| MRR@10 | ${summary.metrics.mrrAt10.toFixed(4)} |`);
|
|
1279
1279
|
lines.push(`| nDCG@10 | ${summary.metrics.ndcgAt10.toFixed(4)} |`);
|
|
1280
|
+
lines.push(`| Graph-neighbor recall | ${(summary.metrics.graphNeighborRecall ?? 0).toFixed(4)} |`);
|
|
1280
1281
|
lines.push(`| Distinct Top@3 | ${formatPct(summary.metrics.distinctTop3Ratio)} |`);
|
|
1281
1282
|
lines.push(`| Raw Distinct Top@3 | ${formatPct(summary.metrics.rawDistinctTop3Ratio)} |`);
|
|
1282
1283
|
lines.push(`| Latency p50 | ${formatMs(summary.metrics.latencyMs.p50)} |`);
|
|
@@ -6640,12 +6641,12 @@ function diversifyGroupBySymbol(entries, getCandidate) {
|
|
|
6640
6641
|
return [...primary, ...remainder];
|
|
6641
6642
|
}
|
|
6642
6643
|
function buildDiversityKey(metadata) {
|
|
6643
|
-
const
|
|
6644
|
+
const normalizedPath3 = metadata.filePath.toLowerCase();
|
|
6644
6645
|
const normalizedName = (metadata.name ?? "").trim().toLowerCase();
|
|
6645
6646
|
if (normalizedName.length > 0) {
|
|
6646
|
-
return `${
|
|
6647
|
+
return `${normalizedPath3}#${normalizedName}`;
|
|
6647
6648
|
}
|
|
6648
|
-
return
|
|
6649
|
+
return normalizedPath3;
|
|
6649
6650
|
}
|
|
6650
6651
|
function rankHybridResults(query, semanticResults, keywordResults, options) {
|
|
6651
6652
|
const prioritizeSourcePaths = options.prioritizeSourcePaths ?? classifyQueryIntentRaw(query) === "source";
|
|
@@ -7094,9 +7095,9 @@ function normalizeFilePathForHintMatch(filePath) {
|
|
|
7094
7095
|
return filePath.replace(/\\/g, "/").toLowerCase().replace(/^\.\//, "");
|
|
7095
7096
|
}
|
|
7096
7097
|
function pathMatchesHint(filePath, hint) {
|
|
7097
|
-
const
|
|
7098
|
+
const normalizedPath3 = normalizeFilePathForHintMatch(filePath);
|
|
7098
7099
|
const normalizedHint = normalizeFilePathForHintMatch(hint);
|
|
7099
|
-
return
|
|
7100
|
+
return normalizedPath3.endsWith(normalizedHint) || normalizedPath3.includes(`/${normalizedHint}`) || normalizedPath3.includes(normalizedHint);
|
|
7100
7101
|
}
|
|
7101
7102
|
function extractFilePathHint(query) {
|
|
7102
7103
|
const match = query.match(FILE_PATH_HINT_SUFFIX_REGEX);
|
|
@@ -11370,6 +11371,20 @@ var Indexer = class _Indexer {
|
|
|
11370
11371
|
requestedLimit = nextLimit;
|
|
11371
11372
|
}
|
|
11372
11373
|
}
|
|
11374
|
+
buildCandidateSnapshot(candidate) {
|
|
11375
|
+
return {
|
|
11376
|
+
id: candidate.id,
|
|
11377
|
+
filePath: candidate.metadata.filePath,
|
|
11378
|
+
startLine: candidate.metadata.startLine,
|
|
11379
|
+
endLine: candidate.metadata.endLine,
|
|
11380
|
+
score: candidate.score,
|
|
11381
|
+
chunkType: candidate.metadata.chunkType,
|
|
11382
|
+
name: candidate.metadata.name
|
|
11383
|
+
};
|
|
11384
|
+
}
|
|
11385
|
+
buildCandidateSnapshotList(candidates) {
|
|
11386
|
+
return candidates.map((candidate) => this.buildCandidateSnapshot(candidate));
|
|
11387
|
+
}
|
|
11373
11388
|
searchSemanticCandidates(store, embedding, initialLimit, branchChunkIds, shouldPrefilterByBranch) {
|
|
11374
11389
|
return this.searchCandidatesWithBranchPrefilter(
|
|
11375
11390
|
initialLimit,
|
|
@@ -11561,6 +11576,16 @@ var Indexer = class _Indexer {
|
|
|
11561
11576
|
prefilterMs: Math.round(prefilterMs * 100) / 100,
|
|
11562
11577
|
fusionMs: Math.round(fusionMs * 100) / 100
|
|
11563
11578
|
});
|
|
11579
|
+
if (options?.trace) {
|
|
11580
|
+
options.trace({
|
|
11581
|
+
semanticCandidates: this.buildCandidateSnapshotList(scopedSemanticCandidates),
|
|
11582
|
+
keywordCandidates: this.buildCandidateSnapshotList(scopedKeywordCandidates),
|
|
11583
|
+
hybridCandidates: this.buildCandidateSnapshotList(combined),
|
|
11584
|
+
postExternalRerankCandidates: this.buildCandidateSnapshotList(rerankedCombined),
|
|
11585
|
+
tieredCandidates: this.buildCandidateSnapshotList(tiered),
|
|
11586
|
+
finalCandidates: this.buildCandidateSnapshotList(finalResults)
|
|
11587
|
+
});
|
|
11588
|
+
}
|
|
11564
11589
|
const metadataOnly = options?.metadataOnly ?? false;
|
|
11565
11590
|
return Promise.all(
|
|
11566
11591
|
finalResults.map(async (r) => {
|
|
@@ -12609,6 +12634,42 @@ var Indexer = class _Indexer {
|
|
|
12609
12634
|
}
|
|
12610
12635
|
};
|
|
12611
12636
|
|
|
12637
|
+
// src/tools/contracts.ts
|
|
12638
|
+
var CHUNK_TYPES = [
|
|
12639
|
+
"function",
|
|
12640
|
+
"class",
|
|
12641
|
+
"method",
|
|
12642
|
+
"interface",
|
|
12643
|
+
"type",
|
|
12644
|
+
"enum",
|
|
12645
|
+
"struct",
|
|
12646
|
+
"impl",
|
|
12647
|
+
"trait",
|
|
12648
|
+
"module",
|
|
12649
|
+
"other"
|
|
12650
|
+
];
|
|
12651
|
+
var CALL_GRAPH_DIRECTIONS = ["callers", "callees"];
|
|
12652
|
+
var RELATIONSHIP_TYPES = [
|
|
12653
|
+
"Call",
|
|
12654
|
+
"MethodCall",
|
|
12655
|
+
"Constructor",
|
|
12656
|
+
"Import",
|
|
12657
|
+
"Inherits",
|
|
12658
|
+
"Implements"
|
|
12659
|
+
];
|
|
12660
|
+
var INDEX_LOG_CATEGORIES = ["search", "embedding", "cache", "gc", "branch", "general"];
|
|
12661
|
+
var INDEX_LOG_LEVELS = ["error", "warn", "info", "debug"];
|
|
12662
|
+
var MIN_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT = 1;
|
|
12663
|
+
var MAX_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT = 20;
|
|
12664
|
+
var DEFAULT_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT = 5;
|
|
12665
|
+
var CODE_COMMUNITIES_MIN_SIZE = 1;
|
|
12666
|
+
var CODE_COMMUNITIES_DEFAULT_LIMIT = 20;
|
|
12667
|
+
var CODE_COMMUNITIES_MAX_LIMIT = 100;
|
|
12668
|
+
var CODE_COMMUNITIES_DEFAULT_HUB_THRESHOLD = 5;
|
|
12669
|
+
var CODE_COMMUNITIES_MIN_COUPLING = 1;
|
|
12670
|
+
var CODE_COMMUNITIES_DEFAULT_COUPLING_LIMIT = 20;
|
|
12671
|
+
var CODE_COMMUNITIES_MAX_COUPLING_LIMIT = 100;
|
|
12672
|
+
|
|
12612
12673
|
// src/tools/operations.ts
|
|
12613
12674
|
import { existsSync as existsSync12, realpathSync as realpathSync5, statSync as statSync5 } from "fs";
|
|
12614
12675
|
import * as path21 from "path";
|
|
@@ -12737,39 +12798,6 @@ function formatCodeCommunities(result) {
|
|
|
12737
12798
|
return lines.join("\n");
|
|
12738
12799
|
}
|
|
12739
12800
|
|
|
12740
|
-
// src/tools/contracts.ts
|
|
12741
|
-
var CHUNK_TYPES = [
|
|
12742
|
-
"function",
|
|
12743
|
-
"class",
|
|
12744
|
-
"method",
|
|
12745
|
-
"interface",
|
|
12746
|
-
"type",
|
|
12747
|
-
"enum",
|
|
12748
|
-
"struct",
|
|
12749
|
-
"impl",
|
|
12750
|
-
"trait",
|
|
12751
|
-
"module",
|
|
12752
|
-
"other"
|
|
12753
|
-
];
|
|
12754
|
-
var CALL_GRAPH_DIRECTIONS = ["callers", "callees"];
|
|
12755
|
-
var RELATIONSHIP_TYPES = [
|
|
12756
|
-
"Call",
|
|
12757
|
-
"MethodCall",
|
|
12758
|
-
"Constructor",
|
|
12759
|
-
"Import",
|
|
12760
|
-
"Inherits",
|
|
12761
|
-
"Implements"
|
|
12762
|
-
];
|
|
12763
|
-
var INDEX_LOG_CATEGORIES = ["search", "embedding", "cache", "gc", "branch", "general"];
|
|
12764
|
-
var INDEX_LOG_LEVELS = ["error", "warn", "info", "debug"];
|
|
12765
|
-
var CODE_COMMUNITIES_MIN_SIZE = 1;
|
|
12766
|
-
var CODE_COMMUNITIES_DEFAULT_LIMIT = 20;
|
|
12767
|
-
var CODE_COMMUNITIES_MAX_LIMIT = 100;
|
|
12768
|
-
var CODE_COMMUNITIES_DEFAULT_HUB_THRESHOLD = 5;
|
|
12769
|
-
var CODE_COMMUNITIES_MIN_COUPLING = 1;
|
|
12770
|
-
var CODE_COMMUNITIES_DEFAULT_COUPLING_LIMIT = 20;
|
|
12771
|
-
var CODE_COMMUNITIES_MAX_COUPLING_LIMIT = 100;
|
|
12772
|
-
|
|
12773
12801
|
// src/tools/context-pack.ts
|
|
12774
12802
|
import { get_encoding } from "tiktoken";
|
|
12775
12803
|
var MIN_CONTEXT_PACK_TOKEN_BUDGET = 128;
|
|
@@ -12871,6 +12899,16 @@ function compactEvidenceValue(value, maxChars) {
|
|
|
12871
12899
|
}
|
|
12872
12900
|
var MAX_EXACT_SEARCH_HANDOFF_NAMES = 3;
|
|
12873
12901
|
var MAX_EXACT_SEARCH_HANDOFF_NAME_CHARS = 64;
|
|
12902
|
+
function toContextPackTraceCandidate(result) {
|
|
12903
|
+
return {
|
|
12904
|
+
filePath: result.filePath,
|
|
12905
|
+
startLine: result.startLine,
|
|
12906
|
+
endLine: result.endLine,
|
|
12907
|
+
score: result.score,
|
|
12908
|
+
chunkType: result.chunkType,
|
|
12909
|
+
name: result.name
|
|
12910
|
+
};
|
|
12911
|
+
}
|
|
12874
12912
|
function formatExactSearchHandoff(results) {
|
|
12875
12913
|
const suggestedNames = [];
|
|
12876
12914
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -12919,13 +12957,13 @@ function buildContextPack(results, options = {}) {
|
|
|
12919
12957
|
const maxResults = Math.max(0, Math.floor(options.maxResults ?? results.length));
|
|
12920
12958
|
const includeExactSearchHandoff = options.includeExactSearchHandoff ?? false;
|
|
12921
12959
|
const candidateCount = results.length;
|
|
12922
|
-
const
|
|
12923
|
-
|
|
12924
|
-
|
|
12925
|
-
|
|
12926
|
-
|
|
12927
|
-
);
|
|
12928
|
-
const
|
|
12960
|
+
const preserveInputOrder = options.preserveInputOrder ?? false;
|
|
12961
|
+
const ranked = preserveInputOrder ? results.map((result, originalIndex) => ({ result, originalIndex })) : rankContextCandidates(results, options.preferImplementationPaths ?? false);
|
|
12962
|
+
const rankedCandidates = ranked.map((entry) => toContextPackTraceCandidate(entry.result));
|
|
12963
|
+
const deduplicated = deduplicateContextCandidates(ranked);
|
|
12964
|
+
const deduplicatedCandidates = deduplicated.map((result) => toContextPackTraceCandidate(result));
|
|
12965
|
+
const diversified = preserveInputOrder ? deduplicated : diversifyContextCandidates(deduplicated);
|
|
12966
|
+
const diversifiedCandidates = diversified.map((result) => toContextPackTraceCandidate(result));
|
|
12929
12967
|
const duplicateCount = candidateCount - deduplicated.length;
|
|
12930
12968
|
const selectable = diversified.slice(0, maxResults);
|
|
12931
12969
|
const limitOmittedCount = deduplicated.length - selectable.length;
|
|
@@ -12958,6 +12996,15 @@ function buildContextPack(results, options = {}) {
|
|
|
12958
12996
|
const fitted = fitTextToContextBudget(text, tokenBudget);
|
|
12959
12997
|
const budgetOmittedCount = selectable.length - selected.length;
|
|
12960
12998
|
const omittedCount = candidateCount - selected.length;
|
|
12999
|
+
if (options.trace) {
|
|
13000
|
+
options.trace({
|
|
13001
|
+
inputCandidates: results.map(toContextPackTraceCandidate),
|
|
13002
|
+
rankedCandidates,
|
|
13003
|
+
deduplicatedCandidates,
|
|
13004
|
+
diversifiedCandidates,
|
|
13005
|
+
selectedCandidates: selected.map(toContextPackTraceCandidate)
|
|
13006
|
+
});
|
|
13007
|
+
}
|
|
12961
13008
|
return {
|
|
12962
13009
|
requestedTokenBudget,
|
|
12963
13010
|
tokenBudget,
|
|
@@ -14705,7 +14752,8 @@ async function searchCodebase(projectRoot, host, query, options = {}) {
|
|
|
14705
14752
|
definitionIntent: options.definitionIntent,
|
|
14706
14753
|
blameAuthor: options.blameAuthor,
|
|
14707
14754
|
blameSha: options.blameSha,
|
|
14708
|
-
blameSince: options.blameSince
|
|
14755
|
+
blameSince: options.blameSince,
|
|
14756
|
+
trace: options.trace
|
|
14709
14757
|
});
|
|
14710
14758
|
}
|
|
14711
14759
|
async function searchCodebaseWithEffectiveness(projectRoot, host, route, query, options, render) {
|
|
@@ -14759,15 +14807,19 @@ async function implementationLookup(projectRoot, host, query, options = {}) {
|
|
|
14759
14807
|
return indexer.search(query, options.limit, {
|
|
14760
14808
|
fileType: options.fileType,
|
|
14761
14809
|
directory: options.directory,
|
|
14762
|
-
definitionIntent: true
|
|
14810
|
+
definitionIntent: true,
|
|
14811
|
+
trace: options.trace
|
|
14763
14812
|
});
|
|
14764
14813
|
}
|
|
14765
14814
|
async function getCallGraphData(projectRoot, host, params) {
|
|
14766
14815
|
await ensureAutoIndexReadyForRetrieval(projectRoot, host);
|
|
14767
14816
|
const root = getProjectRoot(projectRoot, host);
|
|
14768
14817
|
const indexer = getIndexerForProject(root, host);
|
|
14818
|
+
return getCallGraphDataForIndexer(indexer, root, params);
|
|
14819
|
+
}
|
|
14820
|
+
async function getCallGraphDataForIndexer(indexer, projectRoot, params) {
|
|
14769
14821
|
const symbols = await indexer.getCallGraphSymbols();
|
|
14770
|
-
const resolution = resolveCallGraphSymbol(symbols,
|
|
14822
|
+
const resolution = resolveCallGraphSymbol(symbols, projectRoot, params.name, params.filePath, params.symbolId);
|
|
14771
14823
|
const direction = params.direction === "callees" ? "callees" : "callers";
|
|
14772
14824
|
if (resolution.status !== "resolved") {
|
|
14773
14825
|
return { direction, resolution, callers: [], callees: [], relationshipType: params.relationshipType };
|
|
@@ -15095,6 +15147,27 @@ function buildRecoveryDetails(attempts, successIndex) {
|
|
|
15095
15147
|
successfulAttemptIndex: successIndex
|
|
15096
15148
|
};
|
|
15097
15149
|
}
|
|
15150
|
+
function serializeAttempts(attempts) {
|
|
15151
|
+
return attempts.map((attempt) => ({
|
|
15152
|
+
kind: attempt.kind,
|
|
15153
|
+
scope: attempt.scope,
|
|
15154
|
+
resultCount: attempt.resultCount,
|
|
15155
|
+
relaxedFields: attempt.relaxedFields
|
|
15156
|
+
}));
|
|
15157
|
+
}
|
|
15158
|
+
function buildSearchDiagnostic(attempt) {
|
|
15159
|
+
if (!attempt) {
|
|
15160
|
+
return void 0;
|
|
15161
|
+
}
|
|
15162
|
+
return {
|
|
15163
|
+
route: attempt.kind,
|
|
15164
|
+
routedQuery: attempt.query,
|
|
15165
|
+
searchQuery: attempt.query,
|
|
15166
|
+
searchScope: attempt.scopeFilter,
|
|
15167
|
+
searchTrace: attempt.searchTrace,
|
|
15168
|
+
contextPackTrace: attempt.contextPackTrace
|
|
15169
|
+
};
|
|
15170
|
+
}
|
|
15098
15171
|
function trimOrUndefined2(value) {
|
|
15099
15172
|
const normalized = value?.trim();
|
|
15100
15173
|
if (!normalized) {
|
|
@@ -15134,6 +15207,7 @@ async function resolveSearchContext(input, operations) {
|
|
|
15134
15207
|
const hasFilters = Boolean(fileType || directory);
|
|
15135
15208
|
const relaxedFields = relaxedHintFields(fileType, directory);
|
|
15136
15209
|
const attempts = [];
|
|
15210
|
+
const attemptStates = [];
|
|
15137
15211
|
const decisions = {
|
|
15138
15212
|
inferredDefinitionMiss: false,
|
|
15139
15213
|
fallbackFromOriginalConceptualToInferred: false,
|
|
@@ -15162,8 +15236,20 @@ async function resolveSearchContext(input, operations) {
|
|
|
15162
15236
|
if (seenAttempts.has(key)) {
|
|
15163
15237
|
return [];
|
|
15164
15238
|
}
|
|
15165
|
-
const
|
|
15239
|
+
const attemptState = {
|
|
15240
|
+
kind,
|
|
15241
|
+
scope: describeScope(scope.fileType, scope.directory),
|
|
15242
|
+
resultCount: 0,
|
|
15243
|
+
relaxedFields: [...relaxedFieldsForAttempt],
|
|
15244
|
+
query: attemptQuery,
|
|
15245
|
+
scopeFilter: scope
|
|
15246
|
+
};
|
|
15247
|
+
const results = await runAttempt((trace) => {
|
|
15248
|
+
attemptState.searchTrace = trace;
|
|
15249
|
+
});
|
|
15250
|
+
attemptState.resultCount = results.length;
|
|
15166
15251
|
seenAttempts.add(key);
|
|
15252
|
+
attemptStates.push(attemptState);
|
|
15167
15253
|
attempts.push({
|
|
15168
15254
|
kind,
|
|
15169
15255
|
scope: describeScope(scope.fileType, scope.directory),
|
|
@@ -15183,7 +15269,7 @@ async function resolveSearchContext(input, operations) {
|
|
|
15183
15269
|
symbol,
|
|
15184
15270
|
scope,
|
|
15185
15271
|
relaxedFieldsForAttempt,
|
|
15186
|
-
() => operations.lookup(symbol, MAX_CONTEXT_RESULT_LIMIT, scope)
|
|
15272
|
+
(trace) => operations.lookup(symbol, MAX_CONTEXT_RESULT_LIMIT, scope, input.diagnostic ? trace : void 0)
|
|
15187
15273
|
);
|
|
15188
15274
|
};
|
|
15189
15275
|
const tryConceptualSearch = async (searchQuery, scope, relaxedFieldsForAttempt) => {
|
|
@@ -15192,13 +15278,23 @@ async function resolveSearchContext(input, operations) {
|
|
|
15192
15278
|
searchQuery,
|
|
15193
15279
|
scope,
|
|
15194
15280
|
relaxedFieldsForAttempt,
|
|
15195
|
-
() => operations.search(searchQuery, MAX_CONTEXT_RESULT_LIMIT, scope)
|
|
15281
|
+
(trace) => operations.search(searchQuery, MAX_CONTEXT_RESULT_LIMIT, scope, input.diagnostic ? trace : void 0)
|
|
15196
15282
|
);
|
|
15197
15283
|
};
|
|
15198
|
-
const
|
|
15284
|
+
const findSuccessfulAttemptState = (route) => {
|
|
15285
|
+
for (let index = attemptStates.length - 1; index >= 0; index -= 1) {
|
|
15286
|
+
const attempt = attemptStates[index];
|
|
15287
|
+
if (attempt.kind === route && attempt.resultCount > 0) {
|
|
15288
|
+
return attempt;
|
|
15289
|
+
}
|
|
15290
|
+
}
|
|
15291
|
+
return void 0;
|
|
15292
|
+
};
|
|
15293
|
+
const toResult = (route, routedQuery, pack, successfulAttempt) => {
|
|
15199
15294
|
const base = packedResult(route, routedQuery, pack);
|
|
15200
15295
|
const baseDetails = base.details;
|
|
15201
15296
|
const successIndex = findSuccessfulAttemptIndex(route, attempts);
|
|
15297
|
+
const successState = successfulAttempt ?? findSuccessfulAttemptState(route);
|
|
15202
15298
|
return {
|
|
15203
15299
|
text: base.text,
|
|
15204
15300
|
details: {
|
|
@@ -15206,7 +15302,10 @@ async function resolveSearchContext(input, operations) {
|
|
|
15206
15302
|
tokenBudget: baseDetails.tokenBudget,
|
|
15207
15303
|
tokenEstimate: baseDetails.tokenEstimate,
|
|
15208
15304
|
truncated: false,
|
|
15209
|
-
recovery: buildRecoveryDetails(
|
|
15305
|
+
recovery: buildRecoveryDetails(serializeAttempts(attemptStates), successIndex),
|
|
15306
|
+
...input.diagnostic && {
|
|
15307
|
+
diagnostic: buildSearchDiagnostic(successState)
|
|
15308
|
+
}
|
|
15210
15309
|
}
|
|
15211
15310
|
};
|
|
15212
15311
|
};
|
|
@@ -15220,8 +15319,18 @@ async function resolveSearchContext(input, operations) {
|
|
|
15220
15319
|
buildContextPack(scopedDefinitionResults, {
|
|
15221
15320
|
tokenBudget,
|
|
15222
15321
|
maxResults: limit,
|
|
15223
|
-
heading
|
|
15224
|
-
|
|
15322
|
+
heading,
|
|
15323
|
+
preserveInputOrder: true,
|
|
15324
|
+
...input.diagnostic ? {
|
|
15325
|
+
trace: (trace) => {
|
|
15326
|
+
const attemptState = findSuccessfulAttemptState("definition");
|
|
15327
|
+
if (attemptState) {
|
|
15328
|
+
attemptState.contextPackTrace = trace;
|
|
15329
|
+
}
|
|
15330
|
+
}
|
|
15331
|
+
} : void 0
|
|
15332
|
+
}),
|
|
15333
|
+
findSuccessfulAttemptState("definition")
|
|
15225
15334
|
);
|
|
15226
15335
|
}
|
|
15227
15336
|
if (explicitSymbol) {
|
|
@@ -15239,8 +15348,18 @@ async function resolveSearchContext(input, operations) {
|
|
|
15239
15348
|
buildContextPack(unscopedDefinitionResults, {
|
|
15240
15349
|
tokenBudget,
|
|
15241
15350
|
maxResults: limit,
|
|
15242
|
-
heading: heading2
|
|
15243
|
-
|
|
15351
|
+
heading: heading2,
|
|
15352
|
+
preserveInputOrder: true,
|
|
15353
|
+
...input.diagnostic ? {
|
|
15354
|
+
trace: (trace) => {
|
|
15355
|
+
const attemptState = findSuccessfulAttemptState("definition");
|
|
15356
|
+
if (attemptState) {
|
|
15357
|
+
attemptState.contextPackTrace = trace;
|
|
15358
|
+
}
|
|
15359
|
+
}
|
|
15360
|
+
} : void 0
|
|
15361
|
+
}),
|
|
15362
|
+
findSuccessfulAttemptState("definition")
|
|
15244
15363
|
);
|
|
15245
15364
|
}
|
|
15246
15365
|
}
|
|
@@ -15259,7 +15378,10 @@ Explicit symbol lookup only; conceptual search was not attempted.`
|
|
|
15259
15378
|
tokenBudget: heading.tokenBudget,
|
|
15260
15379
|
tokenEstimate: heading.tokenEstimate,
|
|
15261
15380
|
truncated: heading.truncated,
|
|
15262
|
-
recovery: buildRecoveryDetails(
|
|
15381
|
+
recovery: buildRecoveryDetails(serializeAttempts(attemptStates), null),
|
|
15382
|
+
...input.diagnostic && {
|
|
15383
|
+
diagnostic: buildSearchDiagnostic(attemptStates[attemptStates.length - 1])
|
|
15384
|
+
}
|
|
15263
15385
|
}
|
|
15264
15386
|
};
|
|
15265
15387
|
}
|
|
@@ -15299,8 +15421,17 @@ Explicit symbol lookup only; conceptual search was not attempted.`
|
|
|
15299
15421
|
maxResults: limit,
|
|
15300
15422
|
heading,
|
|
15301
15423
|
includeExactSearchHandoff: true,
|
|
15302
|
-
preferImplementationPaths: intent.preferSourcePaths || intent.primary !== "docs" && intent.primary !== "test"
|
|
15303
|
-
|
|
15424
|
+
preferImplementationPaths: intent.preferSourcePaths || intent.primary !== "docs" && intent.primary !== "test",
|
|
15425
|
+
...input.diagnostic ? {
|
|
15426
|
+
trace: (trace) => {
|
|
15427
|
+
const attemptState = findSuccessfulAttemptState("conceptual");
|
|
15428
|
+
if (attemptState) {
|
|
15429
|
+
attemptState.contextPackTrace = trace;
|
|
15430
|
+
}
|
|
15431
|
+
}
|
|
15432
|
+
} : void 0
|
|
15433
|
+
}),
|
|
15434
|
+
findSuccessfulAttemptState("conceptual")
|
|
15304
15435
|
);
|
|
15305
15436
|
}
|
|
15306
15437
|
}
|
|
@@ -15316,7 +15447,10 @@ Explicit symbol lookup only; conceptual search was not attempted.`
|
|
|
15316
15447
|
tokenBudget: fallbackText.tokenBudget,
|
|
15317
15448
|
tokenEstimate: fallbackText.tokenEstimate,
|
|
15318
15449
|
truncated: fallbackText.truncated,
|
|
15319
|
-
recovery: buildRecoveryDetails(
|
|
15450
|
+
recovery: buildRecoveryDetails(serializeAttempts(attemptStates), null),
|
|
15451
|
+
...input.diagnostic && {
|
|
15452
|
+
diagnostic: buildSearchDiagnostic(attemptStates[attemptStates.length - 1])
|
|
15453
|
+
}
|
|
15320
15454
|
}
|
|
15321
15455
|
};
|
|
15322
15456
|
}
|
|
@@ -15397,17 +15531,27 @@ async function resolveCodebaseContextUnmeasured(projectRoot, host, input) {
|
|
|
15397
15531
|
details: fittedDetails("path", fitted, 0)
|
|
15398
15532
|
};
|
|
15399
15533
|
}
|
|
15400
|
-
return resolveSearchContext({
|
|
15401
|
-
|
|
15534
|
+
return resolveSearchContext({
|
|
15535
|
+
query: input.query,
|
|
15536
|
+
symbol,
|
|
15537
|
+
limit,
|
|
15538
|
+
tokenBudget,
|
|
15539
|
+
fileType,
|
|
15540
|
+
directory,
|
|
15541
|
+
diagnostic: input.diagnostic
|
|
15542
|
+
}, {
|
|
15543
|
+
lookup: (lookupSymbol, retrievalLimit, scope, trace) => implementationLookup(projectRoot, host, lookupSymbol, {
|
|
15402
15544
|
limit: retrievalLimit,
|
|
15403
15545
|
fileType: scope.fileType,
|
|
15404
|
-
directory: scope.directory
|
|
15546
|
+
directory: scope.directory,
|
|
15547
|
+
trace
|
|
15405
15548
|
}),
|
|
15406
|
-
search: (queryText, retrievalLimit, scope) => searchCodebase(projectRoot, host, queryText, {
|
|
15549
|
+
search: (queryText, retrievalLimit, scope, trace) => searchCodebase(projectRoot, host, queryText, {
|
|
15407
15550
|
limit: retrievalLimit,
|
|
15408
15551
|
fileType: scope.fileType,
|
|
15409
15552
|
directory: scope.directory,
|
|
15410
|
-
metadataOnly: true
|
|
15553
|
+
metadataOnly: true,
|
|
15554
|
+
trace
|
|
15411
15555
|
})
|
|
15412
15556
|
});
|
|
15413
15557
|
}
|
|
@@ -15472,6 +15616,181 @@ async function resolveCodebaseContext(projectRoot, host, input) {
|
|
|
15472
15616
|
}
|
|
15473
15617
|
}
|
|
15474
15618
|
|
|
15619
|
+
// src/tools/edit-context.ts
|
|
15620
|
+
function edgeLimit(value) {
|
|
15621
|
+
if (value === null || value === void 0 || !Number.isFinite(value)) {
|
|
15622
|
+
return DEFAULT_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT;
|
|
15623
|
+
}
|
|
15624
|
+
return Math.min(
|
|
15625
|
+
MAX_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT,
|
|
15626
|
+
Math.max(MIN_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT, Math.floor(value))
|
|
15627
|
+
);
|
|
15628
|
+
}
|
|
15629
|
+
function normalizedPath(value) {
|
|
15630
|
+
return value.replaceAll("\\", "/").replace(/^\.\//, "");
|
|
15631
|
+
}
|
|
15632
|
+
function pathsMatch(left, right) {
|
|
15633
|
+
const normalizedLeft = normalizedPath(left);
|
|
15634
|
+
const normalizedRight = normalizedPath(right);
|
|
15635
|
+
return normalizedLeft === normalizedRight || normalizedLeft.endsWith(`/${normalizedRight}`) || normalizedRight.endsWith(`/${normalizedLeft}`);
|
|
15636
|
+
}
|
|
15637
|
+
function targetSource(results, resolution) {
|
|
15638
|
+
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);
|
|
15639
|
+
}
|
|
15640
|
+
function formatSource(result) {
|
|
15641
|
+
const name = result.name ? ` ${result.name}` : "";
|
|
15642
|
+
return [
|
|
15643
|
+
"## Target implementation",
|
|
15644
|
+
`${result.filePath}:${result.startLine}-${result.endLine} (${result.chunkType}${name})`,
|
|
15645
|
+
"```",
|
|
15646
|
+
result.content,
|
|
15647
|
+
"```"
|
|
15648
|
+
].join("\n");
|
|
15649
|
+
}
|
|
15650
|
+
function formatCallers(edges) {
|
|
15651
|
+
if (edges.length === 0) return "## Direct callers\nNone found.";
|
|
15652
|
+
return [
|
|
15653
|
+
"## Direct callers",
|
|
15654
|
+
...edges.map((edge) => `- ${edge.fromSymbolName ?? "<unknown>"} at ${edge.fromSymbolFilePath ?? "<unknown file>"}:${edge.line} (${edge.callType}, ${edge.isResolved ? "resolved" : "unresolved"})`)
|
|
15655
|
+
].join("\n");
|
|
15656
|
+
}
|
|
15657
|
+
function formatCallees(edges, sourceFilePath) {
|
|
15658
|
+
if (edges.length === 0) return "## Direct callees\nNone found.";
|
|
15659
|
+
return [
|
|
15660
|
+
"## Direct callees",
|
|
15661
|
+
...edges.map((edge) => `- ${edge.targetName} from ${sourceFilePath}:${edge.line} (${edge.callType}, ${edge.isResolved ? "resolved" : "unresolved"})`)
|
|
15662
|
+
].join("\n");
|
|
15663
|
+
}
|
|
15664
|
+
function formatResolutionRisk(resolution) {
|
|
15665
|
+
if (resolution.status === "ambiguous") {
|
|
15666
|
+
const candidates = resolution.candidates.map((candidate) => `${candidate.filePath}:${candidate.startLine}`).join(", ");
|
|
15667
|
+
return `Risk: symbol "${resolution.name}" is ambiguous. Pass filePath to select a target.${candidates ? ` Candidates: ${candidates}.` : ""}`;
|
|
15668
|
+
}
|
|
15669
|
+
if (resolution.filePath && resolution.totalCandidates > 0) {
|
|
15670
|
+
return `Risk: symbol "${resolution.name}" did not resolve at filePath="${resolution.filePath}". Review the conceptual evidence before editing.`;
|
|
15671
|
+
}
|
|
15672
|
+
return `Risk: symbol "${resolution.name}" could not be resolved. Review the conceptual evidence before editing.`;
|
|
15673
|
+
}
|
|
15674
|
+
async function fallbackPack(dependencies, query, risk, resolution, tokenBudget, candidateSource = []) {
|
|
15675
|
+
const conceptual = await dependencies.searchCodebase(query, { limit: 5 });
|
|
15676
|
+
const pack = buildContextPack([...candidateSource, ...conceptual], {
|
|
15677
|
+
tokenBudget: tokenBudget ?? void 0,
|
|
15678
|
+
heading: "## Conceptual evidence",
|
|
15679
|
+
maxResults: 5,
|
|
15680
|
+
includeExactSearchHandoff: false,
|
|
15681
|
+
preferImplementationPaths: true
|
|
15682
|
+
});
|
|
15683
|
+
const fitted = fitTextToContextBudget(`${risk}
|
|
15684
|
+
|
|
15685
|
+
${pack.text}`, tokenBudget ?? void 0);
|
|
15686
|
+
return {
|
|
15687
|
+
text: fitted.text,
|
|
15688
|
+
details: {
|
|
15689
|
+
resolution,
|
|
15690
|
+
tokenBudget: fitted.tokenBudget,
|
|
15691
|
+
tokenEstimate: fitted.tokenEstimate,
|
|
15692
|
+
truncated: fitted.truncated,
|
|
15693
|
+
sourceIncluded: candidateSource.length > 0,
|
|
15694
|
+
callerCount: 0,
|
|
15695
|
+
calleeCount: 0
|
|
15696
|
+
}
|
|
15697
|
+
};
|
|
15698
|
+
}
|
|
15699
|
+
async function resolveCodebaseEditContextWithDependencies(input, dependencies) {
|
|
15700
|
+
const symbol = input.symbol?.trim();
|
|
15701
|
+
if (!symbol) {
|
|
15702
|
+
return fallbackPack(
|
|
15703
|
+
dependencies,
|
|
15704
|
+
input.query,
|
|
15705
|
+
"Risk: no authoritative symbol was supplied. Review the conceptual evidence before editing.",
|
|
15706
|
+
"not_requested",
|
|
15707
|
+
input.tokenBudget
|
|
15708
|
+
);
|
|
15709
|
+
}
|
|
15710
|
+
let callersResult;
|
|
15711
|
+
try {
|
|
15712
|
+
callersResult = await dependencies.getCallGraphData({
|
|
15713
|
+
name: symbol,
|
|
15714
|
+
filePath: input.filePath ?? void 0,
|
|
15715
|
+
direction: "callers"
|
|
15716
|
+
});
|
|
15717
|
+
} catch (error) {
|
|
15718
|
+
const candidates = await dependencies.implementationLookup(symbol, { limit: 5 });
|
|
15719
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
15720
|
+
return fallbackPack(
|
|
15721
|
+
dependencies,
|
|
15722
|
+
input.query,
|
|
15723
|
+
`Risk: graph data is unavailable (${message}). Target and dependencies are not graph-verified.`,
|
|
15724
|
+
"graph_unavailable",
|
|
15725
|
+
input.tokenBudget,
|
|
15726
|
+
candidates
|
|
15727
|
+
);
|
|
15728
|
+
}
|
|
15729
|
+
if (callersResult.resolution.status !== "resolved") {
|
|
15730
|
+
return fallbackPack(
|
|
15731
|
+
dependencies,
|
|
15732
|
+
input.query,
|
|
15733
|
+
formatResolutionRisk(callersResult.resolution),
|
|
15734
|
+
callersResult.resolution.status,
|
|
15735
|
+
input.tokenBudget
|
|
15736
|
+
);
|
|
15737
|
+
}
|
|
15738
|
+
const resolution = callersResult.resolution;
|
|
15739
|
+
const [definitionsResult, calleesResult] = await Promise.allSettled([
|
|
15740
|
+
dependencies.implementationLookup(symbol, { limit: 10 }),
|
|
15741
|
+
dependencies.getCallGraphData({
|
|
15742
|
+
name: symbol,
|
|
15743
|
+
filePath: input.filePath ?? resolution.filePath,
|
|
15744
|
+
direction: "callees"
|
|
15745
|
+
})
|
|
15746
|
+
]);
|
|
15747
|
+
if (definitionsResult.status === "rejected") throw definitionsResult.reason;
|
|
15748
|
+
let graphRisk;
|
|
15749
|
+
let callees = [];
|
|
15750
|
+
if (calleesResult.status === "rejected") {
|
|
15751
|
+
const message = calleesResult.reason instanceof Error ? calleesResult.reason.message : String(calleesResult.reason);
|
|
15752
|
+
graphRisk = `Risk: callee graph data is unavailable (${message}). Dependency evidence is incomplete.`;
|
|
15753
|
+
} else if (calleesResult.value.resolution.status !== "resolved") {
|
|
15754
|
+
graphRisk = "Risk: the target resolved for callers but not callees. Dependency evidence is incomplete.";
|
|
15755
|
+
} else {
|
|
15756
|
+
callees = calleesResult.value.callees.slice(0, edgeLimit(input.calleeLimit));
|
|
15757
|
+
}
|
|
15758
|
+
const source = targetSource(definitionsResult.value, resolution);
|
|
15759
|
+
const callers = callersResult.callers.slice(0, edgeLimit(input.callerLimit));
|
|
15760
|
+
const sourceBudget = Math.max(
|
|
15761
|
+
MIN_CONTEXT_PACK_TOKEN_BUDGET,
|
|
15762
|
+
Math.floor((input.tokenBudget ?? DEFAULT_CONTEXT_PACK_TOKEN_BUDGET) * 0.6)
|
|
15763
|
+
);
|
|
15764
|
+
const sourceText = source ? fitTextToContextBudget(formatSource(source), sourceBudget).text : `## Target implementation
|
|
15765
|
+
Risk: no implementation source matched the resolved target at ${resolution.filePath}:${resolution.startLine}.`;
|
|
15766
|
+
const fitted = fitTextToContextBudget([
|
|
15767
|
+
`# Pre-edit context for ${resolution.name}`,
|
|
15768
|
+
graphRisk,
|
|
15769
|
+
sourceText,
|
|
15770
|
+
formatCallers(callers),
|
|
15771
|
+
formatCallees(callees, resolution.filePath)
|
|
15772
|
+
].filter((section) => section !== void 0).join("\n\n"), input.tokenBudget ?? void 0);
|
|
15773
|
+
return {
|
|
15774
|
+
text: fitted.text,
|
|
15775
|
+
details: {
|
|
15776
|
+
resolution: "resolved",
|
|
15777
|
+
tokenBudget: fitted.tokenBudget,
|
|
15778
|
+
tokenEstimate: fitted.tokenEstimate,
|
|
15779
|
+
truncated: fitted.truncated,
|
|
15780
|
+
sourceIncluded: source !== void 0,
|
|
15781
|
+
callerCount: callers.length,
|
|
15782
|
+
calleeCount: callees.length
|
|
15783
|
+
}
|
|
15784
|
+
};
|
|
15785
|
+
}
|
|
15786
|
+
async function resolveCodebaseEditContext(projectRoot, host, input) {
|
|
15787
|
+
return resolveCodebaseEditContextWithDependencies(input, {
|
|
15788
|
+
searchCodebase: (query, options) => searchCodebase(projectRoot, host, query, options),
|
|
15789
|
+
implementationLookup: (query, options) => implementationLookup(projectRoot, host, query, options),
|
|
15790
|
+
getCallGraphData: (params) => getCallGraphData(projectRoot, host, params)
|
|
15791
|
+
});
|
|
15792
|
+
}
|
|
15793
|
+
|
|
15475
15794
|
// src/eval/budget.ts
|
|
15476
15795
|
function evaluateBudgetGate(budget, summary, comparison) {
|
|
15477
15796
|
const BASELINE_P95_EPSILON_MS = 1e-3;
|
|
@@ -15495,6 +15814,24 @@ function evaluateBudgetGate(budget, summary, comparison) {
|
|
|
15495
15814
|
message: `Raw Distinct Top@3 ${summary.metrics.rawDistinctTop3Ratio.toFixed(4)} is below minimum ${thresholds.minRawDistinctTop3Ratio.toFixed(4)}`
|
|
15496
15815
|
});
|
|
15497
15816
|
}
|
|
15817
|
+
if (thresholds.minGraphNeighborRecall !== void 0 && summary.metrics.graphNeighborRecall !== void 0 && summary.metrics.graphNeighborRecall < thresholds.minGraphNeighborRecall) {
|
|
15818
|
+
violations.push({
|
|
15819
|
+
metric: "minGraphNeighborRecall",
|
|
15820
|
+
message: `Graph-neighbor recall ${summary.metrics.graphNeighborRecall.toFixed(4)} is below minimum ${thresholds.minGraphNeighborRecall.toFixed(4)}`
|
|
15821
|
+
});
|
|
15822
|
+
}
|
|
15823
|
+
if (thresholds.minRouteAccuracy !== void 0 && summary.metrics.routeAccuracy < thresholds.minRouteAccuracy) {
|
|
15824
|
+
violations.push({
|
|
15825
|
+
metric: "minRouteAccuracy",
|
|
15826
|
+
message: `Route accuracy ${summary.metrics.routeAccuracy.toFixed(4)} is below minimum ${thresholds.minRouteAccuracy.toFixed(4)}`
|
|
15827
|
+
});
|
|
15828
|
+
}
|
|
15829
|
+
if (thresholds.minOutcomeAccuracy !== void 0 && summary.metrics.outcomeAccuracy < thresholds.minOutcomeAccuracy) {
|
|
15830
|
+
violations.push({
|
|
15831
|
+
metric: "minOutcomeAccuracy",
|
|
15832
|
+
message: `Outcome accuracy ${summary.metrics.outcomeAccuracy.toFixed(4)} is below minimum ${thresholds.minOutcomeAccuracy.toFixed(4)}`
|
|
15833
|
+
});
|
|
15834
|
+
}
|
|
15498
15835
|
if (comparison) {
|
|
15499
15836
|
if (thresholds.hitAt5MaxDrop !== void 0 && comparison.deltas.hitAt5.absolute < -thresholds.hitAt5MaxDrop) {
|
|
15500
15837
|
violations.push({
|
|
@@ -15672,6 +16009,14 @@ function isSymbolIntended(query) {
|
|
|
15672
16009
|
function isExpectedFile(filePath, relevant) {
|
|
15673
16010
|
return relevant.some((entry) => pathMatchesExpected(filePath, entry.path));
|
|
15674
16011
|
}
|
|
16012
|
+
function graphNeighborMatches(query, result) {
|
|
16013
|
+
const expected = query.expected.graphNeighbor;
|
|
16014
|
+
if (!expected || result.graphDirection !== expected.direction) return false;
|
|
16015
|
+
if (expected.filePath !== void 0 && !pathMatchesExpected(result.filePath, expected.filePath)) {
|
|
16016
|
+
return false;
|
|
16017
|
+
}
|
|
16018
|
+
return expected.symbol === void 0 || result.name === expected.symbol;
|
|
16019
|
+
}
|
|
15675
16020
|
function resultRelevance(filePath, symbol, relevant, isSymbolIntendedQuery) {
|
|
15676
16021
|
let relevance = 0;
|
|
15677
16022
|
for (const entry of relevant) {
|
|
@@ -15819,6 +16164,7 @@ function buildPerQueryResult(query, results, latencyMs, k, route = {
|
|
|
15819
16164
|
routeMatched: query.expected.expectedRoute ? query.expected.expectedRoute === route.resolvedRoute : void 0,
|
|
15820
16165
|
outcomeMatched: query.expected.expectedOutcome === void 0 ? void 0 : query.expected.expectedOutcome === "results" ? deduped.length > 0 : deduped.length === 0,
|
|
15821
16166
|
recoveryMatched: query.expected.recoveryExpectation === void 0 ? void 0 : query.expected.recoveryExpectation === "filter-relaxed" ? context?.recoveryRelaxed === true : context?.recoveryUsed !== true,
|
|
16167
|
+
graphNeighborMatched: query.expected.graphNeighbor === void 0 ? void 0 : results.some((result) => graphNeighborMatches(query, result)),
|
|
15822
16168
|
language: query.language,
|
|
15823
16169
|
difficulty: query.difficulty,
|
|
15824
16170
|
tags: query.tags,
|
|
@@ -15868,7 +16214,7 @@ function computeEvalMetrics(queries, perQuery, embeddingCallCount, embeddingToke
|
|
|
15868
16214
|
"no-relevant-hit-top-k": 0
|
|
15869
16215
|
};
|
|
15870
16216
|
const latencies = perQuery.map((item) => item.latencyMs);
|
|
15871
|
-
const contextQueries = perQuery.filter((item) => item.retrievalMode
|
|
16217
|
+
const contextQueries = perQuery.filter((item) => item.retrievalMode !== "search");
|
|
15872
16218
|
const contextResponseTokens = contextQueries.map((item) => item.responseTokens);
|
|
15873
16219
|
const totalContextResponseTokens = contextResponseTokens.reduce((sum2, value) => sum2 + value, 0);
|
|
15874
16220
|
const contextTokenUnits = totalContextResponseTokens / 1e3;
|
|
@@ -15878,6 +16224,8 @@ function computeEvalMetrics(queries, perQuery, embeddingCallCount, embeddingToke
|
|
|
15878
16224
|
let outcomeExpectedCount = 0;
|
|
15879
16225
|
let recoveryMatchedCount = 0;
|
|
15880
16226
|
let recoveryExpectedCount = 0;
|
|
16227
|
+
let graphNeighborMatchedCount = 0;
|
|
16228
|
+
let graphNeighborExpectedCount = 0;
|
|
15881
16229
|
for (const query of perQuery) {
|
|
15882
16230
|
if (positiveQueryIds.has(query.id)) {
|
|
15883
16231
|
if (query.hitAt1) sum.hitAt1 += 1;
|
|
@@ -15906,6 +16254,10 @@ function computeEvalMetrics(queries, perQuery, embeddingCallCount, embeddingToke
|
|
|
15906
16254
|
recoveryExpectedCount += 1;
|
|
15907
16255
|
if (query.recoveryMatched) recoveryMatchedCount += 1;
|
|
15908
16256
|
}
|
|
16257
|
+
if (query.graphNeighborMatched !== void 0) {
|
|
16258
|
+
graphNeighborExpectedCount += 1;
|
|
16259
|
+
if (query.graphNeighborMatched) graphNeighborMatchedCount += 1;
|
|
16260
|
+
}
|
|
15909
16261
|
}
|
|
15910
16262
|
const queryTokens = queries.reduce((acc, q) => acc + estimateTokens(q.query), 0);
|
|
15911
16263
|
return {
|
|
@@ -15918,6 +16270,7 @@ function computeEvalMetrics(queries, perQuery, embeddingCallCount, embeddingToke
|
|
|
15918
16270
|
routeAccuracy: routeExpectedCount === 0 ? 0 : routeMatchedCount / routeExpectedCount,
|
|
15919
16271
|
outcomeAccuracy: outcomeExpectedCount === 0 ? 0 : outcomeMatchedCount / outcomeExpectedCount,
|
|
15920
16272
|
recoveryAccuracy: recoveryExpectedCount === 0 ? 0 : recoveryMatchedCount / recoveryExpectedCount,
|
|
16273
|
+
graphNeighborRecall: graphNeighborExpectedCount === 0 ? 0 : graphNeighborMatchedCount / graphNeighborExpectedCount,
|
|
15921
16274
|
distinctTop3Ratio: safeDiv(sum.distinctTop3Ratio),
|
|
15922
16275
|
rawDistinctTop3Ratio: safeDiv(sum.rawDistinctTop3Ratio),
|
|
15923
16276
|
latencyMs: {
|
|
@@ -16183,14 +16536,29 @@ function parseQueryArgs(value, path31) {
|
|
|
16183
16536
|
throw new Error(`${path31} must be an object`);
|
|
16184
16537
|
}
|
|
16185
16538
|
const symbol = parseStringOrUndefined(value.symbol, `${path31}.symbol`);
|
|
16539
|
+
const filePath = parseStringOrUndefined(value.filePath, `${path31}.filePath`);
|
|
16186
16540
|
const fileType = parseStringOrUndefined(value.fileType, `${path31}.fileType`);
|
|
16187
16541
|
const directory = parseStringOrUndefined(value.directory, `${path31}.directory`);
|
|
16542
|
+
const callerLimit = parsePositiveIntegerOrUndefined(value.callerLimit, `${path31}.callerLimit`);
|
|
16543
|
+
const calleeLimit = parsePositiveIntegerOrUndefined(value.calleeLimit, `${path31}.calleeLimit`);
|
|
16544
|
+
const tokenBudget = parsePositiveIntegerOrUndefined(value.tokenBudget, `${path31}.tokenBudget`);
|
|
16188
16545
|
return {
|
|
16189
16546
|
...symbol !== void 0 ? { symbol } : {},
|
|
16547
|
+
...filePath !== void 0 ? { filePath } : {},
|
|
16190
16548
|
...fileType !== void 0 ? { fileType } : {},
|
|
16191
|
-
...directory !== void 0 ? { directory } : {}
|
|
16549
|
+
...directory !== void 0 ? { directory } : {},
|
|
16550
|
+
...callerLimit !== void 0 ? { callerLimit } : {},
|
|
16551
|
+
...calleeLimit !== void 0 ? { calleeLimit } : {},
|
|
16552
|
+
...tokenBudget !== void 0 ? { tokenBudget } : {}
|
|
16192
16553
|
};
|
|
16193
16554
|
}
|
|
16555
|
+
function parsePositiveIntegerOrUndefined(value, path31) {
|
|
16556
|
+
if (value === void 0 || value === null) return void 0;
|
|
16557
|
+
if (typeof value !== "number" || !Number.isInteger(value) || value <= 0) {
|
|
16558
|
+
throw new Error(`${path31} must be a positive integer`);
|
|
16559
|
+
}
|
|
16560
|
+
return value;
|
|
16561
|
+
}
|
|
16194
16562
|
var SEMVER_VERSION_PATTERN = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
|
|
16195
16563
|
function parseSemanticVersion(value, path31) {
|
|
16196
16564
|
if (!isNonEmptyString(value)) {
|
|
@@ -16203,8 +16571,8 @@ function parseSemanticVersion(value, path31) {
|
|
|
16203
16571
|
}
|
|
16204
16572
|
function parseRetrievalMode(value, path31) {
|
|
16205
16573
|
if (value === void 0 || value === "search") return "search";
|
|
16206
|
-
if (value === "context") return value;
|
|
16207
|
-
throw new Error(`${path31} must be one of: search, context`);
|
|
16574
|
+
if (value === "context" || value === "edit-context") return value;
|
|
16575
|
+
throw new Error(`${path31} must be one of: search, context, edit-context`);
|
|
16208
16576
|
}
|
|
16209
16577
|
function parseStringOrUndefined(value, path31) {
|
|
16210
16578
|
if (value === void 0 || value === null) return void 0;
|
|
@@ -16244,6 +16612,25 @@ function parseEvidenceRelevance(value, path31) {
|
|
|
16244
16612
|
}
|
|
16245
16613
|
return value;
|
|
16246
16614
|
}
|
|
16615
|
+
function parseExpectedGraphNeighbor(value, path31) {
|
|
16616
|
+
if (value === void 0) return void 0;
|
|
16617
|
+
if (!isRecord3(value)) {
|
|
16618
|
+
throw new Error(`${path31} must be an object`);
|
|
16619
|
+
}
|
|
16620
|
+
if (value.direction !== "caller" && value.direction !== "callee") {
|
|
16621
|
+
throw new Error(`${path31}.direction must be one of: caller, callee`);
|
|
16622
|
+
}
|
|
16623
|
+
const filePath = parseStringOrUndefined(value.filePath, `${path31}.filePath`);
|
|
16624
|
+
const symbol = parseStringOrUndefined(value.symbol, `${path31}.symbol`);
|
|
16625
|
+
if (filePath === void 0 && symbol === void 0) {
|
|
16626
|
+
throw new Error(`${path31} must include filePath or symbol`);
|
|
16627
|
+
}
|
|
16628
|
+
return {
|
|
16629
|
+
direction: value.direction,
|
|
16630
|
+
...filePath !== void 0 ? { filePath } : {},
|
|
16631
|
+
...symbol !== void 0 ? { symbol } : {}
|
|
16632
|
+
};
|
|
16633
|
+
}
|
|
16247
16634
|
function parseExpected(input, path31) {
|
|
16248
16635
|
if (!isRecord3(input)) {
|
|
16249
16636
|
throw new Error(`${path31} must be an object`);
|
|
@@ -16256,9 +16643,11 @@ function parseExpected(input, path31) {
|
|
|
16256
16643
|
const expectedOutcomeRaw = input.expectedOutcome;
|
|
16257
16644
|
const recoveryExpectationRaw = input.recoveryExpectation;
|
|
16258
16645
|
const gradedEvidenceRaw = input.gradedEvidence;
|
|
16646
|
+
const graphNeighborRaw = input.graphNeighbor;
|
|
16259
16647
|
const filePath = parseStringOrUndefined(filePathRaw, `${path31}.filePath`);
|
|
16260
16648
|
const acceptableFiles = isStringArray4(acceptableFilesRaw) ? acceptableFilesRaw : void 0;
|
|
16261
16649
|
const gradedEvidence = parseGradedEvidence(gradedEvidenceRaw, `${path31}.gradedEvidence`);
|
|
16650
|
+
const graphNeighbor = parseExpectedGraphNeighbor(graphNeighborRaw, `${path31}.graphNeighbor`);
|
|
16262
16651
|
const expectedOutcome = parseExpectedOutcome(expectedOutcomeRaw, `${path31}.expectedOutcome`);
|
|
16263
16652
|
if (expectedOutcome !== "no-results" && !filePath && (!acceptableFiles || acceptableFiles.length === 0) && gradedEvidence.length === 0) {
|
|
16264
16653
|
throw new Error(
|
|
@@ -16287,7 +16676,8 @@ function parseExpected(input, path31) {
|
|
|
16287
16676
|
expectedRoute,
|
|
16288
16677
|
expectedOutcome,
|
|
16289
16678
|
recoveryExpectation,
|
|
16290
|
-
...gradedEvidence.length > 0 ? { gradedEvidence } : {}
|
|
16679
|
+
...gradedEvidence.length > 0 ? { gradedEvidence } : {},
|
|
16680
|
+
...graphNeighbor !== void 0 ? { graphNeighbor } : {}
|
|
16291
16681
|
};
|
|
16292
16682
|
}
|
|
16293
16683
|
function parseQueryLanguage(value, path31) {
|
|
@@ -16422,6 +16812,21 @@ function parseBudget(raw, sourceLabel) {
|
|
|
16422
16812
|
"minRawDistinctTop3Ratio",
|
|
16423
16813
|
sourceLabel
|
|
16424
16814
|
),
|
|
16815
|
+
minGraphNeighborRecall: parseThresholdValue(
|
|
16816
|
+
thresholds.minGraphNeighborRecall,
|
|
16817
|
+
"minGraphNeighborRecall",
|
|
16818
|
+
sourceLabel
|
|
16819
|
+
),
|
|
16820
|
+
minRouteAccuracy: parseThresholdValue(
|
|
16821
|
+
thresholds.minRouteAccuracy,
|
|
16822
|
+
"minRouteAccuracy",
|
|
16823
|
+
sourceLabel
|
|
16824
|
+
),
|
|
16825
|
+
minOutcomeAccuracy: parseThresholdValue(
|
|
16826
|
+
thresholds.minOutcomeAccuracy,
|
|
16827
|
+
"minOutcomeAccuracy",
|
|
16828
|
+
sourceLabel
|
|
16829
|
+
),
|
|
16425
16830
|
maxContextResponseTokensAverage: parseThresholdValue(
|
|
16426
16831
|
thresholds.maxContextResponseTokensAverage,
|
|
16427
16832
|
"maxContextResponseTokensAverage",
|
|
@@ -16486,6 +16891,120 @@ function buildDatasetFingerprint(dataset) {
|
|
|
16486
16891
|
const canonical = JSON.stringify(normalizeForFingerprint(dataset));
|
|
16487
16892
|
return crypto2.createHash("sha256").update(canonical).digest("hex");
|
|
16488
16893
|
}
|
|
16894
|
+
function normalizedPath2(value) {
|
|
16895
|
+
return value.replaceAll("\\", "/").replace(/^\.\//, "");
|
|
16896
|
+
}
|
|
16897
|
+
function pathsMatch2(left, right) {
|
|
16898
|
+
const normalizedLeft = normalizedPath2(left);
|
|
16899
|
+
const normalizedRight = normalizedPath2(right);
|
|
16900
|
+
return normalizedLeft === normalizedRight || normalizedLeft.endsWith(`/${normalizedRight}`) || normalizedRight.endsWith(`/${normalizedLeft}`);
|
|
16901
|
+
}
|
|
16902
|
+
function toEvalSearchResult(result) {
|
|
16903
|
+
return {
|
|
16904
|
+
filePath: result.filePath,
|
|
16905
|
+
startLine: result.startLine,
|
|
16906
|
+
endLine: result.endLine,
|
|
16907
|
+
score: result.score,
|
|
16908
|
+
chunkType: result.chunkType,
|
|
16909
|
+
name: result.name
|
|
16910
|
+
};
|
|
16911
|
+
}
|
|
16912
|
+
function selectResolvedTarget(definitions, resolution) {
|
|
16913
|
+
if (resolution?.status !== "resolved") return definitions[0];
|
|
16914
|
+
return definitions.find((result) => pathsMatch2(result.filePath, resolution.filePath) && result.startLine <= resolution.startLine && result.endLine >= resolution.startLine) ?? definitions.find((result) => pathsMatch2(result.filePath, resolution.filePath) && result.name === resolution.name) ?? definitions[0];
|
|
16915
|
+
}
|
|
16916
|
+
function callerResult(edge) {
|
|
16917
|
+
if (!edge.fromSymbolFilePath) return void 0;
|
|
16918
|
+
return {
|
|
16919
|
+
filePath: edge.fromSymbolFilePath,
|
|
16920
|
+
startLine: edge.line,
|
|
16921
|
+
endLine: edge.line,
|
|
16922
|
+
score: 0,
|
|
16923
|
+
chunkType: "graph-caller",
|
|
16924
|
+
name: edge.fromSymbolName,
|
|
16925
|
+
graphDirection: "caller"
|
|
16926
|
+
};
|
|
16927
|
+
}
|
|
16928
|
+
function calleeResult(edge, symbols) {
|
|
16929
|
+
const symbol = edge.toSymbolId ? symbols.find((candidate) => candidate.id === edge.toSymbolId) : symbols.filter((candidate) => candidate.name === edge.targetName).length === 1 ? symbols.find((candidate) => candidate.name === edge.targetName) : void 0;
|
|
16930
|
+
if (!symbol) return void 0;
|
|
16931
|
+
return {
|
|
16932
|
+
filePath: symbol.filePath,
|
|
16933
|
+
startLine: symbol.startLine,
|
|
16934
|
+
endLine: symbol.endLine,
|
|
16935
|
+
score: 0,
|
|
16936
|
+
chunkType: "graph-callee",
|
|
16937
|
+
name: symbol.name,
|
|
16938
|
+
graphDirection: "callee"
|
|
16939
|
+
};
|
|
16940
|
+
}
|
|
16941
|
+
async function runEditContextQuery(indexer, projectRoot, query) {
|
|
16942
|
+
let definitions = [];
|
|
16943
|
+
let conceptual = [];
|
|
16944
|
+
let callers;
|
|
16945
|
+
let callees;
|
|
16946
|
+
const editContext = await resolveCodebaseEditContextWithDependencies({
|
|
16947
|
+
query: query.query,
|
|
16948
|
+
symbol: query.args?.symbol,
|
|
16949
|
+
filePath: query.args?.filePath ?? query.expected.filePath,
|
|
16950
|
+
callerLimit: query.args?.callerLimit,
|
|
16951
|
+
calleeLimit: query.args?.calleeLimit,
|
|
16952
|
+
tokenBudget: query.args?.tokenBudget
|
|
16953
|
+
}, {
|
|
16954
|
+
searchCodebase: async (searchQuery, options) => {
|
|
16955
|
+
conceptual = await indexer.search(searchQuery, options?.limit, {
|
|
16956
|
+
filterByBranch: !!query.expected.branch
|
|
16957
|
+
});
|
|
16958
|
+
return conceptual;
|
|
16959
|
+
},
|
|
16960
|
+
implementationLookup: async (symbol, options) => {
|
|
16961
|
+
definitions = await indexer.search(symbol, options?.limit, {
|
|
16962
|
+
filterByBranch: !!query.expected.branch,
|
|
16963
|
+
definitionIntent: true
|
|
16964
|
+
});
|
|
16965
|
+
return definitions;
|
|
16966
|
+
},
|
|
16967
|
+
getCallGraphData: async (params) => {
|
|
16968
|
+
const result = await getCallGraphDataForIndexer(indexer, projectRoot, params);
|
|
16969
|
+
if (params.direction === "callers") callers = result;
|
|
16970
|
+
else callees = result;
|
|
16971
|
+
return result;
|
|
16972
|
+
}
|
|
16973
|
+
});
|
|
16974
|
+
const resolution = callers?.resolution;
|
|
16975
|
+
const target = selectResolvedTarget(definitions, resolution);
|
|
16976
|
+
const targetCandidates = target ? [target] : [...definitions, ...conceptual];
|
|
16977
|
+
const results = targetCandidates.filter((candidate) => (resolution?.status !== "resolved" || editContext.details.sourceIncluded) && editContext.text.includes(
|
|
16978
|
+
`${candidate.filePath}:${candidate.startLine}-${candidate.endLine}`
|
|
16979
|
+
)).map(toEvalSearchResult);
|
|
16980
|
+
if (query.expected.graphNeighbor) {
|
|
16981
|
+
const symbols = await indexer.getCallGraphSymbols();
|
|
16982
|
+
const callerLimit = query.args?.callerLimit ?? DEFAULT_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT;
|
|
16983
|
+
const calleeLimit = query.args?.calleeLimit ?? DEFAULT_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT;
|
|
16984
|
+
const publishedCallers = (callers?.callers ?? []).slice(0, callerLimit).filter((edge) => editContext.text.includes(
|
|
16985
|
+
`${edge.fromSymbolName ?? "<unknown>"} at ${edge.fromSymbolFilePath ?? "<unknown file>"}:${edge.line} (${edge.callType}, ${edge.isResolved ? "resolved" : "unresolved"})`
|
|
16986
|
+
));
|
|
16987
|
+
const publishedCallees = (callees?.callees ?? []).slice(0, calleeLimit).filter((edge) => resolution?.status === "resolved" && editContext.text.includes(
|
|
16988
|
+
`${edge.targetName} from ${resolution.filePath}:${edge.line} (${edge.callType}, ${edge.isResolved ? "resolved" : "unresolved"})`
|
|
16989
|
+
));
|
|
16990
|
+
results.push(
|
|
16991
|
+
...publishedCallers.map(callerResult).filter((item) => item !== void 0),
|
|
16992
|
+
...publishedCallees.map((edge) => calleeResult(edge, symbols)).filter((item) => item !== void 0)
|
|
16993
|
+
);
|
|
16994
|
+
}
|
|
16995
|
+
return {
|
|
16996
|
+
results,
|
|
16997
|
+
resolvedRoute: resolution?.status === "resolved" ? "definition" : "search",
|
|
16998
|
+
routedQuery: query.args?.symbol ?? query.query,
|
|
16999
|
+
context: {
|
|
17000
|
+
tokenBudget: editContext.details.tokenBudget,
|
|
17001
|
+
responseTokens: editContext.details.tokenEstimate,
|
|
17002
|
+
candidateCount: results.length,
|
|
17003
|
+
deduplicatedCount: results.length,
|
|
17004
|
+
omittedCount: 0
|
|
17005
|
+
}
|
|
17006
|
+
};
|
|
17007
|
+
}
|
|
16489
17008
|
async function runEvaluation(options) {
|
|
16490
17009
|
const datasetPath = toAbsolute(options.projectRoot, options.datasetPath);
|
|
16491
17010
|
const againstPath = options.againstPath ? toAbsolute(options.projectRoot, options.againstPath) : void 0;
|
|
@@ -16517,6 +17036,7 @@ async function runEvaluation(options) {
|
|
|
16517
17036
|
);
|
|
16518
17037
|
}
|
|
16519
17038
|
const start = performance3.now();
|
|
17039
|
+
const editContextResult = query.retrievalMode === "edit-context" ? await runEditContextQuery(indexer, options.projectRoot, query) : void 0;
|
|
16520
17040
|
const contextResult = query.retrievalMode === "context" ? await resolveSearchContext({
|
|
16521
17041
|
query: query.query,
|
|
16522
17042
|
symbol: query.args?.symbol,
|
|
@@ -16540,31 +17060,32 @@ async function runEvaluation(options) {
|
|
|
16540
17060
|
directory: scope.directory
|
|
16541
17061
|
})
|
|
16542
17062
|
}) : void 0;
|
|
16543
|
-
const result = contextResult?.details?.results ?? await indexer.search(query.query, 10, {
|
|
17063
|
+
const result = editContextResult?.results ?? contextResult?.details?.results ?? await indexer.search(query.query, 10, {
|
|
16544
17064
|
metadataOnly: true,
|
|
16545
17065
|
filterByBranch: !!query.expected.branch,
|
|
16546
17066
|
fileType: query.args?.fileType,
|
|
16547
17067
|
directory: query.args?.directory
|
|
16548
17068
|
});
|
|
16549
17069
|
const elapsed = performance3.now() - start;
|
|
16550
|
-
const resolvedRoute = contextResult?.details?.route === "definition" ? "definition" : "search";
|
|
16551
|
-
const routedQuery = contextResult?.details?.routedQuery ?? query.query;
|
|
17070
|
+
const resolvedRoute = editContextResult?.resolvedRoute ?? (contextResult?.details?.route === "definition" ? "definition" : "search");
|
|
17071
|
+
const routedQuery = editContextResult?.routedQuery ?? contextResult?.details?.routedQuery ?? query.query;
|
|
16552
17072
|
const successfulRecoveryAttempt = contextResult?.details?.recovery?.successfulAttemptIndex;
|
|
16553
17073
|
const recoveryAttempts = contextResult?.details?.recovery?.attempts ?? [];
|
|
16554
17074
|
const recoveryRelaxed = successfulRecoveryAttempt === void 0 ? false : (recoveryAttempts[successfulRecoveryAttempt]?.relaxedFields.length ?? 0) > 0;
|
|
16555
17075
|
const recoveryUsed = recoveryAttempts.length > 1 || recoveryAttempts.some((attempt) => attempt.relaxedFields.length > 0);
|
|
16556
|
-
const materialized = result.map((item) =>
|
|
16557
|
-
|
|
16558
|
-
|
|
16559
|
-
|
|
16560
|
-
|
|
16561
|
-
|
|
16562
|
-
|
|
16563
|
-
|
|
16564
|
-
|
|
16565
|
-
|
|
16566
|
-
|
|
16567
|
-
}
|
|
17076
|
+
const materialized = result.map((item) => {
|
|
17077
|
+
const graphDirection = "graphDirection" in item && (item.graphDirection === "caller" || item.graphDirection === "callee") ? item.graphDirection : void 0;
|
|
17078
|
+
return {
|
|
17079
|
+
filePath: item.filePath,
|
|
17080
|
+
startLine: item.startLine,
|
|
17081
|
+
endLine: item.endLine,
|
|
17082
|
+
score: item.score,
|
|
17083
|
+
chunkType: item.chunkType,
|
|
17084
|
+
name: item.name,
|
|
17085
|
+
graphDirection
|
|
17086
|
+
};
|
|
17087
|
+
});
|
|
17088
|
+
const contextMeasurement = editContextResult?.context ?? (contextResult?.details ? {
|
|
16568
17089
|
tokenBudget: contextResult.details.tokenBudget,
|
|
16569
17090
|
responseTokens: contextResult.details.tokenEstimate,
|
|
16570
17091
|
candidateCount: contextResult.details.candidateCount ?? 0,
|
|
@@ -16572,7 +17093,11 @@ async function runEvaluation(options) {
|
|
|
16572
17093
|
omittedCount: contextResult.details.omittedCount ?? 0,
|
|
16573
17094
|
recoveryUsed,
|
|
16574
17095
|
recoveryRelaxed
|
|
16575
|
-
} : void 0)
|
|
17096
|
+
} : void 0);
|
|
17097
|
+
perQuery.push(buildPerQueryResult(query, materialized, elapsed, 10, {
|
|
17098
|
+
resolvedRoute,
|
|
17099
|
+
routedQuery
|
|
17100
|
+
}, contextMeasurement));
|
|
16576
17101
|
}
|
|
16577
17102
|
const logger = indexer.getLogger();
|
|
16578
17103
|
const metricSnapshot = logger.getMetrics();
|
|
@@ -17108,7 +17633,11 @@ import { z as z2 } from "zod";
|
|
|
17108
17633
|
|
|
17109
17634
|
// src/tools/execute-common.ts
|
|
17110
17635
|
async function executeCodebaseContext(projectRoot, host, args) {
|
|
17111
|
-
|
|
17636
|
+
const result = await resolveCodebaseContext(projectRoot, host, args);
|
|
17637
|
+
return { text: result.text, details: result.details };
|
|
17638
|
+
}
|
|
17639
|
+
async function executeCodebaseEditContext(projectRoot, host, args) {
|
|
17640
|
+
return { text: (await resolveCodebaseEditContext(projectRoot, host, args)).text };
|
|
17112
17641
|
}
|
|
17113
17642
|
async function executeIndexCodebase(projectRoot, host, args, onProgress) {
|
|
17114
17643
|
const result = await runIndexCodebase(projectRoot, host, args, onProgress);
|
|
@@ -17224,6 +17753,7 @@ function formatPrImpact(result) {
|
|
|
17224
17753
|
// src/tools/tool-names.ts
|
|
17225
17754
|
var TOOL_NAME = {
|
|
17226
17755
|
CODEBASE_CONTEXT: "codebase_context",
|
|
17756
|
+
CODEBASE_EDIT_CONTEXT: "codebase_edit_context",
|
|
17227
17757
|
CODEBASE_SEARCH: "codebase_search",
|
|
17228
17758
|
CODEBASE_PEEK: "codebase_peek",
|
|
17229
17759
|
FIND_SIMILAR: "find_similar",
|
|
@@ -17247,6 +17777,7 @@ var TOOL_NAME = {
|
|
|
17247
17777
|
};
|
|
17248
17778
|
var PORTABLE_TOOL_NAMES = [
|
|
17249
17779
|
TOOL_NAME.CODEBASE_CONTEXT,
|
|
17780
|
+
TOOL_NAME.CODEBASE_EDIT_CONTEXT,
|
|
17250
17781
|
TOOL_NAME.CODEBASE_SEARCH,
|
|
17251
17782
|
TOOL_NAME.CODEBASE_PEEK,
|
|
17252
17783
|
TOOL_NAME.INDEX_CODEBASE,
|
|
@@ -17263,6 +17794,7 @@ var PORTABLE_TOOL_NAMES = [
|
|
|
17263
17794
|
];
|
|
17264
17795
|
var OPENCODE_TOOL_NAMES = [
|
|
17265
17796
|
TOOL_NAME.CODEBASE_CONTEXT,
|
|
17797
|
+
TOOL_NAME.CODEBASE_EDIT_CONTEXT,
|
|
17266
17798
|
TOOL_NAME.CODEBASE_SEARCH,
|
|
17267
17799
|
TOOL_NAME.CODEBASE_PEEK,
|
|
17268
17800
|
TOOL_NAME.INDEX_CODEBASE,
|
|
@@ -17283,6 +17815,7 @@ var OPENCODE_TOOL_NAMES = [
|
|
|
17283
17815
|
];
|
|
17284
17816
|
var PI_TOOL_NAMES = [
|
|
17285
17817
|
TOOL_NAME.CODEBASE_CONTEXT,
|
|
17818
|
+
TOOL_NAME.CODEBASE_EDIT_CONTEXT,
|
|
17286
17819
|
TOOL_NAME.CODEBASE_SEARCH,
|
|
17287
17820
|
TOOL_NAME.CODEBASE_PEEK,
|
|
17288
17821
|
TOOL_NAME.FIND_SIMILAR,
|
|
@@ -17326,10 +17859,30 @@ function registerMcpTools(server, runtime) {
|
|
|
17326
17859
|
directory: allowNullAsUndefined(z2.string().optional()).describe("Filter by directory path (e.g., 'src/utils', 'lib')"),
|
|
17327
17860
|
tokenBudget: allowNullAsUndefined(
|
|
17328
17861
|
z2.number().int().min(MIN_CONTEXT_PACK_TOKEN_BUDGET).max(MAX_CONTEXT_PACK_TOKEN_BUDGET).optional().default(DEFAULT_CONTEXT_PACK_TOKEN_BUDGET)
|
|
17329
|
-
).describe(`Maximum response tokens for this context pack (${MIN_CONTEXT_PACK_TOKEN_BUDGET}-${MAX_CONTEXT_PACK_TOKEN_BUDGET})`)
|
|
17862
|
+
).describe(`Maximum response tokens for this context pack (${MIN_CONTEXT_PACK_TOKEN_BUDGET}-${MAX_CONTEXT_PACK_TOKEN_BUDGET})`),
|
|
17863
|
+
diagnostic: z2.boolean().optional().describe("Collect diagnostic routing and search traces without changing normal text output.")
|
|
17330
17864
|
},
|
|
17331
17865
|
async (args) => {
|
|
17332
17866
|
const result = await executeCodebaseContext(runtime.projectRoot, runtime.host, args);
|
|
17867
|
+
return {
|
|
17868
|
+
content: [{ type: "text", text: result.text }],
|
|
17869
|
+
...args.diagnostic ? { structuredContent: result.details } : {}
|
|
17870
|
+
};
|
|
17871
|
+
}
|
|
17872
|
+
);
|
|
17873
|
+
server.tool(
|
|
17874
|
+
TOOL_NAME.CODEBASE_EDIT_CONTEXT,
|
|
17875
|
+
"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 resolution is unsafe.",
|
|
17876
|
+
{
|
|
17877
|
+
query: z2.string().describe("The requested change or target behavior."),
|
|
17878
|
+
symbol: allowNullAsUndefined(z2.string().optional()).describe("Authoritative target symbol when known."),
|
|
17879
|
+
filePath: allowNullAsUndefined(z2.string().optional()).describe("Optional file path used to disambiguate duplicate symbol names."),
|
|
17880
|
+
callerLimit: allowNullAsUndefined(z2.number().int().min(MIN_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT).max(MAX_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT).optional().default(DEFAULT_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT)),
|
|
17881
|
+
calleeLimit: allowNullAsUndefined(z2.number().int().min(MIN_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT).max(MAX_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT).optional().default(DEFAULT_CODEBASE_EDIT_CONTEXT_EDGE_LIMIT)),
|
|
17882
|
+
tokenBudget: allowNullAsUndefined(z2.number().int().min(MIN_CONTEXT_PACK_TOKEN_BUDGET).max(MAX_CONTEXT_PACK_TOKEN_BUDGET).optional().default(DEFAULT_CONTEXT_PACK_TOKEN_BUDGET))
|
|
17883
|
+
},
|
|
17884
|
+
async (args) => {
|
|
17885
|
+
const result = await executeCodebaseEditContext(runtime.projectRoot, runtime.host, args);
|
|
17333
17886
|
return { content: [{ type: "text", text: result.text }] };
|
|
17334
17887
|
}
|
|
17335
17888
|
);
|
|
@@ -19786,9 +20339,9 @@ function parseGitActivity(output) {
|
|
|
19786
20339
|
if (!filePath || addedRaw === "-" || deletedRaw === "-") continue;
|
|
19787
20340
|
const churn = Number(addedRaw) + Number(deletedRaw);
|
|
19788
20341
|
if (!Number.isFinite(churn) || churn <= 0) continue;
|
|
19789
|
-
const
|
|
19790
|
-
const previous = activity.get(
|
|
19791
|
-
activity.set(
|
|
20342
|
+
const normalizedPath3 = normalizePath4(filePath);
|
|
20343
|
+
const previous = activity.get(normalizedPath3);
|
|
20344
|
+
activity.set(normalizedPath3, {
|
|
19792
20345
|
churn: (previous?.churn ?? 0) + churn,
|
|
19793
20346
|
commits: (previous?.commits ?? 0) + 1,
|
|
19794
20347
|
latestDate: previous?.latestDate ?? latestDate,
|
|
@@ -20378,8 +20931,8 @@ function transformForVisualization(symbols, edges, options = {}) {
|
|
|
20378
20931
|
const normalizedAbsoluteSuffix = `/${normalizedDirWithSlash}`;
|
|
20379
20932
|
filteredSymbols = symbols.filter(
|
|
20380
20933
|
(s) => {
|
|
20381
|
-
const
|
|
20382
|
-
return
|
|
20934
|
+
const normalizedPath3 = s.filePath.replace(/\\/g, "/");
|
|
20935
|
+
return normalizedPath3 === normalizedDir || normalizedPath3.startsWith(normalizedDirWithSlash) || normalizedPath3.endsWith(`/${normalizedDir}`) || normalizedPath3.includes(normalizedAbsoluteSuffix);
|
|
20383
20936
|
}
|
|
20384
20937
|
);
|
|
20385
20938
|
}
|