grepmax 0.17.23 → 0.18.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/dist/commands/audit.js +10 -2
- package/dist/commands/dead.js +3 -0
- package/dist/commands/doctor.js +103 -10
- package/dist/commands/impact.js +3 -0
- package/dist/commands/peek.js +3 -0
- package/dist/commands/related.js +3 -0
- package/dist/commands/search-output.js +531 -0
- package/dist/commands/search.js +46 -462
- package/dist/commands/similar.js +3 -0
- package/dist/commands/test-find.js +3 -0
- package/dist/commands/trace.js +3 -0
- package/dist/config.js +80 -5
- package/dist/eval-graph-nav.js +374 -0
- package/dist/eval-graph-sanity.js +138 -19
- package/dist/lib/daemon/daemon.js +29 -643
- package/dist/lib/daemon/mlx-server-manager.js +191 -0
- package/dist/lib/daemon/process-manager.js +139 -0
- package/dist/lib/daemon/watcher-manager.js +484 -0
- package/dist/lib/graph/graph-builder.js +30 -8
- package/dist/lib/graph/impact.js +5 -3
- package/dist/lib/index/chunker.js +149 -4
- package/dist/lib/llm/tools.js +58 -16
- package/dist/lib/store/vector-db.js +43 -13
- package/dist/lib/utils/stale-hint.js +164 -0
- package/dist/lib/workers/orchestrator.js +2 -1
- package/package.json +17 -3
- package/plugins/grepmax/.claude-plugin/plugin.json +1 -1
package/dist/commands/audit.js
CHANGED
|
@@ -46,11 +46,11 @@ exports.audit = void 0;
|
|
|
46
46
|
exports.computeAudit = computeAudit;
|
|
47
47
|
const commander_1 = require("commander");
|
|
48
48
|
const callsites_1 = require("../lib/graph/callsites");
|
|
49
|
+
const vector_db_1 = require("../lib/store/vector-db");
|
|
49
50
|
const arrow_1 = require("../lib/utils/arrow");
|
|
50
51
|
const exit_1 = require("../lib/utils/exit");
|
|
51
52
|
const project_registry_1 = require("../lib/utils/project-registry");
|
|
52
53
|
const project_root_1 = require("../lib/utils/project-root");
|
|
53
|
-
const vector_db_1 = require("../lib/store/vector-db");
|
|
54
54
|
const useColors = process.stdout.isTTY && !process.env.NO_COLOR;
|
|
55
55
|
const style = {
|
|
56
56
|
bold: (s) => (useColors ? `\x1b[1m${s}\x1b[22m` : s),
|
|
@@ -291,6 +291,7 @@ exports.audit = new commander_1.Command("audit")
|
|
|
291
291
|
"start_line",
|
|
292
292
|
"defined_symbols",
|
|
293
293
|
"referenced_symbols",
|
|
294
|
+
"type_referenced_symbols",
|
|
294
295
|
"is_exported",
|
|
295
296
|
])
|
|
296
297
|
.where(buildScopeWhere(scope))
|
|
@@ -308,7 +309,14 @@ exports.audit = new commander_1.Command("audit")
|
|
|
308
309
|
start_line: Number(r.start_line || 0),
|
|
309
310
|
is_exported: Boolean(r.is_exported),
|
|
310
311
|
defined_symbols: (0, arrow_1.toArr)(r.defined_symbols),
|
|
311
|
-
|
|
312
|
+
// Union call-position + type-position edges so god-node ranking and
|
|
313
|
+
// dead-candidate detection see references made purely in type position.
|
|
314
|
+
referenced_symbols: [
|
|
315
|
+
...new Set([
|
|
316
|
+
...(0, arrow_1.toArr)(r.referenced_symbols),
|
|
317
|
+
...(0, arrow_1.toArr)(r.type_referenced_symbols),
|
|
318
|
+
]),
|
|
319
|
+
],
|
|
312
320
|
})), prefix, top);
|
|
313
321
|
console.log(opts.agent ? formatAgent(result) : formatHuman(result));
|
|
314
322
|
}
|
package/dist/commands/dead.js
CHANGED
|
@@ -50,6 +50,7 @@ const agent_errors_1 = require("../lib/utils/agent-errors");
|
|
|
50
50
|
const exit_1 = require("../lib/utils/exit");
|
|
51
51
|
const filter_builder_1 = require("../lib/utils/filter-builder");
|
|
52
52
|
const project_registry_1 = require("../lib/utils/project-registry");
|
|
53
|
+
const stale_hint_1 = require("../lib/utils/stale-hint");
|
|
53
54
|
const project_root_1 = require("../lib/utils/project-root");
|
|
54
55
|
const useColors = process.stdout.isTTY && !process.env.NO_COLOR;
|
|
55
56
|
const style = {
|
|
@@ -118,6 +119,8 @@ exports.dead = new commander_1.Command("dead")
|
|
|
118
119
|
let vectorDb = null;
|
|
119
120
|
try {
|
|
120
121
|
const projectRoot = (_a = (0, project_root_1.findProjectRoot)(root)) !== null && _a !== void 0 ? _a : root;
|
|
122
|
+
(0, stale_hint_1.maybeWarnStaleChunker)(projectRoot, { agent: opts.agent });
|
|
123
|
+
(0, stale_hint_1.maybeWarnStaleEmbedding)(projectRoot, { agent: opts.agent });
|
|
121
124
|
const paths = (0, project_root_1.ensureProjectPaths)(projectRoot);
|
|
122
125
|
vectorDb = new vector_db_1.VectorDB(paths.lancedbDir);
|
|
123
126
|
const { resolveScope, buildScopeWhere } = yield Promise.resolve().then(() => __importStar(require("../lib/utils/scope-filter")));
|
package/dist/commands/doctor.js
CHANGED
|
@@ -85,7 +85,7 @@ exports.doctor = new commander_1.Command("doctor")
|
|
|
85
85
|
.option("--fix", "Auto-fix detected issues (compact, prune, remove stale locks)", false)
|
|
86
86
|
.option("--agent", "Compact output for AI agents", false)
|
|
87
87
|
.action((opts) => __awaiter(void 0, void 0, void 0, function* () {
|
|
88
|
-
var _a, _b, _c, _d;
|
|
88
|
+
var _a, _b, _c, _d, _e, _f;
|
|
89
89
|
if (!opts.agent)
|
|
90
90
|
console.log("gmax Doctor\n");
|
|
91
91
|
const root = config_1.PATHS.globalRoot;
|
|
@@ -236,12 +236,18 @@ exports.doctor = new commander_1.Command("doctor")
|
|
|
236
236
|
availBytes = diskStats.bavail * diskStats.bsize;
|
|
237
237
|
diskLevel = availBytes < config_1.DISK_CRITICAL_BYTES ? "CRITICAL" : availBytes < config_1.DISK_LOW_BYTES ? "LOW" : "ok";
|
|
238
238
|
}
|
|
239
|
-
catch (
|
|
239
|
+
catch (_g) { }
|
|
240
240
|
const staleChunkerProjects = projects.filter((p) => {
|
|
241
241
|
var _a;
|
|
242
242
|
return p.status === "indexed" &&
|
|
243
243
|
((_a = p.chunkerVersion) !== null && _a !== void 0 ? _a : 1) < config_1.CONFIG.CHUNKER_VERSION;
|
|
244
244
|
});
|
|
245
|
+
// Projects whose stored embedding model/dim no longer matches the global
|
|
246
|
+
// config. Visibility only — recovery is a manual `gmax index --reset`
|
|
247
|
+
// (a dim change can't be auto-fixed in the shared fixed-dim table; that's
|
|
248
|
+
// the deferred Phase 1B re-embed work).
|
|
249
|
+
const staleEmbeddingProjects = projects.filter((p) => p.status === "indexed" &&
|
|
250
|
+
(0, config_1.describeEmbeddingGap)({ modelTier: p.modelTier, vectorDim: p.vectorDim }, { modelTier: globalConfig.modelTier, vectorDim: globalConfig.vectorDim }) !== null);
|
|
245
251
|
if (opts.agent) {
|
|
246
252
|
const fields = [
|
|
247
253
|
"index_health",
|
|
@@ -257,12 +263,38 @@ exports.doctor = new commander_1.Command("doctor")
|
|
|
257
263
|
`daemon=${daemonUp ? "running" : "stopped"}`,
|
|
258
264
|
`orphaned=${orphanedProjects.length}`,
|
|
259
265
|
`stale_chunker=${staleChunkerProjects.length}`,
|
|
266
|
+
`stale_embedding=${staleEmbeddingProjects.length}`,
|
|
260
267
|
];
|
|
261
268
|
console.log(fields.join("\t"));
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
269
|
+
for (const p of staleChunkerProjects) {
|
|
270
|
+
const gap = (0, config_1.describeChunkerGap)(p.chunkerVersion);
|
|
271
|
+
if (!gap)
|
|
272
|
+
continue;
|
|
273
|
+
console.log([
|
|
274
|
+
"stale_chunker_project",
|
|
275
|
+
`name=${p.name || path.basename(p.root)}`,
|
|
276
|
+
`indexed_v=${gap.fromVersion}`,
|
|
277
|
+
`current_v=${gap.toVersion}`,
|
|
278
|
+
`severity=${gap.severity}`,
|
|
279
|
+
`note=${gap.notes.join("; ")}`,
|
|
280
|
+
`fix=gmax index --reset (in ${p.root})`,
|
|
281
|
+
].join("\t"));
|
|
282
|
+
}
|
|
283
|
+
for (const p of staleEmbeddingProjects) {
|
|
284
|
+
const gap = (0, config_1.describeEmbeddingGap)({ modelTier: p.modelTier, vectorDim: p.vectorDim }, { modelTier: globalConfig.modelTier, vectorDim: globalConfig.vectorDim });
|
|
285
|
+
if (!gap)
|
|
286
|
+
continue;
|
|
287
|
+
console.log([
|
|
288
|
+
"stale_embedding_project",
|
|
289
|
+
`name=${p.name || path.basename(p.root)}`,
|
|
290
|
+
`indexed_model=${gap.fromModel}`,
|
|
291
|
+
`current_model=${gap.toModel}`,
|
|
292
|
+
`indexed_dim=${gap.fromDim}`,
|
|
293
|
+
`current_dim=${gap.toDim}`,
|
|
294
|
+
`dim_changed=${gap.dimChanged}`,
|
|
295
|
+
`severity=${gap.severity}`,
|
|
296
|
+
`fix=gmax index --reset (in ${p.root})`,
|
|
297
|
+
].join("\t"));
|
|
266
298
|
}
|
|
267
299
|
}
|
|
268
300
|
else {
|
|
@@ -307,13 +339,42 @@ exports.doctor = new commander_1.Command("doctor")
|
|
|
307
339
|
}
|
|
308
340
|
// Daemon
|
|
309
341
|
console.log(`${daemonUp ? "ok" : "INFO"} Daemon: ${daemonUp ? "running" : "not running"}`);
|
|
310
|
-
// Index built by an older chunker — graph metadata fixes need a reindex
|
|
342
|
+
// Index built by an older chunker — graph metadata fixes need a reindex.
|
|
343
|
+
// Severity (and the WARN/INFO label) is driven by CHUNKER_VERSION_HISTORY:
|
|
344
|
+
// a breaking gap means stale metadata is wrong, an additive gap only
|
|
345
|
+
// means newer edges are missing.
|
|
311
346
|
if (staleChunkerProjects.length > 0) {
|
|
312
|
-
|
|
347
|
+
const anyBreaking = staleChunkerProjects.some((p) => { var _a; return ((_a = (0, config_1.describeChunkerGap)(p.chunkerVersion)) === null || _a === void 0 ? void 0 : _a.severity) === "breaking"; });
|
|
348
|
+
console.log(`${anyBreaking ? "WARN" : "INFO"} Stale chunker: ${staleChunkerProjects.length} project(s) indexed before chunker v${config_1.CONFIG.CHUNKER_VERSION} — run 'gmax doctor --fix' to reindex`);
|
|
313
349
|
for (const p of staleChunkerProjects) {
|
|
314
|
-
|
|
350
|
+
const gap = (0, config_1.describeChunkerGap)(p.chunkerVersion);
|
|
351
|
+
if (!gap)
|
|
352
|
+
continue;
|
|
353
|
+
console.log(` - ${p.name || path.basename(p.root)} (v${gap.fromVersion}→v${gap.toVersion}, ${gap.severity}): ${gap.notes.join(" ")}`);
|
|
354
|
+
console.log(` run 'gmax index --reset' in ${p.root}`);
|
|
315
355
|
}
|
|
316
356
|
}
|
|
357
|
+
// Index built with a different embedding model/dim than the current
|
|
358
|
+
// config. A dim change is breaking (search scores are invalid until a
|
|
359
|
+
// re-embed); a same-dim model swap is additive. Unlike the stale-chunker
|
|
360
|
+
// case this is NOT auto-fixed by `--fix`: a dim change can't coexist in
|
|
361
|
+
// the shared fixed-dim table (deferred Phase 1B), so we point at the
|
|
362
|
+
// manual reset instead.
|
|
363
|
+
if (staleEmbeddingProjects.length > 0) {
|
|
364
|
+
const gaps = staleEmbeddingProjects.map((p) => (0, config_1.describeEmbeddingGap)({ modelTier: p.modelTier, vectorDim: p.vectorDim }, { modelTier: globalConfig.modelTier, vectorDim: globalConfig.vectorDim }));
|
|
365
|
+
const anyBreaking = gaps.some((g) => (g === null || g === void 0 ? void 0 : g.severity) === "breaking");
|
|
366
|
+
console.log(`${anyBreaking ? "WARN" : "INFO"} Stale embedding: ${staleEmbeddingProjects.length} project(s) indexed with a different embedding model/dim — run 'gmax index --reset' per project`);
|
|
367
|
+
staleEmbeddingProjects.forEach((p, i) => {
|
|
368
|
+
const gap = gaps[i];
|
|
369
|
+
if (!gap)
|
|
370
|
+
return;
|
|
371
|
+
const change = gap.dimChanged
|
|
372
|
+
? `${gap.fromDim}d→${gap.toDim}d`
|
|
373
|
+
: `model ${gap.fromModel}→${gap.toModel}`;
|
|
374
|
+
console.log(` - ${p.name || path.basename(p.root)} (${change}, ${gap.severity})`);
|
|
375
|
+
console.log(` run 'gmax index --reset' in ${p.root}`);
|
|
376
|
+
});
|
|
377
|
+
}
|
|
317
378
|
// Projects
|
|
318
379
|
if (orphanedProjects.length > 0) {
|
|
319
380
|
console.log(`WARN Orphaned projects: ${orphanedProjects.length} (directories no longer exist)`);
|
|
@@ -342,7 +403,7 @@ exports.doctor = new commander_1.Command("doctor")
|
|
|
342
403
|
}
|
|
343
404
|
yield mc.close();
|
|
344
405
|
}
|
|
345
|
-
catch (
|
|
406
|
+
catch (_h) { }
|
|
346
407
|
}
|
|
347
408
|
}
|
|
348
409
|
// --fix auto-remediation
|
|
@@ -372,6 +433,38 @@ exports.doctor = new commander_1.Command("doctor")
|
|
|
372
433
|
console.log(`ok Removed ${orphanedProjects.length} orphaned project(s) from registry`);
|
|
373
434
|
fixed++;
|
|
374
435
|
}
|
|
436
|
+
// Reindex projects whose index predates the current chunker. This is a
|
|
437
|
+
// full `--reset` reindex per project (routed through the daemon), so it
|
|
438
|
+
// can be slow on large repos — unlike the cheap fixes above.
|
|
439
|
+
if (staleChunkerProjects.length > 0) {
|
|
440
|
+
const { ensureDaemonRunning, sendStreamingCommand } = yield Promise.resolve().then(() => __importStar(require("../lib/utils/daemon-client")));
|
|
441
|
+
if (!(yield ensureDaemonRunning())) {
|
|
442
|
+
if (!opts.agent)
|
|
443
|
+
console.log("WARN Stale chunker: daemon not running — start it (gmax watch --daemon -b) or run 'gmax index --reset' per project");
|
|
444
|
+
}
|
|
445
|
+
else {
|
|
446
|
+
for (const p of staleChunkerProjects) {
|
|
447
|
+
const name = p.name || path.basename(p.root);
|
|
448
|
+
if (!opts.agent)
|
|
449
|
+
console.log(`... Reindexing ${name} (--reset)...`);
|
|
450
|
+
const done = yield sendStreamingCommand({ cmd: "index", root: p.root, reset: true }, () => { }).catch((e) => ({ ok: false, error: String(e) }));
|
|
451
|
+
if (done.ok) {
|
|
452
|
+
(0, project_registry_1.registerProject)(Object.assign(Object.assign({}, p), { status: "indexed", chunkerVersion: config_1.CONFIG.CHUNKER_VERSION, lastIndexed: new Date().toISOString(), chunkCount: (_e = done.indexed) !== null && _e !== void 0 ? _e : p.chunkCount }));
|
|
453
|
+
const chunks = (_f = done.indexed) !== null && _f !== void 0 ? _f : 0;
|
|
454
|
+
if (opts.agent) {
|
|
455
|
+
console.log(`stale_chunker_reindexed\tname=${name}\tchunks=${chunks}`);
|
|
456
|
+
}
|
|
457
|
+
else {
|
|
458
|
+
console.log(`ok ${name} reindexed (${chunks} chunks)`);
|
|
459
|
+
}
|
|
460
|
+
fixed++;
|
|
461
|
+
}
|
|
462
|
+
else if (!opts.agent) {
|
|
463
|
+
console.log(`FAIL ${name}: reindex failed (${done.error})`);
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
}
|
|
375
468
|
if (fixed === 0) {
|
|
376
469
|
if (!opts.agent)
|
|
377
470
|
console.log("ok Nothing to fix");
|
package/dist/commands/impact.js
CHANGED
|
@@ -51,6 +51,7 @@ const vector_db_1 = require("../lib/store/vector-db");
|
|
|
51
51
|
const agent_errors_1 = require("../lib/utils/agent-errors");
|
|
52
52
|
const exit_1 = require("../lib/utils/exit");
|
|
53
53
|
const project_registry_1 = require("../lib/utils/project-registry");
|
|
54
|
+
const stale_hint_1 = require("../lib/utils/stale-hint");
|
|
54
55
|
const project_root_1 = require("../lib/utils/project-root");
|
|
55
56
|
exports.impact = new commander_1.Command("impact")
|
|
56
57
|
.description("Analyze change impact: dependents and affected tests")
|
|
@@ -72,6 +73,8 @@ exports.impact = new commander_1.Command("impact")
|
|
|
72
73
|
if (root === null)
|
|
73
74
|
return;
|
|
74
75
|
const projectRoot = (_a = (0, project_root_1.findProjectRoot)(root)) !== null && _a !== void 0 ? _a : root;
|
|
76
|
+
(0, stale_hint_1.maybeWarnStaleChunker)(projectRoot, { agent: opts.agent });
|
|
77
|
+
(0, stale_hint_1.maybeWarnStaleEmbedding)(projectRoot, { agent: opts.agent });
|
|
75
78
|
const paths = (0, project_root_1.ensureProjectPaths)(projectRoot);
|
|
76
79
|
vectorDb = new vector_db_1.VectorDB(paths.lancedbDir);
|
|
77
80
|
const { symbols, resolvedAsFile } = yield (0, impact_1.resolveTargetSymbols)(target, vectorDb, projectRoot);
|
package/dist/commands/peek.js
CHANGED
|
@@ -53,6 +53,7 @@ const exit_1 = require("../lib/utils/exit");
|
|
|
53
53
|
const filter_builder_1 = require("../lib/utils/filter-builder");
|
|
54
54
|
const language_1 = require("../lib/utils/language");
|
|
55
55
|
const project_registry_1 = require("../lib/utils/project-registry");
|
|
56
|
+
const stale_hint_1 = require("../lib/utils/stale-hint");
|
|
56
57
|
const project_root_1 = require("../lib/utils/project-root");
|
|
57
58
|
const useColors = process.stdout.isTTY && !process.env.NO_COLOR;
|
|
58
59
|
const style = {
|
|
@@ -129,6 +130,8 @@ exports.peek = new commander_1.Command("peek")
|
|
|
129
130
|
const depth = Math.min(Math.max(Number.parseInt(opts.depth || "1", 10), 1), 3);
|
|
130
131
|
try {
|
|
131
132
|
const projectRoot = (_a = (0, project_root_1.findProjectRoot)(root)) !== null && _a !== void 0 ? _a : root;
|
|
133
|
+
(0, stale_hint_1.maybeWarnStaleChunker)(projectRoot, { agent: opts.agent });
|
|
134
|
+
(0, stale_hint_1.maybeWarnStaleEmbedding)(projectRoot, { agent: opts.agent });
|
|
132
135
|
const paths = (0, project_root_1.ensureProjectPaths)(projectRoot);
|
|
133
136
|
vectorDb = new vector_db_1.VectorDB(paths.lancedbDir);
|
|
134
137
|
const { resolveScope, buildScopeWhere } = yield Promise.resolve().then(() => __importStar(require("../lib/utils/scope-filter")));
|
package/dist/commands/related.js
CHANGED
|
@@ -52,6 +52,7 @@ const exit_1 = require("../lib/utils/exit");
|
|
|
52
52
|
const project_registry_1 = require("../lib/utils/project-registry");
|
|
53
53
|
const project_root_1 = require("../lib/utils/project-root");
|
|
54
54
|
const query_timeout_1 = require("../lib/utils/query-timeout");
|
|
55
|
+
const stale_hint_1 = require("../lib/utils/stale-hint");
|
|
55
56
|
const arrow_1 = require("../lib/utils/arrow");
|
|
56
57
|
exports.related = new commander_1.Command("related")
|
|
57
58
|
.description("Find files related by shared symbol references")
|
|
@@ -70,6 +71,8 @@ exports.related = new commander_1.Command("related")
|
|
|
70
71
|
if (root === null)
|
|
71
72
|
return;
|
|
72
73
|
const projectRoot = (_a = (0, project_root_1.findProjectRoot)(root)) !== null && _a !== void 0 ? _a : root;
|
|
74
|
+
(0, stale_hint_1.maybeWarnStaleChunker)(projectRoot, { agent: opts.agent });
|
|
75
|
+
(0, stale_hint_1.maybeWarnStaleEmbedding)(projectRoot, { agent: opts.agent });
|
|
73
76
|
const paths = (0, project_root_1.ensureProjectPaths)(projectRoot);
|
|
74
77
|
vectorDb = new vector_db_1.VectorDB(paths.lancedbDir);
|
|
75
78
|
const absPath = path.resolve(projectRoot, file);
|