opencode-codebase-index 0.9.0 → 0.11.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/README.md +4 -2
- package/dist/cli.cjs +78 -28
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +78 -28
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +244 -113
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +244 -113
- package/dist/index.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 +3 -2
package/README.md
CHANGED
|
@@ -575,7 +575,8 @@ Zero-config by default (uses `auto` mode). Customize in `.opencode/codebase-inde
|
|
|
575
575
|
"rrfK": 60, // RRF smoothing constant
|
|
576
576
|
"rerankTopN": 20, // Deterministic rerank depth
|
|
577
577
|
"contextLines": 0, // Extra lines before/after match
|
|
578
|
-
"routingHints": true
|
|
578
|
+
"routingHints": true, // Runtime nudges for local discovery/definition queries
|
|
579
|
+
"routingHintRole": "system" // system | developer (message role used for hints)
|
|
579
580
|
},
|
|
580
581
|
"reranker": {
|
|
581
582
|
"enabled": false,
|
|
@@ -646,6 +647,7 @@ String values in `codebase-index.json` can reference environment variables with
|
|
|
646
647
|
| `rerankTopN` | `20` | Deterministic rerank depth cap. Applies lightweight name/path/chunk-type rerank to top-N only |
|
|
647
648
|
| `contextLines` | `0` | Extra lines to include before/after each match |
|
|
648
649
|
| `routingHints` | `true` | Inject lightweight runtime hints for local conceptual discovery and definition lookups. Set to `false` to disable plugin-side routing nudges. |
|
|
650
|
+
| `routingHintRole` | `"system"` | Message role used when injecting routing hints: `"system"` (default) or `"developer"`. |
|
|
649
651
|
| **reranker** | | Optional second-stage model reranker for the top candidate pool |
|
|
650
652
|
| `enabled` | `false` | Turn external reranking on/off |
|
|
651
653
|
| `provider` | `"custom"` | Hosted shortcuts: `cohere`, `jina`, or `custom` |
|
|
@@ -676,7 +678,7 @@ These warnings improve observability but do **not** change the recovery behavior
|
|
|
676
678
|
### Retrieval ranking behavior
|
|
677
679
|
|
|
678
680
|
- `codebase_search` and `codebase_peek` use the hybrid path: semantic + keyword retrieval → fusion (`fusionStrategy`) → deterministic rerank (`rerankTopN`) → optional external reranker (`reranker`) → filtering.
|
|
679
|
-
- When `search.routingHints` is enabled (default), the plugin adds tiny per-turn runtime hints for local conceptual discovery and definition queries. Conceptual discovery is nudged toward `codebase_peek` / `codebase_search`, while definition questions are nudged toward `implementation_lookup`. Exact identifier and unrelated operational tasks are left alone.
|
|
681
|
+
- When `search.routingHints` is enabled (default), the plugin adds tiny per-turn runtime hints for local conceptual discovery and definition queries. Conceptual discovery is nudged toward `codebase_peek` / `codebase_search`, while definition questions are nudged toward `implementation_lookup`. Exact identifier and unrelated operational tasks are left alone. Set `search.routingHintRole` to `"developer"` if your client/runtime expects developer-role guidance instead of system-role guidance.
|
|
680
682
|
- `find_similar` stays semantic-only: semantic retrieval + deterministic rerank only (no keyword retrieval, no RRF).
|
|
681
683
|
- For compatibility rollbacks, set `search.fusionStrategy` to `"weighted"` to use the legacy weighted fusion path.
|
|
682
684
|
- When enabled, the external reranker sees path metadata plus a bounded on-disk code snippet for each candidate so it can distinguish real implementations from docs/tests more reliably.
|
package/dist/cli.cjs
CHANGED
|
@@ -8,7 +8,11 @@ var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
|
8
8
|
var __getProtoOf = Object.getPrototypeOf;
|
|
9
9
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
10
10
|
var __commonJS = (cb, mod) => function __require() {
|
|
11
|
-
|
|
11
|
+
try {
|
|
12
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
13
|
+
} catch (e) {
|
|
14
|
+
throw mod = 0, e;
|
|
15
|
+
}
|
|
12
16
|
};
|
|
13
17
|
var __copyProps = (to, from, except, desc) => {
|
|
14
18
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
@@ -794,7 +798,8 @@ function getDefaultSearchConfig() {
|
|
|
794
798
|
rrfK: 60,
|
|
795
799
|
rerankTopN: 20,
|
|
796
800
|
contextLines: 0,
|
|
797
|
-
routingHints: true
|
|
801
|
+
routingHints: true,
|
|
802
|
+
routingHintRole: "system"
|
|
798
803
|
};
|
|
799
804
|
}
|
|
800
805
|
function getDefaultRerankerBaseUrl(provider) {
|
|
@@ -915,7 +920,8 @@ function parseConfig(raw) {
|
|
|
915
920
|
rrfK: typeof rawSearch.rrfK === "number" ? Math.max(1, Math.floor(rawSearch.rrfK)) : defaultSearch.rrfK,
|
|
916
921
|
rerankTopN: typeof rawSearch.rerankTopN === "number" ? Math.min(200, Math.max(0, Math.floor(rawSearch.rerankTopN))) : defaultSearch.rerankTopN,
|
|
917
922
|
contextLines: typeof rawSearch.contextLines === "number" ? Math.min(50, Math.max(0, rawSearch.contextLines)) : defaultSearch.contextLines,
|
|
918
|
-
routingHints: typeof rawSearch.routingHints === "boolean" ? rawSearch.routingHints : defaultSearch.routingHints
|
|
923
|
+
routingHints: typeof rawSearch.routingHints === "boolean" ? rawSearch.routingHints : defaultSearch.routingHints,
|
|
924
|
+
routingHintRole: rawSearch.routingHintRole === "developer" || rawSearch.routingHintRole === "system" ? rawSearch.routingHintRole : defaultSearch.routingHintRole
|
|
919
925
|
};
|
|
920
926
|
const rawDebug = input.debug && typeof input.debug === "object" ? input.debug : {};
|
|
921
927
|
const debug = {
|
|
@@ -2497,6 +2503,8 @@ var BaseEmbeddingProvider = class {
|
|
|
2497
2503
|
this.credentials = credentials;
|
|
2498
2504
|
this.modelInfo = modelInfo;
|
|
2499
2505
|
}
|
|
2506
|
+
credentials;
|
|
2507
|
+
modelInfo;
|
|
2500
2508
|
async embedQuery(query) {
|
|
2501
2509
|
const result = await this.embedBatch([query]);
|
|
2502
2510
|
return {
|
|
@@ -4237,17 +4245,17 @@ var Database = class {
|
|
|
4237
4245
|
if (edges.length === 0) return;
|
|
4238
4246
|
this.inner.upsertCallEdgesBatch(edges);
|
|
4239
4247
|
}
|
|
4240
|
-
getCallers(targetName, branch) {
|
|
4248
|
+
getCallers(targetName, branch, callTypeFilter) {
|
|
4241
4249
|
this.throwIfClosed();
|
|
4242
|
-
return this.inner.getCallers(targetName, branch);
|
|
4250
|
+
return this.inner.getCallers(targetName, branch, callTypeFilter ?? null);
|
|
4243
4251
|
}
|
|
4244
|
-
getCallersWithContext(targetName, branch) {
|
|
4252
|
+
getCallersWithContext(targetName, branch, callTypeFilter) {
|
|
4245
4253
|
this.throwIfClosed();
|
|
4246
|
-
return this.inner.getCallersWithContext(targetName, branch);
|
|
4254
|
+
return this.inner.getCallersWithContext(targetName, branch, callTypeFilter ?? null);
|
|
4247
4255
|
}
|
|
4248
|
-
getCallees(symbolId, branch) {
|
|
4256
|
+
getCallees(symbolId, branch, callTypeFilter) {
|
|
4249
4257
|
this.throwIfClosed();
|
|
4250
|
-
return this.inner.getCallees(symbolId, branch);
|
|
4258
|
+
return this.inner.getCallees(symbolId, branch, callTypeFilter ?? null);
|
|
4251
4259
|
}
|
|
4252
4260
|
deleteCallEdgesByFile(filePath) {
|
|
4253
4261
|
this.throwIfClosed();
|
|
@@ -4257,6 +4265,10 @@ var Database = class {
|
|
|
4257
4265
|
this.throwIfClosed();
|
|
4258
4266
|
this.inner.resolveCallEdge(edgeId, toSymbolId);
|
|
4259
4267
|
}
|
|
4268
|
+
findShortestPath(fromName, toName, branch, maxDepth) {
|
|
4269
|
+
this.throwIfClosed();
|
|
4270
|
+
return this.inner.findShortestPath(fromName, toName, branch, maxDepth ?? null);
|
|
4271
|
+
}
|
|
4260
4272
|
addSymbolsToBranch(branch, symbolIds) {
|
|
4261
4273
|
this.throwIfClosed();
|
|
4262
4274
|
this.inner.addSymbolsToBranch(branch, symbolIds);
|
|
@@ -7055,6 +7067,7 @@ var Indexer = class {
|
|
|
7055
7067
|
targetName: site.calleeName,
|
|
7056
7068
|
toSymbolId: void 0,
|
|
7057
7069
|
callType: site.callType,
|
|
7070
|
+
confidence: site.confidence,
|
|
7058
7071
|
line: site.line,
|
|
7059
7072
|
col: site.column,
|
|
7060
7073
|
isResolved: false
|
|
@@ -8174,12 +8187,12 @@ var Indexer = class {
|
|
|
8174
8187
|
})
|
|
8175
8188
|
);
|
|
8176
8189
|
}
|
|
8177
|
-
async getCallers(targetName) {
|
|
8190
|
+
async getCallers(targetName, callTypeFilter) {
|
|
8178
8191
|
const { database } = await this.ensureInitialized();
|
|
8179
8192
|
const seen = /* @__PURE__ */ new Set();
|
|
8180
8193
|
const results = [];
|
|
8181
8194
|
for (const branchKey of this.getBranchCatalogKeys()) {
|
|
8182
|
-
for (const edge of database.getCallersWithContext(targetName, branchKey)) {
|
|
8195
|
+
for (const edge of database.getCallersWithContext(targetName, branchKey, callTypeFilter)) {
|
|
8183
8196
|
if (!seen.has(edge.id)) {
|
|
8184
8197
|
seen.add(edge.id);
|
|
8185
8198
|
results.push(edge);
|
|
@@ -8188,12 +8201,12 @@ var Indexer = class {
|
|
|
8188
8201
|
}
|
|
8189
8202
|
return results;
|
|
8190
8203
|
}
|
|
8191
|
-
async getCallees(symbolId) {
|
|
8204
|
+
async getCallees(symbolId, callTypeFilter) {
|
|
8192
8205
|
const { database } = await this.ensureInitialized();
|
|
8193
8206
|
const seen = /* @__PURE__ */ new Set();
|
|
8194
8207
|
const results = [];
|
|
8195
8208
|
for (const branchKey of this.getBranchCatalogKeys()) {
|
|
8196
|
-
for (const edge of database.getCallees(symbolId, branchKey)) {
|
|
8209
|
+
for (const edge of database.getCallees(symbolId, branchKey, callTypeFilter)) {
|
|
8197
8210
|
if (!seen.has(edge.id)) {
|
|
8198
8211
|
seen.add(edge.id);
|
|
8199
8212
|
results.push(edge);
|
|
@@ -8202,6 +8215,17 @@ var Indexer = class {
|
|
|
8202
8215
|
}
|
|
8203
8216
|
return results;
|
|
8204
8217
|
}
|
|
8218
|
+
async findCallPath(fromName, toName, maxDepth) {
|
|
8219
|
+
const { database } = await this.ensureInitialized();
|
|
8220
|
+
let shortest = [];
|
|
8221
|
+
for (const branchKey of this.getBranchCatalogKeys()) {
|
|
8222
|
+
const path18 = database.findShortestPath(fromName, toName, branchKey, maxDepth);
|
|
8223
|
+
if (path18.length > 0 && (shortest.length === 0 || path18.length < shortest.length)) {
|
|
8224
|
+
shortest = path18;
|
|
8225
|
+
}
|
|
8226
|
+
}
|
|
8227
|
+
return shortest;
|
|
8228
|
+
}
|
|
8205
8229
|
async close() {
|
|
8206
8230
|
await this.database?.close();
|
|
8207
8231
|
this.database = null;
|
|
@@ -9977,11 +10001,12 @@ ${formatted.join("\n\n")}` }] };
|
|
|
9977
10001
|
);
|
|
9978
10002
|
server.tool(
|
|
9979
10003
|
"call_graph",
|
|
9980
|
-
"Query the call graph to find callers or callees of a function/method. Use to understand code flow and dependencies.",
|
|
10004
|
+
"Query the call graph to find callers or callees of a function/method. Use to understand code flow and dependencies. Supports relationship types: Call, MethodCall, Constructor, Import, Inherits, Implements.",
|
|
9981
10005
|
{
|
|
9982
10006
|
name: import_zod2.z.string().describe("Function or method name to query"),
|
|
9983
10007
|
direction: import_zod2.z.enum(["callers", "callees"]).default("callers").describe("Direction: 'callers' finds who calls this function, 'callees' finds what this function calls"),
|
|
9984
|
-
symbolId: import_zod2.z.string().optional().describe("Symbol ID (required for 'callees' direction)")
|
|
10008
|
+
symbolId: import_zod2.z.string().optional().describe("Symbol ID (required for 'callees' direction)"),
|
|
10009
|
+
relationshipType: import_zod2.z.enum(["Call", "MethodCall", "Constructor", "Import", "Inherits", "Implements"]).optional().describe("Filter by relationship type. Omit to show all.")
|
|
9985
10010
|
},
|
|
9986
10011
|
async (args) => {
|
|
9987
10012
|
await runtime.ensureInitialized();
|
|
@@ -9990,26 +10015,52 @@ ${formatted.join("\n\n")}` }] };
|
|
|
9990
10015
|
if (!args.symbolId) {
|
|
9991
10016
|
return { content: [{ type: "text", text: "Error: 'symbolId' is required when direction is 'callees'." }] };
|
|
9992
10017
|
}
|
|
9993
|
-
const callees = await indexer.getCallees(args.symbolId);
|
|
10018
|
+
const callees = await indexer.getCallees(args.symbolId, args.relationshipType);
|
|
9994
10019
|
if (callees.length === 0) {
|
|
9995
|
-
return { content: [{ type: "text", text: `No callees found for symbol ${args.symbolId}.` }] };
|
|
10020
|
+
return { content: [{ type: "text", text: `No callees found for symbol ${args.symbolId}${args.relationshipType ? ` with type ${args.relationshipType}` : ""}.` }] };
|
|
9996
10021
|
}
|
|
9997
|
-
const formatted2 = callees.map(
|
|
9998
|
-
|
|
9999
|
-
|
|
10022
|
+
const formatted2 = callees.map((e, i) => {
|
|
10023
|
+
const conf = e.confidence !== "Direct" ? ` [${e.confidence.toLowerCase()}]` : "";
|
|
10024
|
+
return `[${i + 1}] \u2192 ${e.targetName} (${e.callType})${conf} at line ${e.line}${e.isResolved ? ` [resolved: ${e.toSymbolId}]` : " [unresolved]"}`;
|
|
10025
|
+
});
|
|
10000
10026
|
return { content: [{ type: "text", text: `Callees (${callees.length}):
|
|
10001
10027
|
|
|
10002
10028
|
${formatted2.join("\n")}` }] };
|
|
10003
10029
|
}
|
|
10004
|
-
const callers = await indexer.getCallers(args.name);
|
|
10030
|
+
const callers = await indexer.getCallers(args.name, args.relationshipType);
|
|
10005
10031
|
if (callers.length === 0) {
|
|
10006
|
-
return { content: [{ type: "text", text: `No callers found for "${args.name}".` }] };
|
|
10032
|
+
return { content: [{ type: "text", text: `No callers found for "${args.name}"${args.relationshipType ? ` with type ${args.relationshipType}` : ""}.` }] };
|
|
10007
10033
|
}
|
|
10008
|
-
const formatted = callers.map(
|
|
10009
|
-
|
|
10010
|
-
|
|
10034
|
+
const formatted = callers.map((e, i) => {
|
|
10035
|
+
const conf = e.confidence !== "Direct" ? ` [${e.confidence.toLowerCase()}]` : "";
|
|
10036
|
+
return `[${i + 1}] \u2190 from ${e.fromSymbolName ?? "<unknown>"} in ${e.fromSymbolFilePath ?? "<unknown file>"} [${e.fromSymbolId}] (${e.callType})${conf} at line ${e.line}${e.isResolved ? " [resolved]" : " [unresolved]"}`;
|
|
10037
|
+
});
|
|
10011
10038
|
return { content: [{ type: "text", text: `"${args.name}" is called by ${callers.length} function(s):
|
|
10012
10039
|
|
|
10040
|
+
${formatted.join("\n")}` }] };
|
|
10041
|
+
}
|
|
10042
|
+
);
|
|
10043
|
+
server.tool(
|
|
10044
|
+
"call_graph_path",
|
|
10045
|
+
"Find the shortest connection path between two symbols in the call graph. Returns the chain of calls connecting them.",
|
|
10046
|
+
{
|
|
10047
|
+
from: import_zod2.z.string().describe("Source function/method name (starting point)"),
|
|
10048
|
+
to: import_zod2.z.string().describe("Target function/method name (destination)"),
|
|
10049
|
+
maxDepth: import_zod2.z.number().optional().default(10).describe("Maximum traversal depth (default: 10)")
|
|
10050
|
+
},
|
|
10051
|
+
async (args) => {
|
|
10052
|
+
await runtime.ensureInitialized();
|
|
10053
|
+
const indexer = runtime.getIndexer();
|
|
10054
|
+
const path18 = await indexer.findCallPath(args.from, args.to, args.maxDepth);
|
|
10055
|
+
if (path18.length === 0) {
|
|
10056
|
+
return { content: [{ type: "text", text: `No path found between "${args.from}" and "${args.to}". They may be in disconnected components, or the call graph index needs updating.` }] };
|
|
10057
|
+
}
|
|
10058
|
+
const formatted = path18.map((hop, i) => {
|
|
10059
|
+
const prefix = i === 0 ? "[start]" : `--${hop.callType}-->`;
|
|
10060
|
+
const location = hop.filePath ? ` (${hop.filePath}:${hop.line})` : "";
|
|
10061
|
+
return `${prefix} ${hop.symbolName}${location}`;
|
|
10062
|
+
});
|
|
10063
|
+
return { content: [{ type: "text", text: `Path (${path18.length} hops):
|
|
10013
10064
|
${formatted.join("\n")}` }] };
|
|
10014
10065
|
}
|
|
10015
10066
|
);
|
|
@@ -10088,9 +10139,8 @@ async function main() {
|
|
|
10088
10139
|
process.on("SIGINT", shutdown);
|
|
10089
10140
|
process.on("SIGTERM", shutdown);
|
|
10090
10141
|
}
|
|
10091
|
-
main().catch((
|
|
10092
|
-
|
|
10093
|
-
console.error(`Fatal: ${message}`);
|
|
10142
|
+
main().catch((_error) => {
|
|
10143
|
+
console.error("Fatal: failed to start MCP server (check config and network)");
|
|
10094
10144
|
process.exit(1);
|
|
10095
10145
|
});
|
|
10096
10146
|
//# sourceMappingURL=cli.cjs.map
|