grepmax 0.7.8 → 0.7.10
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
CHANGED
|
@@ -120,6 +120,14 @@ const TOOLS = [
|
|
|
120
120
|
type: "string",
|
|
121
121
|
description: "Filter by chunk role: 'ORCHESTRATION' (logic/flow), 'DEFINITION' (types/classes), or 'IMPLEMENTATION'.",
|
|
122
122
|
},
|
|
123
|
+
context_lines: {
|
|
124
|
+
type: "number",
|
|
125
|
+
description: "Include N lines before and after the chunk (like grep -C). Only with detail 'code' or 'full'. Max 20.",
|
|
126
|
+
},
|
|
127
|
+
mode: {
|
|
128
|
+
type: "string",
|
|
129
|
+
description: "Search mode: 'default' (semantic only) or 'symbol' (semantic + call graph trace appended). Use 'symbol' when query is a function/class name.",
|
|
130
|
+
},
|
|
123
131
|
},
|
|
124
132
|
required: ["query"],
|
|
125
133
|
},
|
|
@@ -174,6 +182,10 @@ const TOOLS = [
|
|
|
174
182
|
type: "string",
|
|
175
183
|
description: "Comma-separated project names to exclude (e.g. 'capstone,power').",
|
|
176
184
|
},
|
|
185
|
+
context_lines: {
|
|
186
|
+
type: "number",
|
|
187
|
+
description: "Include N lines before/after chunk. Only with detail 'code' or 'full'. Max 20.",
|
|
188
|
+
},
|
|
177
189
|
},
|
|
178
190
|
required: ["query"],
|
|
179
191
|
},
|
|
@@ -541,19 +553,42 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
541
553
|
? ` ${parentStr}${callsStr}`
|
|
542
554
|
: "";
|
|
543
555
|
let snippet = "";
|
|
556
|
+
const contextN = typeof args.context_lines === "number"
|
|
557
|
+
? Math.min(Math.max(args.context_lines, 0), 20)
|
|
558
|
+
: 0;
|
|
544
559
|
if (detail === "code" || detail === "full") {
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
560
|
+
if (contextN > 0 && absPath) {
|
|
561
|
+
// Read surrounding context from file
|
|
562
|
+
try {
|
|
563
|
+
const fileContent = fs.readFileSync(absPath, "utf-8");
|
|
564
|
+
const fileLines = fileContent.split("\n");
|
|
565
|
+
const ctxStart = Math.max(0, startLine - contextN);
|
|
566
|
+
const ctxEnd = Math.min(fileLines.length, endLine + 1 + contextN);
|
|
567
|
+
snippet =
|
|
568
|
+
"\n" +
|
|
569
|
+
fileLines
|
|
570
|
+
.slice(ctxStart, ctxEnd)
|
|
571
|
+
.map((l, i) => `${ctxStart + i + 1}│${l}`)
|
|
572
|
+
.join("\n");
|
|
573
|
+
}
|
|
574
|
+
catch (_o) {
|
|
575
|
+
// Fall through to chunk content
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
if (!snippet) {
|
|
579
|
+
const raw = typeof r.content === "string"
|
|
580
|
+
? r.content
|
|
581
|
+
: typeof r.text === "string"
|
|
582
|
+
? r.text
|
|
583
|
+
: "";
|
|
584
|
+
const allLines = raw.split("\n");
|
|
585
|
+
const linesToShow = detail === "full" ? allLines : allLines.slice(0, 4);
|
|
586
|
+
snippet =
|
|
587
|
+
"\n" +
|
|
588
|
+
linesToShow
|
|
589
|
+
.map((l, i) => `${startLine + i + 1}│${l}`)
|
|
590
|
+
.join("\n");
|
|
591
|
+
}
|
|
557
592
|
}
|
|
558
593
|
const text = line1 +
|
|
559
594
|
(summaryStr ? `\n${summaryStr}` : "") +
|
|
@@ -578,7 +613,50 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
578
613
|
return true;
|
|
579
614
|
});
|
|
580
615
|
}
|
|
581
|
-
|
|
616
|
+
let output = results.map((r) => r.text).join("\n\n");
|
|
617
|
+
// Symbol mode: append call graph
|
|
618
|
+
const mode = typeof args.mode === "string" ? args.mode : "default";
|
|
619
|
+
if (mode === "symbol" && !searchAll) {
|
|
620
|
+
try {
|
|
621
|
+
const db = getVectorDb();
|
|
622
|
+
const builder = new graph_builder_1.GraphBuilder(db);
|
|
623
|
+
const graph = yield builder.buildGraph(query);
|
|
624
|
+
if (graph.center) {
|
|
625
|
+
const traceLines = ["", "--- Call graph ---"];
|
|
626
|
+
const centerRel = graph.center.file.startsWith(projectRoot)
|
|
627
|
+
? graph.center.file.slice(projectRoot.length + 1)
|
|
628
|
+
: graph.center.file;
|
|
629
|
+
traceLines.push(`${graph.center.symbol} [${graph.center.role}] ${centerRel}:${graph.center.line + 1}`);
|
|
630
|
+
if (graph.callers.length > 0) {
|
|
631
|
+
traceLines.push("Callers:");
|
|
632
|
+
for (const caller of graph.callers) {
|
|
633
|
+
const rel = caller.file.startsWith(projectRoot)
|
|
634
|
+
? caller.file.slice(projectRoot.length + 1)
|
|
635
|
+
: caller.file;
|
|
636
|
+
traceLines.push(` <- ${caller.symbol} ${rel}:${caller.line + 1}`);
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
if (graph.callees.length > 0) {
|
|
640
|
+
traceLines.push("Calls:");
|
|
641
|
+
for (const callee of graph.callees.slice(0, 15)) {
|
|
642
|
+
if (callee.file) {
|
|
643
|
+
const rel = callee.file.startsWith(projectRoot)
|
|
644
|
+
? callee.file.slice(projectRoot.length + 1)
|
|
645
|
+
: callee.file;
|
|
646
|
+
traceLines.push(` -> ${callee.symbol} ${rel}:${callee.line + 1}`);
|
|
647
|
+
}
|
|
648
|
+
else {
|
|
649
|
+
traceLines.push(` -> ${callee.symbol} (not indexed)`);
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
output += `\n${traceLines.join("\n")}`;
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
catch (_b) {
|
|
657
|
+
// Trace failed — return search results without trace
|
|
658
|
+
}
|
|
659
|
+
}
|
|
582
660
|
if ((_a = result.warnings) === null || _a === void 0 ? void 0 : _a.length) {
|
|
583
661
|
return ok(`${result.warnings.join("\n")}\n\n${output}`);
|
|
584
662
|
}
|
|
@@ -590,6 +668,31 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
590
668
|
}
|
|
591
669
|
});
|
|
592
670
|
}
|
|
671
|
+
function annotateSkeletonLines(skeleton, sourceContent) {
|
|
672
|
+
const sourceLines = sourceContent.split("\n");
|
|
673
|
+
const skelLines = skeleton.split("\n");
|
|
674
|
+
const used = new Set();
|
|
675
|
+
return skelLines
|
|
676
|
+
.map((skelLine) => {
|
|
677
|
+
const trimmed = skelLine.trim();
|
|
678
|
+
if (!trimmed ||
|
|
679
|
+
trimmed.startsWith("//") ||
|
|
680
|
+
trimmed.startsWith("*") ||
|
|
681
|
+
trimmed.startsWith("/*")) {
|
|
682
|
+
return skelLine;
|
|
683
|
+
}
|
|
684
|
+
// Match against source lines using first 40 chars
|
|
685
|
+
const matchStr = trimmed.slice(0, 40);
|
|
686
|
+
for (let i = 0; i < sourceLines.length; i++) {
|
|
687
|
+
if (!used.has(i) && sourceLines[i].includes(matchStr)) {
|
|
688
|
+
used.add(i);
|
|
689
|
+
return `${String(i + 1).padStart(4)}│${skelLine}`;
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
return skelLine;
|
|
693
|
+
})
|
|
694
|
+
.join("\n");
|
|
695
|
+
}
|
|
593
696
|
function handleCodeSkeleton(args) {
|
|
594
697
|
return __awaiter(this, void 0, void 0, function* () {
|
|
595
698
|
const target = String(args.target || "");
|
|
@@ -630,25 +733,35 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
630
733
|
parts.push(`// ${t} — file not found`);
|
|
631
734
|
continue;
|
|
632
735
|
}
|
|
736
|
+
// Read source for line annotations
|
|
737
|
+
let sourceContent = "";
|
|
738
|
+
try {
|
|
739
|
+
sourceContent = fs.readFileSync(absPath, "utf-8");
|
|
740
|
+
}
|
|
741
|
+
catch (_a) { }
|
|
633
742
|
// Try cached skeleton first
|
|
634
743
|
try {
|
|
635
744
|
const db = getVectorDb();
|
|
636
745
|
const cached = yield (0, retriever_1.getStoredSkeleton)(db, absPath);
|
|
637
746
|
if (cached) {
|
|
638
747
|
const tokens = Math.ceil(cached.length / 4);
|
|
639
|
-
|
|
748
|
+
const annotated = sourceContent
|
|
749
|
+
? annotateSkeletonLines(cached, sourceContent)
|
|
750
|
+
: cached;
|
|
751
|
+
parts.push(`// ${t} (~${tokens} tokens)\n\n${annotated}`);
|
|
640
752
|
continue;
|
|
641
753
|
}
|
|
642
754
|
}
|
|
643
|
-
catch (
|
|
755
|
+
catch (_b) {
|
|
644
756
|
// Index may not exist yet — fall through to live generation
|
|
645
757
|
}
|
|
646
758
|
// Generate live
|
|
647
759
|
try {
|
|
648
|
-
const content = fs.readFileSync(absPath, "utf-8");
|
|
760
|
+
const content = sourceContent || fs.readFileSync(absPath, "utf-8");
|
|
649
761
|
const result = yield skel.skeletonizeFile(absPath, content);
|
|
650
762
|
if (result.success) {
|
|
651
|
-
|
|
763
|
+
const annotated = annotateSkeletonLines(result.skeleton, content);
|
|
764
|
+
parts.push(`// ${t} (~${result.tokenEstimate} tokens)\n\n${annotated}`);
|
|
652
765
|
}
|
|
653
766
|
else {
|
|
654
767
|
parts.push(`// ${t} — skeleton failed: ${result.error}`);
|
|
@@ -732,7 +845,7 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
732
845
|
const table = yield db.ensureTable();
|
|
733
846
|
let query = table
|
|
734
847
|
.query()
|
|
735
|
-
.select(["defined_symbols", "path", "start_line"])
|
|
848
|
+
.select(["defined_symbols", "path", "start_line", "role", "is_exported"])
|
|
736
849
|
.where("array_length(defined_symbols) > 0")
|
|
737
850
|
.limit(pattern ? 10000 : Math.max(limit * 50, 2000));
|
|
738
851
|
if (pathPrefix) {
|
|
@@ -748,6 +861,8 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
748
861
|
const defs = toStringArray(row.defined_symbols);
|
|
749
862
|
const rowPath = String(row.path || "");
|
|
750
863
|
const line = Number(row.start_line || 0);
|
|
864
|
+
const role = String(row.role || "");
|
|
865
|
+
const exported = Boolean(row.is_exported);
|
|
751
866
|
for (const sym of defs) {
|
|
752
867
|
if (pattern && !sym.toLowerCase().includes(pattern.toLowerCase())) {
|
|
753
868
|
continue;
|
|
@@ -762,6 +877,8 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
762
877
|
count: 1,
|
|
763
878
|
path: rowPath,
|
|
764
879
|
line: Math.max(1, line + 1),
|
|
880
|
+
role,
|
|
881
|
+
exported,
|
|
765
882
|
});
|
|
766
883
|
}
|
|
767
884
|
}
|
|
@@ -780,7 +897,9 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
780
897
|
const rel = e.path.startsWith(projectRoot)
|
|
781
898
|
? e.path.slice(projectRoot.length + 1)
|
|
782
899
|
: e.path;
|
|
783
|
-
|
|
900
|
+
const roleTag = e.role ? ` [${e.role.slice(0, 4)}]` : "";
|
|
901
|
+
const expTag = e.exported ? " exported" : "";
|
|
902
|
+
return `${e.symbol}${roleTag}${expTag}\t${rel}:${e.line}`;
|
|
784
903
|
});
|
|
785
904
|
return ok(lines.join("\n"));
|
|
786
905
|
}
|
package/package.json
CHANGED
|
@@ -40,12 +40,14 @@ Parameters:
|
|
|
40
40
|
- `root` (optional): Absolute path to search a different indexed directory.
|
|
41
41
|
- `path` (optional): Restrict to path prefix (e.g. "src/auth/"). Relative to the search root.
|
|
42
42
|
- `detail` (optional): `"pointer"` (default), `"code"` (4-line snippets), or `"full"` (complete chunk with line numbers)
|
|
43
|
+
- `context_lines` (optional): Include N lines before/after the chunk (like grep -C). Only with detail "code" or "full". Max 20.
|
|
43
44
|
- `min_score` (optional): Filter by minimum relevance score (0-1)
|
|
44
45
|
- `max_per_file` (optional): Cap results per file for diversity
|
|
45
46
|
- `file` (optional): Filter to files matching this name (e.g. "syncer.ts"). Matches filename, not full path.
|
|
46
47
|
- `exclude` (optional): Exclude files under this path prefix (e.g. "tests/" or "dist/")
|
|
47
48
|
- `language` (optional): Filter by file extension (e.g. "ts", "py", "go"). Omit the dot.
|
|
48
49
|
- `role` (optional): Filter by chunk role: "ORCHESTRATION" (logic/flow), "DEFINITION" (types), or "IMPLEMENTATION"
|
|
50
|
+
- `mode` (optional): `"default"` (semantic only) or `"symbol"` (semantic + call graph appended). Use "symbol" when query is a function or class name — gets search results + callers/callees in one call.
|
|
49
51
|
|
|
50
52
|
**When to use which mode:**
|
|
51
53
|
- `pointer` — navigation, finding locations, understanding architecture
|
|
@@ -70,11 +72,13 @@ Call graph — who calls a symbol and what it calls. Callers and callees include
|
|
|
70
72
|
- `symbol` (required): Function/method/class name
|
|
71
73
|
|
|
72
74
|
### list_symbols
|
|
73
|
-
List indexed symbols with definition locations.
|
|
75
|
+
List indexed symbols with definition locations, role, and export status.
|
|
74
76
|
- `pattern` (optional): Filter by name (case-insensitive substring match)
|
|
75
77
|
- `limit` (optional): Max results (default 20, max 100)
|
|
76
78
|
- `path` (optional): Only symbols under this path prefix
|
|
77
79
|
|
|
80
|
+
Output: `symbolName [ORCH] exported src/path/file.ts:42`
|
|
81
|
+
|
|
78
82
|
### index_status
|
|
79
83
|
Check centralized index health — chunks, files, indexed directories, model info, watcher status.
|
|
80
84
|
|