grepmax 0.7.42 → 0.7.44

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/README.md CHANGED
@@ -24,7 +24,7 @@ Natural-language search that works like `grep`. Fast, local, and built for codin
24
24
  - **Role Detection:** Distinguishes `ORCHESTRATION` (high-level logic) from `DEFINITION` (types/classes).
25
25
  - **Local & Private:** 100% local embeddings via ONNX (CPU) or MLX (Apple Silicon GPU).
26
26
  - **Centralized Index:** One database at `~/.gmax/` — index once, search from anywhere.
27
- - **LLM Summaries:** Optional Qwen3-Coder generates one-line descriptions per code chunk at index time.
27
+ - **LLM Summaries:** Optional Qwen3-Coder generates one-line descriptions per code chunk on demand.
28
28
  - **Agent-Ready:** Pointer mode returns metadata (symbol, role, calls, summary) — no code snippets, ~80% fewer tokens.
29
29
 
30
30
  ## Quick Start
@@ -186,7 +186,7 @@ gmax index --reset # Full re-index from scratch
186
186
 
187
187
  ### `gmax watch`
188
188
 
189
- Background file watcher for live reindexing. Watches for file changes and incrementally updates the centralized index.
189
+ Background file watcher for live reindexing. Watches for file changes and incrementally updates the centralized index. Uses FSEvents on macOS (kernel-level, low overhead) and polling on Linux.
190
190
 
191
191
  ```bash
192
192
  gmax watch -b # Background mode (auto-stops after 30min idle)
@@ -197,6 +197,17 @@ gmax watch stop --all # Stop all watchers
197
197
 
198
198
  The MCP server auto-starts a watcher on session start. You rarely need to run this manually.
199
199
 
200
+ ### `gmax summarize`
201
+
202
+ Generate one-line LLM summaries for indexed chunks. Requires the summarizer server (Qwen3-Coder via MLX on Apple Silicon). Summaries are stored in LanceDB and appear in search results.
203
+
204
+ ```bash
205
+ gmax summarize # Summarize all unsummarized chunks
206
+ gmax summarize --path src/lib/ # Only summarize chunks under a directory
207
+ ```
208
+
209
+ Summarization is **on-demand only** — it does not run automatically during indexing or file watching. The `summarize_directory` MCP tool provides the same functionality for AI agents.
210
+
200
211
  ### `gmax serve`
201
212
 
202
213
  HTTP server with live file watching. Useful for non-MCP integrations.
@@ -307,9 +318,15 @@ To force CPU mode: `GMAX_EMBED_MODE=cpu gmax index`
307
318
 
308
319
  ### LLM Summaries
309
320
 
310
- gmax can generate one-line natural language descriptions for every code chunk using a local LLM (Qwen3-Coder-30B-A3B via MLX). Summaries are pre-computed at index time and stored in LanceDB — zero latency at search time.
321
+ gmax can generate one-line natural language descriptions for every code chunk using a local LLM (Qwen3-Coder-30B-A3B via MLX). Summaries are stored in LanceDB — zero latency at search time.
322
+
323
+ Summarization is **on-demand**, not automatic. Run `gmax summarize` or use the `summarize_directory` MCP tool after indexing. The summarizer server runs on port `8101` and must be started separately. If unavailable, `gmax summarize` will report the server is not running.
311
324
 
312
- The summarizer server runs on port `8101` and auto-starts alongside the embed server. If unavailable, indexing proceeds without summaries.
325
+ ```bash
326
+ gmax summarize # Generate summaries for all unsummarized chunks
327
+ gmax summarize --path src/lib/ # Scope to a directory
328
+ gmax doctor # Check summarizer status + coverage
329
+ ```
313
330
 
314
331
  Example search output with summaries:
315
332
  ```
@@ -364,6 +381,7 @@ fixtures/
364
381
  | `GMAX_WORKER_TASK_TIMEOUT_MS` | Worker task timeout in ms | `120000` |
