grepmax 0.7.1 → 0.7.3

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.
@@ -33,7 +33,8 @@ function installPlugin() {
33
33
  return __awaiter(this, void 0, void 0, function* () {
34
34
  try {
35
35
  yield runClaudeCommand(["marketplace", "add", "reowens/grepmax"]);
36
- console.log(" Successfully added the gmax marketplace");
36
+ yield runClaudeCommand(["marketplace", "update", "grepmax"]);
37
+ console.log("✅ Marketplace updated");
37
38
  yield runClaudeCommand(["install", "grepmax"]);
38
39
  console.log("✅ Successfully installed the gmax plugin for Claude Code");
39
40
  console.log("\nNext steps:");
@@ -246,6 +246,8 @@ exports.mcp = new commander_1.Command("mcp")
246
246
  let _searcher = null;
247
247
  let _skeletonizer = null;
248
248
  let _indexReady = false;
249
+ let _indexing = false;
250
+ let _indexProgress = "";
249
251
  const cleanup = () => __awaiter(void 0, void 0, void 0, function* () {
250
252
  if (_vectorDb) {
251
253
  try {
@@ -310,14 +312,33 @@ exports.mcp = new commander_1.Command("mcp")
310
312
  const db = getVectorDb();
311
313
  const hasIndex = yield db.hasRowsForPath(projectRoot);
312
314
  if (!hasIndex) {
315
+ if (_indexing)
316
+ return; // Already indexing in background
317
+ _indexing = true;
318
+ _indexProgress = "starting...";
313
319
  console.log("[MCP] No index found, running initial sync...");
314
- yield (0, syncer_1.initialSync)({ projectRoot });
315
- console.log("[MCP] Initial sync complete.");
320
+ (0, syncer_1.initialSync)({
321
+ projectRoot,
322
+ onProgress: (info) => {
323
+ _indexProgress = `${info.processed}/${info.total || "?"} files`;
324
+ },
325
+ })
326
+ .then(() => {
327
+ _indexReady = true;
328
+ _indexing = false;
329
+ _indexProgress = "";
330
+ console.log("[MCP] Initial sync complete.");
331
+ })
332
+ .catch((e) => {
333
+ _indexing = false;
334
+ _indexProgress = "";
335
+ console.error("[MCP] Index sync failed:", e);
336
+ });
316
337
  }
317
338
  else {
318
339
  console.log("[MCP] Index exists, ready.");
340
+ _indexReady = true;
319
341
  }
320
- _indexReady = true;
321
342
  }
322
343
  catch (e) {
323
344
  console.error("[MCP] Index sync failed:", e);
@@ -345,6 +366,9 @@ exports.mcp = new commander_1.Command("mcp")
345
366
  const limit = Math.min(Math.max(Number(args.limit) || 3, 1), 50);
346
367
  yield ensureIndexReady();
347
368
  ensureWatcher();
369
+ if (_indexing) {
370
+ return ok(`Indexing in progress (${_indexProgress}). Results may be incomplete or empty — try again shortly.`);
371
+ }
348
372
  try {
349
373
  const searcher = getSearcher();
350
374
  // Determine path prefix and display root for relative paths
@@ -492,6 +516,9 @@ exports.mcp = new commander_1.Command("mcp")
492
516
  const symbol = String(args.symbol || "");
493
517
  if (!symbol)
494
518
  return err("Missing required parameter: symbol");
519
+ if (_indexing) {
520
+ return ok(`Indexing in progress (${_indexProgress}). trace_calls requires a complete index — try again shortly.`);
521
+ }
495
522
  try {
496
523
  const db = getVectorDb();
497
524
  const builder = new graph_builder_1.GraphBuilder(db);
@@ -534,6 +561,9 @@ exports.mcp = new commander_1.Command("mcp")
534
561
  const pattern = typeof args.pattern === "string" ? args.pattern : undefined;
535
562
  const limit = Math.min(Math.max(Number(args.limit) || 20, 1), 100);
536
563
  const pathPrefix = typeof args.path === "string" ? args.path : undefined;
564
+ if (_indexing) {
565
+ return ok(`Indexing in progress (${_indexProgress}). list_symbols requires a complete index — try again shortly.`);
566
+ }
537
567
  try {
538
568
  const db = getVectorDb();
539
569
  const table = yield db.ensureTable();
@@ -621,6 +651,9 @@ exports.mcp = new commander_1.Command("mcp")
621
651
  watcherLine += " — search results may be incomplete";
622
652
  }
623
653
  }
654
+ const indexingLine = _indexing
655
+ ? `Indexing: in progress (${_indexProgress})`
656
+ : "";
624
657
  const lines = [
625
658
  `Index: ~/.gmax/lancedb (${stats.chunks} chunks, ${fileCount} files)`,
626
659
  `Model: ${globalConfig.embedMode === "gpu" ? ((_d = (_c = (_b = config_1.MODEL_TIERS[globalConfig.modelTier]) === null || _b === void 0 ? void 0 : _b.mlxModel) !== null && _c !== void 0 ? _c : config === null || config === void 0 ? void 0 : config.embedModel) !== null && _d !== void 0 ? _d : "unknown") : ((_e = config === null || config === void 0 ? void 0 : config.embedModel) !== null && _e !== void 0 ? _e : "unknown")} (${(_f = config === null || config === void 0 ? void 0 : config.vectorDim) !== null && _f !== void 0 ? _f : "?"}d, ${globalConfig.embedMode})`,
@@ -628,6 +661,7 @@ exports.mcp = new commander_1.Command("mcp")
628
661
  ? `Last indexed: ${config.indexedAt}`
629
662
  : "",
630
663
  watcherLine,
664
+ indexingLine,
631
665
  "",
632
666
  "Indexed directories:",
633
667
  ...projects.map((p) => { var _a; return ` ${p.name}\t${p.root}\t${(_a = p.lastIndexed) !== null && _a !== void 0 ? _a : "unknown"}`; }),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "grepmax",
3
- "version": "0.7.1",
3
+ "version": "0.7.3",
4
4
  "author": "Robert Owens <robowens@me.com>",
5
5
  "homepage": "https://github.com/reowens/grepmax",
6
6
  "bugs": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "grepmax",
3
- "version": "0.7.1",
3
+ "version": "0.7.3",
4
4
  "description": "Semantic code search for Claude Code. Automatically indexes your project and provides intelligent search capabilities.",
5
5
  "author": {
6
6
  "name": "Robert Owens",
@@ -1,7 +1,7 @@
1
1
  const fs = require("node:fs");
2
2
  const _path = require("node:path");
3
3
  const http = require("node:http");
4
- const { spawn } = require("node:child_process");
4
+ const { spawn, execFileSync } = require("node:child_process");
5
5
 
6
6
  function isServerRunning(port) {
7
7
  return new Promise((resolve) => {
@@ -20,12 +20,30 @@ function isServerRunning(port) {
20
20
  });
21
21
  }
22
22
 
23
- function startPythonServer(scriptName, logName) {
23
+ function findMlxServerDir() {
24
+ // Try to find mlx-embed-server relative to the gmax binary (npm install location)
25
+ try {
26
+ const gmaxPath = execFileSync("which gmax", {
27
+ encoding: "utf-8",
28
+ }).trim();
29
+ // gmax binary is a symlink in .bin/ → resolve to package root
30
+ const realPath = fs.realpathSync(gmaxPath);
31
+ const pkgRoot = _path.resolve(_path.dirname(realPath), "..");
32
+ const serverDir = _path.join(pkgRoot, "mlx-embed-server");
33
+ if (fs.existsSync(_path.join(serverDir, "server.py"))) return serverDir;
34
+ } catch {}
35
+
36
+ // Fallback: dev mode — relative to plugin root
24
37
  const pluginRoot = __dirname.replace(/\/hooks$/, "");
25
- const gmaxRoot = _path.resolve(pluginRoot, "../..");
26
- const serverDir = _path.join(gmaxRoot, "mlx-embed-server");
38
+ const devRoot = _path.resolve(pluginRoot, "../..");
39
+ const devDir = _path.join(devRoot, "mlx-embed-server");
40
+ if (fs.existsSync(_path.join(devDir, "server.py"))) return devDir;
27
41
 
28
- if (!fs.existsSync(_path.join(serverDir, scriptName))) return;
42
+ return null;
43
+ }
44
+
45
+ function startPythonServer(serverDir, scriptName, logName) {
46
+ if (!serverDir) return;
29
47
 
30
48
  const logPath = `/tmp/${logName}.log`;
31
49
  const out = fs.openSync(logPath, "a");
@@ -41,7 +59,6 @@ function startPythonServer(scriptName, logName) {
41
59
 
42
60
  function startWatcher() {
43
61
  try {
44
- const { execFileSync } = require("node:child_process");
45
62
  execFileSync("gmax", ["watch", "-b"], { timeout: 5000, stdio: "ignore" });
46
63
  } catch {
47
64
  // Watcher may already be running or gmax not in PATH — ignore
@@ -49,18 +66,19 @@ function startWatcher() {
49
66
  }
50
67
 
51
68
  async function main() {
52
- const embedMode =
53
- process.env.GMAX_EMBED_MODE || process.env.OSGREP_EMBED_MODE || "auto";
69
+ const embedMode = process.env.GMAX_EMBED_MODE || "auto";
54
70
 
55
71
  if (embedMode !== "cpu") {
72
+ const serverDir = findMlxServerDir();
73
+
56
74
  // Start MLX embed server (port 8100)
57
- if (!(await isServerRunning(8100))) {
58
- startPythonServer("server.py", "mlx-embed-server");
75
+ if (serverDir && !(await isServerRunning(8100))) {
76
+ startPythonServer(serverDir, "server.py", "mlx-embed-server");
59
77
  }
60
78
 
61
79
  // Start LLM summarizer server (port 8101)
62
- if (!(await isServerRunning(8101))) {
63
- startPythonServer("summarizer.py", "mlx-summarizer");
80
+ if (serverDir && !(await isServerRunning(8101))) {
81
+ startPythonServer(serverDir, "summarizer.py", "mlx-summarizer");
64
82
  }
65
83
  }
66
84
 
@@ -71,7 +89,7 @@ async function main() {
71
89
  hookSpecificOutput: {
72
90
  hookEventName: "SessionStart",
73
91
  additionalContext:
74
- 'gmax MCP ready; prefer `gmax "<complete question>"` over grep (plain output is agent-friendly).',
92
+ "gmax MCP ready. Use semantic_search for concept-based code search (5+ words recommended). Use code_skeleton before reading large files. index_status to check health.",
75
93
  },
76
94
  };
77
95
  process.stdout.write(JSON.stringify(response));