grepmax 0.17.21 → 0.17.22
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/impact.js +20 -11
- package/dist/commands/search-run.js +227 -0
- package/dist/commands/search-skeletons.js +133 -0
- package/dist/commands/search.js +43 -450
- package/dist/lib/daemon/daemon.js +14 -101
- package/dist/lib/daemon/search-handler.js +159 -0
- package/dist/lib/output/compact-results.js +244 -0
- package/package.json +1 -1
- package/plugins/grepmax/.claude-plugin/plugin.json +1 -1
package/dist/commands/search.js
CHANGED
|
@@ -43,315 +43,21 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
43
43
|
};
|
|
44
44
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
45
|
exports.search = void 0;
|
|
46
|
-
const fs = __importStar(require("node:fs"));
|
|
47
46
|
const path = __importStar(require("node:path"));
|
|
48
47
|
const commander_1 = require("commander");
|
|
49
|
-
const grammar_loader_1 = require("../lib/index/grammar-loader");
|
|
50
|
-
const sync_helpers_1 = require("../lib/index/sync-helpers");
|
|
51
|
-
const syncer_1 = require("../lib/index/syncer");
|
|
52
48
|
const agent_search_formatter_1 = require("../lib/output/agent-search-formatter");
|
|
49
|
+
const compact_results_1 = require("../lib/output/compact-results");
|
|
53
50
|
const index_state_footer_1 = require("../lib/output/index-state-footer");
|
|
54
|
-
const searcher_1 = require("../lib/search/searcher");
|
|
55
51
|
const setup_helpers_1 = require("../lib/setup/setup-helpers");
|
|
56
|
-
const skeleton_1 = require("../lib/skeleton");
|
|
57
|
-
const retriever_1 = require("../lib/skeleton/retriever");
|
|
58
|
-
const vector_db_1 = require("../lib/store/vector-db");
|
|
59
52
|
const cross_project_1 = require("../lib/utils/cross-project");
|
|
60
53
|
const exit_1 = require("../lib/utils/exit");
|
|
61
54
|
const formatter_1 = require("../lib/utils/formatter");
|
|
62
55
|
const import_extractor_1 = require("../lib/utils/import-extractor");
|
|
63
|
-
const lock_1 = require("../lib/utils/lock");
|
|
64
56
|
const project_registry_1 = require("../lib/utils/project-registry");
|
|
65
57
|
const project_root_1 = require("../lib/utils/project-root");
|
|
66
58
|
const server_registry_1 = require("../lib/utils/server-registry");
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
var _a, _b, _c, _d, _e, _f;
|
|
70
|
-
const rawPath = typeof ((_a = r.metadata) === null || _a === void 0 ? void 0 : _a.path) === "string"
|
|
71
|
-
? r.metadata.path
|
|
72
|
-
: "Unknown path";
|
|
73
|
-
const start = typeof ((_b = r.generated_metadata) === null || _b === void 0 ? void 0 : _b.start_line) === "number"
|
|
74
|
-
? r.generated_metadata.start_line
|
|
75
|
-
: 0;
|
|
76
|
-
const end = typeof ((_c = r.generated_metadata) === null || _c === void 0 ? void 0 : _c.end_line) === "number"
|
|
77
|
-
? r.generated_metadata.end_line
|
|
78
|
-
: start + Math.max(0, ((_e = (_d = r.generated_metadata) === null || _d === void 0 ? void 0 : _d.num_lines) !== null && _e !== void 0 ? _e : 1) - 1);
|
|
79
|
-
return {
|
|
80
|
-
path: rawPath,
|
|
81
|
-
score: r.score,
|
|
82
|
-
content: r.text || "",
|
|
83
|
-
chunk_type: (_f = r.generated_metadata) === null || _f === void 0 ? void 0 : _f.type,
|
|
84
|
-
start_line: start,
|
|
85
|
-
end_line: end,
|
|
86
|
-
};
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
function getPreviewText(chunk) {
|
|
90
|
-
var _a, _b, _c, _d, _e;
|
|
91
|
-
const maxLen = 140;
|
|
92
|
-
const lines = (_b = (_a = chunk.text) === null || _a === void 0 ? void 0 : _a.split("\n").map((l) => l.trim()).filter(Boolean)) !== null && _b !== void 0 ? _b : [];
|
|
93
|
-
let preview = (_c = lines[0]) !== null && _c !== void 0 ? _c : "";
|
|
94
|
-
if (!preview && ((_d = chunk.defined_symbols) === null || _d === void 0 ? void 0 : _d.length)) {
|
|
95
|
-
preview = (_e = chunk.defined_symbols[0]) !== null && _e !== void 0 ? _e : "";
|
|
96
|
-
}
|
|
97
|
-
if (preview.length > maxLen) {
|
|
98
|
-
preview = `${preview.slice(0, maxLen)}...`;
|
|
99
|
-
}
|
|
100
|
-
return preview;
|
|
101
|
-
}
|
|
102
|
-
function toCompactHits(data) {
|
|
103
|
-
return data.map((chunk) => {
|
|
104
|
-
var _a, _b, _c, _d, _e, _f;
|
|
105
|
-
const rawPath = typeof ((_a = chunk.metadata) === null || _a === void 0 ? void 0 : _a.path) === "string"
|
|
106
|
-
? chunk.metadata.path
|
|
107
|
-
: "Unknown path";
|
|
108
|
-
const start = typeof ((_b = chunk.generated_metadata) === null || _b === void 0 ? void 0 : _b.start_line) === "number"
|
|
109
|
-
? chunk.generated_metadata.start_line
|
|
110
|
-
: 0;
|
|
111
|
-
const end = typeof ((_c = chunk.generated_metadata) === null || _c === void 0 ? void 0 : _c.end_line) === "number"
|
|
112
|
-
? chunk.generated_metadata.end_line
|
|
113
|
-
: start + Math.max(0, ((_e = (_d = chunk.generated_metadata) === null || _d === void 0 ? void 0 : _d.num_lines) !== null && _e !== void 0 ? _e : 1) - 1);
|
|
114
|
-
return {
|
|
115
|
-
path: rawPath,
|
|
116
|
-
range: `${start + 1}-${end + 1}`,
|
|
117
|
-
start_line: start,
|
|
118
|
-
end_line: end,
|
|
119
|
-
role: chunk.role,
|
|
120
|
-
confidence: chunk.confidence,
|
|
121
|
-
score: chunk.score,
|
|
122
|
-
defined: Array.isArray(chunk.defined_symbols)
|
|
123
|
-
? chunk.defined_symbols.slice(0, 3)
|
|
124
|
-
: typeof chunk.defined_symbols === "string"
|
|
125
|
-
? [chunk.defined_symbols]
|
|
126
|
-
: typeof ((_f = chunk.defined_symbols) === null || _f === void 0 ? void 0 : _f.toArray) === "function"
|
|
127
|
-
? chunk.defined_symbols.toArray().slice(0, 3)
|
|
128
|
-
: [],
|
|
129
|
-
preview: getPreviewText(chunk),
|
|
130
|
-
summary: typeof chunk.summary === "string" ? chunk.summary : undefined,
|
|
131
|
-
};
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
function compactRole(role) {
|
|
135
|
-
if (!role)
|
|
136
|
-
return "UNK";
|
|
137
|
-
if (role.startsWith("ORCH"))
|
|
138
|
-
return "ORCH";
|
|
139
|
-
if (role.startsWith("DEF"))
|
|
140
|
-
return "DEF";
|
|
141
|
-
if (role.startsWith("IMP"))
|
|
142
|
-
return "IMPL";
|
|
143
|
-
return role.slice(0, 4).toUpperCase();
|
|
144
|
-
}
|
|
145
|
-
function compactConf(conf) {
|
|
146
|
-
if (!conf)
|
|
147
|
-
return "U";
|
|
148
|
-
const c = conf.toUpperCase();
|
|
149
|
-
if (c.startsWith("H"))
|
|
150
|
-
return "H";
|
|
151
|
-
if (c.startsWith("M"))
|
|
152
|
-
return "M";
|
|
153
|
-
if (c.startsWith("L"))
|
|
154
|
-
return "L";
|
|
155
|
-
return "U";
|
|
156
|
-
}
|
|
157
|
-
function compactScore(score) {
|
|
158
|
-
if (typeof score !== "number")
|
|
159
|
-
return "";
|
|
160
|
-
const fixed = score.toFixed(3);
|
|
161
|
-
return fixed
|
|
162
|
-
.replace(/^0\./, ".")
|
|
163
|
-
.replace(/\.?0+$/, (m) => (m.startsWith(".") ? "" : m));
|
|
164
|
-
}
|
|
165
|
-
function truncateEnd(s, max) {
|
|
166
|
-
if (max <= 0)
|
|
167
|
-
return "";
|
|
168
|
-
if (s.length <= max)
|
|
169
|
-
return s;
|
|
170
|
-
if (max <= 3)
|
|
171
|
-
return s.slice(0, max);
|
|
172
|
-
return `${s.slice(0, max - 3)}...`;
|
|
173
|
-
}
|
|
174
|
-
function padR(s, w) {
|
|
175
|
-
const n = Math.max(0, w - s.length);
|
|
176
|
-
return s + " ".repeat(n);
|
|
177
|
-
}
|
|
178
|
-
function padL(s, w) {
|
|
179
|
-
const n = Math.max(0, w - s.length);
|
|
180
|
-
return " ".repeat(n) + s;
|
|
181
|
-
}
|
|
182
|
-
function formatCompactTSV(hits, projectRoot, query) {
|
|
183
|
-
var _a, _b;
|
|
184
|
-
if (!hits.length)
|
|
185
|
-
return "No matches found.";
|
|
186
|
-
const lines = [];
|
|
187
|
-
lines.push(`gmax hits\tquery=${query}\tcount=${hits.length}`);
|
|
188
|
-
lines.push("path\tlines\tscore\trole\tconf\tdefined\tsummary");
|
|
189
|
-
for (const hit of hits) {
|
|
190
|
-
const relPath = path.isAbsolute(hit.path)
|
|
191
|
-
? path.relative(projectRoot, hit.path)
|
|
192
|
-
: hit.path;
|
|
193
|
-
const score = compactScore(hit.score);
|
|
194
|
-
const role = compactRole(hit.role);
|
|
195
|
-
const conf = compactConf(hit.confidence);
|
|
196
|
-
const defs = ((_a = hit.defined) !== null && _a !== void 0 ? _a : []).join(",");
|
|
197
|
-
const summary = (_b = hit.summary) !== null && _b !== void 0 ? _b : "";
|
|
198
|
-
lines.push([relPath, hit.range, score, role, conf, defs, summary].join("\t"));
|
|
199
|
-
}
|
|
200
|
-
return lines.join("\n");
|
|
201
|
-
}
|
|
202
|
-
function formatCompactPretty(hits, projectRoot, query, termWidth, useAnsi) {
|
|
203
|
-
var _a;
|
|
204
|
-
if (!hits.length)
|
|
205
|
-
return "No matches found.";
|
|
206
|
-
const dim = (s) => (useAnsi ? `\x1b[90m${s}\x1b[0m` : s);
|
|
207
|
-
const bold = (s) => (useAnsi ? `\x1b[1m${s}\x1b[0m` : s);
|
|
208
|
-
const wLines = 9;
|
|
209
|
-
const wScore = 6;
|
|
210
|
-
const wRole = 4;
|
|
211
|
-
const wConf = 1;
|
|
212
|
-
const wDef = 20;
|
|
213
|
-
const gutters = 5;
|
|
214
|
-
const fixed = wLines + wScore + wRole + wConf + wDef + gutters;
|
|
215
|
-
const wPath = Math.max(24, Math.min(64, termWidth - fixed));
|
|
216
|
-
const header = `gmax hits count=${hits.length} query="${query}"`;
|
|
217
|
-
const cols = [
|
|
218
|
-
padR("path", wPath),
|
|
219
|
-
padR("lines", wLines),
|
|
220
|
-
padL("score", wScore),
|
|
221
|
-
padR("role", wRole),
|
|
222
|
-
padR("c", wConf),
|
|
223
|
-
padR("defined", wDef),
|
|
224
|
-
].join(" ");
|
|
225
|
-
const out = [];
|
|
226
|
-
out.push(bold(header));
|
|
227
|
-
out.push(dim(cols));
|
|
228
|
-
for (const hit of hits) {
|
|
229
|
-
const relPath = path.isAbsolute(hit.path)
|
|
230
|
-
? path.relative(projectRoot, hit.path)
|
|
231
|
-
: hit.path;
|
|
232
|
-
const score = compactScore(hit.score);
|
|
233
|
-
const role = compactRole(hit.role);
|
|
234
|
-
const conf = compactConf(hit.confidence);
|
|
235
|
-
const defs = ((_a = hit.defined) !== null && _a !== void 0 ? _a : []).join(",") || "-";
|
|
236
|
-
const displayPath = `${relPath}:${hit.start_line + 1}`;
|
|
237
|
-
const paddedPath = padR(displayPath, wPath);
|
|
238
|
-
const row = [
|
|
239
|
-
paddedPath,
|
|
240
|
-
padR(hit.range, wLines),
|
|
241
|
-
padL(score || "", wScore),
|
|
242
|
-
padR(role, wRole),
|
|
243
|
-
padR(conf, wConf),
|
|
244
|
-
padR(truncateEnd(defs, wDef), wDef),
|
|
245
|
-
].join(" ");
|
|
246
|
-
out.push(row);
|
|
247
|
-
}
|
|
248
|
-
return out.join("\n");
|
|
249
|
-
}
|
|
250
|
-
function formatCompactTable(hits, projectRoot, query, opts) {
|
|
251
|
-
var _a;
|
|
252
|
-
if (!hits.length)
|
|
253
|
-
return "No matches found.";
|
|
254
|
-
if (!opts.isTTY || opts.plain) {
|
|
255
|
-
return formatCompactTSV(hits, projectRoot, query);
|
|
256
|
-
}
|
|
257
|
-
const termWidth = Math.max(80, (_a = process.stdout.columns) !== null && _a !== void 0 ? _a : 120);
|
|
258
|
-
return formatCompactPretty(hits, projectRoot, query, termWidth, true);
|
|
259
|
-
}
|
|
260
|
-
// Reuse Skeletonizer instance
|
|
261
|
-
let globalSkeletonizer = null;
|
|
262
|
-
function outputSkeletons(results, projectRoot, limit, db, precomputed) {
|
|
263
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
264
|
-
var _a, _b;
|
|
265
|
-
const seenPaths = new Set();
|
|
266
|
-
const filesToProcess = [];
|
|
267
|
-
for (const result of results) {
|
|
268
|
-
const p = (_a = result.metadata) === null || _a === void 0 ? void 0 : _a.path;
|
|
269
|
-
if (typeof p === "string" && !seenPaths.has(p)) {
|
|
270
|
-
seenPaths.add(p);
|
|
271
|
-
filesToProcess.push(p);
|
|
272
|
-
if (filesToProcess.length >= limit)
|
|
273
|
-
break;
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
if (filesToProcess.length === 0) {
|
|
277
|
-
console.log("No skeleton matches found.");
|
|
278
|
-
console.log("\nTry: broaden your query, or use `gmax skeleton <path>` to view a specific file's structure.");
|
|
279
|
-
process.exitCode = 1;
|
|
280
|
-
return;
|
|
281
|
-
}
|
|
282
|
-
// Reuse or init skeletonizer for fallbacks
|
|
283
|
-
if (!globalSkeletonizer) {
|
|
284
|
-
globalSkeletonizer = new skeleton_1.Skeletonizer();
|
|
285
|
-
// Lazy init only if we actually fallback
|
|
286
|
-
}
|
|
287
|
-
const skeletonOpts = { includeSummary: true };
|
|
288
|
-
const skeletonResults = [];
|
|
289
|
-
for (const filePath of filesToProcess) {
|
|
290
|
-
// Paths from search results are now absolute (centralized index)
|
|
291
|
-
const absPath = path.isAbsolute(filePath)
|
|
292
|
-
? filePath
|
|
293
|
-
: path.resolve(projectRoot, filePath);
|
|
294
|
-
// 0. Daemon-supplied (preferred — already-warm DB lookup, no cold open)
|
|
295
|
-
const fromDaemon = (_b = precomputed === null || precomputed === void 0 ? void 0 : precomputed[absPath]) !== null && _b !== void 0 ? _b : precomputed === null || precomputed === void 0 ? void 0 : precomputed[filePath];
|
|
296
|
-
if (fromDaemon) {
|
|
297
|
-
skeletonResults.push({
|
|
298
|
-
file: filePath,
|
|
299
|
-
skeleton: fromDaemon,
|
|
300
|
-
tokens: Math.ceil(fromDaemon.length / 4),
|
|
301
|
-
});
|
|
302
|
-
continue;
|
|
303
|
-
}
|
|
304
|
-
// 1. Try DB cache
|
|
305
|
-
if (db) {
|
|
306
|
-
const cached = yield (0, retriever_1.getStoredSkeleton)(db, absPath);
|
|
307
|
-
if (cached) {
|
|
308
|
-
skeletonResults.push({
|
|
309
|
-
file: filePath,
|
|
310
|
-
skeleton: cached,
|
|
311
|
-
tokens: Math.ceil(cached.length / 4), // Rough estimate
|
|
312
|
-
});
|
|
313
|
-
continue;
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
// 2. Fallback to fresh generation
|
|
317
|
-
yield globalSkeletonizer.init();
|
|
318
|
-
if (!fs.existsSync(absPath)) {
|
|
319
|
-
skeletonResults.push({
|
|
320
|
-
file: filePath,
|
|
321
|
-
skeleton: `// File not found: ${filePath}`,
|
|
322
|
-
tokens: 0,
|
|
323
|
-
error: "File not found",
|
|
324
|
-
});
|
|
325
|
-
continue;
|
|
326
|
-
}
|
|
327
|
-
const content = fs.readFileSync(absPath, "utf-8");
|
|
328
|
-
const res = yield globalSkeletonizer.skeletonizeFile(absPath, content, skeletonOpts);
|
|
329
|
-
skeletonResults.push({
|
|
330
|
-
file: filePath,
|
|
331
|
-
skeleton: res.skeleton,
|
|
332
|
-
tokens: res.tokenEstimate,
|
|
333
|
-
error: res.error,
|
|
334
|
-
});
|
|
335
|
-
}
|
|
336
|
-
// Since search doesn't support --json explicitly yet, we just print text.
|
|
337
|
-
// But if we ever add it, we have the structure.
|
|
338
|
-
for (const res of skeletonResults) {
|
|
339
|
-
console.log(res.skeleton);
|
|
340
|
-
console.log(""); // Separator
|
|
341
|
-
}
|
|
342
|
-
});
|
|
343
|
-
}
|
|
344
|
-
function resultCountHeader(results, maxCount) {
|
|
345
|
-
var _a, _b, _c;
|
|
346
|
-
const files = new Set();
|
|
347
|
-
for (const r of results) {
|
|
348
|
-
const p = (_c = (_a = r.path) !== null && _a !== void 0 ? _a : (_b = r.metadata) === null || _b === void 0 ? void 0 : _b.path) !== null && _c !== void 0 ? _c : "";
|
|
349
|
-
if (p)
|
|
350
|
-
files.add(p);
|
|
351
|
-
}
|
|
352
|
-
const showing = results.length < maxCount ? `${results.length}` : `top ${results.length}`;
|
|
353
|
-
return `Found ${results.length} match${results.length === 1 ? "" : "es"} (showing ${showing}) across ${files.size} file${files.size === 1 ? "" : "s"}`;
|
|
354
|
-
}
|
|
59
|
+
const search_run_1 = require("./search-run");
|
|
60
|
+
const search_skeletons_1 = require("./search-skeletons");
|
|
355
61
|
exports.search = new commander_1.Command("search")
|
|
356
62
|
.description("Search code by meaning (default command)")
|
|
357
63
|
.option("-m <max_count>, --max-count <max_count>", "The maximum number of results to return (total)", "5")
|
|
@@ -397,7 +103,7 @@ Examples:
|
|
|
397
103
|
gmax "auth middleware" --projects api,gateway --plain
|
|
398
104
|
`)
|
|
399
105
|
.action((pattern, exec_path, _options, cmd) => __awaiter(void 0, void 0, void 0, function* () {
|
|
400
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m
|
|
106
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
401
107
|
const options = cmd.optsWithGlobals();
|
|
402
108
|
const root = process.cwd();
|
|
403
109
|
const minScore = Number.isFinite(Number.parseFloat(options.minScore))
|
|
@@ -465,7 +171,7 @@ Examples:
|
|
|
465
171
|
const searchResult = { data: body.results };
|
|
466
172
|
const filteredData = searchResult.data.filter((r) => typeof r.score !== "number" || r.score >= minScore);
|
|
467
173
|
if (options.skeleton) {
|
|
468
|
-
yield outputSkeletons(filteredData, projectRootForServer, parseInt(options.m, 10),
|
|
174
|
+
yield (0, search_skeletons_1.outputSkeletons)(filteredData, projectRootForServer, parseInt(options.m, 10),
|
|
469
175
|
// Server doesn't easily expose DB instance here in HTTP client mode,
|
|
470
176
|
// but we are in client. Wait, this text implies "Server Search" block.
|
|
471
177
|
// Client talks to server. The server returns JSON.
|
|
@@ -476,7 +182,7 @@ Examples:
|
|
|
476
182
|
return;
|
|
477
183
|
}
|
|
478
184
|
const compactHits = options.compact
|
|
479
|
-
? toCompactHits(filteredData)
|
|
185
|
+
? (0, compact_results_1.toCompactHits)(filteredData)
|
|
480
186
|
: [];
|
|
481
187
|
if (options.compact) {
|
|
482
188
|
if (!compactHits.length) {
|
|
@@ -485,7 +191,7 @@ Examples:
|
|
|
485
191
|
process.exitCode = 1;
|
|
486
192
|
}
|
|
487
193
|
else {
|
|
488
|
-
console.log(formatCompactTable(compactHits, projectRootForServer, pattern, {
|
|
194
|
+
console.log((0, compact_results_1.formatCompactTable)(compactHits, projectRootForServer, pattern, {
|
|
489
195
|
isTTY: !!process.stdout.isTTY,
|
|
490
196
|
plain: !!options.plain,
|
|
491
197
|
}));
|
|
@@ -520,11 +226,11 @@ Examples:
|
|
|
520
226
|
const shouldBePlain = options.plain || !isTTY;
|
|
521
227
|
_searchResultCount = filteredData.length;
|
|
522
228
|
if (!options.agent && !options.compact) {
|
|
523
|
-
console.log(resultCountHeader(filteredData, parseInt(options.m, 10)));
|
|
229
|
+
console.log((0, compact_results_1.resultCountHeader)(filteredData, parseInt(options.m, 10)));
|
|
524
230
|
console.log();
|
|
525
231
|
}
|
|
526
232
|
if (shouldBePlain) {
|
|
527
|
-
const mappedResults = toTextResults(filteredData);
|
|
233
|
+
const mappedResults = (0, compact_results_1.toTextResults)(filteredData);
|
|
528
234
|
const output = (0, formatter_1.formatTextResults)(mappedResults, pattern, projectRootForServer, {
|
|
529
235
|
isPlain: true,
|
|
530
236
|
compact: options.compact,
|
|
@@ -643,138 +349,25 @@ Examples:
|
|
|
643
349
|
const seedFiles = splitSeeds(options.seedFile);
|
|
644
350
|
const seedSymbols = splitSeeds(options.seedSymbol);
|
|
645
351
|
const seeds = seedFiles || seedSymbols ? { files: seedFiles, symbols: seedSymbols } : undefined;
|
|
646
|
-
//
|
|
647
|
-
//
|
|
648
|
-
//
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
: undefined,
|
|
666
|
-
pathPrefix: pathFilter,
|
|
667
|
-
rerank: process.env.GMAX_RERANK === "1",
|
|
668
|
-
explain: options.explain,
|
|
669
|
-
seeds,
|
|
670
|
-
includeSkeletons: options.skeleton,
|
|
671
|
-
includeGraph: options.symbol,
|
|
672
|
-
}, { timeoutMs: 60000 });
|
|
673
|
-
if (resp.ok) {
|
|
674
|
-
searchResult = {
|
|
675
|
-
data: resp.data,
|
|
676
|
-
warnings: resp.warnings,
|
|
677
|
-
};
|
|
678
|
-
precomputedSkeletons = resp.skeletons;
|
|
679
|
-
precomputedGraph = resp.graph;
|
|
680
|
-
indexState = resp.indexState;
|
|
681
|
-
}
|
|
682
|
-
else if (process.env.GMAX_DEBUG === "1") {
|
|
683
|
-
console.error(`[search] daemon path unavailable: ${(_e = resp.error) !== null && _e !== void 0 ? _e : "unknown"}`);
|
|
684
|
-
}
|
|
685
|
-
}
|
|
686
|
-
}
|
|
687
|
-
catch (err) {
|
|
688
|
-
if (process.env.GMAX_DEBUG === "1") {
|
|
689
|
-
console.error("[search] daemon attempt threw:", err);
|
|
690
|
-
}
|
|
691
|
-
}
|
|
692
|
-
}
|
|
693
|
-
// In-process fallback: open VectorDB, ensure index, run Searcher.
|
|
694
|
-
// Only entered when the daemon path didn't produce results.
|
|
695
|
-
if (!searchResult) {
|
|
696
|
-
vectorDb = new vector_db_1.VectorDB(paths.lancedbDir);
|
|
697
|
-
// Check for active indexing lock and warn if present
|
|
698
|
-
const locked = (0, lock_1.isLocked)(paths.dataDir);
|
|
699
|
-
if (!options.agent && locked) {
|
|
700
|
-
console.warn("⚠️ Warning: Indexing in progress... search results may be incomplete.");
|
|
701
|
-
}
|
|
702
|
-
// No daemon here, so no precise pending count — surface the coarse
|
|
703
|
-
// signal (active lock or initial index not yet complete) so agent mode
|
|
704
|
-
// still gets a partial-index footer.
|
|
705
|
-
if (!indexState && (locked || project.status === "pending")) {
|
|
706
|
-
indexState = { indexing: true, pendingFiles: 0 };
|
|
707
|
-
}
|
|
708
|
-
const hasRows = yield vectorDb.hasAnyRows();
|
|
709
|
-
const needsSync = options.sync || !hasRows;
|
|
710
|
-
if (needsSync) {
|
|
711
|
-
const isTTY = process.stdout.isTTY;
|
|
712
|
-
let abortController;
|
|
713
|
-
let signal;
|
|
714
|
-
if (!isTTY) {
|
|
715
|
-
abortController = new AbortController();
|
|
716
|
-
signal = abortController.signal;
|
|
717
|
-
setTimeout(() => {
|
|
718
|
-
abortController === null || abortController === void 0 ? void 0 : abortController.abort();
|
|
719
|
-
}, 60000); // 60 seconds timeout for non-TTY auto-indexing
|
|
720
|
-
}
|
|
721
|
-
const { spinner, onProgress } = (0, sync_helpers_1.createIndexingSpinner)(projectRoot, options.sync ? "Indexing..." : "Indexing repository (first run)...");
|
|
722
|
-
try {
|
|
723
|
-
yield (0, grammar_loader_1.ensureGrammars)(console.log, { silent: true });
|
|
724
|
-
const result = yield (0, syncer_1.initialSync)({
|
|
725
|
-
projectRoot,
|
|
726
|
-
dryRun: options.dryRun,
|
|
727
|
-
onProgress,
|
|
728
|
-
signal,
|
|
729
|
-
});
|
|
730
|
-
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
731
|
-
spinner.warn(`Indexing timed out (${result.processed}/${result.total}). Results may be partial.`);
|
|
732
|
-
}
|
|
733
|
-
if (options.dryRun) {
|
|
734
|
-
spinner.succeed(`Dry run complete (${result.processed}/${result.total}) • would have indexed ${result.indexed}`);
|
|
735
|
-
console.log((0, sync_helpers_1.formatDryRunSummary)(result, {
|
|
736
|
-
actionDescription: "would have indexed",
|
|
737
|
-
includeTotal: true,
|
|
738
|
-
}));
|
|
739
|
-
return;
|
|
740
|
-
}
|
|
741
|
-
yield vectorDb.createFTSIndex();
|
|
742
|
-
// Update registry after sync
|
|
743
|
-
const { readGlobalConfig } = yield Promise.resolve().then(() => __importStar(require("../lib/index/index-config")));
|
|
744
|
-
const { registerProject } = yield Promise.resolve().then(() => __importStar(require("../lib/utils/project-registry")));
|
|
745
|
-
const gc = readGlobalConfig();
|
|
746
|
-
registerProject({
|
|
747
|
-
root: projectRoot,
|
|
748
|
-
name: path.basename(projectRoot),
|
|
749
|
-
vectorDim: gc.vectorDim,
|
|
750
|
-
modelTier: gc.modelTier,
|
|
751
|
-
embedMode: gc.embedMode,
|
|
752
|
-
lastIndexed: new Date().toISOString(),
|
|
753
|
-
chunkCount: result.indexed,
|
|
754
|
-
status: "indexed",
|
|
755
|
-
});
|
|
756
|
-
const failedSuffix = result.failedFiles > 0 ? ` • ${result.failedFiles} failed` : "";
|
|
757
|
-
spinner.succeed(`${options.sync ? "Indexing" : "Initial indexing"} complete (${result.processed}/${result.total}) • indexed ${result.indexed}${failedSuffix}`);
|
|
758
|
-
}
|
|
759
|
-
catch (e) {
|
|
760
|
-
spinner.fail("Indexing failed");
|
|
761
|
-
throw e;
|
|
762
|
-
}
|
|
763
|
-
}
|
|
764
|
-
// Ensure a watcher is running for live reindexing
|
|
765
|
-
if (!process.env.VITEST && !((_f = process.env.NODE_ENV) === null || _f === void 0 ? void 0 : _f.includes("test"))) {
|
|
766
|
-
const { launchWatcher } = yield Promise.resolve().then(() => __importStar(require("../lib/utils/watcher-launcher")));
|
|
767
|
-
const launched = yield launchWatcher(projectRoot);
|
|
768
|
-
if (!launched.ok && launched.reason === "spawn-failed") {
|
|
769
|
-
console.warn(`[search] ${launched.message}`);
|
|
770
|
-
}
|
|
771
|
-
}
|
|
772
|
-
const searcher = new searcher_1.Searcher(vectorDb);
|
|
773
|
-
searchResult = yield searcher.search(pattern, parseInt(options.m, 10), { rerank: process.env.GMAX_RERANK === "1", explain: options.explain, seeds }, Object.keys(searchFilters).length > 0
|
|
774
|
-
? searchFilters
|
|
775
|
-
: undefined, pathFilter);
|
|
776
|
-
} // end if (!searchResult) — in-process fallback
|
|
777
|
-
if (!options.agent && ((_g = searchResult.warnings) === null || _g === void 0 ? void 0 : _g.length)) {
|
|
352
|
+
// Acquire results: daemon-mediated first, in-process fallback otherwise.
|
|
353
|
+
// The render stage below is shared across both. `runSearch` reports the
|
|
354
|
+
// VectorDB it opens via the callback so the `finally` can close it.
|
|
355
|
+
const acquired = yield (0, search_run_1.runSearch)({
|
|
356
|
+
pattern,
|
|
357
|
+
options,
|
|
358
|
+
projectRoot,
|
|
359
|
+
effectiveRoot,
|
|
360
|
+
paths,
|
|
361
|
+
projectStatus: project.status,
|
|
362
|
+
searchFilters,
|
|
363
|
+
pathFilter,
|
|
364
|
+
seeds,
|
|
365
|
+
});
|
|
366
|
+
vectorDb = acquired.vectorDb;
|
|
367
|
+
if (acquired.kind === "dry-run")
|
|
368
|
+
return;
|
|
369
|
+
const { searchResult, precomputedSkeletons, precomputedGraph, indexState } = acquired;
|
|
370
|
+
if (!options.agent && ((_e = searchResult.warnings) === null || _e === void 0 ? void 0 : _e.length)) {
|
|
778
371
|
for (const w of searchResult.warnings) {
|
|
779
372
|
console.warn(`Warning: ${w}`);
|
|
780
373
|
}
|
|
@@ -799,7 +392,7 @@ Examples:
|
|
|
799
392
|
return defs.some((d) => regex.test(d));
|
|
800
393
|
});
|
|
801
394
|
}
|
|
802
|
-
catch (
|
|
395
|
+
catch (_o) {
|
|
803
396
|
// Invalid regex — skip
|
|
804
397
|
}
|
|
805
398
|
}
|
|
@@ -856,13 +449,13 @@ Examples:
|
|
|
856
449
|
});
|
|
857
450
|
}
|
|
858
451
|
else if (options.compact) {
|
|
859
|
-
body = formatCompactTable(toCompactHits(g.items), g.root, pattern, {
|
|
452
|
+
body = (0, compact_results_1.formatCompactTable)((0, compact_results_1.toCompactHits)(g.items), g.root, pattern, {
|
|
860
453
|
isTTY: !!isTTY,
|
|
861
454
|
plain: !!options.plain,
|
|
862
455
|
});
|
|
863
456
|
}
|
|
864
457
|
else if (shouldBePlain) {
|
|
865
|
-
body = (0, formatter_1.formatTextResults)(toTextResults(g.items), pattern, g.root, {
|
|
458
|
+
body = (0, formatter_1.formatTextResults)((0, compact_results_1.toTextResults)(g.items), pattern, g.root, {
|
|
866
459
|
isPlain: true,
|
|
867
460
|
compact: options.compact,
|
|
868
461
|
content: options.content,
|
|
@@ -927,7 +520,7 @@ Examples:
|
|
|
927
520
|
}
|
|
928
521
|
}
|
|
929
522
|
}
|
|
930
|
-
catch (
|
|
523
|
+
catch (_p) { }
|
|
931
524
|
}
|
|
932
525
|
// Partial-index footer last, so it's the final line the agent reads —
|
|
933
526
|
// and emitted even on "(none)", where an empty result may just mean the
|
|
@@ -938,7 +531,7 @@ Examples:
|
|
|
938
531
|
return;
|
|
939
532
|
}
|
|
940
533
|
if (options.skeleton) {
|
|
941
|
-
yield outputSkeletons(filteredData, projectRoot, parseInt(options.m, 10), vectorDb, precomputedSkeletons);
|
|
534
|
+
yield (0, search_skeletons_1.outputSkeletons)(filteredData, projectRoot, parseInt(options.m, 10), vectorDb, precomputedSkeletons);
|
|
942
535
|
return;
|
|
943
536
|
}
|
|
944
537
|
if (!filteredData.length) {
|
|
@@ -948,8 +541,8 @@ Examples:
|
|
|
948
541
|
return;
|
|
949
542
|
}
|
|
950
543
|
if (options.compact) {
|
|
951
|
-
const compactHits = toCompactHits(filteredData);
|
|
952
|
-
console.log(formatCompactTable(compactHits, projectRoot, pattern, {
|
|
544
|
+
const compactHits = (0, compact_results_1.toCompactHits)(filteredData);
|
|
545
|
+
console.log((0, compact_results_1.formatCompactTable)(compactHits, projectRoot, pattern, {
|
|
953
546
|
isTTY: !!process.stdout.isTTY,
|
|
954
547
|
plain: !!options.plain,
|
|
955
548
|
}));
|
|
@@ -962,7 +555,7 @@ Examples:
|
|
|
962
555
|
const { extractImportsFromContent } = yield Promise.resolve().then(() => __importStar(require("../lib/utils/import-extractor")));
|
|
963
556
|
const { packByBudget } = yield Promise.resolve().then(() => __importStar(require("../lib/utils/budget-pack")));
|
|
964
557
|
const budget = parseInt(options.budget, 10) || 8000;
|
|
965
|
-
console.log(resultCountHeader(filteredData, parseInt(options.m, 10)));
|
|
558
|
+
console.log((0, compact_results_1.resultCountHeader)(filteredData, parseInt(options.m, 10)));
|
|
966
559
|
// Build every candidate blob up front (token cost needs the rendered
|
|
967
560
|
// text), then pack to budget. Token-aware packing skips an oversized
|
|
968
561
|
// chunk and keeps filling with smaller, still-relevant ones rather than
|
|
@@ -1018,14 +611,14 @@ Examples:
|
|
|
1018
611
|
const isTTY = process.stdout.isTTY;
|
|
1019
612
|
const shouldBePlain = options.plain || !isTTY;
|
|
1020
613
|
if (!options.agent && !options.compact) {
|
|
1021
|
-
console.log(resultCountHeader(filteredData, parseInt(options.m, 10)));
|
|
614
|
+
console.log((0, compact_results_1.resultCountHeader)(filteredData, parseInt(options.m, 10)));
|
|
1022
615
|
console.log();
|
|
1023
616
|
}
|
|
1024
617
|
// Print imports per unique file before results when --imports is used
|
|
1025
618
|
if (options.imports) {
|
|
1026
619
|
const seenFiles = new Set();
|
|
1027
620
|
for (const r of filteredData) {
|
|
1028
|
-
const absP = (
|
|
621
|
+
const absP = (_h = (_f = r.path) !== null && _f !== void 0 ? _f : (_g = r.metadata) === null || _g === void 0 ? void 0 : _g.path) !== null && _h !== void 0 ? _h : "";
|
|
1029
622
|
if (absP && !seenFiles.has(absP)) {
|
|
1030
623
|
seenFiles.add(absP);
|
|
1031
624
|
const imports = getImportsForFile(absP);
|
|
@@ -1039,7 +632,7 @@ Examples:
|
|
|
1039
632
|
}
|
|
1040
633
|
}
|
|
1041
634
|
if (shouldBePlain) {
|
|
1042
|
-
const mappedResults = toTextResults(filteredData);
|
|
635
|
+
const mappedResults = (0, compact_results_1.toTextResults)(filteredData);
|
|
1043
636
|
const output = (0, formatter_1.formatTextResults)(mappedResults, pattern, projectRoot, {
|
|
1044
637
|
isPlain: true,
|
|
1045
638
|
compact: options.compact,
|
|
@@ -1052,7 +645,7 @@ Examples:
|
|
|
1052
645
|
for (const r of filteredData) {
|
|
1053
646
|
const b = r.scoreBreakdown;
|
|
1054
647
|
if (b) {
|
|
1055
|
-
const absP = (
|
|
648
|
+
const absP = (_l = (_j = r.path) !== null && _j !== void 0 ? _j : (_k = r.metadata) === null || _k === void 0 ? void 0 : _k.path) !== null && _l !== void 0 ? _l : "";
|
|
1056
649
|
const relPath = absP.startsWith(projectRoot)
|
|
1057
650
|
? absP.slice(projectRoot.length + 1)
|
|
1058
651
|
: absP;
|
|
@@ -1114,7 +707,7 @@ Examples:
|
|
|
1114
707
|
console.log(lines.join("\n"));
|
|
1115
708
|
}
|
|
1116
709
|
}
|
|
1117
|
-
catch (
|
|
710
|
+
catch (_q) {
|
|
1118
711
|
// Trace failed — skip silently
|
|
1119
712
|
}
|
|
1120
713
|
}
|
|
@@ -1134,13 +727,13 @@ Examples:
|
|
|
1134
727
|
source: "cli",
|
|
1135
728
|
tool: "search",
|
|
1136
729
|
query: pattern,
|
|
1137
|
-
project: (
|
|
730
|
+
project: (_m = (0, project_root_1.findProjectRoot)(root)) !== null && _m !== void 0 ? _m : root,
|
|
1138
731
|
results: _searchResultCount,
|
|
1139
732
|
ms: Date.now() - _searchStartMs,
|
|
1140
733
|
error: _searchError,
|
|
1141
734
|
});
|
|
1142
735
|
}
|
|
1143
|
-
catch (
|
|
736
|
+
catch (_r) { }
|
|
1144
737
|
if (vectorDb) {
|
|
1145
738
|
try {
|
|
1146
739
|
yield vectorDb.close();
|