grepmax 0.7.10 → 0.7.12
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
|
},
|
|
@@ -268,6 +276,19 @@ const TOOLS = [
|
|
|
268
276
|
},
|
|
269
277
|
},
|
|
270
278
|
},
|
|
279
|
+
{
|
|
280
|
+
name: "summarize_project",
|
|
281
|
+
description: "High-level overview of an indexed project — languages, directory structure, role distribution, key symbols, and entry points. Use when first exploring a codebase.",
|
|
282
|
+
inputSchema: {
|
|
283
|
+
type: "object",
|
|
284
|
+
properties: {
|
|
285
|
+
root: {
|
|
286
|
+
type: "string",
|
|
287
|
+
description: "Project root (absolute path). Defaults to current project.",
|
|
288
|
+
},
|
|
289
|
+
},
|
|
290
|
+
},
|
|
291
|
+
},
|
|
271
292
|
];
|
|
272
293
|
// ---------------------------------------------------------------------------
|
|
273
294
|
// Helpers
|
|
@@ -444,6 +465,49 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
444
465
|
child.unref();
|
|
445
466
|
console.log(`[MCP] Started background watcher for ${projectRoot}`);
|
|
446
467
|
}
|
|
468
|
+
// --- Utilities ---
|
|
469
|
+
function extractImports(filePath) {
|
|
470
|
+
try {
|
|
471
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
472
|
+
const lines = content.split("\n");
|
|
473
|
+
const importLines = [];
|
|
474
|
+
let inMultiLine = false;
|
|
475
|
+
for (const line of lines) {
|
|
476
|
+
const trimmed = line.trim();
|
|
477
|
+
if (inMultiLine) {
|
|
478
|
+
importLines.push(line);
|
|
479
|
+
if (trimmed === ")" || trimmed === ");")
|
|
480
|
+
inMultiLine = false;
|
|
481
|
+
continue;
|
|
482
|
+
}
|
|
483
|
+
if (!trimmed ||
|
|
484
|
+
trimmed.startsWith("//") ||
|
|
485
|
+
trimmed.startsWith("#") ||
|
|
486
|
+
trimmed.startsWith("*") ||
|
|
487
|
+
trimmed.startsWith("/*")) {
|
|
488
|
+
continue;
|
|
489
|
+
}
|
|
490
|
+
if (trimmed.startsWith("import ") ||
|
|
491
|
+
trimmed.startsWith("from ") ||
|
|
492
|
+
(trimmed.startsWith("const ") && trimmed.includes("require(")) ||
|
|
493
|
+
trimmed.startsWith("require(") ||
|
|
494
|
+
trimmed.startsWith("use ") ||
|
|
495
|
+
trimmed.startsWith("using ") ||
|
|
496
|
+
trimmed.startsWith("package ")) {
|
|
497
|
+
importLines.push(line);
|
|
498
|
+
if (trimmed.includes("(") && !trimmed.includes(")")) {
|
|
499
|
+
inMultiLine = true;
|
|
500
|
+
}
|
|
501
|
+
continue;
|
|
502
|
+
}
|
|
503
|
+
break;
|
|
504
|
+
}
|
|
505
|
+
return importLines.length > 0 ? importLines.join("\n") : "";
|
|
506
|
+
}
|
|
507
|
+
catch (_a) {
|
|
508
|
+
return "";
|
|
509
|
+
}
|
|
510
|
+
}
|
|
447
511
|
// --- Tool handlers ---
|
|
448
512
|
function handleSemanticSearch(args_1) {
|
|
449
513
|
return __awaiter(this, arguments, void 0, function* (args, searchAll = false) {
|
|
@@ -525,6 +589,8 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
525
589
|
const minScore = typeof args.min_score === "number" ? args.min_score : 0;
|
|
526
590
|
const maxPerFile = typeof args.max_per_file === "number" ? args.max_per_file : 0;
|
|
527
591
|
const detail = typeof args.detail === "string" ? args.detail : "pointer";
|
|
592
|
+
const includeImports = Boolean(args.include_imports);
|
|
593
|
+
const importCache = new Map();
|
|
528
594
|
let results = result.data.map((r) => {
|
|
529
595
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
530
596
|
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 : "";
|
|
@@ -590,10 +656,19 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
590
656
|
.join("\n");
|
|
591
657
|
}
|
|
592
658
|
}
|
|
593
|
-
|
|
659
|
+
let text = line1 +
|
|
594
660
|
(summaryStr ? `\n${summaryStr}` : "") +
|
|
595
661
|
(line2 ? `\n${line2}` : "") +
|
|
596
662
|
snippet;
|
|
663
|
+
if (includeImports && absPath) {
|
|
664
|
+
if (!importCache.has(absPath)) {
|
|
665
|
+
importCache.set(absPath, extractImports(absPath));
|
|
666
|
+
}
|
|
667
|
+
const imports = importCache.get(absPath);
|
|
668
|
+
if (imports) {
|
|
669
|
+
text = `imports:\n${imports}\n\n${text}`;
|
|
670
|
+
}
|
|
671
|
+
}
|
|
597
672
|
return {
|
|
598
673
|
absPath,
|
|
599
674
|
text,
|
|
@@ -998,6 +1073,130 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
998
1073
|
}
|
|
999
1074
|
});
|
|
1000
1075
|
}
|
|
1076
|
+
function handleSummarizeProject(args) {
|
|
1077
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1078
|
+
var _a;
|
|
1079
|
+
const root = typeof args.root === "string"
|
|
1080
|
+
? path.resolve(args.root)
|
|
1081
|
+
: projectRoot;
|
|
1082
|
+
const prefix = root.endsWith("/") ? root : `${root}/`;
|
|
1083
|
+
const projectName = path.basename(root);
|
|
1084
|
+
try {
|
|
1085
|
+
const db = getVectorDb();
|
|
1086
|
+
const table = yield db.ensureTable();
|
|
1087
|
+
const rows = yield table
|
|
1088
|
+
.query()
|
|
1089
|
+
.select([
|
|
1090
|
+
"path",
|
|
1091
|
+
"role",
|
|
1092
|
+
"is_exported",
|
|
1093
|
+
"complexity",
|
|
1094
|
+
"defined_symbols",
|
|
1095
|
+
"referenced_symbols",
|
|
1096
|
+
])
|
|
1097
|
+
.where(`path LIKE '${(0, filter_builder_1.escapeSqlString)(prefix)}%'`)
|
|
1098
|
+
.limit(200000)
|
|
1099
|
+
.toArray();
|
|
1100
|
+
if (rows.length === 0) {
|
|
1101
|
+
return ok(`No indexed data found for ${root}. Run: gmax index --path ${root}`);
|
|
1102
|
+
}
|
|
1103
|
+
const files = new Set();
|
|
1104
|
+
const extCounts = new Map();
|
|
1105
|
+
const dirCounts = new Map();
|
|
1106
|
+
const roleCounts = new Map();
|
|
1107
|
+
const symbolRefs = new Map();
|
|
1108
|
+
const entryPoints = [];
|
|
1109
|
+
for (const row of rows) {
|
|
1110
|
+
const p = String(row.path || "");
|
|
1111
|
+
const role = String(row.role || "IMPLEMENTATION");
|
|
1112
|
+
const exported = Boolean(row.is_exported);
|
|
1113
|
+
const complexity = Number(row.complexity || 0);
|
|
1114
|
+
const defs = toStringArray(row.defined_symbols);
|
|
1115
|
+
const refs = toStringArray(row.referenced_symbols);
|
|
1116
|
+
files.add(p);
|
|
1117
|
+
const ext = path.extname(p).toLowerCase() || path.basename(p);
|
|
1118
|
+
extCounts.set(ext, (extCounts.get(ext) || 0) + 1);
|
|
1119
|
+
const rel = p.startsWith(prefix)
|
|
1120
|
+
? p.slice(prefix.length)
|
|
1121
|
+
: p;
|
|
1122
|
+
const parts = rel.split("/");
|
|
1123
|
+
const dir = parts.length > 2
|
|
1124
|
+
? `${parts.slice(0, 2).join("/")}/`
|
|
1125
|
+
: parts.length > 1
|
|
1126
|
+
? `${parts[0]}/`
|
|
1127
|
+
: "(root)";
|
|
1128
|
+
if (!dirCounts.has(dir)) {
|
|
1129
|
+
dirCounts.set(dir, { files: new Set(), chunks: 0 });
|
|
1130
|
+
}
|
|
1131
|
+
const dc = dirCounts.get(dir);
|
|
1132
|
+
dc.files.add(p);
|
|
1133
|
+
dc.chunks++;
|
|
1134
|
+
roleCounts.set(role, (roleCounts.get(role) || 0) + 1);
|
|
1135
|
+
for (const ref of refs) {
|
|
1136
|
+
symbolRefs.set(ref, (symbolRefs.get(ref) || 0) + 1);
|
|
1137
|
+
}
|
|
1138
|
+
if (exported &&
|
|
1139
|
+
role === "ORCHESTRATION" &&
|
|
1140
|
+
complexity >= 5 &&
|
|
1141
|
+
defs.length > 0) {
|
|
1142
|
+
const relPath = p.startsWith(prefix)
|
|
1143
|
+
? p.slice(prefix.length)
|
|
1144
|
+
: p;
|
|
1145
|
+
entryPoints.push({ symbol: defs[0], path: relPath });
|
|
1146
|
+
}
|
|
1147
|
+
}
|
|
1148
|
+
const lines = [];
|
|
1149
|
+
const projects = (0, project_registry_1.listProjects)();
|
|
1150
|
+
const proj = projects.find((p) => p.root === root);
|
|
1151
|
+
lines.push(`Project: ${projectName} (${root})`);
|
|
1152
|
+
lines.push(`Last indexed: ${(_a = proj === null || proj === void 0 ? void 0 : proj.lastIndexed) !== null && _a !== void 0 ? _a : "unknown"} • ${rows.length} chunks • ${files.size} files`);
|
|
1153
|
+
lines.push("");
|
|
1154
|
+
const extEntries = Array.from(extCounts.entries())
|
|
1155
|
+
.sort((a, b) => b[1] - a[1])
|
|
1156
|
+
.slice(0, 8);
|
|
1157
|
+
const langLine = extEntries
|
|
1158
|
+
.map(([ext, count]) => `${ext} (${Math.round((count / rows.length) * 100)}%)`)
|
|
1159
|
+
.join(", ");
|
|
1160
|
+
lines.push(`Languages: ${langLine}`);
|
|
1161
|
+
lines.push("");
|
|
1162
|
+
lines.push("Directory structure:");
|
|
1163
|
+
const dirEntries = Array.from(dirCounts.entries())
|
|
1164
|
+
.sort((a, b) => b[1].chunks - a[1].chunks)
|
|
1165
|
+
.slice(0, 12);
|
|
1166
|
+
for (const [dir, data] of dirEntries) {
|
|
1167
|
+
lines.push(` ${dir.padEnd(25)} (${data.files.size} files, ${data.chunks} chunks)`);
|
|
1168
|
+
}
|
|
1169
|
+
lines.push("");
|
|
1170
|
+
const roleEntries = Array.from(roleCounts.entries()).sort((a, b) => b[1] - a[1]);
|
|
1171
|
+
const roleLine = roleEntries
|
|
1172
|
+
.map(([role, count]) => `${Math.round((count / rows.length) * 100)}% ${role}`)
|
|
1173
|
+
.join(", ");
|
|
1174
|
+
lines.push(`Roles: ${roleLine}`);
|
|
1175
|
+
lines.push("");
|
|
1176
|
+
const topSymbols = Array.from(symbolRefs.entries())
|
|
1177
|
+
.sort((a, b) => b[1] - a[1])
|
|
1178
|
+
.slice(0, 8);
|
|
1179
|
+
if (topSymbols.length > 0) {
|
|
1180
|
+
lines.push("Key symbols (by reference count):");
|
|
1181
|
+
for (const [sym, count] of topSymbols) {
|
|
1182
|
+
lines.push(` ${sym.padEnd(25)} (referenced ${count}x)`);
|
|
1183
|
+
}
|
|
1184
|
+
lines.push("");
|
|
1185
|
+
}
|
|
1186
|
+
if (entryPoints.length > 0) {
|
|
1187
|
+
lines.push("Entry points (exported orchestration):");
|
|
1188
|
+
for (const ep of entryPoints.slice(0, 10)) {
|
|
1189
|
+
lines.push(` ${ep.symbol.padEnd(25)} ${ep.path}`);
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
return ok(lines.join("\n"));
|
|
1193
|
+
}
|
|
1194
|
+
catch (e) {
|
|
1195
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
1196
|
+
return err(`Project summary failed: ${msg}`);
|
|
1197
|
+
}
|
|
1198
|
+
});
|
|
1199
|
+
}
|
|
1001
1200
|
// --- MCP server setup ---
|
|
1002
1201
|
const transport = new stdio_js_1.StdioServerTransport();
|
|
1003
1202
|
const server = new index_js_1.Server({
|
|
@@ -1031,6 +1230,8 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
1031
1230
|
return handleIndexStatus();
|
|
1032
1231
|
case "summarize_directory":
|
|
1033
1232
|
return handleSummarizeDirectory(toolArgs);
|
|
1233
|
+
case "summarize_project":
|
|
1234
|
+
return handleSummarizeProject(toolArgs);
|
|
1034
1235
|
default:
|
|
1035
1236
|
return err(`Unknown tool: ${name}`);
|
|
1036
1237
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: grepmax
|
|
3
3
|
description: Semantic code search. Use alongside grep - grep for exact strings, gmax for concepts.
|
|
4
|
-
allowed-tools: "mcp__grepmax__semantic_search, mcp__grepmax__search_all, mcp__grepmax__code_skeleton, mcp__grepmax__trace_calls, mcp__grepmax__list_symbols, mcp__grepmax__index_status, mcp__grepmax__summarize_directory, Bash(gmax:*), Read"
|
|
4
|
+
allowed-tools: "mcp__grepmax__semantic_search, mcp__grepmax__search_all, mcp__grepmax__code_skeleton, mcp__grepmax__trace_calls, mcp__grepmax__list_symbols, mcp__grepmax__index_status, mcp__grepmax__summarize_directory, mcp__grepmax__summarize_project, Bash(gmax:*), Read"
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
## What gmax does
|
|
@@ -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
|
|
@@ -79,6 +80,10 @@ List indexed symbols with definition locations, role, and export status.
|
|
|
79
80
|
|
|
80
81
|
Output: `symbolName [ORCH] exported src/path/file.ts:42`
|
|
81
82
|
|
|
83
|
+
### summarize_project
|
|
84
|
+
High-level project overview — languages, directory structure, role distribution, key symbols, entry points. Use when first exploring a new codebase.
|
|
85
|
+
- `root` (optional): Project root path. Defaults to current project.
|
|
86
|
+
|
|
82
87
|
### index_status
|
|
83
88
|
Check centralized index health — chunks, files, indexed directories, model info, watcher status.
|
|
84
89
|
|