grepmax 0.26.67 → 0.26.68
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.
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"name": "grepmax",
|
|
11
11
|
"source": "./plugins/grepmax",
|
|
12
12
|
"description": "Semantic code search for Claude Code. Automatically indexes your project and provides intelligent search capabilities.",
|
|
13
|
-
"version": "0.26.
|
|
13
|
+
"version": "0.26.68",
|
|
14
14
|
"author": {
|
|
15
15
|
"name": "Robert Owens",
|
|
16
16
|
"email": "robowens@me.com"
|
package/README.md
CHANGED
|
@@ -240,7 +240,7 @@ gmax status # See all projects + watcher status
|
|
|
240
240
|
|
|
241
241
|
Adding or indexing a project can start the daemon automatically. MCP acquires primary-project watch leases lazily when an index-reading tool is used; discovery and catalog listing start no background work. It shuts down after 4 hours of inactivity, and hands off to a fresh daemon after 24 hours or once its memory footprint passes 2.5 GB. File-change batches are processed on up to four worker processes by default, added only when work backs up, with one kept free for searches; full-table compaction and new FTS/ANN index builds are disabled by containment. Existing indexes remain readable. Host safety stops persist across restart and block heavy operations.
|
|
242
242
|
|
|
243
|
-
`gmax watch status` reports failed files, native watcher recovery or polling, dropped-event counts, and the last complete filesystem reconciliation. FSEvents dropped-event warnings keep the native stream attached and preserve the accompanying events. A reconciliation covers the gap; repeated warnings coalesce into one later scan, with a 30-second scan interval. Recovery stays visible until a complete scan covers the latest gap. Other backend errors still trigger subscription recovery; repeated terminal failures fall back to five-minute polling, where recent edits can lag. Search and MCP responses retain health warnings even after the file queue drains. A complete reconciliation means the filesystem scan completed; queued embedding work can still be pending.
|
|
243
|
+
`gmax watch status` reports failed files, native watcher recovery or polling, dropped-event counts, and the last complete filesystem reconciliation. FSEvents dropped-event warnings keep the native stream attached and preserve the accompanying events. A reconciliation covers the gap; repeated warnings coalesce into one later scan, with a 30-second scan interval. Recovery stays visible until a complete scan covers the latest gap. Other backend errors still trigger subscription recovery; repeated terminal failures fall back to five-minute polling, where recent edits can lag. Search and MCP responses retain health warnings even after the file queue drains. Live edit batches can run during reconciliation instead of waiting for the full filesystem walk. Whole-project reindex and removal still quiesce the watcher and drain its work before changing the project. A complete reconciliation means the filesystem scan completed; queued embedding work can still be pending.
|
|
244
244
|
|
|
245
245
|
Live filesystem edits take priority over background catchup and cleanup. Background batches dispatch one file at a time, with at most four catchup files or 50 cleanup paths. They yield between files when a live edit arrives or the two-second dispatch window is reached; an active file or store commit finishes before yielding. Catchup and cleanup alternate, and one background file is admitted after three consecutive live batches so cleanup continues during sustained editing. Existing retry backoff and worker limits remain in effect.
|
|
246
246
|
|
|
@@ -192,7 +192,14 @@ class Daemon {
|
|
|
192
192
|
evictSearcher: (root) => {
|
|
193
193
|
this.searchers.delete(root);
|
|
194
194
|
},
|
|
195
|
-
runProjectOperation: (root, name, signal, fn) =>
|
|
195
|
+
runProjectOperation: (root, name, signal, fn) => {
|
|
196
|
+
// A filesystem walk can take minutes. Keep it lifecycle-tracked and
|
|
197
|
+
// admitted, but let live batches hold the project's write lock while
|
|
198
|
+
// the scan yields. Project removal/reindex quiesces the watcher first.
|
|
199
|
+
if (name === "watch-catchup")
|
|
200
|
+
return this.runSharedOperation(name, signal, fn);
|
|
201
|
+
return this.withProjectLock(root, signal, () => this.runSharedOperation(name, signal, fn));
|
|
202
|
+
},
|
|
196
203
|
});
|
|
197
204
|
this.projectMutex = new keyed_mutex_1.KeyedMutex();
|
|
198
205
|
// Tests construct daemons against the real HOME; keep their leases in memory.
|
|
@@ -1237,7 +1244,15 @@ class Daemon {
|
|
|
1237
1244
|
this.vectorDb.pauseMaintenanceLoop();
|
|
1238
1245
|
const stopHeartbeat = (0, ipc_handler_1.startHeartbeat)(conn);
|
|
1239
1246
|
let lastProgressTime = 0;
|
|
1247
|
+
const wasWatching = this.processors.has(root);
|
|
1248
|
+
let watcherQuiesced = false;
|
|
1240
1249
|
try {
|
|
1250
|
+
// Re-adding a watched project is also a full sync. A catchup scan no
|
|
1251
|
+
// longer holds the write lock, so explicitly drain it before syncing.
|
|
1252
|
+
if (wasWatching) {
|
|
1253
|
+
yield this.unwatchProjectWithinOperation(root);
|
|
1254
|
+
watcherQuiesced = true;
|
|
1255
|
+
}
|
|
1241
1256
|
const result = yield (0, syncer_1.initialSync)({
|
|
1242
1257
|
projectRoot: root,
|
|
1243
1258
|
vectorDb: this.vectorDb,
|
|
@@ -1287,6 +1302,7 @@ class Daemon {
|
|
|
1287
1302
|
});
|
|
1288
1303
|
}
|
|
1289
1304
|
yield this.watchProjectWithinOperation(root);
|
|
1305
|
+
watcherQuiesced = false;
|
|
1290
1306
|
(0, ipc_handler_1.writeDone)(conn, {
|
|
1291
1307
|
ok: true,
|
|
1292
1308
|
processed: result.processed,
|
|
@@ -1316,6 +1332,15 @@ class Daemon {
|
|
|
1316
1332
|
}
|
|
1317
1333
|
finally {
|
|
1318
1334
|
stopHeartbeat();
|
|
1335
|
+
if (watcherQuiesced && !this.shuttingDown) {
|
|
1336
|
+
try {
|
|
1337
|
+
this.assertHeavyOperationAdmission("watch");
|
|
1338
|
+
yield this.watchProjectWithinOperation(root);
|
|
1339
|
+
}
|
|
1340
|
+
catch (error) {
|
|
1341
|
+
console.error("[daemon] Could not restore watcher after add:", error);
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1319
1344
|
(_a = this.vectorDb) === null || _a === void 0 ? void 0 : _a.resumeMaintenanceLoop();
|
|
1320
1345
|
}
|
|
1321
1346
|
});
|
|
@@ -653,6 +653,7 @@ class WatcherManager {
|
|
|
653
653
|
// Fast path: if only mtime changed but size is identical and we have a hash,
|
|
654
654
|
// just verify the hash in-process instead of sending to a worker.
|
|
655
655
|
if ((cached === null || cached === void 0 ? void 0 : cached.hash) && cached.size === stats.size) {
|
|
656
|
+
const observed = Object.assign({}, cached);
|
|
656
657
|
const snapshot = yield (0, file_utils_1.readFileSnapshot)(absPath, {
|
|
657
658
|
projectRoot: root,
|
|
658
659
|
});
|
|
@@ -664,11 +665,21 @@ class WatcherManager {
|
|
|
664
665
|
continue;
|
|
665
666
|
}
|
|
666
667
|
const hash = (0, file_utils_1.computeContentHash)(snapshot.buffer, absPath);
|
|
667
|
-
if (hash ===
|
|
668
|
+
if (hash === observed.hash) {
|
|
668
669
|
// Content unchanged — update mtime in cache and skip worker
|
|
669
670
|
if (signal.aborted)
|
|
670
671
|
return false;
|
|
671
|
-
|
|
672
|
+
// A live batch can finish while this read yields. Never replace
|
|
673
|
+
// newer metadata or resurrect a cache entry it removed.
|
|
674
|
+
const current = metaCache.get(absPath);
|
|
675
|
+
if (current &&
|
|
676
|
+
current.hash === observed.hash &&
|
|
677
|
+
current.mtimeMs === observed.mtimeMs &&
|
|
678
|
+
current.size === observed.size &&
|
|
679
|
+
current.hashVersion === observed.hashVersion &&
|
|
680
|
+
current.hasVectors === observed.hasVectors) {
|
|
681
|
+
metaCache.put(absPath, Object.assign(Object.assign({}, observed), { mtimeMs: stats.mtimeMs }));
|
|
682
|
+
}
|
|
672
683
|
skipped++;
|
|
673
684
|
continue;
|
|
674
685
|
}
|
package/package.json
CHANGED