grepmax 0.26.46 → 0.26.48
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/README.md +2 -0
- package/dist/commands/mcp.js +89 -74
- package/dist/lib/daemon/graph-handler.js +1 -1
- package/dist/lib/daemon/rows-handler.js +13 -9
- package/dist/lib/search/searcher.js +6 -2
- package/dist/lib/utils/daemon-client.js +4 -1
- package/dist/lib/utils/mcp-execution.js +67 -0
- package/dist/lib/utils/store-access.js +12 -5
- package/package.json +1 -1
- package/plugins/grepmax/.claude-plugin/plugin.json +1 -1
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"name": "grepmax",
|
|
11
11
|
"source": "./plugins/grepmax",
|
|
12
12
|
"description": "Semantic code search for Claude Code. Automatically indexes your project and provides intelligent search capabilities.",
|
|
13
|
-
"version": "0.26.
|
|
13
|
+
"version": "0.26.48",
|
|
14
14
|
"author": {
|
|
15
15
|
"name": "Robert Owens",
|
|
16
16
|
"email": "robowens@me.com"
|
package/README.md
CHANGED
|
@@ -130,6 +130,8 @@ MCP is local-only: the client spawns it and communicates through stdin/stdout pi
|
|
|
130
130
|
|
|
131
131
|
`gmax mcp` uses the official MCP SDK v2.3.0 and serves both legacy (2025 handshake) and modern (2026-07-28 discovery and per-request metadata) clients over the same stdio entry. Discovery and catalog listing perform no daemon, model or watcher startup. Index-reading tools acquire watch leases lazily; one timer renews the primary projects actually used, and disconnect closes the SDK connection and its timer.
|
|
132
132
|
|
|
133
|
+
Clients requesting progress receive operation-stage messages with increasing stage counts and no estimated percentage. Cancelling a daemon read closes that request's IPC connection and prevents subsequent tool operations or fallback work; concurrent requests and the session's watch leases continue. An already-running local native query finishes under its existing deadline before its store closes. Cancellation does not undo indexing writes or interrupt optional LLM work.
|
|
134
|
+
|
|
133
135
|
`gmax mcp` starts a stdio-based MCP server for clients that support MCP but can't run shell commands (Cursor, Windsurf, custom agents). Search-backed tools use the singleton daemon when available, avoiding a separate embedding worker per MCP session, and use an in-process worker for supported offline/secondary-store access. An unsupported daemon command requires `gmax watch restart`.
|
|
134
136
|
|
|
135
137
|
`semantic_search`, `trace_calls`, `dead`, and `index_status` also advertise output schemas and return `structuredContent` with `schemaVersion: 1`, alongside the existing text. Search matches follow the same scope and display filters and include paths, one-based start/end lines, symbols, scores (null when unavailable), and warnings. Trace results preserve caller ancestry and edge confidence; unresolved callees have no location, and omitted callee/importer counts are explicit. Graph conclusions carry `approximate: true`. Index health includes embedding identity, watcher/reconciliation state, and the last compaction result; unavailable health is null or unobserved. These four tools advertise read-only, non-destructive, closed-world annotations. Other tools retain their current contracts.
|
package/dist/commands/mcp.js
CHANGED
|
@@ -97,6 +97,7 @@ const daemon_client_1 = require("../lib/utils/daemon-client");
|
|
|
97
97
|
const file_utils_1 = require("../lib/utils/file-utils");
|
|
98
98
|
const format_helpers_1 = require("../lib/utils/format-helpers");
|
|
99
99
|
const import_extractor_1 = require("../lib/utils/import-extractor");
|
|
100
|
+
const mcp_execution_1 = require("../lib/utils/mcp-execution");
|
|
100
101
|
const path_containment_1 = require("../lib/utils/path-containment");
|
|
101
102
|
const project_registry_1 = require("../lib/utils/project-registry");
|
|
102
103
|
const project_root_1 = require("../lib/utils/project-root");
|
|
@@ -414,20 +415,26 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
414
415
|
// Propagate project root to worker processes
|
|
415
416
|
process.env.GMAX_PROJECT_ROOT = paths.root;
|
|
416
417
|
// --- Store access ---
|
|
418
|
+
function sendMcpCommand(cmd, opts) {
|
|
419
|
+
return (0, mcp_execution_1.mcpOperation)(`Daemon: ${cmd.cmd}`, () => (0, daemon_client_1.sendDaemonCommand)(cmd, Object.assign(Object.assign({}, opts), { signal: (0, mcp_execution_1.mcpSignal)() })));
|
|
420
|
+
}
|
|
417
421
|
/**
|
|
418
422
|
* One read through the access policy, with MCP's fallback allowances. The
|
|
419
423
|
* `inProcess` branch is entered only when no daemon serves the verb.
|
|
420
424
|
*/
|
|
421
425
|
function readStore(name, opts) {
|
|
422
|
-
return (0, store_access_1.withStoreRead)(name, Object.assign(Object.assign(Object.assign({}, opts), MCP_STORE_FALLBACK), { skipDaemon: secondary() }));
|
|
426
|
+
return (0, store_access_1.withStoreRead)(name, Object.assign(Object.assign(Object.assign({ signal: (0, mcp_execution_1.mcpSignal)() }, opts), MCP_STORE_FALLBACK), { skipDaemon: secondary() }));
|
|
423
427
|
}
|
|
424
428
|
/** Open the shared store for the duration of one fallback, then close it. */
|
|
425
429
|
function localStore(fn) {
|
|
426
|
-
return (0, rows_handler_1.withLocalStore)(storeDir(),
|
|
430
|
+
return (0, mcp_execution_1.mcpOperation)("Reading selected local store", () => (0, rows_handler_1.withLocalStore)(storeDir(), (deps) => __awaiter(this, void 0, void 0, function* () {
|
|
431
|
+
(0, mcp_execution_1.checkMcpCancellation)();
|
|
432
|
+
return fn(deps);
|
|
433
|
+
}), storeConfig().vectorDim));
|
|
427
434
|
}
|
|
428
435
|
/** A graph verb with MCP's fallback allowances. */
|
|
429
436
|
function graphVerb(verb, call) {
|
|
430
|
-
return (0, graph_handler_1.callGraphVerb)(verb, Object.assign(Object.assign({}, call), { fallback: Object.assign(Object.assign({}, MCP_STORE_FALLBACK), (secondary() ? { skipDaemon: true } : {})) }));
|
|
437
|
+
return (0, mcp_execution_1.mcpOperation)(`Reading ${verb}`, () => (0, graph_handler_1.callGraphVerb)(verb, Object.assign(Object.assign({}, call), { signal: (0, mcp_execution_1.mcpSignal)(), fallback: Object.assign(Object.assign({}, MCP_STORE_FALLBACK), (secondary() ? { skipDaemon: true } : {})) })));
|
|
431
438
|
}
|
|
432
439
|
/**
|
|
433
440
|
* MCP tools take no `--in`/`--exclude`, so a tool's scope is always the
|
|
@@ -457,7 +464,7 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
457
464
|
*/
|
|
458
465
|
function searchStore(args) {
|
|
459
466
|
return readStore("search", {
|
|
460
|
-
daemon: () => { var _a; return (
|
|
467
|
+
daemon: () => { var _a; return sendMcpCommand(Object.assign({ cmd: ((_a = args.filters) === null || _a === void 0 ? void 0 : _a.projectRoots) ? "search-v2" : "search" }, args), { timeoutMs: 60000 }); },
|
|
461
468
|
render: (resp) => {
|
|
462
469
|
const warnings = Array.isArray(resp.warnings)
|
|
463
470
|
? resp.warnings.filter((w) => typeof w === "string")
|
|
@@ -476,7 +483,7 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
476
483
|
: undefined;
|
|
477
484
|
try {
|
|
478
485
|
const searcher = new searcher_1.Searcher(deps.vectorDb, pool);
|
|
479
|
-
return yield searcher.search(args.query, args.limit, { rerank: args.rerank, seeds: args.seeds }, args.filters, args.pathPrefix);
|
|
486
|
+
return yield searcher.search(args.query, args.limit, { rerank: args.rerank, seeds: args.seeds }, args.filters, args.pathPrefix, undefined, (0, mcp_execution_1.mcpSignal)());
|
|
480
487
|
}
|
|
481
488
|
finally {
|
|
482
489
|
yield pool === null || pool === void 0 ? void 0 : pool.destroy();
|
|
@@ -548,7 +555,7 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
548
555
|
* order. Batched so a per-symbol loop costs one round trip, not hundreds.
|
|
549
556
|
*/
|
|
550
557
|
function locateRows(root, req) {
|
|
551
|
-
return (0, rows_handler_1.readRows)(Object.assign({ name: "locate", projectRoot: root, lancedbDir: storeDir(), vectorDim: storeConfig().vectorDim, scope: projectScope(root), fallback: Object.assign(Object.assign({}, MCP_STORE_FALLBACK), { skipDaemon: secondary() }) }, req));
|
|
558
|
+
return (0, mcp_execution_1.mcpOperation)("Locating indexed rows", () => (0, rows_handler_1.readRows)(Object.assign({ signal: (0, mcp_execution_1.mcpSignal)(), name: "locate", projectRoot: root, lancedbDir: storeDir(), vectorDim: storeConfig().vectorDim, scope: projectScope(root), fallback: Object.assign(Object.assign({}, MCP_STORE_FALLBACK), { skipDaemon: secondary() }) }, req)));
|
|
552
559
|
}
|
|
553
560
|
/**
|
|
554
561
|
* Chunk and file totals for `index_status`, summed per registered project.
|
|
@@ -566,8 +573,9 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
566
573
|
let chunks = 0;
|
|
567
574
|
let files = 0;
|
|
568
575
|
for (const project of projects) {
|
|
576
|
+
(0, mcp_execution_1.checkMcpCancellation)();
|
|
569
577
|
const totals = yield readStore("project-stats", {
|
|
570
|
-
daemon: () => (
|
|
578
|
+
daemon: () => sendMcpCommand({ cmd: "project-stats", root: project.root }, { timeoutMs: 30000 }),
|
|
571
579
|
render: (resp) => ({
|
|
572
580
|
chunks: typeof resp.chunks === "number" ? resp.chunks : 0,
|
|
573
581
|
files: typeof resp.files === "number" ? resp.files : 0,
|
|
@@ -591,7 +599,7 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
591
599
|
/** `rows.skeleton`: the stored per-file skeleton (and the symbol lookup). */
|
|
592
600
|
function lookupSkeleton(root, req) {
|
|
593
601
|
return readStore("skeleton", {
|
|
594
|
-
daemon: () => (
|
|
602
|
+
daemon: () => sendMcpCommand(Object.assign({ cmd: "rows.skeleton", projectRoot: root }, req), { timeoutMs: 30000 }),
|
|
595
603
|
render: (resp) => { var _a, _b; return ({
|
|
596
604
|
path: ((_a = resp.path) !== null && _a !== void 0 ? _a : null),
|
|
597
605
|
skeleton: ((_b = resp.skeleton) !== null && _b !== void 0 ? _b : null),
|
|
@@ -618,32 +626,34 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
618
626
|
};
|
|
619
627
|
function ensureWatcher(root) {
|
|
620
628
|
return __awaiter(this, void 0, void 0, function* () {
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
629
|
+
return (0, mcp_execution_1.withoutMcpExecution)(() => __awaiter(this, void 0, void 0, function* () {
|
|
630
|
+
var _a;
|
|
631
|
+
try {
|
|
632
|
+
const watchRoot = root !== null && root !== void 0 ? root : (_a = resolveMcpProject(undefined, currentRoot(), storeProjects())) === null || _a === void 0 ? void 0 : _a.root;
|
|
633
|
+
if (!watchRoot ||
|
|
634
|
+
secondary() ||
|
|
635
|
+
(0, stores_1.matchStore)(watchRoot).kind !== "primary")
|
|
636
|
+
return;
|
|
637
|
+
const result = yield (0, watcher_launcher_1.launchWatcher)(watchRoot, WATCH_LEASE);
|
|
638
|
+
if (closing)
|
|
639
|
+
return;
|
|
640
|
+
if (result.ok) {
|
|
641
|
+
watchedRoots.add(watchRoot);
|
|
642
|
+
// Discovery/catalog requests never reach this path. Renew only roots
|
|
643
|
+
// actually read by this session, with one timer for the whole process.
|
|
644
|
+
watchTimer !== null && watchTimer !== void 0 ? watchTimer : (watchTimer = setInterval(() => {
|
|
645
|
+
for (const root of watchedRoots)
|
|
646
|
+
void ensureWatcher(root);
|
|
647
|
+
}, MCP_WATCH_LEASE_RENEW_MS).unref());
|
|
648
|
+
}
|
|
649
|
+
if (result.ok && !result.reused) {
|
|
650
|
+
console.log(`[MCP] Started background watcher for ${watchRoot} (PID: ${result.pid})`);
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
catch (err) {
|
|
654
|
+
console.error("[MCP] Watcher startup failed:", err);
|
|
655
|
+
}
|
|
656
|
+
}));
|
|
647
657
|
});
|
|
648
658
|
}
|
|
649
659
|
// Resolve the registered project this server scopes to. The server pins to
|
|
@@ -1566,7 +1576,7 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
1566
1576
|
// returns the summary plus the findings this will print, and drops the
|
|
1567
1577
|
// raw `pairs` array entirely.
|
|
1568
1578
|
const result = yield readStore("surprises", {
|
|
1569
|
-
daemon: () => (
|
|
1579
|
+
daemon: () => sendMcpCommand({
|
|
1570
1580
|
cmd: "vector.surprises",
|
|
1571
1581
|
projectRoot: root,
|
|
1572
1582
|
options,
|
|
@@ -1742,7 +1752,7 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
1742
1752
|
? root
|
|
1743
1753
|
: `${root}/`;
|
|
1744
1754
|
const entries = yield readStore("symbols", {
|
|
1745
|
-
daemon: () => (
|
|
1755
|
+
daemon: () => sendMcpCommand({
|
|
1746
1756
|
cmd: "rows.symbols",
|
|
1747
1757
|
projectRoot: root,
|
|
1748
1758
|
pathPrefix: absPrefix,
|
|
@@ -1828,7 +1838,7 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
1828
1838
|
const { chunks, files } = yield indexTotals(projects);
|
|
1829
1839
|
const daemonStatus = secondary()
|
|
1830
1840
|
? { ok: true, projects: [] }
|
|
1831
|
-
: yield (
|
|
1841
|
+
: yield sendMcpCommand({ cmd: "status" });
|
|
1832
1842
|
const watched = (Array.isArray(daemonStatus.projects) ? daemonStatus.projects : []);
|
|
1833
1843
|
const daemonProject = watched.find((p) => p.root === (currentProject === null || currentProject === void 0 ? void 0 : currentProject.root));
|
|
1834
1844
|
// Only use the registry when no daemon answered; sandboxed reads stay IPC-only.
|
|
@@ -1954,7 +1964,7 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
1954
1964
|
// rows it was computed from — the same aggregation `gmax project` runs,
|
|
1955
1965
|
// in whichever process holds the store.
|
|
1956
1966
|
const overview = yield readStore("project", {
|
|
1957
|
-
daemon: () => (
|
|
1967
|
+
daemon: () => sendMcpCommand({ cmd: "rows.project", projectRoot: root }, { timeoutMs: 120000 }),
|
|
1958
1968
|
render: (resp) => resp.overview,
|
|
1959
1969
|
inProcess: () => localStore((deps) => (0, rows_handler_1.runProject)(deps, root)),
|
|
1960
1970
|
});
|
|
@@ -2390,7 +2400,7 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
2390
2400
|
// The source chunk's vector never leaves the store: the daemon looks it
|
|
2391
2401
|
// up, runs the vector search, and returns the ranked chunks.
|
|
2392
2402
|
const result = yield readStore("similar", {
|
|
2393
|
-
daemon: () => (
|
|
2403
|
+
daemon: () => sendMcpCommand({
|
|
2394
2404
|
cmd: "vector.similar",
|
|
2395
2405
|
projectRoot: root,
|
|
2396
2406
|
absPath,
|
|
@@ -2663,7 +2673,7 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
2663
2673
|
});
|
|
2664
2674
|
// Best-effort query logging, applied uniformly to every tool exactly as the
|
|
2665
2675
|
// old single CallToolRequestSchema dispatch did before each return.
|
|
2666
|
-
const logToolCall = (
|
|
2676
|
+
const logToolCall = (name_1, toolArgs_1, startMs_1, result_1, ...args_1) => __awaiter(this, [name_1, toolArgs_1, startMs_1, result_1, ...args_1], void 0, function* (name, toolArgs, startMs, result, root = currentRoot()) {
|
|
2667
2677
|
var _a, _b;
|
|
2668
2678
|
var _c;
|
|
2669
2679
|
try {
|
|
@@ -2675,7 +2685,7 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
2675
2685
|
source: "mcp",
|
|
2676
2686
|
tool: name,
|
|
2677
2687
|
query: mcpLogQuery(name, toolArgs),
|
|
2678
|
-
project:
|
|
2688
|
+
project: root,
|
|
2679
2689
|
results: resultLines,
|
|
2680
2690
|
ms: Date.now() - startMs,
|
|
2681
2691
|
error: result.isError ? text.slice(0, 200) : undefined,
|
|
@@ -2696,42 +2706,47 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
2696
2706
|
openWorldHint: false,
|
|
2697
2707
|
},
|
|
2698
2708
|
}
|
|
2699
|
-
: {})), { inputSchema: zod_1.z.object(Object.assign({ root: zod_1.z.string().optional() }, config.inputSchema)) }), (rawArgs) => __awaiter(this, void 0, void 0, function* () {
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
if (
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2709
|
+
: {})), { inputSchema: zod_1.z.object(Object.assign({ root: zod_1.z.string().optional() }, config.inputSchema)) }), (rawArgs, context) => __awaiter(this, void 0, void 0, function* () {
|
|
2710
|
+
return (0, mcp_execution_1.withMcpExecution)(context === null || context === void 0 ? void 0 : context.mcpReq, () => __awaiter(this, void 0, void 0, function* () {
|
|
2711
|
+
let args = (rawArgs !== null && rawArgs !== void 0 ? rawArgs : {});
|
|
2712
|
+
const startMs = Date.now();
|
|
2713
|
+
let target = projectRoot;
|
|
2714
|
+
try {
|
|
2715
|
+
(0, mcp_execution_1.checkMcpCancellation)();
|
|
2716
|
+
if (typeof args.root === "string" && args.root.trim()) {
|
|
2717
|
+
const raw = args.root.trim();
|
|
2718
|
+
if (path.isAbsolute(raw) || raw.includes(path.sep))
|
|
2719
|
+
target = path.resolve(raw);
|
|
2720
|
+
else {
|
|
2721
|
+
const projects = [
|
|
2722
|
+
...(0, project_registry_1.listProjects)(),
|
|
2723
|
+
...(0, store_context_1.storeInventory)().flatMap((store) => store.projects),
|
|
2724
|
+
].filter((project, i, all) => all.findIndex((p) => p.root === project.root) === i);
|
|
2725
|
+
const selected = resolveMcpProject(raw, projectRoot, projects);
|
|
2726
|
+
if (!selected)
|
|
2727
|
+
return err(`Unknown or ambiguous registered project: ${raw}. Use list_projects or an exact root.`);
|
|
2728
|
+
target = selected.root;
|
|
2729
|
+
}
|
|
2717
2730
|
}
|
|
2731
|
+
return yield (0, store_context_1.withStoreContext)(target, () => __awaiter(this, void 0, void 0, function* () {
|
|
2732
|
+
if (args.root !== undefined) {
|
|
2733
|
+
const selected = resolveMcpProject(args.root, currentRoot(), storeProjects());
|
|
2734
|
+
if (!selected)
|
|
2735
|
+
return err(`Unknown registered project: ${args.root}. Use list_projects to select a project name or exact root.`);
|
|
2736
|
+
args = Object.assign(Object.assign({}, args), { root: selected.root });
|
|
2737
|
+
(0, store_context_1.currentStoreContext)().root = selected.root;
|
|
2738
|
+
}
|
|
2739
|
+
const result = yield (0, mcp_execution_1.mcpOperation)(`Starting ${name}`, () => handler(args));
|
|
2740
|
+
yield logToolCall(name, args, startMs, result);
|
|
2741
|
+
return result;
|
|
2742
|
+
}));
|
|
2718
2743
|
}
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
if (!selected)
|
|
2723
|
-
return err(`Unknown registered project: ${args.root}. Use list_projects to select a project name or exact root.`);
|
|
2724
|
-
args = Object.assign(Object.assign({}, args), { root: selected.root });
|
|
2725
|
-
(0, store_context_1.currentStoreContext)().root = selected.root;
|
|
2726
|
-
}
|
|
2727
|
-
const result = yield handler(args);
|
|
2728
|
-
yield logToolCall(name, args, startMs, result);
|
|
2744
|
+
catch (error) {
|
|
2745
|
+
const result = toolError("Tool failed", error);
|
|
2746
|
+
yield logToolCall(name, args, startMs, result, target);
|
|
2729
2747
|
return result;
|
|
2730
|
-
}
|
|
2731
|
-
}
|
|
2732
|
-
catch (error) {
|
|
2733
|
-
return toolError("Tool failed", error);
|
|
2734
|
-
}
|
|
2748
|
+
}
|
|
2749
|
+
}));
|
|
2735
2750
|
}));
|
|
2736
2751
|
}
|
|
2737
2752
|
tool("semantic_search", {
|
|
@@ -856,5 +856,5 @@ exports.GRAPH_VERB_TIMEOUT_MS = 60000;
|
|
|
856
856
|
* project skips the daemon outright — see isDaemonReadableProject.
|
|
857
857
|
*/
|
|
858
858
|
function callGraphVerb(verb, call) {
|
|
859
|
-
return (0, store_access_1.withStoreRead)(verb, Object.assign({ skipDaemon: !isDaemonReadableProject(call.projectRoot), daemon: () => (0, daemon_client_1.sendDaemonCommand)(Object.assign(Object.assign({ cmd: verb }, encodeScope(call.projectRoot, call.scope)), call.payload), { timeoutMs: exports.GRAPH_VERB_TIMEOUT_MS }), render: call.render, inProcess: call.inProcess }, call.fallback));
|
|
859
|
+
return (0, store_access_1.withStoreRead)(verb, Object.assign({ signal: call.signal, skipDaemon: !isDaemonReadableProject(call.projectRoot), daemon: () => (0, daemon_client_1.sendDaemonCommand)(Object.assign(Object.assign({ cmd: verb }, encodeScope(call.projectRoot, call.scope)), call.payload), { timeoutMs: exports.GRAPH_VERB_TIMEOUT_MS, signal: call.signal }), render: call.render, inProcess: call.inProcess }, call.fallback));
|
|
860
860
|
}
|
|
@@ -570,7 +570,7 @@ function readRows(opts) {
|
|
|
570
570
|
return [];
|
|
571
571
|
const { sendDaemonCommand } = yield Promise.resolve().then(() => __importStar(require("../utils/daemon-client")));
|
|
572
572
|
const { withStoreRead } = yield Promise.resolve().then(() => __importStar(require("../utils/store-access")));
|
|
573
|
-
return withStoreRead(opts.name, Object.assign({ daemon: () => { var _a; return sendDaemonCommand({
|
|
573
|
+
return withStoreRead(opts.name, Object.assign({ signal: opts.signal, daemon: () => { var _a; return sendDaemonCommand({
|
|
574
574
|
cmd: "rows.locate",
|
|
575
575
|
projectRoot: opts.projectRoot,
|
|
576
576
|
scope: scopeToWire(opts.scope),
|
|
@@ -578,14 +578,18 @@ function readRows(opts) {
|
|
|
578
578
|
matches: opts.matches,
|
|
579
579
|
limit: opts.limit,
|
|
580
580
|
scoped: opts.scoped,
|
|
581
|
-
}, { timeoutMs: (_a = opts.timeoutMs) !== null && _a !== void 0 ? _a : 60000 }); }, render: (resp) => { var _a; return ((_a = resp.rows) !== null && _a !== void 0 ? _a : []); }, inProcess: () => withLocalStore(opts.lancedbDir, (deps) =>
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
581
|
+
}, { timeoutMs: (_a = opts.timeoutMs) !== null && _a !== void 0 ? _a : 60000, signal: opts.signal }); }, render: (resp) => { var _a; return ((_a = resp.rows) !== null && _a !== void 0 ? _a : []); }, inProcess: () => withLocalStore(opts.lancedbDir, (deps) => {
|
|
582
|
+
var _a;
|
|
583
|
+
(_a = opts.signal) === null || _a === void 0 ? void 0 : _a.throwIfAborted();
|
|
584
|
+
return runLocate(deps, {
|
|
585
|
+
projectRoot: opts.projectRoot,
|
|
586
|
+
scope: opts.scope,
|
|
587
|
+
select: opts.select,
|
|
588
|
+
matches: opts.matches,
|
|
589
|
+
limit: opts.limit,
|
|
590
|
+
scoped: opts.scoped,
|
|
591
|
+
});
|
|
592
|
+
}, opts.vectorDim) }, opts.fallback));
|
|
589
593
|
});
|
|
590
594
|
}
|
|
591
595
|
function handleRowsSkeleton(deps, payload) {
|
|
@@ -699,8 +699,12 @@ class Searcher {
|
|
|
699
699
|
}
|
|
700
700
|
const envMaxPerFile = Number.parseInt((_m = process.env.GMAX_MAX_PER_FILE) !== null && _m !== void 0 ? _m : "", 10);
|
|
701
701
|
const MAX_PER_FILE = Number.isFinite(envMaxPerFile) && envMaxPerFile > 0 ? envMaxPerFile : 3;
|
|
702
|
-
|
|
703
|
-
|
|
702
|
+
// Rank the entire bounded candidate pool before trimming the result count.
|
|
703
|
+
// A limit-dependent cut here discarded contenders before structure boosts
|
|
704
|
+
// and dedup, so requesting three results could hide the top match returned
|
|
705
|
+
// by a ten-result request. Expensive reranking stays independently bounded;
|
|
706
|
+
// display columns are still fetched only for the final results below.
|
|
707
|
+
const displayCandidates = [...stage2Candidates];
|
|
704
708
|
const rerankCandidates = stage2Candidates.slice(0, RERANK_TOP);
|
|
705
709
|
// Symbol-definition promotion (1/2): membership. For a bare-symbol query,
|
|
706
710
|
// ensure the chunk(s) that actually DEFINE the symbol reach the rerank set
|
|
@@ -69,7 +69,10 @@ const HEARTBEAT_FRESH_THRESHOLD_MS = 150000;
|
|
|
69
69
|
*/
|
|
70
70
|
function sendDaemonCommand(cmd, opts) {
|
|
71
71
|
var _a;
|
|
72
|
-
|
|
72
|
+
var _b;
|
|
73
|
+
if ((_a = opts === null || opts === void 0 ? void 0 : opts.signal) === null || _a === void 0 ? void 0 : _a.aborted)
|
|
74
|
+
return Promise.resolve({ ok: false, error: "aborted" });
|
|
75
|
+
const timeout = (_b = opts === null || opts === void 0 ? void 0 : opts.timeoutMs) !== null && _b !== void 0 ? _b : DEFAULT_TIMEOUT_MS;
|
|
73
76
|
return new Promise((resolve) => {
|
|
74
77
|
var _a, _b;
|
|
75
78
|
let settled = false;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.withoutMcpExecution = withoutMcpExecution;
|
|
13
|
+
exports.mcpSignal = mcpSignal;
|
|
14
|
+
exports.checkMcpCancellation = checkMcpCancellation;
|
|
15
|
+
exports.mcpOperation = mcpOperation;
|
|
16
|
+
exports.withMcpExecution = withMcpExecution;
|
|
17
|
+
const node_async_hooks_1 = require("node:async_hooks");
|
|
18
|
+
const executions = new node_async_hooks_1.AsyncLocalStorage();
|
|
19
|
+
/** Session background work must not retain the triggering request's signal. */
|
|
20
|
+
function withoutMcpExecution(work) {
|
|
21
|
+
return executions.exit(work);
|
|
22
|
+
}
|
|
23
|
+
function mcpSignal() {
|
|
24
|
+
var _a;
|
|
25
|
+
return (_a = executions.getStore()) === null || _a === void 0 ? void 0 : _a.request.signal;
|
|
26
|
+
}
|
|
27
|
+
/** Check between operations, never race a native query against store close. */
|
|
28
|
+
function checkMcpCancellation() {
|
|
29
|
+
var _a;
|
|
30
|
+
(_a = mcpSignal()) === null || _a === void 0 ? void 0 : _a.throwIfAborted();
|
|
31
|
+
}
|
|
32
|
+
/** Counts started operation stages, not completion percentages. No timers. */
|
|
33
|
+
function mcpOperation(message, work) {
|
|
34
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
35
|
+
var _a;
|
|
36
|
+
checkMcpCancellation();
|
|
37
|
+
const execution = executions.getStore();
|
|
38
|
+
const progressToken = (_a = execution === null || execution === void 0 ? void 0 : execution.request._meta) === null || _a === void 0 ? void 0 : _a.progressToken;
|
|
39
|
+
if (execution && progressToken !== undefined) {
|
|
40
|
+
const progress = ++execution.stages;
|
|
41
|
+
execution.notifications = execution.notifications.then(() => __awaiter(this, void 0, void 0, function* () {
|
|
42
|
+
if (execution.request.signal.aborted)
|
|
43
|
+
return;
|
|
44
|
+
try {
|
|
45
|
+
yield execution.request.notify({
|
|
46
|
+
method: "notifications/progress",
|
|
47
|
+
params: { progressToken, progress, message },
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
catch (_a) {
|
|
51
|
+
// Progress is advisory; a peer declining it must not break a read.
|
|
52
|
+
}
|
|
53
|
+
}));
|
|
54
|
+
yield execution.notifications;
|
|
55
|
+
}
|
|
56
|
+
checkMcpCancellation();
|
|
57
|
+
const result = yield work();
|
|
58
|
+
checkMcpCancellation();
|
|
59
|
+
return result;
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
function withMcpExecution(request, work) {
|
|
63
|
+
// Non-protocol callers (including the catalog's unit fixtures) have no context.
|
|
64
|
+
if (!request)
|
|
65
|
+
return work();
|
|
66
|
+
return executions.run({ request, stages: 0, notifications: Promise.resolve() }, work);
|
|
67
|
+
}
|
|
@@ -271,11 +271,16 @@ function isDaemonBypassed() {
|
|
|
271
271
|
*/
|
|
272
272
|
function withStoreRead(name, opts) {
|
|
273
273
|
return __awaiter(this, void 0, void 0, function* () {
|
|
274
|
-
var _a;
|
|
275
|
-
var
|
|
274
|
+
var _a, _b, _c, _d;
|
|
275
|
+
var _e;
|
|
276
|
+
(_a = opts.signal) === null || _a === void 0 ? void 0 : _a.throwIfAborted();
|
|
276
277
|
const runInProcess = () => __awaiter(this, void 0, void 0, function* () {
|
|
278
|
+
var _a, _b;
|
|
279
|
+
(_a = opts.signal) === null || _a === void 0 ? void 0 : _a.throwIfAborted();
|
|
277
280
|
try {
|
|
278
|
-
|
|
281
|
+
const result = yield opts.inProcess();
|
|
282
|
+
(_b = opts.signal) === null || _b === void 0 ? void 0 : _b.throwIfAborted();
|
|
283
|
+
return result;
|
|
279
284
|
}
|
|
280
285
|
catch (err) {
|
|
281
286
|
throw asStoreAccessError(err);
|
|
@@ -288,6 +293,7 @@ function withStoreRead(name, opts) {
|
|
|
288
293
|
resp = yield opts.daemon();
|
|
289
294
|
}
|
|
290
295
|
catch (err) {
|
|
296
|
+
(_b = opts.signal) === null || _b === void 0 ? void 0 : _b.throwIfAborted();
|
|
291
297
|
if (isStoreAccessRefused(err))
|
|
292
298
|
throw err;
|
|
293
299
|
const cls = classifyDaemonError(err === null || err === void 0 ? void 0 : err.code);
|
|
@@ -297,6 +303,7 @@ function withStoreRead(name, opts) {
|
|
|
297
303
|
throw err;
|
|
298
304
|
return runInProcess();
|
|
299
305
|
}
|
|
306
|
+
(_c = opts.signal) === null || _c === void 0 ? void 0 : _c.throwIfAborted();
|
|
300
307
|
if (resp.ok) {
|
|
301
308
|
return opts.render ? yield opts.render(resp) : resp;
|
|
302
309
|
}
|
|
@@ -308,13 +315,13 @@ function withStoreRead(name, opts) {
|
|
|
308
315
|
}
|
|
309
316
|
if (cls === "no-daemon" ||
|
|
310
317
|
(opts.fallbackOnOversize && isOversizeError(resp.error)) ||
|
|
311
|
-
((
|
|
318
|
+
((_d = opts.extraFallback) === null || _d === void 0 ? void 0 : _d.call(opts, resp.error)) === true) {
|
|
312
319
|
if (process.env.GMAX_DEBUG === "1") {
|
|
313
320
|
console.error(`[${name}] daemon path unavailable: ${resp.error}`);
|
|
314
321
|
}
|
|
315
322
|
return runInProcess();
|
|
316
323
|
}
|
|
317
|
-
throw new Error(((
|
|
324
|
+
throw new Error(((_e = opts.daemonErrorMessage) !== null && _e !== void 0 ? _e : ((r) => defaultDaemonErrorMessage(name, r)))(resp));
|
|
318
325
|
});
|
|
319
326
|
}
|
|
320
327
|
// --- Spawn guard -----------------------------------------------------------
|
package/package.json
CHANGED