grepmax 0.17.22 → 0.17.24
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/add.js +3 -2
- package/dist/commands/audit.js +29 -4
- package/dist/commands/context.js +34 -2
- package/dist/commands/dead.js +2 -0
- package/dist/commands/doctor.js +70 -3
- package/dist/commands/impact.js +11 -8
- package/dist/commands/index.js +16 -6
- package/dist/commands/mcp.js +2 -0
- package/dist/commands/peek.js +96 -17
- package/dist/commands/project.js +17 -4
- package/dist/commands/related.js +7 -3
- package/dist/commands/search.js +5 -0
- package/dist/commands/similar.js +2 -0
- package/dist/commands/test-find.js +10 -14
- package/dist/commands/trace.js +4 -29
- package/dist/config.js +47 -1
- package/dist/eval-graph-nav.js +374 -0
- package/dist/eval-graph-sanity.js +138 -19
- package/dist/eval-like-limit-probe.js +62 -0
- package/dist/lib/daemon/daemon.js +1 -1
- package/dist/lib/graph/callsites.js +148 -0
- package/dist/lib/graph/graph-builder.js +37 -11
- package/dist/lib/graph/impact.js +29 -14
- package/dist/lib/graph/test-hits.js +54 -0
- package/dist/lib/help/agent-cheatsheet.js +5 -0
- package/dist/lib/index/chunker.js +185 -6
- package/dist/lib/llm/tools.js +58 -16
- package/dist/lib/output/agent-search-formatter.js +59 -3
- package/dist/lib/search/searcher.js +2 -1
- package/dist/lib/store/vector-db.js +43 -13
- package/dist/lib/utils/query-timeout.js +52 -0
- package/dist/lib/utils/stale-hint.js +62 -0
- package/dist/lib/workers/orchestrator.js +2 -1
- package/package.json +18 -4
- package/plugins/grepmax/.claude-plugin/plugin.json +1 -1
package/dist/commands/add.js
CHANGED
|
@@ -47,6 +47,7 @@ const fs = __importStar(require("node:fs"));
|
|
|
47
47
|
const os = __importStar(require("node:os"));
|
|
48
48
|
const path = __importStar(require("node:path"));
|
|
49
49
|
const commander_1 = require("commander");
|
|
50
|
+
const config_1 = require("../config");
|
|
50
51
|
const grammar_loader_1 = require("../lib/index/grammar-loader");
|
|
51
52
|
const index_config_1 = require("../lib/index/index-config");
|
|
52
53
|
const sync_helpers_1 = require("../lib/index/sync-helpers");
|
|
@@ -218,7 +219,7 @@ Examples:
|
|
|
218
219
|
if (!done.ok) {
|
|
219
220
|
throw new Error((_c = done.error) !== null && _c !== void 0 ? _c : "daemon add failed");
|
|
220
221
|
}
|
|
221
|
-
(0, project_registry_1.registerProject)(Object.assign(Object.assign({}, pendingEntry), { lastIndexed: new Date().toISOString(), chunkCount: (_d = done.indexed) !== null && _d !== void 0 ? _d : 0, status: "indexed" }));
|
|
222
|
+
(0, project_registry_1.registerProject)(Object.assign(Object.assign({}, pendingEntry), { lastIndexed: new Date().toISOString(), chunkCount: (_d = done.indexed) !== null && _d !== void 0 ? _d : 0, status: "indexed", chunkerVersion: config_1.CONFIG.CHUNKER_VERSION }));
|
|
222
223
|
const failedFiles = (_e = done.failedFiles) !== null && _e !== void 0 ? _e : 0;
|
|
223
224
|
const failedSuffix = failedFiles > 0 ? ` · ${failedFiles} failed` : "";
|
|
224
225
|
spinner.succeed(`Added ${projectName} (${done.total} files, ${done.indexed} chunks${failedSuffix})`);
|
|
@@ -239,7 +240,7 @@ Examples:
|
|
|
239
240
|
projectRoot,
|
|
240
241
|
onProgress,
|
|
241
242
|
});
|
|
242
|
-
(0, project_registry_1.registerProject)(Object.assign(Object.assign({}, pendingEntry), { lastIndexed: new Date().toISOString(), chunkCount: result.indexed, status: "indexed" }));
|
|
243
|
+
(0, project_registry_1.registerProject)(Object.assign(Object.assign({}, pendingEntry), { lastIndexed: new Date().toISOString(), chunkCount: result.indexed, status: "indexed", chunkerVersion: config_1.CONFIG.CHUNKER_VERSION }));
|
|
243
244
|
const failedSuffix = result.failedFiles > 0 ? ` · ${result.failedFiles} failed` : "";
|
|
244
245
|
spinner.succeed(`Added ${projectName} (${result.total} files, ${result.indexed} chunks${failedSuffix})`);
|
|
245
246
|
}
|
package/dist/commands/audit.js
CHANGED
|
@@ -45,11 +45,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
45
45
|
exports.audit = void 0;
|
|
46
46
|
exports.computeAudit = computeAudit;
|
|
47
47
|
const commander_1 = require("commander");
|
|
48
|
+
const callsites_1 = require("../lib/graph/callsites");
|
|
49
|
+
const vector_db_1 = require("../lib/store/vector-db");
|
|
48
50
|
const arrow_1 = require("../lib/utils/arrow");
|
|
49
51
|
const exit_1 = require("../lib/utils/exit");
|
|
50
52
|
const project_registry_1 = require("../lib/utils/project-registry");
|
|
51
53
|
const project_root_1 = require("../lib/utils/project-root");
|
|
52
|
-
const vector_db_1 = require("../lib/store/vector-db");
|
|
53
54
|
const useColors = process.stdout.isTTY && !process.env.NO_COLOR;
|
|
54
55
|
const style = {
|
|
55
56
|
bold: (s) => (useColors ? `\x1b[1m${s}\x1b[22m` : s),
|
|
@@ -71,8 +72,12 @@ function rel(p, prefix) {
|
|
|
71
72
|
* `top` caps each list; `deadTotal` reports the full pre-cap dead count.
|
|
72
73
|
*/
|
|
73
74
|
function computeAudit(rows, prefix, top) {
|
|
75
|
+
var _a, _b;
|
|
74
76
|
// First definition of a symbol wins (matches GraphBuilder semantics).
|
|
75
77
|
const defs = new Map();
|
|
78
|
+
// Distinct files defining each name — name-based edges can't tell same-name
|
|
79
|
+
// symbols apart, so multi-file definitions get flagged in the output.
|
|
80
|
+
const defFileCounts = new Map();
|
|
76
81
|
// Distinct files that reference a symbol (cross-file inbound edges).
|
|
77
82
|
const inboundFiles = new Map();
|
|
78
83
|
const inboundTotal = new Map();
|
|
@@ -91,6 +96,9 @@ function computeAudit(rows, prefix, top) {
|
|
|
91
96
|
if (!defs.has(s)) {
|
|
92
97
|
defs.set(s, { file, line, exported, complexity: 0 });
|
|
93
98
|
}
|
|
99
|
+
if (!defFileCounts.has(s))
|
|
100
|
+
defFileCounts.set(s, new Set());
|
|
101
|
+
defFileCounts.get(s).add(file);
|
|
94
102
|
if (!fileDefs.has(file))
|
|
95
103
|
fileDefs.set(file, new Set());
|
|
96
104
|
fileDefs.get(file).add(s);
|
|
@@ -110,6 +118,10 @@ function computeAudit(rows, prefix, top) {
|
|
|
110
118
|
for (const [symbol, info] of defs) {
|
|
111
119
|
if (symbol.length < MIN_GOD_NAME_LEN)
|
|
112
120
|
continue;
|
|
121
|
+
// Builtin method names (get, set, push, …) leak in via prototype/member
|
|
122
|
+
// definitions and their inbound counts are meaningless name collisions.
|
|
123
|
+
if ((0, callsites_1.isBuiltinCallee)(symbol))
|
|
124
|
+
continue;
|
|
113
125
|
const refFiles = inboundFiles.get(symbol);
|
|
114
126
|
if (!refFiles)
|
|
115
127
|
continue;
|
|
@@ -125,6 +137,7 @@ function computeAudit(rows, prefix, top) {
|
|
|
125
137
|
line: info.line,
|
|
126
138
|
inboundFiles: external,
|
|
127
139
|
totalRefs: inboundTotal.get(symbol) || 0,
|
|
140
|
+
defFiles: (_b = (_a = defFileCounts.get(symbol)) === null || _a === void 0 ? void 0 : _a.size) !== null && _b !== void 0 ? _b : 1,
|
|
128
141
|
});
|
|
129
142
|
}
|
|
130
143
|
godNodes.sort((a, b) => b.inboundFiles - a.inboundFiles || b.totalRefs - a.totalRefs);
|
|
@@ -187,7 +200,10 @@ function formatHuman(r) {
|
|
|
187
200
|
}
|
|
188
201
|
else {
|
|
189
202
|
for (const g of r.godNodes) {
|
|
190
|
-
|
|
203
|
+
const ambiguous = g.defFiles > 1
|
|
204
|
+
? style.dim(` ~defined in ${g.defFiles} files, location is a guess`)
|
|
205
|
+
: "";
|
|
206
|
+
out.push(` ${style.cyan(g.symbol.padEnd(28))} ${style.dim(`${g.inboundFiles} files`)}, ${g.totalRefs} refs ${style.dim(`${g.file}:${g.line + 1}`)}${ambiguous}`);
|
|
191
207
|
}
|
|
192
208
|
}
|
|
193
209
|
out.push("");
|
|
@@ -224,7 +240,8 @@ function formatAgent(r) {
|
|
|
224
240
|
const lines = [];
|
|
225
241
|
lines.push(`scanned\t${r.scannedChunks}\t${r.scannedFiles}`);
|
|
226
242
|
for (const g of r.godNodes) {
|
|
227
|
-
|
|
243
|
+
const ambiguous = g.defFiles > 1 ? `\tdefs=${g.defFiles}` : "";
|
|
244
|
+
lines.push(`god\t${g.symbol}\t${g.file}:${g.line + 1}\t${g.inboundFiles}\t${g.totalRefs}${ambiguous}`);
|
|
228
245
|
}
|
|
229
246
|
for (const h of r.hubFiles) {
|
|
230
247
|
lines.push(`hub\t${h.file}\t${h.dependents}\t${h.defines}\t${h.fanOut}`);
|
|
@@ -274,6 +291,7 @@ exports.audit = new commander_1.Command("audit")
|
|
|
274
291
|
"start_line",
|
|
275
292
|
"defined_symbols",
|
|
276
293
|
"referenced_symbols",
|
|
294
|
+
"type_referenced_symbols",
|
|
277
295
|
"is_exported",
|
|
278
296
|
])
|
|
279
297
|
.where(buildScopeWhere(scope))
|
|
@@ -291,7 +309,14 @@ exports.audit = new commander_1.Command("audit")
|
|
|
291
309
|
start_line: Number(r.start_line || 0),
|
|
292
310
|
is_exported: Boolean(r.is_exported),
|
|
293
311
|
defined_symbols: (0, arrow_1.toArr)(r.defined_symbols),
|
|
294
|
-
|
|
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
|
+
],
|
|
295
320
|
})), prefix, top);
|
|
296
321
|
console.log(opts.agent ? formatAgent(result) : formatHuman(result));
|
|
297
322
|
}
|
package/dist/commands/context.js
CHANGED
|
@@ -43,6 +43,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
43
43
|
};
|
|
44
44
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
45
|
exports.context = void 0;
|
|
46
|
+
exports.findEnclosingSignature = findEnclosingSignature;
|
|
46
47
|
const fs = __importStar(require("node:fs"));
|
|
47
48
|
const path = __importStar(require("node:path"));
|
|
48
49
|
const commander_1 = require("commander");
|
|
@@ -82,6 +83,23 @@ function chunkEndLine(chunk) {
|
|
|
82
83
|
const start = chunkStartLine(chunk);
|
|
83
84
|
return Number((_d = (_b = (_a = chunk.end_line) !== null && _a !== void 0 ? _a : chunk.endLine) !== null && _b !== void 0 ? _b : (_c = chunk.generated_metadata) === null || _c === void 0 ? void 0 : _c.end_line) !== null && _d !== void 0 ? _d : start);
|
|
84
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* The definition line of `parentSymbol` nearest above `startLine` — used to
|
|
88
|
+
* give a mid-function sub-chunk extract its enclosing signature. Requires a
|
|
89
|
+
* definition-shaped line, not just any mention, so recursive calls or
|
|
90
|
+
* references between the definition and the chunk don't win.
|
|
91
|
+
*/
|
|
92
|
+
function findEnclosingSignature(lines, startLine, parentSymbol) {
|
|
93
|
+
if (!parentSymbol || !/^\w+$/.test(parentSymbol))
|
|
94
|
+
return null;
|
|
95
|
+
const defRe = new RegExp(`(?:\\b(?:class|function|interface|enum|struct|trait|impl|def|fn|type|const|let|var)\\b[^=]*\\b${parentSymbol}\\b|\\b${parentSymbol}\\b\\s*[(:=])`);
|
|
96
|
+
for (let i = Math.min(startLine, lines.length) - 1; i >= 0; i--) {
|
|
97
|
+
if (defRe.test(lines[i])) {
|
|
98
|
+
return { text: lines[i].trim(), line: i };
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
85
103
|
function resolveExistingPath(target, root, projectRoot) {
|
|
86
104
|
const candidates = [
|
|
87
105
|
path.isAbsolute(target) ? target : path.resolve(root, target),
|
|
@@ -196,7 +214,8 @@ exports.context = new commander_1.Command("context")
|
|
|
196
214
|
for (const r of entryPoints.slice(0, 5)) {
|
|
197
215
|
const p = chunkPath(r);
|
|
198
216
|
const line = chunkStartLine(r);
|
|
199
|
-
const
|
|
217
|
+
const parentSym = String(r.parent_symbol || "");
|
|
218
|
+
const sym = (_c = (_b = (0, arrow_1.toArr)(r.defined_symbols)) === null || _b === void 0 ? void 0 : _b[0]) !== null && _c !== void 0 ? _c : (parentSym ? `(in ${parentSym})` : "");
|
|
200
219
|
const role = String(r.role || "IMPLEMENTATION");
|
|
201
220
|
epSection.push(`${relPath(projectRoot, p)}:${line + 1} ${sym} [${role}]`);
|
|
202
221
|
}
|
|
@@ -215,13 +234,26 @@ exports.context = new commander_1.Command("context")
|
|
|
215
234
|
const startLine = chunkStartLine(r);
|
|
216
235
|
const endLine = chunkEndLine(r);
|
|
217
236
|
const sym = (_b = (_a = (0, arrow_1.toArr)(r.defined_symbols)) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : "";
|
|
237
|
+
const parentSym = String(r.parent_symbol || "");
|
|
218
238
|
try {
|
|
219
239
|
const content = fs.readFileSync(absP, "utf-8");
|
|
220
240
|
const allLines = content.split("\n");
|
|
221
241
|
const body = allLines
|
|
222
242
|
.slice(startLine, Math.min(endLine + 1, allLines.length))
|
|
223
243
|
.join("\n");
|
|
224
|
-
|
|
244
|
+
// A sub-chunk that starts mid-function has no defined symbol of its
|
|
245
|
+
// own — prepend the enclosing definition's signature so the extract
|
|
246
|
+
// isn't headless code.
|
|
247
|
+
let enclosing = "";
|
|
248
|
+
let label = sym;
|
|
249
|
+
if (!sym && parentSym) {
|
|
250
|
+
label = `(in ${parentSym})`;
|
|
251
|
+
const sig = findEnclosingSignature(allLines, startLine, parentSym);
|
|
252
|
+
if (sig) {
|
|
253
|
+
enclosing = `${sig.text} // :${sig.line + 1}\n// ...\n`;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
return `\n--- ${relPath(projectRoot, absP)}:${startLine + 1} ${label} ---\n${enclosing}${body}`;
|
|
225
257
|
}
|
|
226
258
|
catch (_c) {
|
|
227
259
|
return null; // File not readable — drop
|
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,7 @@ 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 });
|
|
121
123
|
const paths = (0, project_root_1.ensureProjectPaths)(projectRoot);
|
|
122
124
|
vectorDb = new vector_db_1.VectorDB(paths.lancedbDir);
|
|
123
125
|
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,7 +236,12 @@ 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
|
+
const staleChunkerProjects = projects.filter((p) => {
|
|
241
|
+
var _a;
|
|
242
|
+
return p.status === "indexed" &&
|
|
243
|
+
((_a = p.chunkerVersion) !== null && _a !== void 0 ? _a : 1) < config_1.CONFIG.CHUNKER_VERSION;
|
|
244
|
+
});
|
|
240
245
|
if (opts.agent) {
|
|
241
246
|
const fields = [
|
|
242
247
|
"index_health",
|
|
@@ -251,8 +256,23 @@ exports.doctor = new commander_1.Command("doctor")
|
|
|
251
256
|
`lock=${lockStatus.split(" ")[0]}`,
|
|
252
257
|
`daemon=${daemonUp ? "running" : "stopped"}`,
|
|
253
258
|
`orphaned=${orphanedProjects.length}`,
|
|
259
|
+
`stale_chunker=${staleChunkerProjects.length}`,
|
|
254
260
|
];
|
|
255
261
|
console.log(fields.join("\t"));
|
|
262
|
+
for (const p of staleChunkerProjects) {
|
|
263
|
+
const gap = (0, config_1.describeChunkerGap)(p.chunkerVersion);
|
|
264
|
+
if (!gap)
|
|
265
|
+
continue;
|
|
266
|
+
console.log([
|
|
267
|
+
"stale_chunker_project",
|
|
268
|
+
`name=${p.name || path.basename(p.root)}`,
|
|
269
|
+
`indexed_v=${gap.fromVersion}`,
|
|
270
|
+
`current_v=${gap.toVersion}`,
|
|
271
|
+
`severity=${gap.severity}`,
|
|
272
|
+
`note=${gap.notes.join("; ")}`,
|
|
273
|
+
`fix=gmax index --reset (in ${p.root})`,
|
|
274
|
+
].join("\t"));
|
|
275
|
+
}
|
|
256
276
|
}
|
|
257
277
|
else {
|
|
258
278
|
console.log("\nIndex Health\n");
|
|
@@ -296,6 +316,21 @@ exports.doctor = new commander_1.Command("doctor")
|
|
|
296
316
|
}
|
|
297
317
|
// Daemon
|
|
298
318
|
console.log(`${daemonUp ? "ok" : "INFO"} Daemon: ${daemonUp ? "running" : "not running"}`);
|
|
319
|
+
// Index built by an older chunker — graph metadata fixes need a reindex.
|
|
320
|
+
// Severity (and the WARN/INFO label) is driven by CHUNKER_VERSION_HISTORY:
|
|
321
|
+
// a breaking gap means stale metadata is wrong, an additive gap only
|
|
322
|
+
// means newer edges are missing.
|
|
323
|
+
if (staleChunkerProjects.length > 0) {
|
|
324
|
+
const anyBreaking = staleChunkerProjects.some((p) => { var _a; return ((_a = (0, config_1.describeChunkerGap)(p.chunkerVersion)) === null || _a === void 0 ? void 0 : _a.severity) === "breaking"; });
|
|
325
|
+
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`);
|
|
326
|
+
for (const p of staleChunkerProjects) {
|
|
327
|
+
const gap = (0, config_1.describeChunkerGap)(p.chunkerVersion);
|
|
328
|
+
if (!gap)
|
|
329
|
+
continue;
|
|
330
|
+
console.log(` - ${p.name || path.basename(p.root)} (v${gap.fromVersion}→v${gap.toVersion}, ${gap.severity}): ${gap.notes.join(" ")}`);
|
|
331
|
+
console.log(` run 'gmax index --reset' in ${p.root}`);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
299
334
|
// Projects
|
|
300
335
|
if (orphanedProjects.length > 0) {
|
|
301
336
|
console.log(`WARN Orphaned projects: ${orphanedProjects.length} (directories no longer exist)`);
|
|
@@ -324,7 +359,7 @@ exports.doctor = new commander_1.Command("doctor")
|
|
|
324
359
|
}
|
|
325
360
|
yield mc.close();
|
|
326
361
|
}
|
|
327
|
-
catch (
|
|
362
|
+
catch (_h) { }
|
|
328
363
|
}
|
|
329
364
|
}
|
|
330
365
|
// --fix auto-remediation
|
|
@@ -354,6 +389,38 @@ exports.doctor = new commander_1.Command("doctor")
|
|
|
354
389
|
console.log(`ok Removed ${orphanedProjects.length} orphaned project(s) from registry`);
|
|
355
390
|
fixed++;
|
|
356
391
|
}
|
|
392
|
+
// Reindex projects whose index predates the current chunker. This is a
|
|
393
|
+
// full `--reset` reindex per project (routed through the daemon), so it
|
|
394
|
+
// can be slow on large repos — unlike the cheap fixes above.
|
|
395
|
+
if (staleChunkerProjects.length > 0) {
|
|
396
|
+
const { ensureDaemonRunning, sendStreamingCommand } = yield Promise.resolve().then(() => __importStar(require("../lib/utils/daemon-client")));
|
|
397
|
+
if (!(yield ensureDaemonRunning())) {
|
|
398
|
+
if (!opts.agent)
|
|
399
|
+
console.log("WARN Stale chunker: daemon not running — start it (gmax watch --daemon -b) or run 'gmax index --reset' per project");
|
|
400
|
+
}
|
|
401
|
+
else {
|
|
402
|
+
for (const p of staleChunkerProjects) {
|
|
403
|
+
const name = p.name || path.basename(p.root);
|
|
404
|
+
if (!opts.agent)
|
|
405
|
+
console.log(`... Reindexing ${name} (--reset)...`);
|
|
406
|
+
const done = yield sendStreamingCommand({ cmd: "index", root: p.root, reset: true }, () => { }).catch((e) => ({ ok: false, error: String(e) }));
|
|
407
|
+
if (done.ok) {
|
|
408
|
+
(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 }));
|
|
409
|
+
const chunks = (_f = done.indexed) !== null && _f !== void 0 ? _f : 0;
|
|
410
|
+
if (opts.agent) {
|
|
411
|
+
console.log(`stale_chunker_reindexed\tname=${name}\tchunks=${chunks}`);
|
|
412
|
+
}
|
|
413
|
+
else {
|
|
414
|
+
console.log(`ok ${name} reindexed (${chunks} chunks)`);
|
|
415
|
+
}
|
|
416
|
+
fixed++;
|
|
417
|
+
}
|
|
418
|
+
else if (!opts.agent) {
|
|
419
|
+
console.log(`FAIL ${name}: reindex failed (${done.error})`);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
357
424
|
if (fixed === 0) {
|
|
358
425
|
if (!opts.agent)
|
|
359
426
|
console.log("ok Nothing to fix");
|
package/dist/commands/impact.js
CHANGED
|
@@ -46,10 +46,12 @@ exports.impact = void 0;
|
|
|
46
46
|
const path = __importStar(require("node:path"));
|
|
47
47
|
const commander_1 = require("commander");
|
|
48
48
|
const impact_1 = require("../lib/graph/impact");
|
|
49
|
+
const test_hits_1 = require("../lib/graph/test-hits");
|
|
49
50
|
const vector_db_1 = require("../lib/store/vector-db");
|
|
50
51
|
const agent_errors_1 = require("../lib/utils/agent-errors");
|
|
51
52
|
const exit_1 = require("../lib/utils/exit");
|
|
52
53
|
const project_registry_1 = require("../lib/utils/project-registry");
|
|
54
|
+
const stale_hint_1 = require("../lib/utils/stale-hint");
|
|
53
55
|
const project_root_1 = require("../lib/utils/project-root");
|
|
54
56
|
exports.impact = new commander_1.Command("impact")
|
|
55
57
|
.description("Analyze change impact: dependents and affected tests")
|
|
@@ -71,6 +73,7 @@ exports.impact = new commander_1.Command("impact")
|
|
|
71
73
|
if (root === null)
|
|
72
74
|
return;
|
|
73
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 });
|
|
74
77
|
const paths = (0, project_root_1.ensureProjectPaths)(projectRoot);
|
|
75
78
|
vectorDb = new vector_db_1.VectorDB(paths.lancedbDir);
|
|
76
79
|
const { symbols, resolvedAsFile } = yield (0, impact_1.resolveTargetSymbols)(target, vectorDb, projectRoot);
|
|
@@ -110,14 +113,15 @@ exports.impact = new commander_1.Command("impact")
|
|
|
110
113
|
]);
|
|
111
114
|
// Separate test files from non-test dependents
|
|
112
115
|
const nonTestDeps = dependents.filter((d) => !(0, impact_1.isTestPath)(d.file));
|
|
116
|
+
// One line per test file; caller symbols inside it become `via` detail.
|
|
117
|
+
const groupedTests = (0, test_hits_1.groupTestHitsByFile)(tests);
|
|
113
118
|
const rel = (p) => p.startsWith(`${projectRoot}/`) ? p.slice(projectRoot.length + 1) : p;
|
|
114
119
|
if (opts.agent) {
|
|
115
120
|
for (const d of nonTestDeps) {
|
|
116
121
|
console.log(`dep: ${rel(d.file)}\t${d.sharedSymbols}`);
|
|
117
122
|
}
|
|
118
|
-
for (const t of
|
|
119
|
-
|
|
120
|
-
console.log(`test: ${rel(t.file)}:${t.line + 1}\t${t.symbol}\t${hopLabel}`);
|
|
123
|
+
for (const t of groupedTests) {
|
|
124
|
+
console.log(`test: ${rel(t.file)}:${t.line + 1}\t${(0, test_hits_1.hopLabelAgent)(t.hops)}${(0, test_hits_1.formatViaAgent)(t.via)}`);
|
|
121
125
|
}
|
|
122
126
|
if (!nonTestDeps.length && !tests.length) {
|
|
123
127
|
console.log("(no impact detected)");
|
|
@@ -136,11 +140,10 @@ exports.impact = new commander_1.Command("impact")
|
|
|
136
140
|
}
|
|
137
141
|
if (includeTests) {
|
|
138
142
|
console.log("");
|
|
139
|
-
if (
|
|
140
|
-
console.log(`Affected tests (${
|
|
141
|
-
for (const t of
|
|
142
|
-
|
|
143
|
-
console.log(` ${rel(t.file)}:${t.line + 1} ${t.symbol} (${hopLabel})`);
|
|
143
|
+
if (groupedTests.length > 0) {
|
|
144
|
+
console.log(`Affected tests (${groupedTests.length}):`);
|
|
145
|
+
for (const t of groupedTests) {
|
|
146
|
+
console.log(` ${rel(t.file)}:${t.line + 1} (${(0, test_hits_1.hopLabelHuman)(t.hops)}${(0, test_hits_1.formatViaHuman)(t.via)})`);
|
|
144
147
|
}
|
|
145
148
|
}
|
|
146
149
|
else {
|
package/dist/commands/index.js
CHANGED
|
@@ -45,6 +45,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
45
45
|
exports.index = void 0;
|
|
46
46
|
const path = __importStar(require("node:path"));
|
|
47
47
|
const commander_1 = require("commander");
|
|
48
|
+
const config_1 = require("../config");
|
|
48
49
|
const index_config_1 = require("../lib/index/index-config");
|
|
49
50
|
const grammar_loader_1 = require("../lib/index/grammar-loader");
|
|
50
51
|
const sync_helpers_1 = require("../lib/index/sync-helpers");
|
|
@@ -70,7 +71,7 @@ Examples:
|
|
|
70
71
|
gmax index --reset Full re-index from scratch
|
|
71
72
|
`)
|
|
72
73
|
.action((_args, cmd) => __awaiter(void 0, void 0, void 0, function* () {
|
|
73
|
-
var _a, _b, _c, _d;
|
|
74
|
+
var _a, _b, _c, _d, _e;
|
|
74
75
|
const options = cmd.optsWithGlobals();
|
|
75
76
|
let vectorDb = null;
|
|
76
77
|
const ac = new AbortController();
|
|
@@ -90,11 +91,18 @@ Examples:
|
|
|
90
91
|
: process.cwd();
|
|
91
92
|
const projectRoot = (_a = (0, project_root_1.findProjectRoot)(indexRoot)) !== null && _a !== void 0 ? _a : indexRoot;
|
|
92
93
|
// Project must be registered before reindexing
|
|
93
|
-
|
|
94
|
+
const existingEntry = (0, project_registry_1.getProject)(projectRoot);
|
|
95
|
+
if (!existingEntry) {
|
|
94
96
|
console.error(`This project hasn't been added yet.\n\nRun: gmax add ${projectRoot}\n`);
|
|
95
97
|
process.exitCode = 1;
|
|
96
98
|
return;
|
|
97
99
|
}
|
|
100
|
+
// Only a reset rechunks cached files, so only a reset may claim the
|
|
101
|
+
// current chunker version — a plain index would clear the doctor
|
|
102
|
+
// stale-chunker warning without regenerating any chunks.
|
|
103
|
+
const stampedChunkerVersion = options.reset
|
|
104
|
+
? config_1.CONFIG.CHUNKER_VERSION
|
|
105
|
+
: ((_b = existingEntry.chunkerVersion) !== null && _b !== void 0 ? _b : 1);
|
|
98
106
|
if (options.reset) {
|
|
99
107
|
console.log("Resetting index...");
|
|
100
108
|
}
|
|
@@ -115,7 +123,7 @@ Examples:
|
|
|
115
123
|
});
|
|
116
124
|
});
|
|
117
125
|
if (!done.ok) {
|
|
118
|
-
throw new Error((
|
|
126
|
+
throw new Error((_c = done.error) !== null && _c !== void 0 ? _c : "daemon index failed");
|
|
119
127
|
}
|
|
120
128
|
if (options.dryRun) {
|
|
121
129
|
spinner.succeed(`Dry run complete(${done.processed} / ${done.total}) • would have indexed ${done.indexed} `);
|
|
@@ -129,10 +137,11 @@ Examples:
|
|
|
129
137
|
modelTier: globalConfig.modelTier,
|
|
130
138
|
embedMode: globalConfig.embedMode,
|
|
131
139
|
lastIndexed: new Date().toISOString(),
|
|
132
|
-
chunkCount: (
|
|
140
|
+
chunkCount: (_d = done.indexed) !== null && _d !== void 0 ? _d : 0,
|
|
133
141
|
status: "indexed",
|
|
142
|
+
chunkerVersion: stampedChunkerVersion,
|
|
134
143
|
});
|
|
135
|
-
const failedFiles = (
|
|
144
|
+
const failedFiles = (_e = done.failedFiles) !== null && _e !== void 0 ? _e : 0;
|
|
136
145
|
const failedSuffix = failedFiles > 0 ? ` • ${failedFiles} failed` : "";
|
|
137
146
|
spinner.succeed(`Indexing complete(${done.processed} / ${done.total}) • indexed ${done.indexed}${failedSuffix} `);
|
|
138
147
|
}
|
|
@@ -152,7 +161,7 @@ Examples:
|
|
|
152
161
|
try {
|
|
153
162
|
process.kill(watcher.pid, "SIGTERM");
|
|
154
163
|
}
|
|
155
|
-
catch (
|
|
164
|
+
catch (_f) { }
|
|
156
165
|
for (let i = 0; i < 50; i++) {
|
|
157
166
|
if (!(0, watcher_store_1.isProcessRunning)(watcher.pid))
|
|
158
167
|
break;
|
|
@@ -192,6 +201,7 @@ Examples:
|
|
|
192
201
|
lastIndexed: new Date().toISOString(),
|
|
193
202
|
chunkCount: result.indexed,
|
|
194
203
|
status: "indexed",
|
|
204
|
+
chunkerVersion: stampedChunkerVersion,
|
|
195
205
|
});
|
|
196
206
|
const failedSuffix = result.failedFiles > 0 ? ` • ${result.failedFiles} failed` : "";
|
|
197
207
|
spinner.succeed(`Indexing complete(${result.processed} / ${result.total}) • indexed ${result.indexed}${failedSuffix} `);
|
package/dist/commands/mcp.js
CHANGED
|
@@ -623,6 +623,7 @@ function formatMcpPointerSearchResults(data, displayRoot, options = {}) {
|
|
|
623
623
|
return (0, agent_search_formatter_1.formatAgentSearchResults)(filterMcpSearchResults(data, options), displayRoot, {
|
|
624
624
|
includeImports: options.includeImports,
|
|
625
625
|
getImportsForFile: options.getImportsForFile,
|
|
626
|
+
query: options.query,
|
|
626
627
|
});
|
|
627
628
|
}
|
|
628
629
|
// ---------------------------------------------------------------------------
|
|
@@ -834,6 +835,7 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
834
835
|
namePattern,
|
|
835
836
|
includeImports,
|
|
836
837
|
getImportsForFile,
|
|
838
|
+
query,
|
|
837
839
|
});
|
|
838
840
|
if ((_a = result.warnings) === null || _a === void 0 ? void 0 : _a.length) {
|
|
839
841
|
return ok(`${result.warnings.join("\n")}\n\n${output}`);
|