grepmax 0.24.0 → 0.25.0
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/README.md +11 -6
- package/dist/commands/add.js +38 -31
- package/dist/commands/config.js +16 -15
- package/dist/commands/context.js +38 -13
- package/dist/commands/doctor.js +76 -83
- package/dist/commands/extract.js +12 -1
- package/dist/commands/index.js +23 -24
- package/dist/commands/list.js +23 -14
- package/dist/commands/mcp.js +278 -143
- package/dist/commands/peek.js +16 -5
- package/dist/commands/repair.js +54 -120
- package/dist/commands/search-output.js +30 -9
- package/dist/commands/search-run.js +75 -47
- package/dist/commands/search-skeletons.js +28 -18
- package/dist/commands/search.js +45 -49
- package/dist/commands/serve.js +415 -373
- package/dist/commands/setup.js +2 -2
- package/dist/commands/similar.js +5 -5
- package/dist/commands/skeleton.js +67 -41
- package/dist/commands/status.js +5 -2
- package/dist/commands/summarize.js +6 -0
- package/dist/commands/watch.js +102 -38
- package/dist/config.js +3 -0
- package/dist/lib/daemon/daemon.js +1101 -379
- package/dist/lib/daemon/ipc-handler.js +122 -13
- package/dist/lib/daemon/mlx-server-manager.js +268 -125
- package/dist/lib/daemon/process-manager.js +7 -4
- package/dist/lib/daemon/search-handler.js +23 -9
- package/dist/lib/daemon/watcher-manager.js +353 -110
- package/dist/lib/index/batch-processor.js +231 -67
- package/dist/lib/index/embedding-generation.js +109 -0
- package/dist/lib/index/embedding-status.js +23 -0
- package/dist/lib/index/file-policy.js +273 -0
- package/dist/lib/index/ignore-patterns.js +4 -0
- package/dist/lib/index/index-config.js +18 -4
- package/dist/lib/index/syncer.js +256 -79
- package/dist/lib/index/walker.js +66 -86
- package/dist/lib/index/watcher-batch.js +9 -0
- package/dist/lib/index/watcher.js +129 -3
- package/dist/lib/llm/server.js +6 -0
- package/dist/lib/search/searcher.js +30 -19
- package/dist/lib/store/store-lease.js +473 -0
- package/dist/lib/store/vector-db.js +302 -57
- package/dist/lib/utils/blocked-roots.js +63 -0
- package/dist/lib/utils/cross-project.js +7 -3
- package/dist/lib/utils/daemon-client.js +24 -1
- package/dist/lib/utils/daemon-launcher.js +38 -13
- package/dist/lib/utils/doctor-status.js +76 -0
- package/dist/lib/utils/file-utils.js +74 -4
- package/dist/lib/utils/keyed-mutex.js +101 -0
- package/dist/lib/utils/logger.js +57 -1
- package/dist/lib/utils/mlx-hf-cache.js +114 -0
- package/dist/lib/utils/operation-coordinator.js +146 -0
- package/dist/lib/utils/path-containment.js +106 -0
- package/dist/lib/utils/process.js +44 -0
- package/dist/lib/utils/project-registry.js +351 -3
- package/dist/lib/utils/scope-filter.js +3 -9
- package/dist/lib/utils/stale-hint.js +12 -19
- package/dist/lib/utils/watcher-launcher.js +5 -1
- package/dist/lib/utils/watcher-store.js +2 -2
- package/dist/lib/workers/colbert-math.js +15 -12
- package/dist/lib/workers/embeddings/colbert.js +3 -2
- package/dist/lib/workers/embeddings/granite.js +4 -3
- package/dist/lib/workers/embeddings/mlx-client.js +59 -16
- package/dist/lib/workers/orchestrator.js +39 -8
- package/dist/lib/workers/pool.js +146 -82
- package/dist/lib/workers/process-child.js +11 -2
- package/dist/lib/workers/serialized-handler.js +10 -0
- package/dist/lib/workers/worker.js +13 -4
- package/mlx-embed-server/server.py +21 -3
- package/mlx-embed-server/summarizer.py +8 -0
- package/package.json +4 -3
- package/plugins/grepmax/.claude-plugin/plugin.json +1 -1
- package/plugins/grepmax/hooks/start.js +3 -170
|
@@ -42,6 +42,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
42
42
|
});
|
|
43
43
|
};
|
|
44
44
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
|
+
exports.EXCLUSIVE_GENERATION_REBUILD_PROTOCOL = void 0;
|
|
45
46
|
exports.writeProgress = writeProgress;
|
|
46
47
|
exports.writeDone = writeDone;
|
|
47
48
|
exports.startHeartbeat = startHeartbeat;
|
|
@@ -49,6 +50,9 @@ exports.handleCommand = handleCommand;
|
|
|
49
50
|
const fs = __importStar(require("node:fs"));
|
|
50
51
|
const path = __importStar(require("node:path"));
|
|
51
52
|
const logger_1 = require("../utils/logger");
|
|
53
|
+
const operation_coordinator_1 = require("../utils/operation-coordinator");
|
|
54
|
+
const path_containment_1 = require("../utils/path-containment");
|
|
55
|
+
const project_registry_1 = require("../utils/project-registry");
|
|
52
56
|
const DAEMON_VERSION = (() => {
|
|
53
57
|
try {
|
|
54
58
|
return JSON.parse(fs.readFileSync(path.join(__dirname, "../../../package.json"), "utf-8")).version;
|
|
@@ -57,6 +61,7 @@ const DAEMON_VERSION = (() => {
|
|
|
57
61
|
return "unknown";
|
|
58
62
|
}
|
|
59
63
|
})();
|
|
64
|
+
exports.EXCLUSIVE_GENERATION_REBUILD_PROTOCOL = 1;
|
|
60
65
|
/**
|
|
61
66
|
* Write a streaming progress line to the IPC connection.
|
|
62
67
|
*/
|
|
@@ -74,6 +79,19 @@ function writeDone(conn, data) {
|
|
|
74
79
|
conn.write(`${JSON.stringify(Object.assign({ type: "done" }, data))}\n`);
|
|
75
80
|
conn.end();
|
|
76
81
|
}
|
|
82
|
+
function errorResponse(err) {
|
|
83
|
+
if (err instanceof operation_coordinator_1.OperationBusyError ||
|
|
84
|
+
err instanceof operation_coordinator_1.OperationClosedError) {
|
|
85
|
+
return { ok: false, error: err.message, code: err.code };
|
|
86
|
+
}
|
|
87
|
+
return {
|
|
88
|
+
ok: false,
|
|
89
|
+
error: err instanceof Error ? err.message : String(err),
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
function startStreaming(conn, operation) {
|
|
93
|
+
void operation().catch((err) => writeDone(conn, errorResponse(err)));
|
|
94
|
+
}
|
|
77
95
|
const HEARTBEAT_INTERVAL_MS = 5000;
|
|
78
96
|
/**
|
|
79
97
|
* Emit periodic heartbeat lines so the client's watchdog timer resets even
|
|
@@ -102,9 +120,15 @@ function startHeartbeat(conn, intervalMs = HEARTBEAT_INTERVAL_MS) {
|
|
|
102
120
|
*/
|
|
103
121
|
function handleCommand(daemon, cmd, conn) {
|
|
104
122
|
return __awaiter(this, void 0, void 0, function* () {
|
|
105
|
-
var _a, _b, _c, _d, _e;
|
|
123
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
106
124
|
try {
|
|
107
125
|
(0, logger_1.debug)("daemon", `ipc cmd=${cmd.cmd}${cmd.root ? ` root=${cmd.root}` : ""}`);
|
|
126
|
+
if (cmd.cmd !== "ping" &&
|
|
127
|
+
cmd.cmd !== "shutdown" &&
|
|
128
|
+
(daemon.operationStatus() === "closing" ||
|
|
129
|
+
daemon.operationStatus() === "closed")) {
|
|
130
|
+
return errorResponse(new operation_coordinator_1.OperationClosedError());
|
|
131
|
+
}
|
|
108
132
|
// The socket listens before LanceDB/MetaCache are open so liveness probes
|
|
109
133
|
// succeed during slow startup. Gate resource-dependent commands until those
|
|
110
134
|
// stores exist; ping/shutdown must always work (probes + restart).
|
|
@@ -119,6 +143,12 @@ function handleCommand(daemon, cmd, conn) {
|
|
|
119
143
|
pid: process.pid,
|
|
120
144
|
uptime: daemon.uptime(),
|
|
121
145
|
version: DAEMON_VERSION,
|
|
146
|
+
operationStatus: daemon.operationStatus(),
|
|
147
|
+
resourceGeneration: daemon.resourceGenerationId(),
|
|
148
|
+
rebuildPending: daemon.hasUnfinishedRebuild(),
|
|
149
|
+
capabilities: {
|
|
150
|
+
exclusiveGenerationRebuild: exports.EXCLUSIVE_GENERATION_REBUILD_PROTOCOL,
|
|
151
|
+
},
|
|
122
152
|
};
|
|
123
153
|
case "watch": {
|
|
124
154
|
const root = String(cmd.root || "");
|
|
@@ -141,7 +171,17 @@ function handleCommand(daemon, cmd, conn) {
|
|
|
141
171
|
uptime: daemon.uptime(),
|
|
142
172
|
projects: daemon.listProjects(),
|
|
143
173
|
diskPressure: daemon.getDiskPressure(),
|
|
174
|
+
mlx: daemon.getMlxStatus(),
|
|
144
175
|
};
|
|
176
|
+
case "project-stats": {
|
|
177
|
+
const root = String(cmd.root || "");
|
|
178
|
+
if (!root)
|
|
179
|
+
return { ok: false, error: "missing root" };
|
|
180
|
+
const project = (0, project_registry_1.listProjects)().find((entry) => entry.root === root);
|
|
181
|
+
if (!project)
|
|
182
|
+
return { ok: false, error: "project not registered" };
|
|
183
|
+
return Object.assign({ ok: true }, (yield daemon.projectStats(root)));
|
|
184
|
+
}
|
|
145
185
|
case "shutdown": {
|
|
146
186
|
const reason = String((_a = cmd.reason) !== null && _a !== void 0 ? _a : "unknown");
|
|
147
187
|
const fromPid = (_b = cmd.from_pid) !== null && _b !== void 0 ? _b : "?";
|
|
@@ -155,7 +195,9 @@ function handleCommand(daemon, cmd, conn) {
|
|
|
155
195
|
setImmediate(() => daemon.shutdown());
|
|
156
196
|
return { ok: true };
|
|
157
197
|
}
|
|
158
|
-
case "search":
|
|
198
|
+
case "search":
|
|
199
|
+
case "search-v2": {
|
|
200
|
+
const isV2 = cmd.cmd === "search-v2";
|
|
159
201
|
const projectRoot = String(cmd.projectRoot || "");
|
|
160
202
|
if (!projectRoot)
|
|
161
203
|
return { ok: false, error: "missing projectRoot" };
|
|
@@ -169,6 +211,9 @@ function handleCommand(daemon, cmd, conn) {
|
|
|
169
211
|
conn.on("close", onClose);
|
|
170
212
|
try {
|
|
171
213
|
const limitRaw = typeof cmd.limit === "number" ? cmd.limit : 10;
|
|
214
|
+
if (!Number.isInteger(limitRaw) || limitRaw < 1 || limitRaw > 1000) {
|
|
215
|
+
return { ok: false, error: "invalid limit" };
|
|
216
|
+
}
|
|
172
217
|
const skeletonLimitRaw = typeof cmd.skeletonLimit === "number"
|
|
173
218
|
? cmd.skeletonLimit
|
|
174
219
|
: undefined;
|
|
@@ -181,12 +226,57 @@ function handleCommand(daemon, cmd, conn) {
|
|
|
181
226
|
!Array.isArray(cmd.filters)
|
|
182
227
|
? cmd.filters
|
|
183
228
|
: undefined;
|
|
229
|
+
const projectRoots = filters === null || filters === void 0 ? void 0 : filters.projectRoots;
|
|
230
|
+
const eligibleProjects = new Set((0, project_registry_1.listProjects)()
|
|
231
|
+
.filter((project) => project.status !== "error")
|
|
232
|
+
.map((project) => project.root));
|
|
233
|
+
if (isV2) {
|
|
234
|
+
if (!Array.isArray(projectRoots) || projectRoots.length === 0) {
|
|
235
|
+
return { ok: false, error: "missing projectRoots" };
|
|
236
|
+
}
|
|
237
|
+
if (projectRoots.some((root) => typeof root !== "string" || !eligibleProjects.has(root))) {
|
|
238
|
+
return { ok: false, error: "invalid projectRoots" };
|
|
239
|
+
}
|
|
240
|
+
if ((filters === null || filters === void 0 ? void 0 : filters.inPrefixes) !== undefined ||
|
|
241
|
+
(filters === null || filters === void 0 ? void 0 : filters.excludePrefixes) !== undefined) {
|
|
242
|
+
return {
|
|
243
|
+
ok: false,
|
|
244
|
+
error: "project path filters are not valid for cross-project search",
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
else if (projectRoots !== undefined) {
|
|
249
|
+
return { ok: false, error: "projectRoots requires search-v2" };
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
const legacyRoots = filters === null || filters === void 0 ? void 0 : filters.project_roots;
|
|
253
|
+
if (typeof legacyRoots === "string" &&
|
|
254
|
+
legacyRoots.split(",").some((root) => !eligibleProjects.has(root))) {
|
|
255
|
+
return { ok: false, error: "invalid project_roots" };
|
|
256
|
+
}
|
|
257
|
+
for (const prefix of [
|
|
258
|
+
...((_f = filters === null || filters === void 0 ? void 0 : filters.inPrefixes) !== null && _f !== void 0 ? _f : []),
|
|
259
|
+
...((_g = filters === null || filters === void 0 ? void 0 : filters.excludePrefixes) !== null && _g !== void 0 ? _g : []),
|
|
260
|
+
]) {
|
|
261
|
+
(0, path_containment_1.resolveContainedPath)(projectRoot, prefix);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
let pathPrefix;
|
|
265
|
+
if (typeof cmd.pathPrefix === "string") {
|
|
266
|
+
if (isV2) {
|
|
267
|
+
return {
|
|
268
|
+
ok: false,
|
|
269
|
+
error: "pathPrefix is not valid for cross-project search",
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
pathPrefix = `${(0, path_containment_1.resolveContainedPath)(projectRoot, cmd.pathPrefix).replace(/\/$/, "")}/`;
|
|
273
|
+
}
|
|
184
274
|
const resp = yield daemon.search({
|
|
185
275
|
projectRoot,
|
|
186
276
|
query,
|
|
187
277
|
limit: limitRaw,
|
|
188
278
|
filters,
|
|
189
|
-
pathPrefix
|
|
279
|
+
pathPrefix,
|
|
190
280
|
rerank: cmd.rerank === true,
|
|
191
281
|
explain: cmd.explain === true,
|
|
192
282
|
seeds: cmd.seeds &&
|
|
@@ -209,40 +299,60 @@ function handleCommand(daemon, cmd, conn) {
|
|
|
209
299
|
const root = String(cmd.root || "");
|
|
210
300
|
if (!root)
|
|
211
301
|
return { ok: false, error: "missing root" };
|
|
212
|
-
daemon.addProject(root, conn);
|
|
302
|
+
startStreaming(conn, () => daemon.addProject(root, conn));
|
|
303
|
+
return null;
|
|
304
|
+
}
|
|
305
|
+
case "ensure-project": {
|
|
306
|
+
const root = String(cmd.root || "");
|
|
307
|
+
if (!root)
|
|
308
|
+
return { ok: false, error: "missing root" };
|
|
309
|
+
startStreaming(conn, () => daemon.ensureProject(root, conn));
|
|
213
310
|
return null;
|
|
214
311
|
}
|
|
215
312
|
case "index": {
|
|
216
313
|
const root = String(cmd.root || "");
|
|
217
314
|
if (!root)
|
|
218
315
|
return { ok: false, error: "missing root" };
|
|
219
|
-
daemon.indexProject(root, conn, {
|
|
316
|
+
startStreaming(conn, () => daemon.indexProject(root, conn, {
|
|
220
317
|
reset: !!cmd.reset,
|
|
221
318
|
dryRun: !!cmd.dryRun,
|
|
222
|
-
});
|
|
319
|
+
}));
|
|
223
320
|
return null;
|
|
224
321
|
}
|
|
225
322
|
case "remove": {
|
|
226
323
|
const root = String(cmd.root || "");
|
|
227
324
|
if (!root)
|
|
228
325
|
return { ok: false, error: "missing root" };
|
|
229
|
-
daemon.removeProject(root, conn);
|
|
326
|
+
startStreaming(conn, () => daemon.removeProject(root, conn));
|
|
230
327
|
return null;
|
|
231
328
|
}
|
|
232
|
-
case "repair":
|
|
329
|
+
case "repair":
|
|
330
|
+
return {
|
|
331
|
+
ok: false,
|
|
332
|
+
error: "legacy repair protocol is disabled; restart gmax and use repair-v2",
|
|
333
|
+
code: "REBUILD_PROTOCOL_REQUIRED",
|
|
334
|
+
};
|
|
335
|
+
case "repair-v2": {
|
|
336
|
+
if (cmd.protocol !== exports.EXCLUSIVE_GENERATION_REBUILD_PROTOCOL) {
|
|
337
|
+
return {
|
|
338
|
+
ok: false,
|
|
339
|
+
error: "unsupported exclusive rebuild protocol",
|
|
340
|
+
code: "REBUILD_PROTOCOL_REQUIRED",
|
|
341
|
+
};
|
|
342
|
+
}
|
|
233
343
|
// Global drop-and-rebuild recovery for a physical table-width mismatch.
|
|
234
344
|
// Streams per-project progress; daemon manages the connection.
|
|
235
|
-
daemon.repairRebuild(conn);
|
|
345
|
+
startStreaming(conn, () => daemon.repairRebuild(conn));
|
|
236
346
|
return null;
|
|
237
347
|
}
|
|
238
348
|
case "summarize": {
|
|
239
349
|
const root = String(cmd.root || "");
|
|
240
350
|
if (!root)
|
|
241
351
|
return { ok: false, error: "missing root" };
|
|
242
|
-
daemon.summarizeProject(root, conn, {
|
|
352
|
+
startStreaming(conn, () => daemon.summarizeProject(root, conn, {
|
|
243
353
|
limit: typeof cmd.limit === "number" ? cmd.limit : undefined,
|
|
244
354
|
pathPrefix: typeof cmd.pathPrefix === "string" ? cmd.pathPrefix : undefined,
|
|
245
|
-
});
|
|
355
|
+
}));
|
|
246
356
|
return null;
|
|
247
357
|
}
|
|
248
358
|
// --- LLM server management ---
|
|
@@ -265,8 +375,7 @@ function handleCommand(daemon, cmd, conn) {
|
|
|
265
375
|
}
|
|
266
376
|
}
|
|
267
377
|
catch (err) {
|
|
268
|
-
|
|
269
|
-
return { ok: false, error: msg };
|
|
378
|
+
return errorResponse(err);
|
|
270
379
|
}
|
|
271
380
|
});
|
|
272
381
|
}
|