365
382
  | `GMAX_MAX_WORKER_MEMORY_MB` | Max worker memory in MB | 50% of system RAM |
366
383
  | `GMAX_MAX_PER_FILE` | Default max results per file in search | `3` |
384
+ | `GMAX_WATCH_POLL` | Force polling mode for file watcher (`1` to enable) | Off (FSEvents on macOS) |
367
385
 
368
386
  ## Contributing
369
387
 
@@ -0,0 +1,154 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
36
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
37
+ return new (P || (P = Promise))(function (resolve, reject) {
38
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
39
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
40
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
41
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
42
+ });
43
+ };
44
+ Object.defineProperty(exports, "__esModule", { value: true });
45
+ exports.add = void 0;
46
+ const node_child_process_1 = require("node:child_process");
47
+ const path = __importStar(require("node:path"));
48
+ const commander_1 = require("commander");
49
+ const grammar_loader_1 = require("../lib/index/grammar-loader");
50
+ const sync_helpers_1 = require("../lib/index/sync-helpers");
51
+ const syncer_1 = require("../lib/index/syncer");
52
+ const setup_helpers_1 = require("../lib/setup/setup-helpers");
53
+ const vector_db_1 = require("../lib/store/vector-db");
54
+ const exit_1 = require("../lib/utils/exit");
55
+ const project_marker_1 = require("../lib/utils/project-marker");
56
+ const project_registry_1 = require("../lib/utils/project-registry");
57
+ const project_root_1 = require("../lib/utils/project-root");
58
+ const index_config_1 = require("../lib/index/index-config");
59
+ exports.add = new commander_1.Command("add")
60
+ .description("Add a project to the gmax index")
61
+ .argument("[dir]", "Directory to add (defaults to current directory)")
62
+ .option("--no-index", "Register the project without indexing it")
63
+ .addHelpText("after", `
64
+ Examples:
65
+ gmax add Add the current directory
66
+ gmax add ~/projects/myapp Add a specific project
67
+ gmax add . --no-index Register only, index later with gmax index
68
+ `)
69
+ .action((dir, opts) => __awaiter(void 0, void 0, void 0, function* () {
70
+ var _a, _b;
71
+ let vectorDb = null;
72
+ try {
73
+ const targetDir = dir ? path.resolve(dir) : process.cwd();
74
+ const projectRoot = (_a = (0, project_root_1.findProjectRoot)(targetDir)) !== null && _a !== void 0 ? _a : targetDir;
75
+ const projectName = path.basename(projectRoot);
76
+ // Check if already registered
77
+ const existing = (0, project_registry_1.getProject)(projectRoot);
78
+ if (existing || (0, project_marker_1.hasMarker)(projectRoot)) {
79
+ console.log(`${projectName} is already added (${(_b = existing === null || existing === void 0 ? void 0 : existing.chunkCount) !== null && _b !== void 0 ? _b : 0} chunks).`);
80
+ console.log(`Run \`gmax index\` to re-index, or \`gmax index --reset\` for a full rebuild.`);
81
+ return;
82
+ }
83
+ // Create marker file
84
+ (0, project_marker_1.createMarker)(projectRoot);
85
+ // Register as pending
86
+ const globalConfig = (0, index_config_1.readGlobalConfig)();
87
+ (0, project_registry_1.registerProject)({
88
+ root: projectRoot,
89
+ name: projectName,
90
+ vectorDim: globalConfig.vectorDim,
91
+ modelTier: globalConfig.modelTier,
92
+ embedMode: globalConfig.embedMode,
93
+ lastIndexed: "",
94
+ chunkCount: 0,
95
+ status: "pending",
96
+ });
97
+ if (!opts.index) {
98
+ console.log(`Registered ${projectName}. Run \`gmax index\` when ready to index.`);
99
+ return;
100
+ }
101
+ // Index the project
102
+ yield (0, setup_helpers_1.ensureSetup)();
103
+ const paths = (0, project_root_1.ensureProjectPaths)(projectRoot);
104
+ vectorDb = new vector_db_1.VectorDB(paths.lancedbDir);
105
+ yield (0, grammar_loader_1.ensureGrammars)(console.log, { silent: true });
106
+ const { spinner, onProgress } = (0, sync_helpers_1.createIndexingSpinner)(projectRoot, `Adding ${projectName}...`);
107
+ try {
108
+ const result = yield (0, syncer_1.initialSync)({
109
+ projectRoot,
110
+ onProgress,
111
+ });
112
+ const failedSuffix = result.failedFiles > 0 ? ` · ${result.failedFiles} failed` : "";
113
+ spinner.succeed(`Added ${projectName} (${result.total} files, ${result.indexed} chunks${failedSuffix})`);
114
+ }
115
+ catch (e) {
116
+ // Update status to error
117
+ (0, project_registry_1.registerProject)({
118
+ root: projectRoot,
119
+ name: projectName,
120
+ vectorDim: globalConfig.vectorDim,
121
+ modelTier: globalConfig.modelTier,
122
+ embedMode: globalConfig.embedMode,
123
+ lastIndexed: "",
124
+ chunkCount: 0,
125
+ status: "error",
126
+ });
127
+ spinner.fail(`Failed to index ${projectName}`);
128
+ throw e;
129
+ }
130
+ // Start watcher in background
131
+ try {
132
+ const child = (0, node_child_process_1.spawn)(process.argv[0], [process.argv[1], "watch", "--path", projectRoot], { detached: true, stdio: "ignore" });
133
+ child.unref();
134
+ console.log(`Watcher started (PID: ${child.pid})`);
135
+ }
136
+ catch (_c) {
137
+ console.log(`Note: could not start watcher. Run: gmax watch --path ${projectRoot} -b`);
138
+ }
139
+ }
140
+ catch (error) {
141
+ const message = error instanceof Error ? error.message : "Unknown error";
142
+ console.error("Failed to add project:", message);
143
+ process.exitCode = 1;
144
+ }
145
+ finally {
146
+ if (vectorDb) {
147
+ try {
148
+ yield vectorDb.close();
149
+ }
150
+ catch (_d) { }
151
+ }
152
+ yield (0, exit_1.gracefulExit)();
153
+ }
154
+ }));
@@ -1,4 +1,37 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
36
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
37
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -10,6 +43,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
43
  };
