opencode-codebase-index 0.15.0 → 0.16.0
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 +2 -2
- package/README.md +33 -8
- package/dist/cli.cjs +144 -51
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +144 -51
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +13 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +13 -3
- package/dist/index.js.map +1 -1
- package/dist/pi-extension.cjs +92 -9
- package/dist/pi-extension.cjs.map +1 -1
- package/dist/pi-extension.js +92 -9
- package/dist/pi-extension.js.map +1 -1
- package/hooks/hooks.json +2 -2
- 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.win32-x64-msvc.node +0 -0
- package/package.json +1 -1
- package/skills/codebase-search/SKILL.md +9 -7
package/dist/cli.js
CHANGED
|
@@ -8995,10 +8995,19 @@ var Indexer = class {
|
|
|
8995
8995
|
});
|
|
8996
8996
|
const embeddingStartTime = performance2.now();
|
|
8997
8997
|
const embeddingQuery = stripFilePathHint(query);
|
|
8998
|
-
|
|
8998
|
+
let embedding;
|
|
8999
|
+
try {
|
|
9000
|
+
embedding = await this.getQueryEmbedding(embeddingQuery, provider);
|
|
9001
|
+
} catch (error) {
|
|
9002
|
+
this.logger.warn("Query embedding failed; falling back to keyword-only search", {
|
|
9003
|
+
query,
|
|
9004
|
+
error: getErrorMessage2(error),
|
|
9005
|
+
action: "Check the embedding provider configuration and retry search after restoring provider health."
|
|
9006
|
+
});
|
|
9007
|
+
}
|
|
8999
9008
|
const embeddingMs = performance2.now() - embeddingStartTime;
|
|
9000
9009
|
const vectorStartTime = performance2.now();
|
|
9001
|
-
const semanticResults = store.search(embedding, maxResults * 4);
|
|
9010
|
+
const semanticResults = embedding ? store.search(embedding, maxResults * 4) : [];
|
|
9002
9011
|
const vectorMs = performance2.now() - vectorStartTime;
|
|
9003
9012
|
const keywordStartTime = performance2.now();
|
|
9004
9013
|
const keywordResults = await this.keywordSearch(query, maxResults * 4, store, invertedIndex);
|
|
@@ -9033,12 +9042,13 @@ var Indexer = class {
|
|
|
9033
9042
|
});
|
|
9034
9043
|
}
|
|
9035
9044
|
const fusionStartTime = performance2.now();
|
|
9045
|
+
const rankingHybridWeight = embedding === void 0 && fusionStrategy === "weighted" ? 1 : effectiveHybridWeight;
|
|
9036
9046
|
const combined = rankHybridResults(query, semanticCandidates, keywordCandidates, {
|
|
9037
9047
|
fusionStrategy,
|
|
9038
9048
|
rrfK,
|
|
9039
9049
|
rerankTopN,
|
|
9040
9050
|
limit: maxResults,
|
|
9041
|
-
hybridWeight:
|
|
9051
|
+
hybridWeight: rankingHybridWeight,
|
|
9042
9052
|
prioritizeSourcePaths: sourceIntent
|
|
9043
9053
|
});
|
|
9044
9054
|
const rerankedCombined = await this.rerankCandidatesWithApi(query, combined, {
|
|
@@ -11939,20 +11949,87 @@ var CHUNK_TYPE_ENUM = [
|
|
|
11939
11949
|
];
|
|
11940
11950
|
|
|
11941
11951
|
// src/mcp-server/register-tools.ts
|
|
11952
|
+
function allowNullAsUndefined(schema) {
|
|
11953
|
+
return z2.preprocess((value) => value === null ? void 0 : value, schema);
|
|
11954
|
+
}
|
|
11942
11955
|
function registerMcpTools(server, runtime) {
|
|
11956
|
+
server.tool(
|
|
11957
|
+
"codebase_context",
|
|
11958
|
+
"PREFERRED FIRST TOOL for any question about this repository. Use before built-in code search, grep, shell search, or broad file reads. Provide from+to for a dependency path, symbol for a definition, or only query for low-token conceptual discovery. Use call_graph directly for callers or callees.",
|
|
11959
|
+
{
|
|
11960
|
+
query: z2.string().describe("The codebase question or behavior to locate. Always provide the user's repository question here."),
|
|
11961
|
+
from: allowNullAsUndefined(z2.string().optional()).describe("Source symbol. For dependency-path questions, extract the first endpoint and provide it here."),
|
|
11962
|
+
to: allowNullAsUndefined(z2.string().optional()).describe("Target symbol. For dependency-path questions, extract the second endpoint and provide it here."),
|
|
11963
|
+
symbol: allowNullAsUndefined(z2.string().optional()).describe("Exact symbol for an authoritative definition lookup. Omit when from and to are supplied."),
|
|
11964
|
+
limit: allowNullAsUndefined(z2.number().optional().default(10)).describe("Maximum number of search or definition results"),
|
|
11965
|
+
maxDepth: allowNullAsUndefined(z2.number().optional().default(10)).describe("Maximum call-graph traversal depth for from/to path lookup"),
|
|
11966
|
+
fileType: allowNullAsUndefined(z2.string().optional()).describe("Filter by file extension (e.g., 'ts', 'py', 'rs')"),
|
|
11967
|
+
directory: allowNullAsUndefined(z2.string().optional()).describe("Filter by directory path (e.g., 'src/utils', 'lib')")
|
|
11968
|
+
},
|
|
11969
|
+
async (args) => {
|
|
11970
|
+
if (args.from && args.to) {
|
|
11971
|
+
const path27 = await getCallGraphPath(runtime.projectRoot, runtime.host, args.from, args.to, args.maxDepth);
|
|
11972
|
+
if (path27.length > 0) {
|
|
11973
|
+
return { content: [{ type: "text", text: formatCallGraphPath(args.from, args.to, path27) }] };
|
|
11974
|
+
}
|
|
11975
|
+
const { callers } = await getCallGraphData(runtime.projectRoot, runtime.host, {
|
|
11976
|
+
name: args.to,
|
|
11977
|
+
direction: "callers"
|
|
11978
|
+
});
|
|
11979
|
+
const directEdge = callers.find((edge) => edge.fromSymbolName === args.from);
|
|
11980
|
+
if (directEdge) {
|
|
11981
|
+
const location = directEdge.fromSymbolFilePath ? ` at ${directEdge.fromSymbolFilePath}:${directEdge.line}` : "";
|
|
11982
|
+
return {
|
|
11983
|
+
content: [{
|
|
11984
|
+
type: "text",
|
|
11985
|
+
text: `Direct path: ${args.from} --${directEdge.callType}--> ${args.to}${location} (edge is ${directEdge.isResolved ? "resolved" : "unresolved"}).`
|
|
11986
|
+
}]
|
|
11987
|
+
};
|
|
11988
|
+
}
|
|
11989
|
+
return { content: [{ type: "text", text: formatCallGraphPath(args.from, args.to, path27) }] };
|
|
11990
|
+
}
|
|
11991
|
+
if (args.symbol) {
|
|
11992
|
+
const results2 = await implementationLookup(runtime.projectRoot, runtime.host, args.symbol, {
|
|
11993
|
+
limit: args.limit ?? 10,
|
|
11994
|
+
fileType: args.fileType,
|
|
11995
|
+
directory: args.directory
|
|
11996
|
+
});
|
|
11997
|
+
return { content: [{ type: "text", text: formatDefinitionLookup(results2, args.symbol) }] };
|
|
11998
|
+
}
|
|
11999
|
+
const results = await searchCodebase(runtime.projectRoot, runtime.host, args.query, {
|
|
12000
|
+
limit: args.limit ?? 10,
|
|
12001
|
+
fileType: args.fileType,
|
|
12002
|
+
directory: args.directory,
|
|
12003
|
+
metadataOnly: true
|
|
12004
|
+
});
|
|
12005
|
+
if (results.length === 0) {
|
|
12006
|
+
return { content: [{ type: "text", text: "No matching code found. Try a different query or run index_codebase first." }] };
|
|
12007
|
+
}
|
|
12008
|
+
return {
|
|
12009
|
+
content: [{
|
|
12010
|
+
type: "text",
|
|
12011
|
+
text: `Found ${results.length} locations for "${args.query}":
|
|
12012
|
+
|
|
12013
|
+
${formatCodebasePeek(results)}
|
|
12014
|
+
|
|
12015
|
+
Use implementation_lookup for an authoritative definition, or call call_graph/call_graph_path once you have a symbol.`
|
|
12016
|
+
}]
|
|
12017
|
+
};
|
|
12018
|
+
}
|
|
12019
|
+
);
|
|
11943
12020
|
server.tool(
|
|
11944
12021
|
"codebase_search",
|
|
11945
|
-
"
|
|
12022
|
+
"FULL-CONTENT semantic retrieval. Use after codebase_peek when you need implementation text, not as the default first step. For exact identifiers or exhaustive matches use grep instead.",
|
|
11946
12023
|
{
|
|
11947
12024
|
query: z2.string().describe("Natural language description of what code you're looking for. Describe behavior, not syntax."),
|
|
11948
|
-
limit: z2.number().optional().default(5).describe("Maximum number of results to return"),
|
|
11949
|
-
fileType: z2.string().optional().describe("Filter by file extension (e.g., 'ts', 'py', 'rs')"),
|
|
11950
|
-
directory: z2.string().optional().describe("Filter by directory path (e.g., 'src/utils', 'lib')"),
|
|
11951
|
-
chunkType: z2.enum(CHUNK_TYPE_ENUM).optional().describe("Filter by code chunk type"),
|
|
11952
|
-
contextLines: z2.number().optional().describe("Number of extra lines to include before/after each match (default: 0)"),
|
|
11953
|
-
blameAuthor: z2.string().optional().describe("Filter by git blame author name or email"),
|
|
11954
|
-
blameSha: z2.string().optional().describe("Filter by git blame commit SHA or prefix"),
|
|
11955
|
-
blameSince: z2.string().optional().describe("Filter to chunks last changed on or after this date")
|
|
12025
|
+
limit: allowNullAsUndefined(z2.number().optional().default(5)).describe("Maximum number of results to return"),
|
|
12026
|
+
fileType: allowNullAsUndefined(z2.string().optional()).describe("Filter by file extension (e.g., 'ts', 'py', 'rs')"),
|
|
12027
|
+
directory: allowNullAsUndefined(z2.string().optional()).describe("Filter by directory path (e.g., 'src/utils', 'lib')"),
|
|
12028
|
+
chunkType: allowNullAsUndefined(z2.enum(CHUNK_TYPE_ENUM).optional()).describe("Filter by code chunk type"),
|
|
12029
|
+
contextLines: allowNullAsUndefined(z2.number().optional()).describe("Number of extra lines to include before/after each match (default: 0)"),
|
|
12030
|
+
blameAuthor: allowNullAsUndefined(z2.string().optional()).describe("Filter by git blame author name or email"),
|
|
12031
|
+
blameSha: allowNullAsUndefined(z2.string().optional()).describe("Filter by git blame commit SHA or prefix"),
|
|
12032
|
+
blameSince: allowNullAsUndefined(z2.string().optional()).describe("Filter to chunks last changed on or after this date")
|
|
11956
12033
|
},
|
|
11957
12034
|
async (args) => {
|
|
11958
12035
|
const results = await searchCodebase(runtime.projectRoot, runtime.host, args.query, {
|
|
@@ -11975,16 +12052,16 @@ ${formatSearchResults(results, "score")}` }] };
|
|
|
11975
12052
|
);
|
|
11976
12053
|
server.tool(
|
|
11977
12054
|
"codebase_peek",
|
|
11978
|
-
"
|
|
12055
|
+
"DIRECT LOW-TOKEN semantic location lookup for unfamiliar-code discovery. Prefer codebase_context when the request may involve definitions or graph navigation; use this specialized tool when you only need conceptual locations.",
|
|
11979
12056
|
{
|
|
11980
12057
|
query: z2.string().describe("Natural language description of what code you're looking for."),
|
|
11981
|
-
limit: z2.number().optional().default(10).describe("Maximum number of results to return"),
|
|
11982
|
-
fileType: z2.string().optional().describe("Filter by file extension (e.g., 'ts', 'py', 'rs')"),
|
|
11983
|
-
directory: z2.string().optional().describe("Filter by directory path (e.g., 'src/utils', 'lib')"),
|
|
11984
|
-
chunkType: z2.enum(CHUNK_TYPE_ENUM).optional().describe("Filter by code chunk type"),
|
|
11985
|
-
blameAuthor: z2.string().optional().describe("Filter by git blame author name or email"),
|
|
11986
|
-
blameSha: z2.string().optional().describe("Filter by git blame commit SHA or prefix"),
|
|
11987
|
-
blameSince: z2.string().optional().describe("Filter to chunks last changed on or after this date")
|
|
12058
|
+
limit: allowNullAsUndefined(z2.number().optional().default(10)).describe("Maximum number of results to return"),
|
|
12059
|
+
fileType: allowNullAsUndefined(z2.string().optional()).describe("Filter by file extension (e.g., 'ts', 'py', 'rs')"),
|
|
12060
|
+
directory: allowNullAsUndefined(z2.string().optional()).describe("Filter by directory path (e.g., 'src/utils', 'lib')"),
|
|
12061
|
+
chunkType: allowNullAsUndefined(z2.enum(CHUNK_TYPE_ENUM).optional()).describe("Filter by code chunk type"),
|
|
12062
|
+
blameAuthor: allowNullAsUndefined(z2.string().optional()).describe("Filter by git blame author name or email"),
|
|
12063
|
+
blameSha: allowNullAsUndefined(z2.string().optional()).describe("Filter by git blame commit SHA or prefix"),
|
|
12064
|
+
blameSince: allowNullAsUndefined(z2.string().optional()).describe("Filter to chunks last changed on or after this date")
|
|
11988
12065
|
},
|
|
11989
12066
|
async (args) => {
|
|
11990
12067
|
const results = await searchCodebase(runtime.projectRoot, runtime.host, args.query, {
|
|
@@ -12009,11 +12086,11 @@ Use Read tool to examine specific files.` }] };
|
|
|
12009
12086
|
);
|
|
12010
12087
|
server.tool(
|
|
12011
12088
|
"index_codebase",
|
|
12012
|
-
"
|
|
12089
|
+
"Create or refresh the semantic index. Call index_status first when readiness is unknown, then use this tool only if the index is missing, stale, or incompatible. Incremental by default; force=true rebuilds everything.",
|
|
12013
12090
|
{
|
|
12014
|
-
force: z2.boolean().optional().default(false).describe("Force reindex even if already indexed"),
|
|
12015
|
-
estimateOnly: z2.boolean().optional().default(false).describe("Only show cost estimate without indexing"),
|
|
12016
|
-
verbose: z2.boolean().optional().default(false).describe("Show detailed info about skipped files and parsing failures")
|
|
12091
|
+
force: allowNullAsUndefined(z2.boolean().optional().default(false)).describe("Force reindex even if already indexed"),
|
|
12092
|
+
estimateOnly: allowNullAsUndefined(z2.boolean().optional().default(false)).describe("Only show cost estimate without indexing"),
|
|
12093
|
+
verbose: allowNullAsUndefined(z2.boolean().optional().default(false)).describe("Show detailed info about skipped files and parsing failures")
|
|
12017
12094
|
},
|
|
12018
12095
|
async (args) => {
|
|
12019
12096
|
const result = await runIndexCodebase(runtime.projectRoot, runtime.host, args);
|
|
@@ -12028,7 +12105,7 @@ Use Read tool to examine specific files.` }] };
|
|
|
12028
12105
|
);
|
|
12029
12106
|
server.tool(
|
|
12030
12107
|
"index_status",
|
|
12031
|
-
"
|
|
12108
|
+
"START HERE once per repository task when index readiness or freshness is unknown. Reports whether semantic retrieval is ready, chunk counts, compatibility, and the embedding provider. If ready, continue with codebase_peek or implementation_lookup; otherwise run index_codebase.",
|
|
12032
12109
|
{},
|
|
12033
12110
|
async () => {
|
|
12034
12111
|
const status = await getIndexStatus(runtime.projectRoot, runtime.host);
|
|
@@ -12060,9 +12137,13 @@ Use Read tool to examine specific files.` }] };
|
|
|
12060
12137
|
"index_logs",
|
|
12061
12138
|
"Get recent debug logs from the codebase indexer. Requires debug.enabled=true in config.",
|
|
12062
12139
|
{
|
|
12063
|
-
limit: z2.number().optional().default(20).describe("Maximum number of log entries to return"),
|
|
12064
|
-
category:
|
|
12065
|
-
|
|
12140
|
+
limit: allowNullAsUndefined(z2.number().optional().default(20)).describe("Maximum number of log entries to return"),
|
|
12141
|
+
category: allowNullAsUndefined(
|
|
12142
|
+
z2.enum(["search", "embedding", "cache", "gc", "branch", "general"]).optional()
|
|
12143
|
+
).describe("Filter by log category"),
|
|
12144
|
+
level: allowNullAsUndefined(
|
|
12145
|
+
z2.enum(["error", "warn", "info", "debug"]).optional()
|
|
12146
|
+
).describe("Filter by minimum log level")
|
|
12066
12147
|
},
|
|
12067
12148
|
async (args) => {
|
|
12068
12149
|
const result = await getIndexLogs(runtime.projectRoot, runtime.host, args);
|
|
@@ -12071,14 +12152,14 @@ Use Read tool to examine specific files.` }] };
|
|
|
12071
12152
|
);
|
|
12072
12153
|
server.tool(
|
|
12073
12154
|
"find_similar",
|
|
12074
|
-
"
|
|
12155
|
+
"Use when you already have a code snippet and need analogous implementations, duplicates, patterns, or refactoring candidates. For a natural-language concept without example code, start with codebase_peek instead.",
|
|
12075
12156
|
{
|
|
12076
12157
|
code: z2.string().describe("The code snippet to find similar code for"),
|
|
12077
|
-
limit: z2.number().optional().default(10).describe("Maximum number of results to return"),
|
|
12078
|
-
fileType: z2.string().optional().describe("Filter by file extension (e.g., 'ts', 'py', 'rs')"),
|
|
12079
|
-
directory: z2.string().optional().describe("Filter by directory path (e.g., 'src/utils', 'lib')"),
|
|
12080
|
-
chunkType: z2.enum(CHUNK_TYPE_ENUM).optional().describe("Filter by code chunk type"),
|
|
12081
|
-
excludeFile: z2.string().optional().describe("Exclude results from this file path")
|
|
12158
|
+
limit: allowNullAsUndefined(z2.number().optional().default(10)).describe("Maximum number of results to return"),
|
|
12159
|
+
fileType: allowNullAsUndefined(z2.string().optional()).describe("Filter by file extension (e.g., 'ts', 'py', 'rs')"),
|
|
12160
|
+
directory: allowNullAsUndefined(z2.string().optional()).describe("Filter by directory path (e.g., 'src/utils', 'lib')"),
|
|
12161
|
+
chunkType: allowNullAsUndefined(z2.enum(CHUNK_TYPE_ENUM).optional()).describe("Filter by code chunk type"),
|
|
12162
|
+
excludeFile: allowNullAsUndefined(z2.string().optional()).describe("Exclude results from this file path")
|
|
12082
12163
|
},
|
|
12083
12164
|
async (args) => {
|
|
12084
12165
|
const results = await findSimilarCode(runtime.projectRoot, runtime.host, args.code, {
|
|
@@ -12098,12 +12179,12 @@ ${formatSearchResults(results)}` }] };
|
|
|
12098
12179
|
);
|
|
12099
12180
|
server.tool(
|
|
12100
12181
|
"implementation_lookup",
|
|
12101
|
-
"
|
|
12182
|
+
"FIRST TOOL only for known-symbol definition questions. Returns authoritative source locations and prefers implementations over tests, docs, examples, and fixtures. Do not use for callers, callees, dependency paths, or code flow; use codebase_context with direction or from/to for those questions.",
|
|
12102
12183
|
{
|
|
12103
12184
|
query: z2.string().describe("Symbol name or natural language description (e.g., 'validateToken', 'where is the payment handler defined')"),
|
|
12104
|
-
limit: z2.number().optional().default(5).describe("Maximum number of results"),
|
|
12105
|
-
fileType: z2.string().optional().describe("Filter by file extension (e.g., 'ts', 'py')"),
|
|
12106
|
-
directory: z2.string().optional().describe("Filter by directory path (e.g., 'src/utils')")
|
|
12185
|
+
limit: allowNullAsUndefined(z2.number().optional().default(5)).describe("Maximum number of results"),
|
|
12186
|
+
fileType: allowNullAsUndefined(z2.string().optional()).describe("Filter by file extension (e.g., 'ts', 'py')"),
|
|
12187
|
+
directory: allowNullAsUndefined(z2.string().optional()).describe("Filter by directory path (e.g., 'src/utils')")
|
|
12107
12188
|
},
|
|
12108
12189
|
async (args) => {
|
|
12109
12190
|
const results = await implementationLookup(runtime.projectRoot, runtime.host, args.query, {
|
|
@@ -12116,12 +12197,16 @@ ${formatSearchResults(results)}` }] };
|
|
|
12116
12197
|
);
|
|
12117
12198
|
server.tool(
|
|
12118
12199
|
"call_graph",
|
|
12119
|
-
"
|
|
12200
|
+
"Use after identifying a symbol to find its direct callers or callees and understand code flow. Use implementation_lookup first if the symbol or definition is still ambiguous. Supports relationship types: Call, MethodCall, Constructor, Import, Inherits, Implements.",
|
|
12120
12201
|
{
|
|
12121
12202
|
name: z2.string().describe("Function or method name to query"),
|
|
12122
|
-
direction:
|
|
12123
|
-
|
|
12124
|
-
|
|
12203
|
+
direction: allowNullAsUndefined(
|
|
12204
|
+
z2.enum(["callers", "callees"]).default("callers")
|
|
12205
|
+
).describe("Direction: 'callers' finds who calls this function, 'callees' finds what this function calls"),
|
|
12206
|
+
symbolId: allowNullAsUndefined(z2.string().optional()).describe("Symbol ID (required for 'callees' direction)"),
|
|
12207
|
+
relationshipType: allowNullAsUndefined(
|
|
12208
|
+
z2.enum(["Call", "MethodCall", "Constructor", "Import", "Inherits", "Implements"]).optional()
|
|
12209
|
+
).describe("Filter by relationship type. Omit to show all.")
|
|
12125
12210
|
},
|
|
12126
12211
|
async (args) => {
|
|
12127
12212
|
if (args.direction === "callees") {
|
|
@@ -12137,11 +12222,11 @@ ${formatSearchResults(results)}` }] };
|
|
|
12137
12222
|
);
|
|
12138
12223
|
server.tool(
|
|
12139
12224
|
"call_graph_path",
|
|
12140
|
-
"
|
|
12225
|
+
"Use after identifying both endpoint symbols to find the shortest known call path between them. Use codebase_peek or implementation_lookup first when either endpoint is unknown.",
|
|
12141
12226
|
{
|
|
12142
12227
|
from: z2.string().describe("Source function/method name (starting point)"),
|
|
12143
12228
|
to: z2.string().describe("Target function/method name (destination)"),
|
|
12144
|
-
maxDepth: z2.number().optional().default(10).describe("Maximum traversal depth (default: 10)")
|
|
12229
|
+
maxDepth: allowNullAsUndefined(z2.number().optional().default(10)).describe("Maximum traversal depth (default: 10)")
|
|
12145
12230
|
},
|
|
12146
12231
|
async (args) => {
|
|
12147
12232
|
const path27 = await getCallGraphPath(runtime.projectRoot, runtime.host, args.from, args.to, args.maxDepth);
|
|
@@ -12150,14 +12235,16 @@ ${formatSearchResults(results)}` }] };
|
|
|
12150
12235
|
);
|
|
12151
12236
|
server.tool(
|
|
12152
12237
|
"pr_impact",
|
|
12153
|
-
"
|
|
12238
|
+
"FIRST TOOL for pull-request or branch blast-radius questions. Analyzes changed files, affected symbols, transitive dependencies, communities, hub nodes, conflicts, and risk before merging.",
|
|
12154
12239
|
{
|
|
12155
|
-
pr: z2.number().optional().describe("Pull request number to analyze"),
|
|
12156
|
-
branch: z2.string().optional().describe("Branch name to analyze (defaults to current branch)"),
|
|
12157
|
-
maxDepth: z2.number().optional().default(5).describe("Maximum traversal depth for transitive callers (default: 5)"),
|
|
12158
|
-
hubThreshold: z2.number().optional().default(10).describe("Minimum caller count to flag a symbol as a hub node (default: 10)"),
|
|
12159
|
-
checkConflicts: z2.boolean().optional().default(false).describe("Check for conflicting open PRs touching the same communities (default: false)"),
|
|
12160
|
-
direction:
|
|
12240
|
+
pr: allowNullAsUndefined(z2.number().optional()).describe("Pull request number to analyze"),
|
|
12241
|
+
branch: allowNullAsUndefined(z2.string().optional()).describe("Branch name to analyze (defaults to current branch)"),
|
|
12242
|
+
maxDepth: allowNullAsUndefined(z2.number().optional().default(5)).describe("Maximum traversal depth for transitive callers (default: 5)"),
|
|
12243
|
+
hubThreshold: allowNullAsUndefined(z2.number().optional().default(10)).describe("Minimum caller count to flag a symbol as a hub node (default: 10)"),
|
|
12244
|
+
checkConflicts: allowNullAsUndefined(z2.boolean().optional().default(false)).describe("Check for conflicting open PRs touching the same communities (default: false)"),
|
|
12245
|
+
direction: allowNullAsUndefined(
|
|
12246
|
+
z2.enum(["callers", "callees", "both"]).optional().default("both")
|
|
12247
|
+
).describe("Call-graph traversal direction: 'callers' for upstream, 'callees' for downstream, 'both' for union (default: both)")
|
|
12161
12248
|
},
|
|
12162
12249
|
async (args) => {
|
|
12163
12250
|
try {
|
|
@@ -12179,6 +12266,10 @@ ${formatSearchResults(results)}` }] };
|
|
|
12179
12266
|
}
|
|
12180
12267
|
|
|
12181
12268
|
// src/mcp-server.ts
|
|
12269
|
+
function getServerInstructions(host) {
|
|
12270
|
+
const hostText = `host ${host}`;
|
|
12271
|
+
return `This MCP server is the preferred codebase-understanding path for ${hostText}. Start a repository task with index_status when index readiness or freshness is unknown. Use codebase_context as the preferred first entry point because it returns low-token locations first and routes to definitions or call-graph helpers when symbol intent is present. Use codebase_peek for direct conceptual location lookup, implementation_lookup for known-symbol definition questions, and codebase_search only when full semantic code content is needed. For exact identifiers or exhaustive matches, use grep. After identifying symbols, use call_graph or call_graph_path to trace dependencies. If the index is unavailable, run index_codebase, then retry the retrieval tool.`;
|
|
12272
|
+
}
|
|
12182
12273
|
function getPackageVersion() {
|
|
12183
12274
|
const raw = JSON.parse(readFileSync11(new URL("../package.json", import.meta.url), "utf-8"));
|
|
12184
12275
|
if (raw && typeof raw === "object" && "version" in raw && typeof raw.version === "string") {
|
|
@@ -12190,6 +12281,8 @@ function createMcpServer(projectRoot, config, host = "opencode") {
|
|
|
12190
12281
|
const server = new McpServer({
|
|
12191
12282
|
name: "opencode-codebase-index",
|
|
12192
12283
|
version: getPackageVersion()
|
|
12284
|
+
}, {
|
|
12285
|
+
instructions: getServerInstructions(host)
|
|
12193
12286
|
});
|
|
12194
12287
|
initializeTools(projectRoot, config, host);
|
|
12195
12288
|
registerMcpTools(server, {
|