grepmax 0.7.11 → 0.7.13
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/dist/commands/mcp.js
CHANGED
|
@@ -128,6 +128,10 @@ const TOOLS = [
|
|
|
128
128
|
type: "string",
|
|
129
129
|
description: "Search mode: 'default' (semantic only) or 'symbol' (semantic + call graph trace appended). Use 'symbol' when query is a function/class name.",
|
|
130
130
|
},
|
|
131
|
+
include_imports: {
|
|
132
|
+
type: "boolean",
|
|
133
|
+
description: "Prepend the file's import/require statements to each result. Deduped per file.",
|
|
134
|
+
},
|
|
131
135
|
},
|
|
132
136
|
required: ["query"],
|
|
133
137
|
},
|
|
@@ -186,6 +190,10 @@ const TOOLS = [
|
|
|
186
190
|
type: "number",
|
|
187
191
|
description: "Include N lines before/after chunk. Only with detail 'code' or 'full'. Max 20.",
|
|
188
192
|
},
|
|
193
|
+
include_imports: {
|
|
194
|
+
type: "boolean",
|
|
195
|
+
description: "Prepend file's import statements to each result.",
|
|
196
|
+
},
|
|
189
197
|
},
|
|
190
198
|
required: ["query"],
|
|
191
199
|
},
|
|
@@ -218,6 +226,10 @@ const TOOLS = [
|
|
|
218
226
|
type: "string",
|
|
219
227
|
description: "The function, method, or class name to trace (e.g. 'handleAuth')",
|
|
220
228
|
},
|
|
229
|
+
depth: {
|
|
230
|
+
type: "number",
|
|
231
|
+
description: "Traversal depth for callers (default 1, max 3). depth: 2 shows callers-of-callers.",
|
|
232
|
+
},
|
|
221
233
|
},
|
|
222
234
|
required: ["symbol"],
|
|
223
235
|
},
|
|
@@ -457,6 +469,49 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
457
469
|
child.unref();
|
|
458
470
|
console.log(`[MCP] Started background watcher for ${projectRoot}`);
|
|
459
471
|
}
|
|
472
|
+
// --- Utilities ---
|
|
473
|
+
function extractImports(filePath) {
|
|
474
|
+
try {
|
|
475
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
476
|
+
const lines = content.split("\n");
|
|
477
|
+
const importLines = [];
|
|
478
|
+
let inMultiLine = false;
|
|
479
|
+
for (const line of lines) {
|
|
480
|
+
const trimmed = line.trim();
|
|
481
|
+
if (inMultiLine) {
|
|
482
|
+
importLines.push(line);
|
|
483
|
+
if (trimmed === ")" || trimmed === ");")
|
|
484
|
+
inMultiLine = false;
|
|
485
|
+
continue;
|
|
486
|
+
}
|
|
487
|
+
if (!trimmed ||
|
|
488
|
+
trimmed.startsWith("//") ||
|
|
489
|
+
trimmed.startsWith("#") ||
|
|
490
|
+
trimmed.startsWith("*") ||
|
|
491
|
+
trimmed.startsWith("/*")) {
|
|
492
|
+
continue;
|
|
493
|
+
}
|
|
494
|
+
if (trimmed.startsWith("import ") ||
|
|
495
|
+
trimmed.startsWith("from ") ||
|
|
496
|
+
(trimmed.startsWith("const ") && trimmed.includes("require(")) ||
|
|
497
|
+
trimmed.startsWith("require(") ||
|
|
498
|
+
trimmed.startsWith("use ") ||
|
|
499
|
+
trimmed.startsWith("using ") ||
|
|
500
|
+
trimmed.startsWith("package ")) {
|
|
501
|
+
importLines.push(line);
|
|
502
|
+
if (trimmed.includes("(") && !trimmed.includes(")")) {
|
|
503
|
+
inMultiLine = true;
|
|
504
|
+
}
|
|
505
|
+
continue;
|
|
506
|
+
}
|
|
507
|
+
break;
|
|
508
|
+
}
|
|
509
|
+
return importLines.length > 0 ? importLines.join("\n") : "";
|
|
510
|
+
}
|
|
511
|
+
catch (_a) {
|
|
512
|
+
return "";
|
|
513
|
+
}
|
|
514
|
+
}
|
|
460
515
|
// --- Tool handlers ---
|
|
461
516
|
function handleSemanticSearch(args_1) {
|
|
462
517
|
return __awaiter(this, arguments, void 0, function* (args, searchAll = false) {
|
|
@@ -538,6 +593,8 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
538
593
|
const minScore = typeof args.min_score === "number" ? args.min_score : 0;
|
|
539
594
|
const maxPerFile = typeof args.max_per_file === "number" ? args.max_per_file : 0;
|
|
540
595
|
const detail = typeof args.detail === "string" ? args.detail : "pointer";
|
|
596
|
+
const includeImports = Boolean(args.include_imports);
|
|
597
|
+
const importCache = new Map();
|
|
541
598
|
let results = result.data.map((r) => {
|
|
542
599
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
543
600
|
const absPath = (_c = (_a = r.path) !== null && _a !== void 0 ? _a : (_b = r.metadata) === null || _b === void 0 ? void 0 : _b.path) !== null && _c !== void 0 ? _c : "";
|
|
@@ -603,10 +660,19 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
603
660
|
.join("\n");
|
|
604
661
|
}
|
|
605
662
|
}
|
|
606
|
-
|
|
663
|
+
let text = line1 +
|
|
607
664
|
(summaryStr ? `\n${summaryStr}` : "") +
|
|
608
665
|
(line2 ? `\n${line2}` : "") +
|
|
609
666
|
snippet;
|
|
667
|
+
if (includeImports && absPath) {
|
|
668
|
+
if (!importCache.has(absPath)) {
|
|
669
|
+
importCache.set(absPath, extractImports(absPath));
|
|
670
|
+
}
|
|
671
|
+
const imports = importCache.get(absPath);
|
|
672
|
+
if (imports) {
|
|
673
|
+
text = `imports:\n${imports}\n\n${text}`;
|
|
674
|
+
}
|
|
675
|
+
}
|
|
610
676
|
return {
|
|
611
677
|
absPath,
|
|
612
678
|
text,
|
|
@@ -799,20 +865,29 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
799
865
|
try {
|
|
800
866
|
const db = getVectorDb();
|
|
801
867
|
const builder = new graph_builder_1.GraphBuilder(db);
|
|
802
|
-
const
|
|
868
|
+
const depth = Math.min(Math.max(Number(args.depth) || 1, 1), 3);
|
|
869
|
+
const graph = yield builder.buildGraphMultiHop(symbol, depth);
|
|
803
870
|
if (!graph.center) {
|
|
804
871
|
return ok(`Symbol '${symbol}' not found in the index.`);
|
|
805
872
|
}
|
|
806
873
|
const lines = [];
|
|
807
874
|
// Center
|
|
808
875
|
lines.push(`${graph.center.symbol} [${graph.center.role}] ${graph.center.file}:${graph.center.line + 1}`);
|
|
809
|
-
// Callers
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
876
|
+
// Callers (recursive tree)
|
|
877
|
+
function formatCallerTree(trees, indent) {
|
|
878
|
+
for (const t of trees) {
|
|
879
|
+
const rel = t.node.file.startsWith(projectRoot)
|
|
880
|
+
? t.node.file.slice(projectRoot.length + 1)
|
|
881
|
+
: t.node.file;
|
|
882
|
+
const pad = " ".repeat(indent);
|
|
883
|
+
lines.push(`${pad}<- ${t.node.symbol} ${rel}:${t.node.line + 1}`);
|
|
884
|
+
formatCallerTree(t.callers, indent + 1);
|
|
814
885
|
}
|
|
815
886
|
}
|
|
887
|
+
if (graph.callerTree.length > 0) {
|
|
888
|
+
lines.push("Callers:");
|
|
889
|
+
formatCallerTree(graph.callerTree, 1);
|
|
890
|
+
}
|
|
816
891
|
else {
|
|
817
892
|
lines.push("Callers: none");
|
|
818
893
|
}
|
|
@@ -105,6 +105,40 @@ class GraphBuilder {
|
|
|
105
105
|
return { center, callers, callees: calleeNodes };
|
|
106
106
|
});
|
|
107
107
|
}
|
|
108
|
+
buildGraphMultiHop(symbol, depth) {
|
|
109
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
110
|
+
const graph = yield this.buildGraph(symbol);
|
|
111
|
+
if (depth <= 1 || !graph.center) {
|
|
112
|
+
return {
|
|
113
|
+
center: graph.center,
|
|
114
|
+
callerTree: graph.callers.map((c) => ({ node: c, callers: [] })),
|
|
115
|
+
callees: graph.callees,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
const visited = new Set([symbol]);
|
|
119
|
+
const callerTree = yield this.expandCallers(graph.callers, depth - 1, visited);
|
|
120
|
+
return { center: graph.center, callerTree, callees: graph.callees };
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
expandCallers(callers, remainingDepth, visited) {
|
|
124
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
125
|
+
const trees = [];
|
|
126
|
+
for (const caller of callers) {
|
|
127
|
+
if (visited.has(caller.symbol)) {
|
|
128
|
+
trees.push({ node: caller, callers: [] });
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
visited.add(caller.symbol);
|
|
132
|
+
let subCallers = [];
|
|
133
|
+
if (remainingDepth > 0) {
|
|
134
|
+
const upstreamCallers = yield this.getCallers(caller.symbol);
|
|
135
|
+
subCallers = yield this.expandCallers(upstreamCallers, remainingDepth - 1, visited);
|
|
136
|
+
}
|
|
137
|
+
trees.push({ node: caller, callers: subCallers });
|
|
138
|
+
}
|
|
139
|
+
return trees;
|
|
140
|
+
});
|
|
141
|
+
}
|
|
108
142
|
mapRowToNode(row, targetSymbol, type) {
|
|
109
143
|
// Helper to convert Arrow Vector to array if needed
|
|
110
144
|
const toArray = (val) => {
|
package/package.json
CHANGED
|
@@ -48,6 +48,7 @@ Parameters:
|
|
|
48
48
|
- `language` (optional): Filter by file extension (e.g. "ts", "py", "go"). Omit the dot.
|
|
49
49
|
- `role` (optional): Filter by chunk role: "ORCHESTRATION" (logic/flow), "DEFINITION" (types), or "IMPLEMENTATION"
|
|
50
50
|
- `mode` (optional): `"default"` (semantic only) or `"symbol"` (semantic + call graph appended). Use "symbol" when query is a function or class name — gets search results + callers/callees in one call.
|
|
51
|
+
- `include_imports` (optional): Prepend file's import/require statements to each result. Deduped per file — see dependencies at a glance.
|
|
51
52
|
|
|
52
53
|
**When to use which mode:**
|
|
53
54
|
- `pointer` — navigation, finding locations, understanding architecture
|
|
@@ -70,6 +71,7 @@ File or directory structure — signatures with bodies collapsed (~4x fewer toke
|
|
|
70
71
|
### trace_calls
|
|
71
72
|
Call graph — who calls a symbol and what it calls. Callers and callees include file:line locations. Unscoped — follows calls across all indexed directories.
|
|
72
73
|
- `symbol` (required): Function/method/class name
|
|
74
|
+
- `depth` (optional): Traversal depth for callers (default 1, max 3). depth: 2 shows callers-of-callers with indentation.
|
|
73
75
|
|
|
74
76
|
### list_symbols
|
|
75
77
|
List indexed symbols with definition locations, role, and export status.
|