grepmax 0.7.32 → 0.7.34
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 +43 -192
- package/dist/commands/serve.js +1 -0
- package/dist/lib/index/watcher.js +6 -1
- package/dist/lib/workers/embeddings/mlx-client.js +16 -6
- package/package.json +1 -1
- package/plugins/grepmax/.claude-plugin/plugin.json +1 -1
- package/plugins/grepmax/skills/grepmax/SKILL.md +3 -8
package/dist/commands/mcp.js
CHANGED
|
@@ -84,260 +84,110 @@ const watcher_registry_1 = require("../lib/utils/watcher-registry");
|
|
|
84
84
|
const TOOLS = [
|
|
85
85
|
{
|
|
86
86
|
name: "semantic_search",
|
|
87
|
-
description: "Search code by meaning
|
|
87
|
+
description: "Search code by meaning. Use scope:'all' for cross-project. Prefer CLI: gmax \"query\" --plain",
|
|
88
88
|
inputSchema: {
|
|
89
89
|
type: "object",
|
|
90
90
|
properties: {
|
|
91
|
-
query: {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
},
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
},
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
},
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
},
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
description: "Output detail: 'pointer' (default, metadata only), 'code' (4-line snippets), or 'full' (complete chunk content with line numbers)",
|
|
110
|
-
},
|
|
111
|
-
min_score: {
|
|
112
|
-
type: "number",
|
|
113
|
-
description: "Minimum relevance score (0-1). Results below this threshold are filtered out. Default: 0 (no filtering)",
|
|
114
|
-
},
|
|
115
|
-
max_per_file: {
|
|
116
|
-
type: "number",
|
|
117
|
-
description: "Max results per file (default: no cap). Useful to get diversity across files.",
|
|
118
|
-
},
|
|
119
|
-
file: {
|
|
120
|
-
type: "string",
|
|
121
|
-
description: "Filter to files matching this name (e.g. 'syncer.ts'). Matches the filename, not the full path.",
|
|
122
|
-
},
|
|
123
|
-
exclude: {
|
|
124
|
-
type: "string",
|
|
125
|
-
description: "Exclude files under this path prefix (e.g. 'tests/' or 'dist/').",
|
|
126
|
-
},
|
|
127
|
-
language: {
|
|
128
|
-
type: "string",
|
|
129
|
-
description: "Filter by file extension (e.g. 'ts', 'py', 'go'). Omit the dot.",
|
|
130
|
-
},
|
|
131
|
-
role: {
|
|
132
|
-
type: "string",
|
|
133
|
-
description: "Filter by chunk role: 'ORCHESTRATION' (logic/flow), 'DEFINITION' (types/classes), or 'IMPLEMENTATION'.",
|
|
134
|
-
},
|
|
135
|
-
context_lines: {
|
|
136
|
-
type: "number",
|
|
137
|
-
description: "Include N lines before and after the chunk (like grep -C). Only with detail 'code' or 'full'. Max 20.",
|
|
138
|
-
},
|
|
139
|
-
mode: {
|
|
140
|
-
type: "string",
|
|
141
|
-
description: "Search mode: 'default' (semantic only) or 'symbol' (semantic + call graph trace appended). Use 'symbol' when query is a function/class name.",
|
|
142
|
-
},
|
|
143
|
-
include_imports: {
|
|
144
|
-
type: "boolean",
|
|
145
|
-
description: "Prepend the file's import/require statements to each result. Deduped per file.",
|
|
146
|
-
},
|
|
147
|
-
name_pattern: {
|
|
148
|
-
type: "string",
|
|
149
|
-
description: "Regex to filter by symbol name (e.g. 'handle.*Auth'). Case-insensitive. Applied after search.",
|
|
150
|
-
},
|
|
151
|
-
},
|
|
152
|
-
required: ["query"],
|
|
153
|
-
},
|
|
154
|
-
},
|
|
155
|
-
{
|
|
156
|
-
name: "search_all",
|
|
157
|
-
description: "Search ALL indexed code across every directory. Use when you need to find code that could be anywhere. Returns results with full absolute paths so you know which project each result is from.",
|
|
158
|
-
inputSchema: {
|
|
159
|
-
type: "object",
|
|
160
|
-
properties: {
|
|
161
|
-
query: {
|
|
162
|
-
type: "string",
|
|
163
|
-
description: "Natural language search query.",
|
|
164
|
-
},
|
|
165
|
-
limit: {
|
|
166
|
-
type: "number",
|
|
167
|
-
description: "Max results to return (default 3, max 50)",
|
|
168
|
-
},
|
|
169
|
-
detail: {
|
|
170
|
-
type: "string",
|
|
171
|
-
description: "Output detail: 'pointer' (default), 'code' (snippets), or 'full' (complete content)",
|
|
172
|
-
},
|
|
173
|
-
min_score: {
|
|
174
|
-
type: "number",
|
|
175
|
-
description: "Minimum relevance score (0-1). Default: 0",
|
|
176
|
-
},
|
|
177
|
-
max_per_file: {
|
|
178
|
-
type: "number",
|
|
179
|
-
description: "Max results per file (default: no cap).",
|
|
180
|
-
},
|
|
181
|
-
file: {
|
|
182
|
-
type: "string",
|
|
183
|
-
description: "Filter to files matching this name (e.g. 'syncer.ts').",
|
|
184
|
-
},
|
|
185
|
-
exclude: {
|
|
186
|
-
type: "string",
|
|
187
|
-
description: "Exclude files under this path prefix (e.g. 'tests/').",
|
|
188
|
-
},
|
|
189
|
-
language: {
|
|
190
|
-
type: "string",
|
|
191
|
-
description: "Filter by file extension (e.g. 'ts', 'py').",
|
|
192
|
-
},
|
|
193
|
-
role: {
|
|
194
|
-
type: "string",
|
|
195
|
-
description: "Filter by role: 'ORCHESTRATION', 'DEFINITION', or 'IMPLEMENTATION'.",
|
|
196
|
-
},
|
|
197
|
-
projects: {
|
|
198
|
-
type: "string",
|
|
199
|
-
description: "Comma-separated project names to include (e.g. 'platform,osgrep'). Use index_status to see names.",
|
|
200
|
-
},
|
|
201
|
-
exclude_projects: {
|
|
202
|
-
type: "string",
|
|
203
|
-
description: "Comma-separated project names to exclude (e.g. 'capstone,power').",
|
|
204
|
-
},
|
|
205
|
-
context_lines: {
|
|
206
|
-
type: "number",
|
|
207
|
-
description: "Include N lines before/after chunk. Only with detail 'code' or 'full'. Max 20.",
|
|
208
|
-
},
|
|
209
|
-
include_imports: {
|
|
210
|
-
type: "boolean",
|
|
211
|
-
description: "Prepend file's import statements to each result.",
|
|
212
|
-
},
|
|
213
|
-
name_pattern: {
|
|
214
|
-
type: "string",
|
|
215
|
-
description: "Regex to filter by symbol name (e.g. 'handle.*Auth').",
|
|
216
|
-
},
|
|
91
|
+
query: { type: "string", description: "Natural language query (5+ words recommended)" },
|
|
92
|
+
limit: { type: "number", description: "Max results (default 3, max 50)" },
|
|
93
|
+
root: { type: "string", description: "Search a different directory (absolute path)" },
|
|
94
|
+
path: { type: "string", description: "Path prefix filter (e.g. 'src/auth/')" },
|
|
95
|
+
detail: { type: "string", description: "'pointer' (default), 'code', or 'full'" },
|
|
96
|
+
min_score: { type: "number", description: "Min score 0-1 (default 0)" },
|
|
97
|
+
max_per_file: { type: "number", description: "Max results per file" },
|
|
98
|
+
file: { type: "string", description: "Filename filter (e.g. 'syncer.ts')" },
|
|
99
|
+
exclude: { type: "string", description: "Exclude path prefix (e.g. 'tests/')" },
|
|
100
|
+
language: { type: "string", description: "Extension filter (e.g. 'ts', 'py')" },
|
|
101
|
+
role: { type: "string", description: "'ORCHESTRATION', 'DEFINITION', or 'IMPLEMENTATION'" },
|
|
102
|
+
context_lines: { type: "number", description: "Lines before/after chunk (max 20)" },
|
|
103
|
+
mode: { type: "string", description: "'default' or 'symbol' (appends call graph)" },
|
|
104
|
+
include_imports: { type: "boolean", description: "Prepend file imports to results" },
|
|
105
|
+
name_pattern: { type: "string", description: "Regex filter on symbol name" },
|
|
106
|
+
scope: { type: "string", description: "'project' (default) or 'all' (search everything)" },
|
|
107
|
+
projects: { type: "string", description: "Project names to include (comma-separated)" },
|
|
108
|
+
exclude_projects: { type: "string", description: "Project names to exclude (comma-separated)" },
|
|
217
109
|
},
|
|
218
110
|
required: ["query"],
|
|
219
111
|
},
|
|
220
112
|
},
|
|
221
113
|
{
|
|
222
114
|
name: "code_skeleton",
|
|
223
|
-
description: "
|
|
115
|
+
description: "File structure with bodies collapsed (~4x fewer tokens). Accepts file, directory, or comma-separated paths.",
|
|
224
116
|
inputSchema: {
|
|
225
117
|
type: "object",
|
|
226
118
|
properties: {
|
|
227
|
-
target: {
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
},
|
|
231
|
-
limit: {
|
|
232
|
-
type: "number",
|
|
233
|
-
description: "Max files for directory mode (default 10, max 20). Ignored for single files.",
|
|
234
|
-
},
|
|
235
|
-
format: {
|
|
236
|
-
type: "string",
|
|
237
|
-
description: "Output format: 'text' (default) or 'json' (structured symbol list with names, lines, signatures).",
|
|
238
|
-
},
|
|
119
|
+
target: { type: "string", description: "File, directory, or comma-separated paths" },
|
|
120
|
+
limit: { type: "number", description: "Max files for directory mode (default 10)" },
|
|
121
|
+
format: { type: "string", description: "'text' (default) or 'json'" },
|
|
239
122
|
},
|
|
240
123
|
required: ["target"],
|
|
241
124
|
},
|
|
242
125
|
},
|
|
243
126
|
{
|
|
244
127
|
name: "trace_calls",
|
|
245
|
-
description: "
|
|
128
|
+
description: "Call graph: importers, callers (multi-hop), callees with file:line.",
|
|
246
129
|
inputSchema: {
|
|
247
130
|
type: "object",
|
|
248
131
|
properties: {
|
|
249
|
-
symbol: {
|
|
250
|
-
|
|
251
|
-
description: "The function, method, or class name to trace (e.g. 'handleAuth')",
|
|
252
|
-
},
|
|
253
|
-
depth: {
|
|
254
|
-
type: "number",
|
|
255
|
-
description: "Traversal depth for callers (default 1, max 3). depth: 2 shows callers-of-callers.",
|
|
256
|
-
},
|
|
132
|
+
symbol: { type: "string", description: "Function/class name to trace" },
|
|
133
|
+
depth: { type: "number", description: "Caller depth (default 1, max 3)" },
|
|
257
134
|
},
|
|
258
135
|
required: ["symbol"],
|
|
259
136
|
},
|
|
260
137
|
},
|
|
261
138
|
{
|
|
262
139
|
name: "list_symbols",
|
|
263
|
-
description: "List indexed symbols
|
|
140
|
+
description: "List indexed symbols with role and export status.",
|
|
264
141
|
inputSchema: {
|
|
265
142
|
type: "object",
|
|
266
143
|
properties: {
|
|
267
|
-
pattern: {
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
},
|
|
271
|
-
limit: {
|
|
272
|
-
type: "number",
|
|
273
|
-
description: "Max symbols to return (default 20, max 100)",
|
|
274
|
-
},
|
|
275
|
-
path: {
|
|
276
|
-
type: "string",
|
|
277
|
-
description: "Only include symbols defined under this path prefix",
|
|
278
|
-
},
|
|
144
|
+
pattern: { type: "string", description: "Name filter (case-insensitive)" },
|
|
145
|
+
limit: { type: "number", description: "Max results (default 20)" },
|
|
146
|
+
path: { type: "string", description: "Path prefix filter" },
|
|
279
147
|
},
|
|
280
148
|
},
|
|
281
149
|
},
|
|
282
150
|
{
|
|
283
151
|
name: "index_status",
|
|
284
|
-
description: "
|
|
285
|
-
inputSchema: {
|
|
286
|
-
type: "object",
|
|
287
|
-
properties: {},
|
|
288
|
-
},
|
|
152
|
+
description: "Index health: chunks, files, projects, watcher status.",
|
|
153
|
+
inputSchema: { type: "object", properties: {} },
|
|
289
154
|
},
|
|
290
155
|
{
|
|
291
156
|
name: "summarize_directory",
|
|
292
|
-
description: "Generate LLM summaries for indexed
|
|
157
|
+
description: "Generate LLM summaries for indexed chunks.",
|
|
293
158
|
inputSchema: {
|
|
294
159
|
type: "object",
|
|
295
160
|
properties: {
|
|
296
|
-
path: {
|
|
297
|
-
|
|
298
|
-
description: "Directory to summarize (absolute or relative). Defaults to current project root.",
|
|
299
|
-
},
|
|
300
|
-
limit: {
|
|
301
|
-
type: "number",
|
|
302
|
-
description: "Max chunks to summarize per call (default 200, max 5000). Run again to continue.",
|
|
303
|
-
},
|
|
161
|
+
path: { type: "string", description: "Directory to summarize (default: project root)" },
|
|
162
|
+
limit: { type: "number", description: "Max chunks (default 200, max 5000)" },
|
|
304
163
|
},
|
|
305
164
|
},
|
|
306
165
|
},
|
|
307
166
|
{
|
|
308
167
|
name: "summarize_project",
|
|
309
|
-
description: "
|
|
168
|
+
description: "Project overview: languages, structure, roles, key symbols, entry points.",
|
|
310
169
|
inputSchema: {
|
|
311
170
|
type: "object",
|
|
312
171
|
properties: {
|
|
313
|
-
root: {
|
|
314
|
-
type: "string",
|
|
315
|
-
description: "Project root (absolute path). Defaults to current project.",
|
|
316
|
-
},
|
|
172
|
+
root: { type: "string", description: "Project root (default: current)" },
|
|
317
173
|
},
|
|
318
174
|
},
|
|
319
175
|
},
|
|
320
176
|
{
|
|
321
177
|
name: "related_files",
|
|
322
|
-
description: "Find
|
|
178
|
+
description: "Find dependencies and dependents of a file by shared symbols.",
|
|
323
179
|
inputSchema: {
|
|
324
180
|
type: "object",
|
|
325
181
|
properties: {
|
|
326
|
-
file: {
|
|
327
|
-
|
|
328
|
-
description: "File path relative to project root (e.g. 'src/lib/index/syncer.ts')",
|
|
329
|
-
},
|
|
330
|
-
limit: {
|
|
331
|
-
type: "number",
|
|
332
|
-
description: "Max related files per direction (default 10)",
|
|
333
|
-
},
|
|
182
|
+
file: { type: "string", description: "File path relative to project root" },
|
|
183
|
+
limit: { type: "number", description: "Max results per direction (default 10)" },
|
|
334
184
|
},
|
|
335
185
|
required: ["file"],
|
|
336
186
|
},
|
|
337
187
|
},
|
|
338
188
|
{
|
|
339
189
|
name: "recent_changes",
|
|
340
|
-
description: "
|
|
190
|
+
description: "Recently modified indexed files with timestamps.",
|
|
341
191
|
inputSchema: {
|
|
342
192
|
type: "object",
|
|
343
193
|
properties: {
|
|
@@ -513,11 +363,12 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
513
363
|
}
|
|
514
364
|
// --- Tool handlers ---
|
|
515
365
|
function handleSemanticSearch(args_1) {
|
|
516
|
-
return __awaiter(this, arguments, void 0, function* (args,
|
|
366
|
+
return __awaiter(this, arguments, void 0, function* (args, isSearchAll = false) {
|
|
517
367
|
var _a;
|
|
518
368
|
const query = String(args.query || "");
|
|
519
369
|
if (!query)
|
|
520
370
|
return err("Missing required parameter: query");
|
|
371
|
+
const searchAll = isSearchAll || args.scope === "all";
|
|
521
372
|
const limit = Math.min(Math.max(Number(args.limit) || 3, 1), 50);
|
|
522
373
|
ensureWatcher();
|
|
523
374
|
if (_indexing) {
|
package/dist/commands/serve.js
CHANGED
|
@@ -380,6 +380,7 @@ exports.serve = new commander_1.Command("serve")
|
|
|
380
380
|
// Ensure we exit if server fails to start
|
|
381
381
|
process.exit(1);
|
|
382
382
|
});
|
|
383
|
+
server.setTimeout(60000); // 60s request timeout
|
|
383
384
|
server.listen(port, () => {
|
|
384
385
|
const address = server.address();
|
|
385
386
|
const actualPort = typeof address === "object" && address ? address.port : port;
|
|
@@ -105,7 +105,12 @@ function startWatcher(opts) {
|
|
|
105
105
|
clearTimeout(debounceTimer);
|
|
106
106
|
debounceTimer = setTimeout(() => processBatch(), DEBOUNCE_MS);
|
|
107
107
|
};
|
|
108
|
-
const
|
|
108
|
+
const taskTimeoutMs = (() => {
|
|
109
|
+
var _a;
|
|
110
|
+
const fromEnv = Number.parseInt((_a = process.env.GMAX_WORKER_TASK_TIMEOUT_MS) !== null && _a !== void 0 ? _a : "", 10);
|
|
111
|
+
return Number.isFinite(fromEnv) && fromEnv > 0 ? fromEnv : 120000;
|
|
112
|
+
})();
|
|
113
|
+
const BATCH_TIMEOUT_MS = Math.max(Math.ceil(taskTimeoutMs * 1.5), 120000);
|
|
109
114
|
const processBatch = () => __awaiter(this, void 0, void 0, function* () {
|
|
110
115
|
var _a;
|
|
111
116
|
if (closed || processing || pending.size === 0)
|
|
@@ -95,13 +95,9 @@ function postJSON(path, body) {
|
|
|
95
95
|
/**
|
|
96
96
|
* Check if MLX server is reachable. Caches result for CHECK_INTERVAL_MS.
|
|
97
97
|
*/
|
|
98
|
-
function
|
|
98
|
+
function checkHealth() {
|
|
99
99
|
return __awaiter(this, void 0, void 0, function* () {
|
|
100
|
-
|
|
101
|
-
if (mlxAvailable !== null && now - lastCheck < CHECK_INTERVAL_MS) {
|
|
102
|
-
return mlxAvailable;
|
|
103
|
-
}
|
|
104
|
-
const result = yield new Promise((resolve) => {
|
|
100
|
+
return new Promise((resolve) => {
|
|
105
101
|
const req = http.get({ hostname: MLX_HOST, port: MLX_PORT, path: "/health", timeout: 2000 }, (res) => {
|
|
106
102
|
res.resume();
|
|
107
103
|
resolve(res.statusCode === 200);
|
|
@@ -112,6 +108,20 @@ function isMlxUp() {
|
|
|
112
108
|
resolve(false);
|
|
113
109
|
});
|
|
114
110
|
});
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
function isMlxUp() {
|
|
114
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
115
|
+
const now = Date.now();
|
|
116
|
+
if (mlxAvailable !== null && now - lastCheck < CHECK_INTERVAL_MS) {
|
|
117
|
+
return mlxAvailable;
|
|
118
|
+
}
|
|
119
|
+
let result = yield checkHealth();
|
|
120
|
+
// On first check (cold start), retry once after 3s — server may still be loading
|
|
121
|
+
if (!result && mlxAvailable === null) {
|
|
122
|
+
yield new Promise((r) => setTimeout(r, 3000));
|
|
123
|
+
result = yield checkHealth();
|
|
124
|
+
}
|
|
115
125
|
mlxAvailable = result;
|
|
116
126
|
lastCheck = now;
|
|
117
127
|
return result;
|
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,
|
|
4
|
+
allowed-tools: "mcp__grepmax__semantic_search, mcp__grepmax__code_skeleton, mcp__grepmax__trace_calls, mcp__grepmax__list_symbols, mcp__grepmax__index_status, mcp__grepmax__summarize_directory, mcp__grepmax__summarize_project, mcp__grepmax__related_files, mcp__grepmax__recent_changes, Bash(gmax:*), Read"
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
## What gmax does
|
|
@@ -85,14 +85,9 @@ gmax doctor # health check
|
|
|
85
85
|
6. **Context** — `Bash(gmax related <file>)` to see what else to look at
|
|
86
86
|
7. **Changes** — `Bash(gmax recent)` after pulls
|
|
87
87
|
|
|
88
|
-
## MCP tools
|
|
88
|
+
## MCP tools
|
|
89
89
|
|
|
90
|
-
MCP
|
|
91
|
-
- `index_status` — quick health check (no CLI equivalent that's cheaper)
|
|
92
|
-
- `summarize_directory` — LLM summary generation
|
|
93
|
-
- `semantic_search` with `detail: "pointer"` — when you need the structured pointer format
|
|
94
|
-
|
|
95
|
-
Full MCP tool documentation: semantic_search (16 params), search_all, code_skeleton, trace_calls, list_symbols, index_status, summarize_project, related_files, recent_changes, summarize_directory.
|
|
90
|
+
Use MCP only for `index_status` and `summarize_directory`. Use CLI for everything else. For cross-project search, use `scope: "all"` on semantic_search (replaces search_all).
|
|
96
91
|
|
|
97
92
|
## Tips
|
|
98
93
|
|