grepmax 0.15.5 → 0.16.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/mcp.js +10 -71
- package/dist/commands/search.js +172 -104
- package/dist/lib/daemon/daemon.js +253 -14
- package/dist/lib/daemon/ipc-handler.js +36 -0
- package/dist/lib/index/batch-processor.js +18 -0
- package/dist/lib/store/vector-db.js +94 -27
- package/dist/lib/workers/pool.js +42 -14
- package/package.json +1 -1
- package/plugins/grepmax/.claude-plugin/plugin.json +1 -1
- package/plugins/grepmax/hooks/cwd-changed.js +6 -38
package/dist/commands/mcp.js
CHANGED
|
@@ -53,7 +53,6 @@ exports.mcp = void 0;
|
|
|
53
53
|
exports.toStringArray = toStringArray;
|
|
54
54
|
exports.ok = ok;
|
|
55
55
|
exports.err = err;
|
|
56
|
-
const node_child_process_1 = require("node:child_process");
|
|
57
56
|
const fs = __importStar(require("node:fs"));
|
|
58
57
|
const path = __importStar(require("node:path"));
|
|
59
58
|
const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
|
|
@@ -363,8 +362,6 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
363
362
|
let _searcher = null;
|
|
364
363
|
let _skeletonizer = null;
|
|
365
364
|
let _indexReady = false;
|
|
366
|
-
let _indexing = false;
|
|
367
|
-
let _indexProgress = "";
|
|
368
365
|
const cleanup = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
369
366
|
if (_vectorDb) {
|
|
370
367
|
try {
|
|
@@ -421,70 +418,15 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
421
418
|
});
|
|
422
419
|
}
|
|
423
420
|
// --- Index sync ---
|
|
424
|
-
let _indexChildPid = null;
|
|
425
|
-
function isIndexProcessRunning() {
|
|
426
|
-
if (!_indexChildPid)
|
|
427
|
-
return false;
|
|
428
|
-
try {
|
|
429
|
-
process.kill(_indexChildPid, 0);
|
|
430
|
-
return true;
|
|
431
|
-
}
|
|
432
|
-
catch (_a) {
|
|
433
|
-
return false;
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
421
|
function ensureIndexReady() {
|
|
437
422
|
return __awaiter(this, void 0, void 0, function* () {
|
|
438
|
-
var _a;
|
|
439
423
|
if (_indexReady)
|
|
440
424
|
return;
|
|
441
|
-
// Check if a previously spawned index process finished
|
|
442
|
-
if (_indexing && !isIndexProcessRunning()) {
|
|
443
|
-
_indexing = false;
|
|
444
|
-
_indexProgress = "";
|
|
445
|
-
_indexChildPid = null;
|
|
446
|
-
}
|
|
447
|
-
// Check project registry — more reliable than querying the DB.
|
|
448
|
-
// Avoids false negatives from lock contention and cascade re-indexing.
|
|
449
425
|
const projects = (0, project_registry_1.listProjects)();
|
|
450
426
|
const isRegistered = projects.some((p) => p.root === projectRoot);
|
|
451
427
|
if (isRegistered) {
|
|
452
428
|
_indexReady = true;
|
|
453
|
-
return;
|
|
454
429
|
}
|
|
455
|
-
// Truly first-time: no registry entry at all
|
|
456
|
-
if (_indexing)
|
|
457
|
-
return;
|
|
458
|
-
_indexing = true;
|
|
459
|
-
_indexProgress = "starting...";
|
|
460
|
-
console.log("[MCP] First-time setup for this project...");
|
|
461
|
-
const child = (0, node_child_process_1.spawn)(process.argv[0], [process.argv[1], "add", projectRoot], { detached: true, stdio: "ignore" });
|
|
462
|
-
_indexChildPid = (_a = child.pid) !== null && _a !== void 0 ? _a : null;
|
|
463
|
-
child.unref();
|
|
464
|
-
_indexProgress = `PID ${_indexChildPid}`;
|
|
465
|
-
const indexTimeout = setTimeout(() => {
|
|
466
|
-
try {
|
|
467
|
-
child.kill("SIGKILL");
|
|
468
|
-
}
|
|
469
|
-
catch (_a) { }
|
|
470
|
-
_indexing = false;
|
|
471
|
-
_indexProgress = "";
|
|
472
|
-
_indexChildPid = null;
|
|
473
|
-
console.error("[MCP] Background indexing timed out after 30 minutes");
|
|
474
|
-
}, 30 * 60 * 1000);
|
|
475
|
-
child.on("exit", (code) => {
|
|
476
|
-
clearTimeout(indexTimeout);
|
|
477
|
-
_indexing = false;
|
|
478
|
-
_indexProgress = "";
|
|
479
|
-
_indexChildPid = null;
|
|
480
|
-
if (code === 0) {
|
|
481
|
-
_indexReady = true;
|
|
482
|
-
console.log("[MCP] First-time setup complete.");
|
|
483
|
-
}
|
|
484
|
-
else {
|
|
485
|
-
console.error(`[MCP] Indexing failed (exit code: ${code})`);
|
|
486
|
-
}
|
|
487
|
-
});
|
|
488
430
|
});
|
|
489
431
|
}
|
|
490
432
|
// --- Background watcher ---
|
|
@@ -511,12 +453,11 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
511
453
|
const searchAll = isSearchAll || args.scope === "all";
|
|
512
454
|
const limit = Math.min(Math.max(Number(args.limit) || 3, 1), 50);
|
|
513
455
|
ensureWatcher();
|
|
514
|
-
if (_indexing) {
|
|
515
|
-
return ok(`Indexing in progress (${_indexProgress}). Results may be incomplete or empty — try again shortly.`);
|
|
516
|
-
}
|
|
517
|
-
// Check if project is pending or has no chunks
|
|
518
456
|
const proj = (0, project_registry_1.getProject)(projectRoot);
|
|
519
|
-
if (
|
|
457
|
+
if (!proj) {
|
|
458
|
+
return err("Project not added to gmax yet. Run `gmax add` to index it first.");
|
|
459
|
+
}
|
|
460
|
+
if (proj.status === "pending" || proj.chunkCount === 0) {
|
|
520
461
|
return err("Project not indexed yet. Run `gmax add` to index it first.");
|
|
521
462
|
}
|
|
522
463
|
try {
|
|
@@ -875,8 +816,9 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
875
816
|
const symbol = String(args.symbol || "");
|
|
876
817
|
if (!symbol)
|
|
877
818
|
return err("Missing required parameter: symbol");
|
|
878
|
-
|
|
879
|
-
|
|
819
|
+
const proj = (0, project_registry_1.getProject)(projectRoot);
|
|
820
|
+
if (!proj) {
|
|
821
|
+
return err("Project not added to gmax yet. Run `gmax add` to index it first.");
|
|
880
822
|
}
|
|
881
823
|
try {
|
|
882
824
|
const db = getVectorDb();
|
|
@@ -1177,8 +1119,9 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
1177
1119
|
const pattern = typeof args.pattern === "string" ? args.pattern : undefined;
|
|
1178
1120
|
const limit = Math.min(Math.max(Number(args.limit) || 20, 1), 100);
|
|
1179
1121
|
const pathPrefix = typeof args.path === "string" ? args.path : undefined;
|
|
1180
|
-
|
|
1181
|
-
|
|
1122
|
+
const proj = (0, project_registry_1.getProject)(projectRoot);
|
|
1123
|
+
if (!proj) {
|
|
1124
|
+
return err("Project not added to gmax yet. Run `gmax add` to index it first.");
|
|
1182
1125
|
}
|
|
1183
1126
|
try {
|
|
1184
1127
|
const db = getVectorDb();
|
|
@@ -1273,9 +1216,6 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
1273
1216
|
watcherLine += " — search results may be incomplete";
|
|
1274
1217
|
}
|
|
1275
1218
|
}
|
|
1276
|
-
const indexingLine = _indexing
|
|
1277
|
-
? `Indexing: in progress (${_indexProgress})`
|
|
1278
|
-
: "";
|
|
1279
1219
|
const lines = [
|
|
1280
1220
|
`Index: ~/.gmax/lancedb (${stats.chunks} chunks, ${fileCount} files)`,
|
|
1281
1221
|
`Model: ${globalConfig.embedMode === "gpu" ? ((_d = (_c = (_b = config_1.MODEL_TIERS[globalConfig.modelTier]) === null || _b === void 0 ? void 0 : _b.mlxModel) !== null && _c !== void 0 ? _c : config === null || config === void 0 ? void 0 : config.embedModel) !== null && _d !== void 0 ? _d : "unknown") : ((_e = config === null || config === void 0 ? void 0 : config.embedModel) !== null && _e !== void 0 ? _e : "unknown")} (${(_f = config === null || config === void 0 ? void 0 : config.vectorDim) !== null && _f !== void 0 ? _f : "?"}d, ${globalConfig.embedMode})`,
|
|
@@ -1283,7 +1223,6 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
1283
1223
|
? `Last indexed: ${config.indexedAt}`
|
|
1284
1224
|
: "",
|
|
1285
1225
|
watcherLine,
|
|
1286
|
-
indexingLine,
|
|
1287
1226
|
"",
|
|
1288
1227
|
"Indexed directories:",
|
|
1289
1228
|
...(yield Promise.all(projects.map((p) => __awaiter(this, void 0, void 0, function* () {
|
package/dist/commands/search.js
CHANGED
|
@@ -256,9 +256,9 @@ function formatCompactTable(hits, projectRoot, query, opts) {
|
|
|
256
256
|
}
|
|
257
257
|
// Reuse Skeletonizer instance
|
|
258
258
|
let globalSkeletonizer = null;
|
|
259
|
-
function outputSkeletons(results, projectRoot, limit, db) {
|
|
259
|
+
function outputSkeletons(results, projectRoot, limit, db, precomputed) {
|
|
260
260
|
return __awaiter(this, void 0, void 0, function* () {
|
|
261
|
-
var _a;
|
|
261
|
+
var _a, _b;
|
|
262
262
|
const seenPaths = new Set();
|
|
263
263
|
const filesToProcess = [];
|
|
264
264
|
for (const result of results) {
|
|
@@ -288,6 +288,16 @@ function outputSkeletons(results, projectRoot, limit, db) {
|
|
|
288
288
|
const absPath = path.isAbsolute(filePath)
|
|
289
289
|
? filePath
|
|
290
290
|
: path.resolve(projectRoot, filePath);
|
|
291
|
+
// 0. Daemon-supplied (preferred — already-warm DB lookup, no cold open)
|
|
292
|
+
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];
|
|
293
|
+
if (fromDaemon) {
|
|
294
|
+
skeletonResults.push({
|
|
295
|
+
file: filePath,
|
|
296
|
+
skeleton: fromDaemon,
|
|
297
|
+
tokens: Math.ceil(fromDaemon.length / 4),
|
|
298
|
+
});
|
|
299
|
+
continue;
|
|
300
|
+
}
|
|
291
301
|
// 1. Try DB cache
|
|
292
302
|
if (db) {
|
|
293
303
|
const cached = yield (0, retriever_1.getStoredSkeleton)(db, absPath);
|
|
@@ -378,7 +388,7 @@ Examples:
|
|
|
378
388
|
gmax "handler" --name "handle.*" --exclude tests/
|
|
379
389
|
`)
|
|
380
390
|
.action((pattern, exec_path, _options, cmd) => __awaiter(void 0, void 0, void 0, function* () {
|
|
381
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9;
|
|
391
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10;
|
|
382
392
|
const options = cmd.optsWithGlobals();
|
|
383
393
|
const root = process.cwd();
|
|
384
394
|
const minScore = Number.isFinite(Number.parseFloat(options.minScore))
|
|
@@ -498,79 +508,10 @@ Examples:
|
|
|
498
508
|
if (project.status === "pending") {
|
|
499
509
|
console.warn("This project is still being indexed. Results may be incomplete.\n");
|
|
500
510
|
}
|
|
501
|
-
|
|
502
|
-
//
|
|
503
|
-
if (!options.agent && (0, lock_1.isLocked)(paths.dataDir)) {
|
|
504
|
-
console.warn("⚠️ Warning: Indexing in progress... search results may be incomplete.");
|
|
505
|
-
}
|
|
506
|
-
const hasRows = yield vectorDb.hasAnyRows();
|
|
507
|
-
const needsSync = options.sync || !hasRows;
|
|
508
|
-
if (needsSync) {
|
|
509
|
-
const isTTY = process.stdout.isTTY;
|
|
510
|
-
let abortController;
|
|
511
|
-
let signal;
|
|
512
|
-
if (!isTTY) {
|
|
513
|
-
abortController = new AbortController();
|
|
514
|
-
signal = abortController.signal;
|
|
515
|
-
setTimeout(() => {
|
|
516
|
-
abortController === null || abortController === void 0 ? void 0 : abortController.abort();
|
|
517
|
-
}, 60000); // 60 seconds timeout for non-TTY auto-indexing
|
|
518
|
-
}
|
|
519
|
-
const { spinner, onProgress } = (0, sync_helpers_1.createIndexingSpinner)(projectRoot, options.sync ? "Indexing..." : "Indexing repository (first run)...");
|
|
520
|
-
try {
|
|
521
|
-
yield (0, grammar_loader_1.ensureGrammars)(console.log, { silent: true });
|
|
522
|
-
const result = yield (0, syncer_1.initialSync)({
|
|
523
|
-
projectRoot,
|
|
524
|
-
dryRun: options.dryRun,
|
|
525
|
-
onProgress,
|
|
526
|
-
signal,
|
|
527
|
-
});
|
|
528
|
-
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
529
|
-
spinner.warn(`Indexing timed out (${result.processed}/${result.total}). Results may be partial.`);
|
|
530
|
-
}
|
|
531
|
-
if (options.dryRun) {
|
|
532
|
-
spinner.succeed(`Dry run complete (${result.processed}/${result.total}) • would have indexed ${result.indexed}`);
|
|
533
|
-
console.log((0, sync_helpers_1.formatDryRunSummary)(result, {
|
|
534
|
-
actionDescription: "would have indexed",
|
|
535
|
-
includeTotal: true,
|
|
536
|
-
}));
|
|
537
|
-
return;
|
|
538
|
-
}
|
|
539
|
-
yield vectorDb.createFTSIndex();
|
|
540
|
-
// Update registry after sync
|
|
541
|
-
const { readGlobalConfig } = yield Promise.resolve().then(() => __importStar(require("../lib/index/index-config")));
|
|
542
|
-
const { registerProject } = yield Promise.resolve().then(() => __importStar(require("../lib/utils/project-registry")));
|
|
543
|
-
const gc = readGlobalConfig();
|
|
544
|
-
registerProject({
|
|
545
|
-
root: projectRoot,
|
|
546
|
-
name: path.basename(projectRoot),
|
|
547
|
-
vectorDim: gc.vectorDim,
|
|
548
|
-
modelTier: gc.modelTier,
|
|
549
|
-
embedMode: gc.embedMode,
|
|
550
|
-
lastIndexed: new Date().toISOString(),
|
|
551
|
-
chunkCount: result.indexed,
|
|
552
|
-
status: "indexed",
|
|
553
|
-
});
|
|
554
|
-
const failedSuffix = result.failedFiles > 0 ? ` • ${result.failedFiles} failed` : "";
|
|
555
|
-
spinner.succeed(`${options.sync ? "Indexing" : "Initial indexing"} complete (${result.processed}/${result.total}) • indexed ${result.indexed}${failedSuffix}`);
|
|
556
|
-
}
|
|
557
|
-
catch (e) {
|
|
558
|
-
spinner.fail("Indexing failed");
|
|
559
|
-
throw e;
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
// Ensure a watcher is running for live reindexing
|
|
563
|
-
if (!process.env.VITEST && !((_d = process.env.NODE_ENV) === null || _d === void 0 ? void 0 : _d.includes("test"))) {
|
|
564
|
-
const { launchWatcher } = yield Promise.resolve().then(() => __importStar(require("../lib/utils/watcher-launcher")));
|
|
565
|
-
const launched = yield launchWatcher(projectRoot);
|
|
566
|
-
if (!launched.ok && launched.reason === "spawn-failed") {
|
|
567
|
-
console.warn(`[search] ${launched.message}`);
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
const searcher = new searcher_1.Searcher(vectorDb);
|
|
571
|
-
// Use --root or fall back to project root
|
|
511
|
+
// Compute effective paths + filters early — both the daemon-mediated
|
|
512
|
+
// and in-process search paths need them.
|
|
572
513
|
const effectiveRoot = options.root
|
|
573
|
-
? (
|
|
514
|
+
? (_d = (0, project_root_1.findProjectRoot)(path.resolve(options.root))) !== null && _d !== void 0 ? _d : path.resolve(options.root)
|
|
574
515
|
: projectRoot;
|
|
575
516
|
const searchPathPrefix = exec_path
|
|
576
517
|
? path.resolve(exec_path)
|
|
@@ -578,7 +519,6 @@ Examples:
|
|
|
578
519
|
const pathFilter = searchPathPrefix.endsWith("/")
|
|
579
520
|
? searchPathPrefix
|
|
580
521
|
: `${searchPathPrefix}/`;
|
|
581
|
-
// Build filters from CLI options
|
|
582
522
|
const searchFilters = {};
|
|
583
523
|
if (options.file)
|
|
584
524
|
searchFilters.file = options.file;
|
|
@@ -588,8 +528,126 @@ Examples:
|
|
|
588
528
|
searchFilters.language = options.lang;
|
|
589
529
|
if (options.role)
|
|
590
530
|
searchFilters.role = options.role;
|
|
591
|
-
|
|
592
|
-
|
|
531
|
+
// Daemon-mediated search: ships query+args over IPC, daemon runs the
|
|
532
|
+
// hybrid+rerank against its already-warm VectorDB and worker pool.
|
|
533
|
+
// Drops cold-start cost (~17s wall, 6GB RAM in the CLI) to <1s. Falls
|
|
534
|
+
// back to in-process on any failure.
|
|
535
|
+
let searchResult = null;
|
|
536
|
+
let precomputedSkeletons;
|
|
537
|
+
let precomputedGraph;
|
|
538
|
+
if (!options.sync && !options.dryRun) {
|
|
539
|
+
try {
|
|
540
|
+
const { isDaemonRunning, sendDaemonCommand } = yield Promise.resolve().then(() => __importStar(require("../lib/utils/daemon-client")));
|
|
541
|
+
if (yield isDaemonRunning()) {
|
|
542
|
+
const resp = yield sendDaemonCommand({
|
|
543
|
+
cmd: "search",
|
|
544
|
+
projectRoot: effectiveRoot,
|
|
545
|
+
query: pattern,
|
|
546
|
+
limit: parseInt(options.m, 10),
|
|
547
|
+
filters: Object.keys(searchFilters).length > 0
|
|
548
|
+
? searchFilters
|
|
549
|
+
: undefined,
|
|
550
|
+
pathPrefix: pathFilter,
|
|
551
|
+
rerank: true,
|
|
552
|
+
explain: options.explain,
|
|
553
|
+
includeSkeletons: options.skeleton,
|
|
554
|
+
includeGraph: options.symbol,
|
|
555
|
+
}, { timeoutMs: 60000 });
|
|
556
|
+
if (resp.ok) {
|
|
557
|
+
searchResult = {
|
|
558
|
+
data: resp.data,
|
|
559
|
+
warnings: resp.warnings,
|
|
560
|
+
};
|
|
561
|
+
precomputedSkeletons = resp.skeletons;
|
|
562
|
+
precomputedGraph = resp.graph;
|
|
563
|
+
}
|
|
564
|
+
else if (process.env.GMAX_DEBUG === "1") {
|
|
565
|
+
console.error(`[search] daemon path unavailable: ${(_e = resp.error) !== null && _e !== void 0 ? _e : "unknown"}`);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
catch (err) {
|
|
570
|
+
if (process.env.GMAX_DEBUG === "1") {
|
|
571
|
+
console.error("[search] daemon attempt threw:", err);
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
// In-process fallback: open VectorDB, ensure index, run Searcher.
|
|
576
|
+
// Only entered when the daemon path didn't produce results.
|
|
577
|
+
if (!searchResult) {
|
|
578
|
+
vectorDb = new vector_db_1.VectorDB(paths.lancedbDir);
|
|
579
|
+
// Check for active indexing lock and warn if present
|
|
580
|
+
if (!options.agent && (0, lock_1.isLocked)(paths.dataDir)) {
|
|
581
|
+
console.warn("⚠️ Warning: Indexing in progress... search results may be incomplete.");
|
|
582
|
+
}
|
|
583
|
+
const hasRows = yield vectorDb.hasAnyRows();
|
|
584
|
+
const needsSync = options.sync || !hasRows;
|
|
585
|
+
if (needsSync) {
|
|
586
|
+
const isTTY = process.stdout.isTTY;
|
|
587
|
+
let abortController;
|
|
588
|
+
let signal;
|
|
589
|
+
if (!isTTY) {
|
|
590
|
+
abortController = new AbortController();
|
|
591
|
+
signal = abortController.signal;
|
|
592
|
+
setTimeout(() => {
|
|
593
|
+
abortController === null || abortController === void 0 ? void 0 : abortController.abort();
|
|
594
|
+
}, 60000); // 60 seconds timeout for non-TTY auto-indexing
|
|
595
|
+
}
|
|
596
|
+
const { spinner, onProgress } = (0, sync_helpers_1.createIndexingSpinner)(projectRoot, options.sync ? "Indexing..." : "Indexing repository (first run)...");
|
|
597
|
+
try {
|
|
598
|
+
yield (0, grammar_loader_1.ensureGrammars)(console.log, { silent: true });
|
|
599
|
+
const result = yield (0, syncer_1.initialSync)({
|
|
600
|
+
projectRoot,
|
|
601
|
+
dryRun: options.dryRun,
|
|
602
|
+
onProgress,
|
|
603
|
+
signal,
|
|
604
|
+
});
|
|
605
|
+
if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
|
|
606
|
+
spinner.warn(`Indexing timed out (${result.processed}/${result.total}). Results may be partial.`);
|
|
607
|
+
}
|
|
608
|
+
if (options.dryRun) {
|
|
609
|
+
spinner.succeed(`Dry run complete (${result.processed}/${result.total}) • would have indexed ${result.indexed}`);
|
|
610
|
+
console.log((0, sync_helpers_1.formatDryRunSummary)(result, {
|
|
611
|
+
actionDescription: "would have indexed",
|
|
612
|
+
includeTotal: true,
|
|
613
|
+
}));
|
|
614
|
+
return;
|
|
615
|
+
}
|
|
616
|
+
yield vectorDb.createFTSIndex();
|
|
617
|
+
// Update registry after sync
|
|
618
|
+
const { readGlobalConfig } = yield Promise.resolve().then(() => __importStar(require("../lib/index/index-config")));
|
|
619
|
+
const { registerProject } = yield Promise.resolve().then(() => __importStar(require("../lib/utils/project-registry")));
|
|
620
|
+
const gc = readGlobalConfig();
|
|
621
|
+
registerProject({
|
|
622
|
+
root: projectRoot,
|
|
623
|
+
name: path.basename(projectRoot),
|
|
624
|
+
vectorDim: gc.vectorDim,
|
|
625
|
+
modelTier: gc.modelTier,
|
|
626
|
+
embedMode: gc.embedMode,
|
|
627
|
+
lastIndexed: new Date().toISOString(),
|
|
628
|
+
chunkCount: result.indexed,
|
|
629
|
+
status: "indexed",
|
|
630
|
+
});
|
|
631
|
+
const failedSuffix = result.failedFiles > 0 ? ` • ${result.failedFiles} failed` : "";
|
|
632
|
+
spinner.succeed(`${options.sync ? "Indexing" : "Initial indexing"} complete (${result.processed}/${result.total}) • indexed ${result.indexed}${failedSuffix}`);
|
|
633
|
+
}
|
|
634
|
+
catch (e) {
|
|
635
|
+
spinner.fail("Indexing failed");
|
|
636
|
+
throw e;
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
// Ensure a watcher is running for live reindexing
|
|
640
|
+
if (!process.env.VITEST && !((_f = process.env.NODE_ENV) === null || _f === void 0 ? void 0 : _f.includes("test"))) {
|
|
641
|
+
const { launchWatcher } = yield Promise.resolve().then(() => __importStar(require("../lib/utils/watcher-launcher")));
|
|
642
|
+
const launched = yield launchWatcher(projectRoot);
|
|
643
|
+
if (!launched.ok && launched.reason === "spawn-failed") {
|
|
644
|
+
console.warn(`[search] ${launched.message}`);
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
const searcher = new searcher_1.Searcher(vectorDb);
|
|
648
|
+
searchResult = yield searcher.search(pattern, parseInt(options.m, 10), { rerank: true, explain: options.explain }, Object.keys(searchFilters).length > 0 ? searchFilters : undefined, pathFilter);
|
|
649
|
+
} // end if (!searchResult) — in-process fallback
|
|
650
|
+
if (!options.agent && ((_g = searchResult.warnings) === null || _g === void 0 ? void 0 : _g.length)) {
|
|
593
651
|
for (const w of searchResult.warnings) {
|
|
594
652
|
console.warn(`Warning: ${w}`);
|
|
595
653
|
}
|
|
@@ -606,7 +664,7 @@ Examples:
|
|
|
606
664
|
return defs.some((d) => regex.test(d));
|
|
607
665
|
});
|
|
608
666
|
}
|
|
609
|
-
catch (
|
|
667
|
+
catch (_11) {
|
|
610
668
|
// Invalid regex — skip
|
|
611
669
|
}
|
|
612
670
|
}
|
|
@@ -632,16 +690,16 @@ Examples:
|
|
|
632
690
|
// In agent mode, print imports header per file
|
|
633
691
|
const seenImportFiles = new Set();
|
|
634
692
|
for (const r of filteredData) {
|
|
635
|
-
const absP = (
|
|
693
|
+
const absP = (_k = (_h = r.path) !== null && _h !== void 0 ? _h : (_j = r.metadata) === null || _j === void 0 ? void 0 : _j.path) !== null && _k !== void 0 ? _k : "";
|
|
636
694
|
const relPath = absP.startsWith(effectiveRoot)
|
|
637
695
|
? absP.slice(effectiveRoot.length + 1)
|
|
638
696
|
: absP;
|
|
639
|
-
const startLine = Math.max(1, ((
|
|
697
|
+
const startLine = Math.max(1, ((_p = (_m = (_l = r.startLine) !== null && _l !== void 0 ? _l : r.start_line) !== null && _m !== void 0 ? _m : (_o = r.generated_metadata) === null || _o === void 0 ? void 0 : _o.start_line) !== null && _p !== void 0 ? _p : 0) + 1);
|
|
640
698
|
const defs = Array.isArray(r.defined_symbols)
|
|
641
699
|
? r.defined_symbols
|
|
642
700
|
: [];
|
|
643
701
|
const symbol = defs[0] || "";
|
|
644
|
-
const role = ((
|
|
702
|
+
const role = ((_q = r.role) !== null && _q !== void 0 ? _q : "")
|
|
645
703
|
.slice(0, 4)
|
|
646
704
|
.toUpperCase();
|
|
647
705
|
let hint = "";
|
|
@@ -650,7 +708,7 @@ Examples:
|
|
|
650
708
|
}
|
|
651
709
|
else {
|
|
652
710
|
// Extract first meaningful signature line from content
|
|
653
|
-
const raw = (
|
|
711
|
+
const raw = (_s = (_r = r.content) !== null && _r !== void 0 ? _r : r.text) !== null && _s !== void 0 ? _s : "";
|
|
654
712
|
const lines = raw.split("\n");
|
|
655
713
|
for (const line of lines) {
|
|
656
714
|
const trimmed = line.trim();
|
|
@@ -692,12 +750,17 @@ Examples:
|
|
|
692
750
|
}
|
|
693
751
|
}
|
|
694
752
|
// Agent trace (compact)
|
|
695
|
-
if (options.symbol &&
|
|
753
|
+
if (options.symbol && filteredData.length > 0) {
|
|
696
754
|
try {
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
755
|
+
let graph = precomputedGraph;
|
|
756
|
+
if (!graph) {
|
|
757
|
+
if (!vectorDb)
|
|
758
|
+
throw new Error("no graph source");
|
|
759
|
+
const { GraphBuilder } = yield Promise.resolve().then(() => __importStar(require("../lib/graph/graph-builder")));
|
|
760
|
+
const builder = new GraphBuilder(vectorDb, effectiveRoot);
|
|
761
|
+
graph = yield builder.buildGraphMultiHop(pattern, 1);
|
|
762
|
+
}
|
|
763
|
+
if (graph === null || graph === void 0 ? void 0 : graph.center) {
|
|
701
764
|
console.log("---");
|
|
702
765
|
for (const t of graph.callerTree) {
|
|
703
766
|
const rel = t.node.file.startsWith(effectiveRoot)
|
|
@@ -715,12 +778,12 @@ Examples:
|
|
|
715
778
|
}
|
|
716
779
|
}
|
|
717
780
|
}
|
|
718
|
-
catch (
|
|
781
|
+
catch (_12) { }
|
|
719
782
|
}
|
|
720
783
|
return;
|
|
721
784
|
}
|
|
722
785
|
if (options.skeleton) {
|
|
723
|
-
yield outputSkeletons(filteredData, projectRoot, parseInt(options.m, 10), vectorDb);
|
|
786
|
+
yield outputSkeletons(filteredData, projectRoot, parseInt(options.m, 10), vectorDb, precomputedSkeletons);
|
|
724
787
|
return;
|
|
725
788
|
}
|
|
726
789
|
if (!filteredData.length) {
|
|
@@ -747,9 +810,9 @@ Examples:
|
|
|
747
810
|
let shown = 0;
|
|
748
811
|
console.log(resultCountHeader(filteredData, parseInt(options.m, 10)));
|
|
749
812
|
for (const r of filteredData) {
|
|
750
|
-
const absP = (
|
|
751
|
-
const startLine = (
|
|
752
|
-
const endLine = (
|
|
813
|
+
const absP = (_v = (_t = r.path) !== null && _t !== void 0 ? _t : (_u = r.metadata) === null || _u === void 0 ? void 0 : _u.path) !== null && _v !== void 0 ? _v : "";
|
|
814
|
+
const startLine = (_z = (_x = (_w = r.startLine) !== null && _w !== void 0 ? _w : r.start_line) !== null && _x !== void 0 ? _x : (_y = r.generated_metadata) === null || _y === void 0 ? void 0 : _y.start_line) !== null && _z !== void 0 ? _z : 0;
|
|
815
|
+
const endLine = (_3 = (_1 = (_0 = r.endLine) !== null && _0 !== void 0 ? _0 : r.end_line) !== null && _1 !== void 0 ? _1 : (_2 = r.generated_metadata) === null || _2 === void 0 ? void 0 : _2.end_line) !== null && _3 !== void 0 ? _3 : startLine;
|
|
753
816
|
const relPath = absP.startsWith(projectRoot)
|
|
754
817
|
? absP.slice(projectRoot.length + 1)
|
|
755
818
|
: absP;
|
|
@@ -782,7 +845,7 @@ Examples:
|
|
|
782
845
|
tokensUsed += blobTokens;
|
|
783
846
|
shown++;
|
|
784
847
|
}
|
|
785
|
-
catch (
|
|
848
|
+
catch (_13) {
|
|
786
849
|
console.log(`\n--- ${relPath} (file not readable) ---`);
|
|
787
850
|
shown++;
|
|
788
851
|
}
|
|
@@ -799,7 +862,7 @@ Examples:
|
|
|
799
862
|
if (options.imports) {
|
|
800
863
|
const seenFiles = new Set();
|
|
801
864
|
for (const r of filteredData) {
|
|
802
|
-
const absP = (
|
|
865
|
+
const absP = (_6 = (_4 = r.path) !== null && _4 !== void 0 ? _4 : (_5 = r.metadata) === null || _5 === void 0 ? void 0 : _5.path) !== null && _6 !== void 0 ? _6 : "";
|
|
803
866
|
if (absP && !seenFiles.has(absP)) {
|
|
804
867
|
seenFiles.add(absP);
|
|
805
868
|
const imports = getImportsForFile(absP);
|
|
@@ -826,7 +889,7 @@ Examples:
|
|
|
826
889
|
for (const r of filteredData) {
|
|
827
890
|
const b = r.scoreBreakdown;
|
|
828
891
|
if (b) {
|
|
829
|
-
const absP = (
|
|
892
|
+
const absP = (_9 = (_7 = r.path) !== null && _7 !== void 0 ? _7 : (_8 = r.metadata) === null || _8 === void 0 ? void 0 : _8.path) !== null && _9 !== void 0 ? _9 : "";
|
|
830
893
|
const relPath = absP.startsWith(projectRoot)
|
|
831
894
|
? absP.slice(projectRoot.length + 1)
|
|
832
895
|
: absP;
|
|
@@ -845,12 +908,17 @@ Examples:
|
|
|
845
908
|
console.log(output);
|
|
846
909
|
}
|
|
847
910
|
// Symbol mode: append call graph
|
|
848
|
-
if (options.symbol
|
|
911
|
+
if (options.symbol) {
|
|
849
912
|
try {
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
913
|
+
let graph = precomputedGraph;
|
|
914
|
+
if (!graph) {
|
|
915
|
+
if (!vectorDb)
|
|
916
|
+
throw new Error("no graph source");
|
|
917
|
+
const { GraphBuilder } = yield Promise.resolve().then(() => __importStar(require("../lib/graph/graph-builder")));
|
|
918
|
+
const builder = new GraphBuilder(vectorDb, effectiveRoot);
|
|
919
|
+
graph = yield builder.buildGraphMultiHop(pattern, 1);
|
|
920
|
+
}
|
|
921
|
+
if (graph === null || graph === void 0 ? void 0 : graph.center) {
|
|
854
922
|
const lines = ["\n--- Call graph ---"];
|
|
855
923
|
const centerRel = path.relative(effectiveRoot, graph.center.file);
|
|
856
924
|
lines.push(`${graph.center.symbol} [${graph.center.role}] ${centerRel}:${graph.center.line + 1}`);
|
|
@@ -883,7 +951,7 @@ Examples:
|
|
|
883
951
|
console.log(lines.join("\n"));
|
|
884
952
|
}
|
|
885
953
|
}
|
|
886
|
-
catch (
|
|
954
|
+
catch (_14) {
|
|
887
955
|
// Trace failed — skip silently
|
|
888
956
|
}
|
|
889
957
|
}
|
|
@@ -903,13 +971,13 @@ Examples:
|
|
|
903
971
|
source: "cli",
|
|
904
972
|
tool: "search",
|
|
905
973
|
query: pattern,
|
|
906
|
-
project: (
|
|
974
|
+
project: (_10 = (0, project_root_1.findProjectRoot)(root)) !== null && _10 !== void 0 ? _10 : root,
|
|
907
975
|
results: _searchResultCount,
|
|
908
976
|
ms: Date.now() - _searchStartMs,
|
|
909
977
|
error: _searchError,
|
|
910
978
|
});
|
|
911
979
|
}
|
|
912
|
-
catch (
|
|
980
|
+
catch (_15) { }
|
|
913
981
|
if (vectorDb) {
|
|
914
982
|
try {
|
|
915
983
|
yield vectorDb.close();
|