grepmax 0.9.2 → 0.9.4
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 +17 -8
- package/dist/commands/skeleton.js +22 -4
- package/dist/lib/index/batch-processor.js +2 -1
- package/dist/lib/skeleton/retriever.js +1 -0
- package/dist/lib/store/meta-cache.js +1 -0
- package/dist/lib/store/vector-db.js +16 -0
- package/package.json +1 -1
- package/plugins/grepmax/.claude-plugin/plugin.json +1 -1
package/README.md
CHANGED
|
@@ -186,16 +186,17 @@ gmax index --reset # Full re-index from scratch
|
|
|
186
186
|
|
|
187
187
|
### `gmax watch`
|
|
188
188
|
|
|
189
|
-
Background file watcher for live reindexing.
|
|
189
|
+
Background file watcher for live reindexing. A single daemon process watches all registered projects through native OS file system events (`@parcel/watcher` — FSEvents on macOS, inotify on Linux). File changes are detected in sub-second and incrementally reindexed.
|
|
190
190
|
|
|
191
191
|
```bash
|
|
192
|
-
gmax watch -b
|
|
193
|
-
gmax watch
|
|
194
|
-
gmax watch status # Show
|
|
195
|
-
gmax watch stop
|
|
192
|
+
gmax watch --daemon -b # Start daemon (watches all projects)
|
|
193
|
+
gmax watch -b # Per-project mode (fallback)
|
|
194
|
+
gmax watch status # Show daemon + watcher status
|
|
195
|
+
gmax watch stop # Stop daemon
|
|
196
|
+
gmax watch stop --all # Stop everything
|
|
196
197
|
```
|
|
197
198
|
|
|
198
|
-
The
|
|
199
|
+
The daemon auto-starts when you run `gmax search` or use MCP tools. It shuts down after 30 minutes of inactivity. CLI commands communicate with the daemon over a Unix domain socket at `~/.gmax/daemon.sock`.
|
|
199
200
|
|
|
200
201
|
### `gmax summarize`
|
|
201
202
|
|
|
@@ -295,6 +296,9 @@ gmax doctor
|
|
|
295
296
|
All data lives in `~/.gmax/`:
|
|
296
297
|
- `~/.gmax/lancedb/` — LanceDB vector store (one database for all indexed directories)
|
|
297
298
|
- `~/.gmax/cache/meta.lmdb` — file metadata cache (content hashes, mtimes)
|
|
299
|
+
- `~/.gmax/cache/watchers.lmdb` — watcher/daemon registry (LMDB, crash-safe)
|
|
300
|
+
- `~/.gmax/daemon.sock` — Unix domain socket for daemon IPC
|
|
301
|
+
- `~/.gmax/logs/` — daemon and watcher logs (5MB rotation)
|
|
298
302
|
- `~/.gmax/config.json` — global config (model tier, embed mode)
|
|
299
303
|
- `~/.gmax/models/` — embedding models
|
|
300
304
|
- `~/.gmax/grammars/` — Tree-sitter grammars
|
|
@@ -304,6 +308,10 @@ All chunks store **absolute file paths**. Search scoping is done via path prefix
|
|
|
304
308
|
|
|
305
309
|
### Performance
|
|
306
310
|
|
|
311
|
+
- **Single Daemon:** One process watches all projects via native OS events — no polling, sub-second file change detection. Shared VectorDB, MetaCache, and worker pool across projects.
|
|
312
|
+
- **Native File Watching:** `@parcel/watcher` uses FSEvents (macOS), inotify (Linux), ReadDirectoryChangesW (Windows) — zero CPU overhead, no file descriptor exhaustion.
|
|
313
|
+
- **Automatic Compaction:** LanceDB table fragments from incremental inserts are compacted every 5 minutes, preventing performance degradation over time.
|
|
314
|
+
- **LMDB Caching:** File metadata reads use LRU/LFU caching for the watcher's hot path.
|
|
307
315
|
- **Bounded Concurrency:** Worker threads scale to 50% of CPU cores (min 4). Override with `GMAX_WORKER_THREADS`.
|
|
308
316
|
- **Smart Chunking:** `tree-sitter` splits code by function/class boundaries for complete logical blocks.
|
|
309
317
|
- **Deduplication:** Identical code blocks are embedded once and cached.
|
|
@@ -389,11 +397,12 @@ See [CLAUDE.md](CLAUDE.md) for development setup, commands, and architecture det
|
|
|
389
397
|
|
|
390
398
|
## Troubleshooting
|
|
391
399
|
|
|
392
|
-
- **Index feels stale?** Run `gmax index` to refresh
|
|
400
|
+
- **Index feels stale?** Run `gmax index` to refresh. The daemon auto-reindexes on file changes.
|
|
393
401
|
- **Weird results?** Run `gmax doctor` to verify models.
|
|
394
402
|
- **Index getting stuck?** Run `gmax index --verbose` to see which file is being processed.
|
|
395
403
|
- **Need a fresh start?** `rm -rf ~/.gmax/lancedb ~/.gmax/cache` then `gmax index`.
|
|
396
|
-
- **
|
|
404
|
+
- **Daemon issues?** Check `~/.gmax/logs/daemon.log`. Run `gmax watch stop` then `gmax watch --daemon -b` to restart.
|
|
405
|
+
- **MLX server won't start?** Check `~/.gmax/logs/mlx-embed-server.log` for errors. Use `GMAX_EMBED_MODE=cpu` to fall back to CPU.
|
|
397
406
|
|
|
398
407
|
## Attribution
|
|
399
408
|
|
|
@@ -63,7 +63,20 @@ const skeletonizer_1 = require("../lib/skeleton/skeletonizer");
|
|
|
63
63
|
const vector_db_1 = require("../lib/store/vector-db");
|
|
64
64
|
const file_utils_1 = require("../lib/utils/file-utils");
|
|
65
65
|
const exit_1 = require("../lib/utils/exit");
|
|
66
|
+
const project_registry_1 = require("../lib/utils/project-registry");
|
|
66
67
|
const project_root_1 = require("../lib/utils/project-root");
|
|
68
|
+
/**
|
|
69
|
+
* Resolve a relative path across all indexed projects.
|
|
70
|
+
* Returns the first match found, or null.
|
|
71
|
+
*/
|
|
72
|
+
function resolveAcrossProjects(relativePath) {
|
|
73
|
+
for (const project of (0, project_registry_1.listProjects)()) {
|
|
74
|
+
const candidate = path.join(project.root, relativePath);
|
|
75
|
+
if (fs.existsSync(candidate))
|
|
76
|
+
return candidate;
|
|
77
|
+
}
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
67
80
|
/**
|
|
68
81
|
* Check if target looks like a file path.
|
|
69
82
|
*/
|
|
@@ -185,11 +198,16 @@ Examples:
|
|
|
185
198
|
}
|
|
186
199
|
if (isFilePath(target)) {
|
|
187
200
|
// === FILE MODE ===
|
|
188
|
-
|
|
201
|
+
let filePath = path.resolve(target);
|
|
189
202
|
if (!fs.existsSync(filePath)) {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
203
|
+
// Try resolving across indexed projects
|
|
204
|
+
const found = resolveAcrossProjects(target);
|
|
205
|
+
if (!found) {
|
|
206
|
+
console.error(`File not found: ${filePath}`);
|
|
207
|
+
process.exitCode = 1;
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
filePath = found;
|
|
193
211
|
}
|
|
194
212
|
if (vectorDb) {
|
|
195
213
|
// Use absolute path for DB lookup (centralized index stores absolute paths)
|
|
@@ -82,9 +82,10 @@ class ProjectBatchProcessor {
|
|
|
82
82
|
return;
|
|
83
83
|
try {
|
|
84
84
|
yield this.vectorDb.createFTSIndex();
|
|
85
|
+
yield this.vectorDb.optimize();
|
|
85
86
|
}
|
|
86
87
|
catch (err) {
|
|
87
|
-
console.error(`[${this.wtag}] FTS rebuild failed:`, err);
|
|
88
|
+
console.error(`[${this.wtag}] FTS rebuild / compaction failed:`, err);
|
|
88
89
|
}
|
|
89
90
|
}), FTS_REBUILD_INTERVAL_MS);
|
|
90
91
|
this.ftsInterval.unref();
|
|
@@ -274,6 +274,22 @@ class VectorDB {
|
|
|
274
274
|
}
|
|
275
275
|
});
|
|
276
276
|
}
|
|
277
|
+
optimize() {
|
|
278
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
279
|
+
const table = yield this.ensureTable();
|
|
280
|
+
try {
|
|
281
|
+
yield table.optimize({
|
|
282
|
+
cleanupOlderThan: new Date(),
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
catch (e) {
|
|
286
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
287
|
+
if (!msg.includes("Nothing to do")) {
|
|
288
|
+
(0, logger_1.log)("vectordb", `Optimize failed: ${msg}`);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
}
|
|
277
293
|
hasAnyRows() {
|
|
278
294
|
return __awaiter(this, void 0, void 0, function* () {
|
|
279
295
|
const table = yield this.ensureTable();
|
package/package.json
CHANGED