grepmax 0.1.0 → 0.2.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.
Files changed (61) hide show
  1. package/LICENSE +1 -1
  2. package/NOTICE +2 -2
  3. package/README.md +72 -72
  4. package/dist/commands/claude-code.js +6 -6
  5. package/dist/commands/codex.js +17 -17
  6. package/dist/commands/doctor.js +6 -5
  7. package/dist/commands/droid.js +22 -22
  8. package/dist/commands/index.js +1 -1
  9. package/dist/commands/list.js +82 -19
  10. package/dist/commands/mcp.js +161 -142
  11. package/dist/commands/opencode.js +26 -26
  12. package/dist/commands/search.js +23 -13
  13. package/dist/commands/serve.js +30 -30
  14. package/dist/commands/setup.js +51 -40
  15. package/dist/commands/skeleton.js +19 -13
  16. package/dist/commands/symbols.js +40 -2
  17. package/dist/commands/verify.js +1 -1
  18. package/dist/commands/watch.js +206 -0
  19. package/dist/config.js +37 -7
  20. package/dist/eval.js +14 -14
  21. package/dist/index.js +11 -7
  22. package/dist/lib/core/languages.js +28 -0
  23. package/dist/lib/index/chunker.js +6 -3
  24. package/dist/lib/index/grammar-loader.js +2 -2
  25. package/dist/lib/index/ignore-patterns.js +1 -1
  26. package/dist/lib/index/index-config.js +50 -10
  27. package/dist/lib/index/sync-helpers.js +1 -1
  28. package/dist/lib/index/syncer.js +67 -45
  29. package/dist/lib/index/walker.js +3 -3
  30. package/dist/lib/index/watcher.js +4 -4
  31. package/dist/lib/output/formatter.js +1 -1
  32. package/dist/lib/search/searcher.js +9 -9
  33. package/dist/lib/setup/model-loader.js +3 -3
  34. package/dist/lib/setup/setup-helpers.js +2 -4
  35. package/dist/lib/skeleton/body-fields.js +20 -0
  36. package/dist/lib/skeleton/retriever.js +1 -1
  37. package/dist/lib/skeleton/skeletonizer.js +8 -2
  38. package/dist/lib/skeleton/summary-formatter.js +1 -4
  39. package/dist/lib/store/meta-cache.js +28 -3
  40. package/dist/lib/store/vector-db.js +17 -9
  41. package/dist/lib/utils/formatter.js +3 -3
  42. package/dist/lib/utils/lock.js +1 -1
  43. package/dist/lib/utils/project-registry.js +83 -0
  44. package/dist/lib/utils/project-root.js +32 -57
  45. package/dist/lib/utils/watcher-registry.js +100 -0
  46. package/dist/lib/workers/colbert-math.js +2 -2
  47. package/dist/lib/workers/download-worker.js +2 -2
  48. package/dist/lib/workers/embeddings/colbert.js +2 -2
  49. package/dist/lib/workers/embeddings/granite.js +4 -4
  50. package/dist/lib/workers/embeddings/mlx-client.js +1 -1
  51. package/dist/lib/workers/orchestrator.js +8 -8
  52. package/dist/lib/workers/pool.js +1 -1
  53. package/dist/lib/workers/worker.js +4 -1
  54. package/package.json +20 -21
  55. package/plugins/{osgrep → grepmax}/.claude-plugin/plugin.json +4 -4
  56. package/plugins/grepmax/hooks/start.js +63 -0
  57. package/plugins/grepmax/hooks/stop.js +3 -0
  58. package/plugins/{osgrep/skills/osgrep → grepmax/skills/gmax}/SKILL.md +11 -11
  59. package/plugins/osgrep/hooks/start.js +0 -90
  60. package/plugins/osgrep/hooks/stop.js +0 -3
  61. /package/plugins/{osgrep → grepmax}/hooks.json +0 -0
@@ -1,14 +1,14 @@
1
1
  {
2
- "name": "osgrep",
3
- "version": "0.1.0",
2
+ "name": "grepmax",
3
+ "version": "0.2.0",
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",
7
7
  "email": "robowens@me.com"
8
8
  },
9
9
  "hooks": "./hooks.json",
10
- "homepage": "https://github.com/reowens/osgrep-max",
11
- "repository": "https://github.com/reowens/osgrep-max",
10
+ "homepage": "https://github.com/reowens/grepmax",
11
+ "repository": "https://github.com/reowens/grepmax",
12
12
  "license": "Apache-2.0",
