grepmax 0.26.1 → 0.26.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.
- package/.claude-plugin/marketplace.json +1 -1
- package/dist/lib/daemon/daemon.js +15 -1
- package/dist/lib/daemon/watcher-manager.js +9 -10
- package/dist/lib/index/batch-processor.js +17 -15
- package/dist/lib/index/watcher.js +1 -0
- package/dist/lib/store/vector-db.js +22 -6
- package/package.json +1 -1
- package/plugins/grepmax/.claude-plugin/plugin.json +1 -1
|
@@ -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.3",
|
|
14
14
|
"author": {
|
|
15
15
|
"name": "Robert Owens",
|
|
16
16
|
"email": "robowens@me.com"
|
|
@@ -1472,8 +1472,11 @@ class Daemon {
|
|
|
1472
1472
|
return;
|
|
1473
1473
|
}
|
|
1474
1474
|
const stopHeartbeat = (0, ipc_handler_1.startHeartbeat)(conn);
|
|
1475
|
+
const wasWatching = this.processors.has(root);
|
|
1476
|
+
let unwatched = false;
|
|
1475
1477
|
try {
|
|
1476
1478
|
yield this.unwatchProjectWithinOperation(root);
|
|
1479
|
+
unwatched = true;
|
|
1477
1480
|
const rootPrefix = root.endsWith("/") ? root : `${root}/`;
|
|
1478
1481
|
yield this.vectorDb.deletePathsWithPrefix(rootPrefix);
|
|
1479
1482
|
const keys = yield this.metaCache.getKeysWithPrefix(rootPrefix);
|
|
@@ -1482,7 +1485,18 @@ class Daemon {
|
|
|
1482
1485
|
(0, ipc_handler_1.writeDone)(conn, { ok: true });
|
|
1483
1486
|
}
|
|
1484
1487
|
catch (err) {
|
|
1485
|
-
|
|
1488
|
+
let reportedError = err;
|
|
1489
|
+
if (unwatched && wasWatching && !this.shuttingDown) {
|
|
1490
|
+
try {
|
|
1491
|
+
yield this.watchProjectWithinOperation(root);
|
|
1492
|
+
}
|
|
1493
|
+
catch (watchError) {
|
|
1494
|
+
reportedError = new Error(`Project removal failed: ${String(err)}; watcher restoration failed: ${String(watchError)}`);
|
|
1495
|
+
}
|
|
1496
|
+
}
|
|
1497
|
+
const msg = reportedError instanceof Error
|
|
1498
|
+
? reportedError.message
|
|
1499
|
+
: String(reportedError);
|
|
1486
1500
|
console.error(`[daemon] removeProject failed for ${path.basename(root)}:`, msg);
|
|
1487
1501
|
(0, ipc_handler_1.writeDone)(conn, { ok: false, error: msg });
|
|
1488
1502
|
}
|
|
@@ -121,12 +121,14 @@ class WatcherManager {
|
|
|
121
121
|
try {
|
|
122
122
|
const filePolicy = new file_policy_1.ProjectFilePolicy(root);
|
|
123
123
|
let processor;
|
|
124
|
+
let lastReindexAt;
|
|
124
125
|
processor = new batch_processor_1.ProjectBatchProcessor(Object.assign(Object.assign({ projectRoot: root, vectorDb,
|
|
125
126
|
metaCache }, (workerPool ? { workerPool } : {})), { filePolicy, onPolicyChange: () => {
|
|
126
127
|
void this.runCatchup(root, processor).catch((err) => {
|
|
127
128
|
console.error(`[daemon:${path.basename(root)}] Policy reconciliation failed:`, err);
|
|
128
129
|
});
|
|
129
130
|
}, onReindex: (files, ms) => __awaiter(this, void 0, void 0, function* () {
|
|
131
|
+
lastReindexAt = Date.now();
|
|
130
132
|
console.log(`[daemon:${path.basename(root)}] Reindexed ${files} file${files !== 1 ? "s" : ""} (${(ms / 1000).toFixed(1)}s)`);
|
|
131
133
|
// Update project registry so gmax status shows fresh data
|
|
132
134
|
const proj = (0, project_registry_1.getProject)(root);
|
|
@@ -140,16 +142,13 @@ class WatcherManager {
|
|
|
140
142
|
}
|
|
141
143
|
(0, project_registry_1.registerProject)(Object.assign(Object.assign({}, proj), { lastIndexed: new Date().toISOString(), chunkCount }));
|
|
142
144
|
}
|
|
143
|
-
|
|
144
|
-
(0, watcher_store_1.registerWatcher)({
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
lastReindex: Date.now(),
|
|
151
|
-
});
|
|
152
|
-
}), onActivity: () => {
|
|
145
|
+
}), onBatchSettled: () => {
|
|
146
|
+
(0, watcher_store_1.registerWatcher)(Object.assign({ pid: process.pid, projectRoot: root, startTime: Date.now(), status: this.isRootDegraded(root)
|
|
147
|
+
? "degraded"
|
|
148
|
+
: processor.progress.pendingFiles > 0
|
|
149
|
+
? "syncing"
|
|
150
|
+
: "watching", lastHeartbeat: Date.now() }, (lastReindexAt ? { lastReindex: lastReindexAt } : {})));
|
|
151
|
+
}, onActivity: () => {
|
|
153
152
|
this.deps.touchActivity();
|
|
154
153
|
// Mark as syncing while processing
|
|
155
154
|
(0, watcher_store_1.registerWatcher)({
|
|
@@ -78,6 +78,7 @@ class ProjectBatchProcessor {
|
|
|
78
78
|
this.workerPool = (_a = opts.workerPool) !== null && _a !== void 0 ? _a : (0, pool_1.getWorkerPool)();
|
|
79
79
|
this.onReindex = opts.onReindex;
|
|
80
80
|
this.onActivity = opts.onActivity;
|
|
81
|
+
this.onBatchSettled = opts.onBatchSettled;
|
|
81
82
|
this.onPolicyChange = opts.onPolicyChange;
|
|
82
83
|
this.onTerminalFailure = opts.onTerminalFailure;
|
|
83
84
|
this.onPathSuccess = opts.onPathSuccess;
|
|
@@ -190,21 +191,12 @@ class ProjectBatchProcessor {
|
|
|
190
191
|
}
|
|
191
192
|
processBatch(operationSignal) {
|
|
192
193
|
return __awaiter(this, void 0, void 0, function* () {
|
|
193
|
-
var _a, _b, _c, _d, _e;
|
|
194
|
+
var _a, _b, _c, _d, _e, _f;
|
|
194
195
|
if (this.closed || this.processing || this.pending.size === 0)
|
|
195
196
|
return;
|
|
196
|
-
|
|
197
|
-
if (
|
|
198
|
-
(0, logger_1.log)(this.wtag, "Disk critically low — deferring
|
|
199
|
-
if (this.debounceTimer)
|
|
200
|
-
clearTimeout(this.debounceTimer);
|
|
201
|
-
this.debounceDueMs = Date.now() + 60000;
|
|
202
|
-
this.debounceTimer = setTimeout(() => {
|
|
203
|
-
this.debounceTimer = null;
|
|
204
|
-
this.debounceDueMs = 0;
|
|
205
|
-
this.startBatch();
|
|
206
|
-
}, 60000);
|
|
207
|
-
return;
|
|
197
|
+
const diskPressure = this.vectorDb.checkDiskPressure();
|
|
198
|
+
if (diskPressure === "critical") {
|
|
199
|
+
(0, logger_1.log)(this.wtag, "Disk critically low — applying deletions and deferring indexing");
|
|
208
200
|
}
|
|
209
201
|
const batch = new Map();
|
|
210
202
|
const batchForceGenerations = new Map();
|
|
@@ -304,6 +296,9 @@ class ProjectBatchProcessor {
|
|
|
304
296
|
continue;
|
|
305
297
|
}
|
|
306
298
|
const stats = classification.stat;
|
|
299
|
+
if (diskPressure === "critical") {
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
307
302
|
const cached = this.metaCache.get(absPath);
|
|
308
303
|
const forceReprocess = batchForceGenerations.has(absPath);
|
|
309
304
|
if (!forceReprocess &&
|
|
@@ -423,6 +418,9 @@ class ProjectBatchProcessor {
|
|
|
423
418
|
requeuePath(absPath, event, retryFailures.has(absPath));
|
|
424
419
|
}
|
|
425
420
|
}
|
|
421
|
+
if (diskPressure === "critical" && this.pending.size > 0) {
|
|
422
|
+
backoffOverrideMs = 60000;
|
|
423
|
+
}
|
|
426
424
|
// Flush to VectorDB: insert first, then delete old (preserving new)
|
|
427
425
|
const newIds = vectors.map((v) => v.id);
|
|
428
426
|
if (vectors.length > 0) {
|
|
@@ -473,7 +471,7 @@ class ProjectBatchProcessor {
|
|
|
473
471
|
(_c = this.onPathSuccess) === null || _c === void 0 ? void 0 : _c.call(this, absPath);
|
|
474
472
|
}
|
|
475
473
|
// Trigger compaction if fragments are accumulating
|
|
476
|
-
if (reindexed > 0) {
|
|
474
|
+
if (reindexed > 0 && diskPressure !== "critical") {
|
|
477
475
|
try {
|
|
478
476
|
yield this.vectorDb.compactIfNeeded();
|
|
479
477
|
}
|
|
@@ -484,7 +482,9 @@ class ProjectBatchProcessor {
|
|
|
484
482
|
}
|
|
485
483
|
catch (err) {
|
|
486
484
|
// Disk pressure: requeue without counting as retries (not the file's fault)
|
|
487
|
-
|
|
485
|
+
const code = err === null || err === void 0 ? void 0 : err.code;
|
|
486
|
+
if (err instanceof vector_db_1.DiskPressureError ||
|
|
487
|
+
(diskPressure === "critical" && code === "ENOSPC")) {
|
|
488
488
|
for (const [absPath, event] of batch) {
|
|
489
489
|
if (this.terminalFailures.has(absPath))
|
|
490
490
|
continue;
|
|
@@ -575,6 +575,8 @@ class ProjectBatchProcessor {
|
|
|
575
575
|
this.schedulePendingBatch();
|
|
576
576
|
}
|
|
577
577
|
}
|
|
578
|
+
if (!this.closed)
|
|
579
|
+
(_f = this.onBatchSettled) === null || _f === void 0 ? void 0 : _f.call(this);
|
|
578
580
|
}
|
|
579
581
|
});
|
|
580
582
|
}
|
|
@@ -195,6 +195,7 @@ function startWatcher(opts) {
|
|
|
195
195
|
processor = new batch_processor_1.ProjectBatchProcessor(Object.assign(Object.assign({}, opts), { filePolicy, onPolicyChange: reconcile, onReindex: (files, durationMs) => {
|
|
196
196
|
var _a;
|
|
197
197
|
(_a = opts.onReindex) === null || _a === void 0 ? void 0 : _a.call(opts, files, durationMs);
|
|
198
|
+
}, onBatchSettled: () => {
|
|
198
199
|
reportHealthyIfSettled();
|
|
199
200
|
}, onTerminalFailure: (absPath) => {
|
|
200
201
|
var _a;
|
|
@@ -589,6 +589,19 @@ class VectorDB {
|
|
|
589
589
|
return table;
|
|
590
590
|
});
|
|
591
591
|
}
|
|
592
|
+
openExistingTableUnsafe() {
|
|
593
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
594
|
+
const db = yield this.getDb();
|
|
595
|
+
try {
|
|
596
|
+
return yield db.openTable(TABLE_NAME);
|
|
597
|
+
}
|
|
598
|
+
catch (err) {
|
|
599
|
+
if (isMissingTableError(err))
|
|
600
|
+
return null;
|
|
601
|
+
throw err;
|
|
602
|
+
}
|
|
603
|
+
});
|
|
604
|
+
}
|
|
592
605
|
insertBatch(records) {
|
|
593
606
|
return __awaiter(this, void 0, void 0, function* () {
|
|
594
607
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r;
|
|
@@ -982,11 +995,12 @@ class VectorDB {
|
|
|
982
995
|
return __awaiter(this, void 0, void 0, function* () {
|
|
983
996
|
if (!paths.length)
|
|
984
997
|
return;
|
|
985
|
-
this.ensureDiskOk();
|
|
986
998
|
const unique = Array.from(new Set(paths));
|
|
987
999
|
const batchSize = 500;
|
|
988
1000
|
yield this.withWriteGate(() => __awaiter(this, void 0, void 0, function* () {
|
|
989
|
-
const table = yield this.
|
|
1001
|
+
const table = yield this.openExistingTableUnsafe();
|
|
1002
|
+
if (!table)
|
|
1003
|
+
return;
|
|
990
1004
|
for (let i = 0; i < unique.length; i += batchSize) {
|
|
991
1005
|
const slice = unique.slice(i, i + batchSize);
|
|
992
1006
|
const values = slice.map((p) => `'${(0, filter_builder_1.escapeSqlString)(p)}'`).join(",");
|
|
@@ -1026,14 +1040,15 @@ class VectorDB {
|
|
|
1026
1040
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1027
1041
|
if (!paths.length)
|
|
1028
1042
|
return;
|
|
1029
|
-
this.ensureDiskOk();
|
|
1030
1043
|
const unique = Array.from(new Set(paths));
|
|
1031
1044
|
const batchSize = 500;
|
|
1032
1045
|
const idExclusion = excludeIds.length > 0
|
|
1033
1046
|
? ` AND id NOT IN (${excludeIds.map((id) => `'${(0, filter_builder_1.escapeSqlString)(id)}'`).join(",")})`
|
|
1034
1047
|
: "";
|
|
1035
1048
|
yield this.withWriteGate(() => __awaiter(this, void 0, void 0, function* () {
|
|
1036
|
-
const table = yield this.
|
|
1049
|
+
const table = yield this.openExistingTableUnsafe();
|
|
1050
|
+
if (!table)
|
|
1051
|
+
return;
|
|
1037
1052
|
for (let i = 0; i < unique.length; i += batchSize) {
|
|
1038
1053
|
const slice = unique.slice(i, i + batchSize);
|
|
1039
1054
|
const values = slice.map((p) => `'${(0, filter_builder_1.escapeSqlString)(p)}'`).join(",");
|
|
@@ -1053,14 +1068,15 @@ class VectorDB {
|
|
|
1053
1068
|
}
|
|
1054
1069
|
deletePathsWithPrefix(prefix) {
|
|
1055
1070
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1056
|
-
this.ensureDiskOk();
|
|
1057
1071
|
// Slash-terminate so a project root can't bleed into a sibling
|
|
1058
1072
|
// (`/repo/app` must not delete `/repo/app2`), and use starts_with so `_`/`%`
|
|
1059
1073
|
// in the path are literal, not LIKE wildcards. Destructive path — keep this
|
|
1060
1074
|
// self-protective even if a caller forgets to normalize.
|
|
1061
1075
|
const dirPrefix = prefix.endsWith("/") ? prefix : `${prefix}/`;
|
|
1062
1076
|
yield this.withWriteGate(() => __awaiter(this, void 0, void 0, function* () {
|
|
1063
|
-
const table = yield this.
|
|
1077
|
+
const table = yield this.openExistingTableUnsafe();
|
|
1078
|
+
if (!table)
|
|
1079
|
+
return;
|
|
1064
1080
|
yield table.delete((0, filter_builder_1.pathStartsWith)(dirPrefix));
|
|
1065
1081
|
}));
|
|
1066
1082
|
});
|
package/package.json
CHANGED