11
44
  Object.defineProperty(exports, "__esModule", { value: true });
12
45
  exports.installClaudeCode = void 0;
46
+ const fs = __importStar(require("node:fs"));
47
+ const path = __importStar(require("node:path"));
13
48
  const node_child_process_1 = require("node:child_process");
14
49
  const commander_1 = require("commander");
15
50
  function runClaudeCommand(args) {
@@ -29,19 +64,47 @@ function runClaudeCommand(args) {
29
64
  });
30
65
  });
31
66
  }
67
+ /**
68
+ * Resolve the gmax package root directory.
69
+ * Works for both npm global installs (symlinked binary) and dev mode.
70
+ * __dirname at runtime is dist/commands/, so go up two levels.
71
+ */
72
+ function getPackageRoot() {
73
+ return path.resolve(__dirname, "../..");
74
+ }
32
75
  function installPlugin() {
33
76
  return __awaiter(this, void 0, void 0, function* () {
34
77
  try {
35
- yield runClaudeCommand(["marketplace", "add", "reowens/grepmax"]);
36
- yield runClaudeCommand(["marketplace", "update", "grepmax"]);
37
- console.log("✅ Marketplace updated");
78
+ const packageRoot = getPackageRoot();
79
+ const marketplacePath = path.resolve(packageRoot);
80
+ // Verify the marketplace.json exists at the package root
81
+ const marketplaceJson = path.join(marketplacePath, ".claude-plugin", "marketplace.json");
82
+ if (!fs.existsSync(marketplaceJson)) {
83
+ console.error(`❌ Could not find marketplace.json at ${marketplaceJson}`);
84
+ console.error(" Is gmax installed correctly?");
85
+ process.exitCode = 1;
86
+ return;
87
+ }
88
+ console.log(`Installing plugin from ${marketplacePath}`);
89
+ // Remove old GitHub-based marketplace if present (ignore errors)
90
+ try {
91
+ yield runClaudeCommand(["marketplace", "remove", "grepmax"]);
92
+ }
93
+ catch (_a) {
94
+ // May not exist — fine
95
+ }
96
+ // Add local package directory as marketplace source
97
+ yield runClaudeCommand(["marketplace", "add", marketplacePath]);
98
+ console.log("✔ Marketplace registered (local)");
99
+ // Install the plugin from the local marketplace
38
100
  yield runClaudeCommand(["install", "grepmax"]);
39
101
  console.log("✅ Successfully installed the gmax plugin for Claude Code");
40
102
  console.log("\nNext steps:");
41
103
  console.log("1. Restart Claude Code if it's running");
42
- console.log("2. The plugin will automatically index your project when you open it");
104
+ console.log("2. Run `gmax add` in your project to index it");
43
105
  console.log("3. Claude will use gmax for semantic code search automatically");
44
- console.log("4. You can also use `gmax` commands directly in your terminal");
106
+ console.log("\nTo update the plugin after upgrading gmax:");
107
+ console.log(" gmax install-claude-code");
45
108
  }
46
109
  catch (error) {
47
110
  console.error("❌ Error installing plugin:");
@@ -49,7 +112,6 @@ function installPlugin() {
49
112
  console.error("\nTroubleshooting:");
50
113
  console.error("- Ensure you have Claude Code version 2.0.36 or higher installed");
51
114
  console.error("- Try running: claude plugin marketplace list");
52
- console.error("- Check the Claude Code documentation: https://code.claude.com/docs");
53
115
  process.exitCode = 1;
54
116
  }
55
117
  });
@@ -13,6 +13,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.uninstallOpencode = exports.installOpencode = void 0;
16
+ const node_child_process_1 = require("node:child_process");
16
17
  const node_fs_1 = __importDefault(require("node:fs"));
17
18
  const node_os_1 = __importDefault(require("node:os"));
18
19
  const node_path_1 = __importDefault(require("node:path"));
@@ -20,7 +21,21 @@ const commander_1 = require("commander");
20
21
  const TOOL_PATH = node_path_1.default.join(node_os_1.default.homedir(), ".config", "opencode", "tool", "gmax.ts");
21
22
  const PLUGIN_PATH = node_path_1.default.join(node_os_1.default.homedir(), ".config", "opencode", "plugin", "gmax.ts");
22
23
  const CONFIG_PATH = node_path_1.default.join(node_os_1.default.homedir(), ".config", "opencode", "opencode.json");
23
- const SHIM_CONTENT = `
24
+ function resolveGmaxBin() {
25
+ try {
26
+ return (0, node_child_process_1.execSync)("which gmax", { encoding: "utf-8" }).trim();
27
+ }
28
+ catch (_a) {
29
+ // Fall back to the path of the current process entry point
30
+ const binDir = node_path_1.default.dirname(process.argv[1]);
31
+ const candidate = node_path_1.default.join(binDir, "gmax");
32
+ if (node_fs_1.default.existsSync(candidate))
33
+ return candidate;
34
+ return "gmax";
35
+ }
36
+ }
37
+ function buildShimContent(gmaxBin) {
38
+ return `
24
39
  import { tool } from "@opencode-ai/plugin";
25
40
 
26
41
  const SKILL = \`
@@ -54,7 +69,7 @@ export async function handleAuth(req: Request) {
54
69
  const claims = await validateToken(token);
55
70
  if (!claims) return unauthorized();
56
71
  const allowed = await checkRole(claims.role, req.path);
57
- ...
72
+ ...
58
73
 
59
74
  - **ORCHESTRATION** = contains logic, coordinates other code
60
75
  - **DEFINITION** = types, interfaces, classes
@@ -102,8 +117,14 @@ gmax trace handleRequest
102
117
  - Don't read entire files. Use the line ranges gmax gives you.
103
118
  - If results seem off, rephrase your query like you'd ask a teammate
104
119
 
120
+ ## If Index is Building
121
+
122
+ If you see "Indexing" or "Syncing": STOP. Tell the user the index is building. Ask if they want to wait or proceed with partial results.
123
+
105
124
  \`;
106
125
 
126
+ const GMAX_BIN = "${gmaxBin}";
127
+
107
128
  export default tool({
108
129
  description: SKILL,
109
130
  args: {
@@ -113,14 +134,23 @@ export default tool({
113
134
  async execute({ argv }) {
114
135
  try {
115
136
  // @ts-ignore
116
- const out = await Bun.spawn(["gmax", ...argv], { stdout: "pipe" }).stdout;
137
+ const out = await Bun.spawn([GMAX_BIN, ...argv], { stdout: "pipe" }).stdout;
117
138
  const text = await new Response(out).text();
139
+ if (text.includes("Indexing") || text.includes("Building") || text.includes("Syncing")) {
140
+ return \`WARN: The index is currently updating.
141
+
142
+ Output so far:
143
+ \${text.trim()}
144
+
145
+ PLEASE READ THE "Indexing" WARNING IN MY SKILL DESCRIPTION.\`;
146
+ }
118
147
  return text.trim();
119
148
  } catch (err) {
120
149
  return \`Error running gmax: \${err}\`;
121
150
  }
122
151
  },
123
152
  })`;
153
+ }
124
154
  function install() {
125
155
  return __awaiter(this, void 0, void 0, function* () {
126
156
  try {
@@ -134,11 +164,14 @@ function install() {
134
164
  console.warn("mnt: Failed to delete legacy plugin:", e);
135
165
  }
136
166
  }
137
- // 2. Create tool shim
167
+ // 2. Resolve absolute path to gmax binary
168
+ const gmaxBin = resolveGmaxBin();
169
+ console.log(` Resolved gmax binary: ${gmaxBin}`);
170
+ // 3. Create tool shim
138
171
  node_fs_1.default.mkdirSync(node_path_1.default.dirname(TOOL_PATH), { recursive: true });
139
- node_fs_1.default.writeFileSync(TOOL_PATH, SHIM_CONTENT);
172
+ node_fs_1.default.writeFileSync(TOOL_PATH, buildShimContent(gmaxBin));
140
173
  console.log("✅ Created tool shim at", TOOL_PATH);
141
- // 3. Register MCP
174
+ // 4. Register MCP
142
175
  if (!node_fs_1.default.existsSync(CONFIG_PATH)) {
143
176
  node_fs_1.default.mkdirSync(node_path_1.default.dirname(CONFIG_PATH), { recursive: true });
144
177
  node_fs_1.default.writeFileSync(CONFIG_PATH, JSON.stringify({}, null, 2));
@@ -150,12 +183,11 @@ function install() {
150
183
  config.mcp = {};
151
184
  config.mcp.gmax = {
152
185
  type: "local",
153
- command: ["gmax", "mcp"],
186
+ command: [gmaxBin, "mcp"],
154
187
  enabled: true,
155
188
  };
156
189
  node_fs_1.default.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2));
157
190
  console.log("✅ Registered MCP server in", CONFIG_PATH);
158
- console.log(" Command: check proper path if 'gmax' is not in PATH of OpenCode.");
159
191
  }
160
192
  catch (err) {
161
193
  console.error("❌ Installation failed:", err);
@@ -59,16 +59,19 @@ exports.related = new commander_1.Command("related")
59
59
  .description("Find files related by shared symbol references")
60
60
  .argument("<file>", "File path relative to project root")
61
61
  .option("-l, --limit <n>", "Max results per direction (default 10)", "10")
62
+ .option("--root <dir>", "Project root directory")
62
63
  .action((file, opts) => __awaiter(void 0, void 0, void 0, function* () {
63
64
  var _a;
64
65
  const limit = Math.min(Math.max(Number.parseInt(opts.limit || "10", 10), 1), 25);
65
66
  let vectorDb = null;
66
67
  try {
67
- const projectRoot = (_a = (0, project_root_1.findProjectRoot)(process.cwd())) !== null && _a !== void 0 ? _a : process.cwd();
68
+ const root = opts.root ? path.resolve(opts.root) : process.cwd();
69
+ const projectRoot = (_a = (0, project_root_1.findProjectRoot)(root)) !== null && _a !== void 0 ? _a : root;
68
70
  const paths = (0, project_root_1.ensureProjectPaths)(projectRoot);
69
71
  vectorDb = new vector_db_1.VectorDB(paths.lancedbDir);
70
72
  const absPath = path.resolve(projectRoot, file);
71
73
  const table = yield vectorDb.ensureTable();
74
+ const pathScope = `path LIKE '${(0, filter_builder_1.escapeSqlString)(projectRoot)}/%'`;
72
75
  const fileChunks = yield table
73
76
  .query()
74
77
  .select(["defined_symbols", "referenced_symbols"])
@@ -94,7 +97,7 @@ exports.related = new commander_1.Command("related")
94
97
  const rows = yield table
95
98
  .query()
96
99
  .select(["path"])
97
- .where(`array_contains(defined_symbols, '${(0, filter_builder_1.escapeSqlString)(sym)}')`)
100
+ .where(`array_contains(defined_symbols, '${(0, filter_builder_1.escapeSqlString)(sym)}') AND ${pathScope}`)
98
101
  .limit(3)
99
102
  .toArray();
100
103
  for (const row of rows) {
@@ -110,7 +113,7 @@ exports.related = new commander_1.Command("related")
110
113
  const rows = yield table
111
114
  .query()
112
115
  .select(["path"])
113
- .where(`array_contains(referenced_symbols, '${(0, filter_builder_1.escapeSqlString)(sym)}')`)
116
+ .where(`array_contains(referenced_symbols, '${(0, filter_builder_1.escapeSqlString)(sym)}') AND ${pathScope}`)
114
117
  .limit(20)
115
118
  .toArray();
116
119
  for (const row of rows) {
@@ -0,0 +1,152 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
36
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
37
+ return new (P || (P = Promise))(function (resolve, reject) {
38
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
39
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
40
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
41
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
42
+ });
43
+ };
44
+ Object.defineProperty(exports, "__esModule", { value: true });
45
+ exports.remove = void 0;
46
+ const path = __importStar(require("node:path"));
47
+ const readline = __importStar(require("node:readline"));
48
+ const commander_1 = require("commander");
49
+ const meta_cache_1 = require("../lib/store/meta-cache");
50
+ const vector_db_1 = require("../lib/store/vector-db");
51
+ const exit_1 = require("../lib/utils/exit");
52
+ const project_marker_1 = require("../lib/utils/project-marker");
53
+ const project_registry_1 = require("../lib/utils/project-registry");
54
+ const project_root_1 = require("../lib/utils/project-root");
55
+ const watcher_registry_1 = require("../lib/utils/watcher-registry");
56
+ function confirm(message) {
57
+ const rl = readline.createInterface({
58
+ input: process.stdin,
59
+ output: process.stdout,
60
+ });
61
+ return new Promise((resolve) => {
62
+ rl.question(`${message} [y/N] `, (answer) => {
63
+ rl.close();
64
+ resolve(answer.toLowerCase() === "y");
65
+ });
66
+ });
67
+ }
68
+ exports.remove = new commander_1.Command("remove")
69
+ .description("Remove a project from the gmax index")
70
+ .argument("[dir]", "Directory to remove (defaults to current directory)")
71
+ .option("-f, --force", "Skip confirmation prompt", false)
72
+ .addHelpText("after", `
73
+ Examples:
74
+ gmax remove Remove the current project
75
+ gmax remove ~/projects/app Remove a specific project
76
+ gmax remove --force Skip confirmation
77
+ `)
78
+ .action((dir, opts) => __awaiter(void 0, void 0, void 0, function* () {
79
+ var _a;
80
+ let vectorDb = null;
81
+ let metaCache = null;
82
+ try {
83
+ const targetDir = dir ? path.resolve(dir) : process.cwd();
84
+ const projectRoot = (_a = (0, project_root_1.findProjectRoot)(targetDir)) !== null && _a !== void 0 ? _a : targetDir;
85
+ const projectName = path.basename(projectRoot);
86
+ const project = (0, project_registry_1.getProject)(projectRoot);
87
+ if (!project) {
88
+ console.log(`${projectName} is not in the gmax index.`);
89
+ return;
90
+ }
91
+ const chunkStr = project.chunkCount
92
+ ? ` (${project.chunkCount.toLocaleString()} chunks)`
93
+ : "";
94
+ if (!opts.force) {
95
+ const ok = yield confirm(`Remove ${projectName}${chunkStr} from the index? This deletes all indexed data.`);
96
+ if (!ok) {
97
+ console.log("Cancelled.");
98
+ return;
99
+ }
100
+ }
101
+ // Stop any watcher
102
+ const watcher = (0, watcher_registry_1.getWatcherForProject)(projectRoot);
103
+ if (watcher) {
104
+ console.log(`Stopping watcher (PID: ${watcher.pid})...`);
105
+ try {
106
+ process.kill(watcher.pid, "SIGTERM");
107
+ }
108
+ catch (_b) { }
109
+ for (let i = 0; i < 50; i++) {
110
+ if (!(0, watcher_registry_1.isProcessRunning)(watcher.pid))
111
+ break;
112
+ yield new Promise((r) => setTimeout(r, 100));
113
+ }
114
+ (0, watcher_registry_1.unregisterWatcher)(watcher.pid);
115
+ }
116
+ // Delete vectors from LanceDB
117
+ const paths = (0, project_root_1.ensureProjectPaths)(projectRoot);
118
+ vectorDb = new vector_db_1.VectorDB(paths.lancedbDir);
119
+ yield vectorDb.deletePathsWithPrefix(projectRoot);
120
+ // Clean MetaCache entries
121
+ metaCache = new meta_cache_1.MetaCache(paths.lmdbPath);
122
+ const keys = yield metaCache.getKeysWithPrefix(projectRoot);
123
+ for (const key of keys) {
124
+ metaCache.delete(key);
125
+ }
126
+ // Remove from registry
127
+ (0, project_registry_1.removeProject)(projectRoot);
128
+ // Delete marker file
129
+ (0, project_marker_1.removeMarker)(projectRoot);
130
+ console.log(`Removed ${projectName}${chunkStr}.`);
131
+ }
132
+ catch (error) {
133
+ const message = error instanceof Error ? error.message : "Unknown error";
134
+ console.error("Failed to remove project:", message);
135
+ process.exitCode = 1;
136
+ }
137
+ finally {
138
+ if (metaCache) {
139
+ try {
140
+ metaCache.close();
141
+ }
142
+ catch (_c) { }
143
+ }
144
+ if (vectorDb) {
145
+ try {
146
+ yield vectorDb.close();
147
+ }
148
+ catch (_d) { }
149
+ }
150
+ yield (0, exit_1.gracefulExit)();
151
+ }
152
+ }));