13
13
  "keywords": [
14
14
  "search",
@@ -0,0 +1,63 @@
1
+ const fs = require("node:fs");
2
+ const _path = require("node:path");
3
+ const http = require("node:http");
4
+ const { spawn } = require("node:child_process");
5
+
6
+ function isMlxRunning() {
7
+ return new Promise((resolve) => {
8
+ const req = http.get(
9
+ { hostname: "127.0.0.1", port: 8100, path: "/health", timeout: 1000 },
10
+ (res) => {
11
+ res.resume();
12
+ resolve(res.statusCode === 200);
13
+ },
14
+ );
15
+ req.on("error", () => resolve(false));
16
+ req.on("timeout", () => {
17
+ req.destroy();
18
+ resolve(false);
19
+ });
20
+ });
21
+ }
22
+
23
+ function startMlxServer() {
24
+ const pluginRoot = __dirname.replace(/\/hooks$/, "");
25
+ const gmaxRoot = _path.resolve(pluginRoot, "../..");
26
+ const serverDir = _path.join(gmaxRoot, "mlx-embed-server");
27
+
28
+ if (!fs.existsSync(_path.join(serverDir, "server.py"))) return;
29
+
30
+ const logPath = "/tmp/mlx-embed-server.log";
31
+ const out = fs.openSync(logPath, "a");
32
+
33
+ const child = spawn("uv", ["run", "python", "server.py"], {
34
+ cwd: serverDir,
35
+ detached: true,
36
+ stdio: ["ignore", out, out],
37
+ });
38
+ child.unref();
39
+ }
40
+
41
+ async function main() {
42
+ // Start MLX embed server if not running (set GMAX_EMBED_MODE=cpu to skip)
43
+ const embedMode =
44
+ process.env.GMAX_EMBED_MODE || process.env.OSGREP_EMBED_MODE || "auto";
45
+ if (embedMode !== "cpu") {
46
+ const mlxUp = await isMlxRunning();
47
+ if (!mlxUp) {
48
+ startMlxServer();
49
+ }
50
+ }
51
+
52
+ // MCP server handles indexing and search directly — no daemon needed
53
+ const response = {
54
+ hookSpecificOutput: {
55
+ hookEventName: "SessionStart",
56
+ additionalContext:
57
+ 'gmax MCP ready; prefer `gmax "<complete question>"` over grep (plain output is agent-friendly).',
58
+ },
59
+ };
60
+ process.stdout.write(JSON.stringify(response));
61
+ }
62
+
63
+ main();
@@ -0,0 +1,3 @@
1
+ // No-op: let gmax serve persist across sessions.
2
+ // The start hook ensures exactly one is running.
3
+ // Use `gmax serve stop` to explicitly shut it down.
@@ -1,15 +1,15 @@
1
1
  ---
2
- name: osgrep
3
- description: Semantic code search. Use alongside grep - grep for exact strings, osgrep for concepts.
4
- allowed-tools: "mcp__osgrep__semantic_search, mcp__osgrep__code_skeleton, mcp__osgrep__trace_calls, mcp__osgrep__list_symbols, Bash(osgrep:*), Read"
2
+ name: gmax
3
+ description: Semantic code search. Use alongside grep - grep for exact strings, gmax for concepts.
4
+ allowed-tools: "mcp__grepmax__semantic_search, mcp__grepmax__code_skeleton, mcp__grepmax__trace_calls, mcp__grepmax__list_symbols, mcp__grepmax__index_status, Bash(gmax:*), Read"
5
5
  ---
6
6
 
7
- ## What osgrep does
7
+ ## What gmax does
8
8
 
9
- Finds code by meaning. When you'd ask a colleague "where do we handle auth?", use osgrep.
9
+ Finds code by meaning. When you'd ask a colleague "where do we handle auth?", use gmax.
10
10
 
11
11
  - grep/ripgrep: exact string match, fast
12
- - osgrep: concept match, finds code you couldn't grep for
12
+ - gmax: concept match, finds code you couldn't grep for
13
13
 
14
14
  ## MCP tools (preferred)
15
15
 
@@ -45,11 +45,11 @@ Check index and daemon health — file count, chunks, embed mode, age, watching
45
45
  If MCP tools aren't available, use the CLI via Bash:
46
46
 
47
47
  ```bash
48
- osgrep "where do we validate user permissions" # Semantic search
49
- osgrep "authentication" --compact # Just file paths + line ranges
50
- osgrep skeleton src/giant-2000-line-file.ts # File structure
51
- osgrep trace handleAuth # Call graph
52
- osgrep symbols booking # Find symbols by name
48
+ gmax "where do we validate user permissions" # Semantic search
49
+ gmax "authentication" --compact # Just file paths + line ranges
50
+ gmax skeleton src/giant-2000-line-file.ts # File structure
51
+ gmax trace handleAuth # Call graph
52
+ gmax symbols booking # Find symbols by name
53
53
  ```
54
54
 
55
55
  ## Output explained (CLI)
@@ -1,90 +0,0 @@
1
- const fs = require("node:fs");
2
- const os = require("node:os");
3
- const _path = require("node:path");
4
- const http = require("node:http");
5
- const { spawn } = require("node:child_process");
6
-
7
- function readPayload() {
8
- try {
9
- const raw = fs.readFileSync(0, "utf-8");
10
- return raw ? JSON.parse(raw) : {};
11
- } catch {
12
- return {};
13
- }
14
- }
15
-
16
- function isServerRunning(cwd) {
17
- // Read the global server registry (matches how osgrep serve registers)
18
- const registryPath = _path.join(os.homedir(), ".osgrep", "servers.json");
19
- try {
20
- const servers = JSON.parse(fs.readFileSync(registryPath, "utf-8"));
21
- const match = servers.find((s) => s.projectRoot === cwd);
22
- if (match && typeof match.pid === "number") {
23
- process.kill(match.pid, 0); // throws if not running
24
- return true;
25
- }
26
- } catch {}
27
- return false;
28
- }
29
-
30
- function isMlxRunning() {
31
- return new Promise((resolve) => {
32
- const req = http.get(
33
- { hostname: "127.0.0.1", port: 8100, path: "/health", timeout: 1000 },
34
- (res) => {
35
- res.resume();
36
- resolve(res.statusCode === 200);
37
- }
38
- );
39
- req.on("error", () => resolve(false));
40
- req.on("timeout", () => { req.destroy(); resolve(false); });
41
- });
42
- }
43
-
44
- function startMlxServer() {
45
- // Find the mlx-embed-server directory relative to plugin root
46
- const pluginRoot = __dirname.replace(/\/hooks$/, "");
47
- const osgrepRoot = _path.resolve(pluginRoot, "../..");
48
- const serverDir = _path.join(osgrepRoot, "mlx-embed-server");
49
-
50
- if (!fs.existsSync(_path.join(serverDir, "server.py"))) return;
51
-
52
- const logPath = "/tmp/mlx-embed-server.log";
53
- const out = fs.openSync(logPath, "a");
54
-
55
- const child = spawn("uv", ["run", "python", "server.py"], {
56
- cwd: serverDir,
57
- detached: true,
58
- stdio: ["ignore", out, out],
59
- });
60
- child.unref();
61
- }
62
-
63
- async function main() {
64
- const payload = readPayload();
65
- const cwd = payload.cwd || process.cwd();
66
-
67
- // Check if osgrep serve is running (read-only — MCP server owns daemon lifecycle)
68
- const daemonUp = isServerRunning(cwd);
69
-
70
- // Start MLX embed server if not running (set OSGREP_EMBED_MODE=cpu to skip)
71
- const embedMode = process.env.OSGREP_EMBED_MODE || "auto";
72
- if (embedMode !== "cpu") {
73
- const mlxUp = await isMlxRunning();
74
- if (!mlxUp) {
75
- startMlxServer();
76
- }
77
- }
78
-
79
- const status = daemonUp ? "running" : "starting via MCP";
80
- const response = {
81
- hookSpecificOutput: {
82
- hookEventName: "SessionStart",
83
- additionalContext:
84
- `osgrep serve ${status}; prefer \`osgrep "<complete question>"\` over grep (plain output is agent-friendly).`,
85
- },
86
- };
87
- process.stdout.write(JSON.stringify(response));
88
- }
89
-
90
- main();
@@ -1,3 +0,0 @@
1
- // No-op: let osgrep serve persist across sessions.
2
- // The start hook ensures exactly one is running.
3
- // Use `osgrep serve stop` to explicitly shut it down.
File without changes