grepmax 0.6.1 → 0.6.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/dist/commands/index.js +17 -0
- package/dist/commands/mcp.js +9 -1
- package/dist/commands/search.js +6 -1
- package/dist/commands/serve.js +1 -1
- package/dist/commands/watch.js +3 -2
- package/dist/lib/index/syncer.js +15 -13
- package/dist/lib/index/watcher.js +42 -9
- package/dist/lib/search/searcher.js +34 -16
- package/dist/lib/skeleton/retriever.js +2 -1
- package/dist/lib/store/meta-cache.js +10 -7
- package/dist/lib/store/vector-db.js +24 -5
- package/dist/lib/workers/pool.js +8 -0
- package/package.json +5 -2
- package/plugins/grepmax/.claude-plugin/plugin.json +1 -1
package/dist/commands/index.js
CHANGED
|
@@ -64,6 +64,16 @@ exports.index = new commander_1.Command("index")
|
|
|
64
64
|
var _a;
|
|
65
65
|
const options = cmd.optsWithGlobals();
|
|
66
66
|
let vectorDb = null;
|
|
67
|
+
const ac = new AbortController();
|
|
68
|
+
let aborted = false;
|
|
69
|
+
const onSignal = () => {
|
|
70
|
+
if (aborted)
|
|
71
|
+
return;
|
|
72
|
+
aborted = true;
|
|
73
|
+
ac.abort();
|
|
74
|
+
};
|
|
75
|
+
process.on("SIGINT", onSignal);
|
|
76
|
+
process.on("SIGTERM", onSignal);
|
|
67
77
|
try {
|
|
68
78
|
yield (0, setup_helpers_1.ensureSetup)();
|
|
69
79
|
const indexRoot = options.path
|
|
@@ -107,7 +117,12 @@ exports.index = new commander_1.Command("index")
|
|
|
107
117
|
dryRun: options.dryRun,
|
|
108
118
|
reset: options.reset,
|
|
109
119
|
onProgress,
|
|
120
|
+
signal: ac.signal,
|
|
110
121
|
});
|
|
122
|
+
if (aborted) {
|
|
123
|
+
spinner.warn(`Indexing interrupted — partial progress saved (${result.indexed} indexed)`);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
111
126
|
if (options.dryRun) {
|
|
112
127
|
spinner.succeed(`Dry run complete(${result.processed} / ${result.total}) • would have indexed ${result.indexed} `);
|
|
113
128
|
console.log((0, sync_helpers_1.formatDryRunSummary)(result, {
|
|
@@ -143,6 +158,8 @@ exports.index = new commander_1.Command("index")
|
|
|
143
158
|
process.exitCode = 1;
|
|
144
159
|
}
|
|
145
160
|
finally {
|
|
161
|
+
process.removeListener("SIGINT", onSignal);
|
|
162
|
+
process.removeListener("SIGTERM", onSignal);
|
|
146
163
|
if (vectorDb) {
|
|
147
164
|
try {
|
|
148
165
|
yield vectorDb.close();
|
package/dist/commands/mcp.js
CHANGED
|
@@ -338,6 +338,7 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
338
338
|
// --- Tool handlers ---
|
|
339
339
|
function handleSemanticSearch(args_1) {
|
|
340
340
|
return __awaiter(this, arguments, void 0, function* (args, searchAll = false) {
|
|
341
|
+
var _a;
|
|
341
342
|
const query = String(args.query || "");
|
|
342
343
|
if (!query)
|
|
343
344
|
return err("Missing required parameter: query");
|
|
@@ -353,6 +354,9 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
353
354
|
const searchRoot = typeof args.root === "string"
|
|
354
355
|
? path.resolve(args.root)
|
|
355
356
|
: path.resolve(projectRoot);
|
|
357
|
+
if (typeof args.root === "string" && !fs.existsSync(searchRoot)) {
|
|
358
|
+
return err(`Directory not found: ${args.root}`);
|
|
359
|
+
}
|
|
356
360
|
displayRoot = searchRoot;
|
|
357
361
|
pathPrefix = searchRoot.endsWith("/")
|
|
358
362
|
? searchRoot
|
|
@@ -434,7 +438,11 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
434
438
|
return true;
|
|
435
439
|
});
|
|
436
440
|
}
|
|
437
|
-
|
|
441
|
+
const output = results.map((r) => r.text).join("\n\n");
|
|
442
|
+
if ((_a = result.warnings) === null || _a === void 0 ? void 0 : _a.length) {
|
|
443
|
+
return ok(`${result.warnings.join("\n")}\n\n${output}`);
|
|
444
|
+
}
|
|
445
|
+
return ok(output);
|
|
438
446
|
}
|
|
439
447
|
catch (e) {
|
|
440
448
|
const msg = e instanceof Error ? e.message : String(e);
|
package/dist/commands/search.js
CHANGED
|
@@ -339,7 +339,7 @@ exports.search = new commander_1.Command("search")
|
|
|
339
339
|
.argument("<pattern>", "The pattern to search for")
|
|
340
340
|
.argument("[path]", "The path to search in")
|
|
341
341
|
.action((pattern, exec_path, _options, cmd) => __awaiter(void 0, void 0, void 0, function* () {
|
|
342
|
-
var _a, _b;
|
|
342
|
+
var _a, _b, _c;
|
|
343
343
|
const options = cmd.optsWithGlobals();
|
|
344
344
|
const root = process.cwd();
|
|
345
345
|
const minScore = Number.isFinite(Number.parseFloat(options.minScore))
|
|
@@ -488,6 +488,11 @@ exports.search = new commander_1.Command("search")
|
|
|
488
488
|
? searchPathPrefix
|
|
489
489
|
: `${searchPathPrefix}/`;
|
|
490
490
|
const searchResult = yield searcher.search(pattern, parseInt(options.m, 10), { rerank: true }, undefined, pathFilter);
|
|
491
|
+
if ((_c = searchResult.warnings) === null || _c === void 0 ? void 0 : _c.length) {
|
|
492
|
+
for (const w of searchResult.warnings) {
|
|
493
|
+
console.warn(`Warning: ${w}`);
|
|
494
|
+
}
|
|
495
|
+
}
|
|
491
496
|
const filteredData = searchResult.data.filter((r) => typeof r.score !== "number" || r.score >= minScore);
|
|
492
497
|
if (options.skeleton) {
|
|
493
498
|
yield outputSkeletons(filteredData, projectRoot, parseInt(options.m, 10), vectorDb);
|
package/dist/commands/serve.js
CHANGED
package/dist/commands/watch.js
CHANGED
|
@@ -48,6 +48,7 @@ const fs = __importStar(require("node:fs"));
|
|
|
48
48
|
const path = __importStar(require("node:path"));
|
|
49
49
|
const commander_1 = require("commander");
|
|
50
50
|
const config_1 = require("../config");
|
|
51
|
+
const filter_builder_1 = require("../lib/utils/filter-builder");
|
|
51
52
|
const syncer_1 = require("../lib/index/syncer");
|
|
52
53
|
const watcher_1 = require("../lib/index/watcher");
|
|
53
54
|
const meta_cache_1 = require("../lib/store/meta-cache");
|
|
@@ -113,7 +114,7 @@ exports.watch = new commander_1.Command("watch")
|
|
|
113
114
|
const indexed = yield table
|
|
114
115
|
.query()
|
|
115
116
|
.select(["id"])
|
|
116
|
-
.where(`path LIKE '${prefix}%'`)
|
|
117
|
+
.where(`path LIKE '${(0, filter_builder_1.escapeSqlString)(prefix)}%'`)
|
|
117
118
|
.limit(1)
|
|
118
119
|
.toArray();
|
|
119
120
|
if (indexed.length === 0) {
|
|
@@ -154,7 +155,7 @@ exports.watch = new commander_1.Command("watch")
|
|
|
154
155
|
yield watcher.close();
|
|
155
156
|
}
|
|
156
157
|
catch (_a) { }
|
|
157
|
-
metaCache.close();
|
|
158
|
+
yield metaCache.close();
|
|
158
159
|
yield vectorDb.close();
|
|
159
160
|
(0, watcher_registry_1.unregisterWatcher)(process.pid);
|
|
160
161
|
yield (0, exit_1.gracefulExit)();
|
package/dist/lib/index/syncer.js
CHANGED
|
@@ -57,6 +57,7 @@ const config_1 = require("../../config");
|
|
|
57
57
|
const logger_1 = require("../utils/logger");
|
|
58
58
|
const meta_cache_1 = require("../store/meta-cache");
|
|
59
59
|
const vector_db_1 = require("../store/vector-db");
|
|
60
|
+
const filter_builder_1 = require("../utils/filter-builder");
|
|
60
61
|
const file_utils_1 = require("../utils/file-utils");
|
|
61
62
|
const lock_1 = require("../utils/lock");
|
|
62
63
|
const project_registry_1 = require("../utils/project-registry");
|
|
@@ -85,7 +86,7 @@ function generateSummaries(db, pathPrefix, onProgress, maxChunks) {
|
|
|
85
86
|
const rows = yield table
|
|
86
87
|
.query()
|
|
87
88
|
.select(["id", "path", "content", "defined_symbols"])
|
|
88
|
-
.where(`path LIKE '${pathPrefix}%' AND (summary IS NULL OR summary = '')`)
|
|
89
|
+
.where(`path LIKE '${(0, filter_builder_1.escapeSqlString)(pathPrefix)}%' AND (summary IS NULL OR summary = '')`)
|
|
89
90
|
.limit(queryLimit)
|
|
90
91
|
.toArray();
|
|
91
92
|
if (rows.length === 0)
|
|
@@ -174,7 +175,7 @@ function createNoopMetaCache() {
|
|
|
174
175
|
delete: (filePath) => {
|
|
175
176
|
store.delete(filePath);
|
|
176
177
|
},
|
|
177
|
-
close: () => { },
|
|
178
|
+
close: () => __awaiter(this, void 0, void 0, function* () { }),
|
|
178
179
|
};
|
|
179
180
|
}
|
|
180
181
|
function initialSync(options) {
|
|
@@ -457,7 +458,17 @@ function initialSync(options) {
|
|
|
457
458
|
? flushError
|
|
458
459
|
: new Error(String(flushError));
|
|
459
460
|
}
|
|
460
|
-
|
|
461
|
+
// Stale cleanup: only remove paths scoped to this project's root
|
|
462
|
+
const stale = Array.from(cachedPaths).filter((p) => !seenPaths.has(p));
|
|
463
|
+
if (!dryRun && stale.length > 0 && !shouldSkipCleanup) {
|
|
464
|
+
(0, logger_1.log)("index", `Stale cleanup: ${stale.length} paths`);
|
|
465
|
+
yield vectorDb.deletePaths(stale);
|
|
466
|
+
stale.forEach((p) => {
|
|
467
|
+
metaCache.delete(p);
|
|
468
|
+
});
|
|
469
|
+
}
|
|
470
|
+
// Only rebuild FTS index if data actually changed
|
|
471
|
+
if (!dryRun && (indexed > 0 || stale.length > 0)) {
|
|
461
472
|
const ftsTimer = (0, logger_1.timer)("index", "FTS");
|
|
462
473
|
onProgress === null || onProgress === void 0 ? void 0 : onProgress({
|
|
463
474
|
processed,
|
|
@@ -468,15 +479,6 @@ function initialSync(options) {
|
|
|
468
479
|
yield vectorDb.createFTSIndex();
|
|
469
480
|
ftsTimer();
|
|
470
481
|
}
|
|
471
|
-
// Stale cleanup: only remove paths scoped to this project's root
|
|
472
|
-
const stale = Array.from(cachedPaths).filter((p) => !seenPaths.has(p));
|
|
473
|
-
if (!dryRun && stale.length > 0 && !shouldSkipCleanup) {
|
|
474
|
-
(0, logger_1.log)("index", `Stale cleanup: ${stale.length} paths`);
|
|
475
|
-
yield vectorDb.deletePaths(stale);
|
|
476
|
-
stale.forEach((p) => {
|
|
477
|
-
metaCache.delete(p);
|
|
478
|
-
});
|
|
479
|
-
}
|
|
480
482
|
syncTimer();
|
|
481
483
|
// Write model config so future runs can detect model changes
|
|
482
484
|
if (!dryRun) {
|
|
@@ -501,7 +503,7 @@ function initialSync(options) {
|
|
|
501
503
|
if (lock) {
|
|
502
504
|
yield lock.release();
|
|
503
505
|
}
|
|
504
|
-
metaCache === null || metaCache === void 0 ? void 0 : metaCache.close();
|
|
506
|
+
yield (metaCache === null || metaCache === void 0 ? void 0 : metaCache.close());
|
|
505
507
|
yield vectorDb.close();
|
|
506
508
|
}
|
|
507
509
|
});
|
|
@@ -47,6 +47,7 @@ exports.startWatcher = startWatcher;
|
|
|
47
47
|
const fs = __importStar(require("node:fs"));
|
|
48
48
|
const path = __importStar(require("node:path"));
|
|
49
49
|
const chokidar_1 = require("chokidar");
|
|
50
|
+
const filter_builder_1 = require("../utils/filter-builder");
|
|
50
51
|
const file_utils_1 = require("../utils/file-utils");
|
|
51
52
|
const logger_1 = require("../utils/logger");
|
|
52
53
|
const lock_1 = require("../utils/lock");
|
|
@@ -75,9 +76,12 @@ const FTS_REBUILD_INTERVAL_MS = 5 * 60 * 1000;
|
|
|
75
76
|
function startWatcher(opts) {
|
|
76
77
|
const { projectRoot, vectorDb, metaCache, dataDir, onReindex } = opts;
|
|
77
78
|
const pending = new Map();
|
|
79
|
+
const retryCount = new Map();
|
|
78
80
|
let debounceTimer = null;
|
|
79
81
|
let processing = false;
|
|
80
82
|
let closed = false;
|
|
83
|
+
let consecutiveLockFailures = 0;
|
|
84
|
+
const MAX_RETRIES = 5;
|
|
81
85
|
const watcher = (0, chokidar_1.watch)(projectRoot, {
|
|
82
86
|
ignored: exports.WATCHER_IGNORE_PATTERNS,
|
|
83
87
|
ignoreInitial: true,
|
|
@@ -98,6 +102,7 @@ function startWatcher(opts) {
|
|
|
98
102
|
debounceTimer = setTimeout(() => processBatch(), DEBOUNCE_MS);
|
|
99
103
|
};
|
|
100
104
|
const processBatch = () => __awaiter(this, void 0, void 0, function* () {
|
|
105
|
+
var _a;
|
|
101
106
|
if (closed || processing || pending.size === 0)
|
|
102
107
|
return;
|
|
103
108
|
processing = true;
|
|
@@ -175,13 +180,19 @@ function startWatcher(opts) {
|
|
|
175
180
|
}
|
|
176
181
|
}
|
|
177
182
|
}
|
|
178
|
-
// Flush to VectorDB
|
|
179
|
-
|
|
180
|
-
yield vectorDb.deletePaths(deletes);
|
|
181
|
-
}
|
|
183
|
+
// Flush to VectorDB: insert first, then delete old (preserving new)
|
|
184
|
+
const newIds = vectors.map((v) => v.id);
|
|
182
185
|
if (vectors.length > 0) {
|
|
183
186
|
yield vectorDb.insertBatch(vectors);
|
|
184
187
|
}
|
|
188
|
+
if (deletes.length > 0) {
|
|
189
|
+
if (newIds.length > 0) {
|
|
190
|
+
yield vectorDb.deletePathsExcludingIds(deletes, newIds);
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
yield vectorDb.deletePaths(deletes);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
185
196
|
// Update MetaCache
|
|
186
197
|
for (const [p, entry] of metaUpdates) {
|
|
187
198
|
metaCache.put(p, entry);
|
|
@@ -198,7 +209,7 @@ function startWatcher(opts) {
|
|
|
198
209
|
try {
|
|
199
210
|
const table = yield vectorDb.ensureTable();
|
|
200
211
|
for (const id of changedIds) {
|
|
201
|
-
const escaped =
|
|
212
|
+
const escaped = (0, filter_builder_1.escapeSqlString)(id);
|
|
202
213
|
const rows = yield table
|
|
203
214
|
.query()
|
|
204
215
|
.select(["id", "path", "content"])
|
|
@@ -222,7 +233,7 @@ function startWatcher(opts) {
|
|
|
222
233
|
}
|
|
223
234
|
}
|
|
224
235
|
}
|
|
225
|
-
catch (
|
|
236
|
+
catch (_b) {
|
|
226
237
|
// Summarizer unavailable — skip silently
|
|
227
238
|
}
|
|
228
239
|
}
|
|
@@ -230,16 +241,38 @@ function startWatcher(opts) {
|
|
|
230
241
|
const duration = Date.now() - start;
|
|
231
242
|
onReindex === null || onReindex === void 0 ? void 0 : onReindex(reindexed, duration);
|
|
232
243
|
}
|
|
244
|
+
consecutiveLockFailures = 0;
|
|
245
|
+
for (const absPath of batch.keys()) {
|
|
246
|
+
retryCount.delete(absPath);
|
|
247
|
+
}
|
|
233
248
|
}
|
|
234
249
|
catch (err) {
|
|
250
|
+
const isLockError = err instanceof Error && err.message.includes("lock already held");
|
|
251
|
+
if (isLockError) {
|
|
252
|
+
consecutiveLockFailures++;
|
|
253
|
+
}
|
|
235
254
|
console.error("[watch] Batch processing failed:", err);
|
|
236
|
-
|
|
255
|
+
let dropped = 0;
|
|
237
256
|
for (const [absPath, event] of batch) {
|
|
238
|
-
|
|
257
|
+
const count = ((_a = retryCount.get(absPath)) !== null && _a !== void 0 ? _a : 0) + 1;
|
|
258
|
+
if (count >= MAX_RETRIES) {
|
|
259
|
+
retryCount.delete(absPath);
|
|
260
|
+
dropped++;
|
|
261
|
+
}
|
|
262
|
+
else if (!pending.has(absPath)) {
|
|
239
263
|
pending.set(absPath, event);
|
|
264
|
+
retryCount.set(absPath, count);
|
|
240
265
|
}
|
|
241
266
|
}
|
|
242
|
-
|
|
267
|
+
if (dropped > 0) {
|
|
268
|
+
console.warn(`[watch] Dropped ${dropped} file(s) after ${MAX_RETRIES} failed retries`);
|
|
269
|
+
}
|
|
270
|
+
if (pending.size > 0) {
|
|
271
|
+
const backoffMs = Math.min(DEBOUNCE_MS * Math.pow(2, consecutiveLockFailures), 30000);
|
|
272
|
+
if (debounceTimer)
|
|
273
|
+
clearTimeout(debounceTimer);
|
|
274
|
+
debounceTimer = setTimeout(() => processBatch(), backoffMs);
|
|
275
|
+
}
|
|
243
276
|
}
|
|
244
277
|
finally {
|
|
245
278
|
processing = false;
|
|
@@ -18,6 +18,8 @@ class Searcher {
|
|
|
18
18
|
constructor(db) {
|
|
19
19
|
this.db = db;
|
|
20
20
|
this.ftsIndexChecked = false;
|
|
21
|
+
this.ftsAvailable = false;
|
|
22
|
+
this.ftsLastCheckedAt = 0;
|
|
21
23
|
}
|
|
22
24
|
mapRecordToChunk(record, score) {
|
|
23
25
|
var _a;
|
|
@@ -307,13 +309,19 @@ class Searcher {
|
|
|
307
309
|
catch (_k) {
|
|
308
310
|
return { data: [] };
|
|
309
311
|
}
|
|
310
|
-
// Ensure FTS index exists (lazy init on
|
|
311
|
-
|
|
312
|
-
|
|
312
|
+
// Ensure FTS index exists (lazy init, retry periodically on failure)
|
|
313
|
+
const now = Date.now();
|
|
314
|
+
if (!this.ftsIndexChecked ||
|
|
315
|
+
(!this.ftsAvailable &&
|
|
316
|
+
now - this.ftsLastCheckedAt > Searcher.FTS_RETRY_INTERVAL_MS)) {
|
|
317
|
+
this.ftsIndexChecked = true;
|
|
318
|
+
this.ftsLastCheckedAt = now;
|
|
313
319
|
try {
|
|
314
320
|
yield this.db.createFTSIndex();
|
|
321
|
+
this.ftsAvailable = true;
|
|
315
322
|
}
|
|
316
323
|
catch (e) {
|
|
324
|
+
this.ftsAvailable = false;
|
|
317
325
|
console.warn("[Searcher] Failed to ensure FTS index:", e);
|
|
318
326
|
}
|
|
319
327
|
}
|
|
@@ -323,16 +331,21 @@ class Searcher {
|
|
|
323
331
|
}
|
|
324
332
|
const vectorResults = (yield vectorQuery.toArray());
|
|
325
333
|
let ftsResults = [];
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
ftsQuery =
|
|
334
|
+
let ftsSearchFailed = false;
|
|
335
|
+
if (this.ftsAvailable) {
|
|
336
|
+
try {
|
|
337
|
+
let ftsQuery = table.search(query).limit(PRE_RERANK_K);
|
|
338
|
+
if (whereClause) {
|
|
339
|
+
ftsQuery = ftsQuery.where(whereClause);
|
|
340
|
+
}
|
|
341
|
+
ftsResults = (yield ftsQuery.toArray());
|
|
342
|
+
}
|
|
343
|
+
catch (e) {
|
|
344
|
+
ftsSearchFailed = true;
|
|
345
|
+
this.ftsAvailable = false;
|
|
346
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
347
|
+
console.warn(`[Searcher] FTS search failed (will retry later): ${msg}`);
|
|
330
348
|
}
|
|
331
|
-
ftsResults = (yield ftsQuery.toArray());
|
|
332
|
-
}
|
|
333
|
-
catch (e) {
|
|
334
|
-
const msg = e instanceof Error ? e.message : String(e);
|
|
335
|
-
console.warn(`[Searcher] FTS search failed: ${msg}`);
|
|
336
349
|
}
|
|
337
350
|
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
338
351
|
const err = new Error("Aborted");
|
|
@@ -453,8 +466,7 @@ class Searcher {
|
|
|
453
466
|
const finalResults = diversified.map((item) => (Object.assign(Object.assign({}, item.record), { _score: item.score, vector: undefined, colbert: undefined })));
|
|
454
467
|
// Item 12: Score Calibration
|
|
455
468
|
const maxScore = finalResults.length > 0 ? finalResults[0]._score : 1.0;
|
|
456
|
-
return {
|
|
457
|
-
data: finalResults.map((r) => {
|
|
469
|
+
return Object.assign({ data: finalResults.map((r) => {
|
|
458
470
|
const chunk = this.mapRecordToChunk(r, r._score || 0);
|
|
459
471
|
// Normalize score relative to top result
|
|
460
472
|
const normalized = maxScore > 0 ? r._score / maxScore : 0;
|
|
@@ -466,9 +478,15 @@ class Searcher {
|
|
|
466
478
|
chunk.score = normalized;
|
|
467
479
|
chunk.confidence = confidence;
|
|
468
480
|
return chunk;
|
|
469
|
-
}),
|
|
470
|
-
|
|
481
|
+
}) }, (!this.ftsAvailable || ftsSearchFailed
|
|
482
|
+
? {
|
|
483
|
+
warnings: [
|
|
484
|
+
"Full-text search unavailable — results may be less precise",
|
|
485
|
+
],
|
|
486
|
+
}
|
|
487
|
+
: {}));
|
|
471
488
|
});
|
|
472
489
|
}
|
|
473
490
|
}
|
|
474
491
|
exports.Searcher = Searcher;
|
|
492
|
+
Searcher.FTS_RETRY_INTERVAL_MS = 5 * 60 * 1000;
|
|
@@ -10,6 +10,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.getStoredSkeleton = getStoredSkeleton;
|
|
13
|
+
const filter_builder_1 = require("../utils/filter-builder");
|
|
13
14
|
function getStoredSkeleton(db, filePath) {
|
|
14
15
|
return __awaiter(this, void 0, void 0, function* () {
|
|
15
16
|
try {
|
|
@@ -17,7 +18,7 @@ function getStoredSkeleton(db, filePath) {
|
|
|
17
18
|
// LanceDB query
|
|
18
19
|
const results = yield table
|
|
19
20
|
.query()
|
|
20
|
-
.where(`path = '${
|
|
21
|
+
.where(`path = '${(0, filter_builder_1.escapeSqlString)(filePath)}' AND is_anchor = true`)
|
|
21
22
|
.limit(1)
|
|
22
23
|
.toArray();
|
|
23
24
|
if (results.length > 0) {
|
|
@@ -156,13 +156,16 @@ class MetaCache {
|
|
|
156
156
|
});
|
|
157
157
|
}
|
|
158
158
|
close() {
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
159
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
160
|
+
var _a;
|
|
161
|
+
if (this.closed)
|
|
162
|
+
return;
|
|
163
|
+
this.closed = true;
|
|
164
|
+
(_a = this.unregisterCleanup) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
165
|
+
this.unregisterCleanup = undefined;
|
|
166
|
+
yield this.db.flushed;
|
|
167
|
+
this.db.close();
|
|
168
|
+
});
|
|
166
169
|
}
|
|
167
170
|
}
|
|
168
171
|
exports.MetaCache = MetaCache;
|
|
@@ -47,6 +47,7 @@ const fs = __importStar(require("node:fs"));
|
|
|
47
47
|
const lancedb = __importStar(require("@lancedb/lancedb"));
|
|
48
48
|
const apache_arrow_1 = require("apache-arrow");
|
|
49
49
|
const config_1 = require("../../config");
|
|
50
|
+
const filter_builder_1 = require("../utils/filter-builder");
|
|
50
51
|
const logger_1 = require("../utils/logger");
|
|
51
52
|
const cleanup_1 = require("../utils/cleanup");
|
|
52
53
|
const TABLE_NAME = "chunks";
|
|
@@ -292,7 +293,7 @@ class VectorDB {
|
|
|
292
293
|
const rows = yield table
|
|
293
294
|
.query()
|
|
294
295
|
.select(["id"])
|
|
295
|
-
.where(`path LIKE '${
|
|
296
|
+
.where(`path LIKE '${(0, filter_builder_1.escapeSqlString)(prefix)}%'`)
|
|
296
297
|
.limit(1)
|
|
297
298
|
.toArray();
|
|
298
299
|
return rows.length > 0;
|
|
@@ -324,7 +325,7 @@ class VectorDB {
|
|
|
324
325
|
const batchSize = 500;
|
|
325
326
|
for (let i = 0; i < unique.length; i += batchSize) {
|
|
326
327
|
const slice = unique.slice(i, i + batchSize);
|
|
327
|
-
const values = slice.map((p) => `'${
|
|
328
|
+
const values = slice.map((p) => `'${(0, filter_builder_1.escapeSqlString)(p)}'`).join(",");
|
|
328
329
|
yield table.delete(`path IN (${values})`);
|
|
329
330
|
}
|
|
330
331
|
});
|
|
@@ -336,7 +337,7 @@ class VectorDB {
|
|
|
336
337
|
return;
|
|
337
338
|
const table = yield this.ensureTable();
|
|
338
339
|
for (let i = 0; i < ids.length; i++) {
|
|
339
|
-
const escaped = ids[i]
|
|
340
|
+
const escaped = (0, filter_builder_1.escapeSqlString)(ids[i]);
|
|
340
341
|
yield table.update({
|
|
341
342
|
where: `id = '${escaped}'`,
|
|
342
343
|
values: { [field]: (_a = values[i]) !== null && _a !== void 0 ? _a : "" },
|
|
@@ -344,11 +345,29 @@ class VectorDB {
|
|
|
344
345
|
}
|
|
345
346
|
});
|
|
346
347
|
}
|
|
348
|
+
deletePathsExcludingIds(paths, excludeIds) {
|
|
349
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
350
|
+
if (!paths.length)
|
|
351
|
+
return;
|
|
352
|
+
const table = yield this.ensureTable();
|
|
353
|
+
const unique = Array.from(new Set(paths));
|
|
354
|
+
const batchSize = 500;
|
|
355
|
+
const idExclusion = excludeIds.length > 0
|
|
356
|
+
? ` AND id NOT IN (${excludeIds.map((id) => `'${(0, filter_builder_1.escapeSqlString)(id)}'`).join(",")})`
|
|
357
|
+
: "";
|
|
358
|
+
for (let i = 0; i < unique.length; i += batchSize) {
|
|
359
|
+
const slice = unique.slice(i, i + batchSize);
|
|
360
|
+
const values = slice
|
|
361
|
+
.map((p) => `'${(0, filter_builder_1.escapeSqlString)(p)}'`)
|
|
362
|
+
.join(",");
|
|
363
|
+
yield table.delete(`path IN (${values})${idExclusion}`);
|
|
364
|
+
}
|
|
365
|
+
});
|
|
366
|
+
}
|
|
347
367
|
deletePathsWithPrefix(prefix) {
|
|
348
368
|
return __awaiter(this, void 0, void 0, function* () {
|
|
349
369
|
const table = yield this.ensureTable();
|
|
350
|
-
|
|
351
|
-
yield table.delete(`path LIKE '${escaped}%'`);
|
|
370
|
+
yield table.delete(`path LIKE '${(0, filter_builder_1.escapeSqlString)(prefix)}%'`);
|
|
352
371
|
});
|
|
353
372
|
}
|
|
354
373
|
drop() {
|
package/dist/lib/workers/pool.js
CHANGED
|
@@ -114,6 +114,7 @@ class WorkerPool {
|
|
|
114
114
|
this.nextId = 1;
|
|
115
115
|
this.destroyed = false;
|
|
116
116
|
this.destroyPromise = null;
|
|
117
|
+
this.consecutiveRespawns = 0;
|
|
117
118
|
const resolved = resolveProcessWorker();
|
|
118
119
|
this.modulePath = resolved.filename;
|
|
119
120
|
this.execArgv = resolved.execArgv;
|
|
@@ -153,6 +154,11 @@ class WorkerPool {
|
|
|
153
154
|
(0, logger_1.log)("pool", `Worker PID:${worker.child.pid} exited (code:${code} signal:${signal})`);
|
|
154
155
|
this.workers = this.workers.filter((w) => w !== worker);
|
|
155
156
|
if (!this.destroyed) {
|
|
157
|
+
this.consecutiveRespawns++;
|
|
158
|
+
if (this.consecutiveRespawns > WorkerPool.MAX_RESPAWNS) {
|
|
159
|
+
console.error(`[pool] Worker respawn limit reached (${WorkerPool.MAX_RESPAWNS}). Not spawning more workers.`);
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
156
162
|
this.spawnWorker();
|
|
157
163
|
this.dispatch();
|
|
158
164
|
}
|
|
@@ -183,6 +189,7 @@ class WorkerPool {
|
|
|
183
189
|
task.resolve(result);
|
|
184
190
|
}
|
|
185
191
|
this.completeTask(task, worker);
|
|
192
|
+
this.consecutiveRespawns = 0;
|
|
186
193
|
this.dispatch();
|
|
187
194
|
};
|
|
188
195
|
const onExit = (code, signal) => this.handleWorkerExit(worker, code, signal);
|
|
@@ -355,6 +362,7 @@ class WorkerPool {
|
|
|
355
362
|
}
|
|
356
363
|
}
|
|
357
364
|
exports.WorkerPool = WorkerPool;
|
|
365
|
+
WorkerPool.MAX_RESPAWNS = 10;
|
|
358
366
|
let singleton = null;
|
|
359
367
|
function getWorkerPool() {
|
|
360
368
|
if (!singleton) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "grepmax",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.4",
|
|
4
4
|
"author": "Robert Owens <robowens@me.com>",
|
|
5
5
|
"homepage": "https://github.com/reowens/grepmax",
|
|
6
6
|
"bugs": {
|
|
@@ -75,6 +75,9 @@
|
|
|
75
75
|
"format": "biome check --write .",
|
|
76
76
|
"format:check": "biome check .",
|
|
77
77
|
"lint": "biome lint .",
|
|
78
|
-
"typecheck": "tsc --noEmit"
|
|
78
|
+
"typecheck": "tsc --noEmit",
|
|
79
|
+
"preversion": "pnpm test && pnpm typecheck",
|
|
80
|
+
"version": "bash scripts/sync-versions.sh && git add -A",
|
|
81
|
+
"postversion": "git push origin main --tags && gh release create v$npm_package_version --generate-notes --title v$npm_package_version && sleep 5 && gh run watch $(gh run list --workflow=release.yml --limit 1 --json databaseId --jq '.[0].databaseId') --exit-status && sleep 30 && npm cache clean --force && npm install -g grepmax@$npm_package_version"
|
|
79
82
|
}
|
|
80
83
|
}
|