grepmax 0.7.8 → 0.7.9
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,10 @@ 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
|
+
},
|
|
123
127
|
},
|
|
124
128
|
required: ["query"],
|
|
125
129
|
},
|
|
@@ -174,6 +178,10 @@ const TOOLS = [
|
|
|
174
178
|
type: "string",
|
|
175
179
|
description: "Comma-separated project names to exclude (e.g. 'capstone,power').",
|
|
176
180
|
},
|
|
181
|
+
context_lines: {
|
|
182
|
+
type: "number",
|
|
183
|
+
description: "Include N lines before/after chunk. Only with detail 'code' or 'full'. Max 20.",
|
|
184
|
+
},
|
|
177
185
|
},
|
|
178
186
|
required: ["query"],
|
|
179
187
|
},
|
|
@@ -541,19 +549,42 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
541
549
|
? ` ${parentStr}${callsStr}`
|
|
542
550
|
: "";
|
|
543
551
|
let snippet = "";
|
|
552
|
+
const contextN = typeof args.context_lines === "number"
|
|
553
|
+
? Math.min(Math.max(args.context_lines, 0), 20)
|
|
554
|
+
: 0;
|
|
544
555
|
if (detail === "code" || detail === "full") {
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
556
|
+
if (contextN > 0 && absPath) {
|
|
557
|
+
// Read surrounding context from file
|
|
558
|
+
try {
|
|
559
|
+
const fileContent = fs.readFileSync(absPath, "utf-8");
|
|
560
|
+
const fileLines = fileContent.split("\n");
|
|
561
|
+
const ctxStart = Math.max(0, startLine - contextN);
|
|
562
|
+
const ctxEnd = Math.min(fileLines.length, endLine + 1 + contextN);
|
|
563
|
+
snippet =
|
|
564
|
+
"\n" +
|
|
565
|
+
fileLines
|
|
566
|
+
.slice(ctxStart, ctxEnd)
|
|
567
|
+
.map((l, i) => `${ctxStart + i + 1}│${l}`)
|
|
568
|
+
.join("\n");
|
|
569
|
+
}
|
|
570
|
+
catch (_o) {
|
|
571
|
+
// Fall through to chunk content
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
if (!snippet) {
|
|
575
|
+
const raw = typeof r.content === "string"
|
|
576
|
+
? r.content
|
|
577
|
+
: typeof r.text === "string"
|
|
578
|
+
? r.text
|
|
579
|
+
: "";
|
|
580
|
+
const allLines = raw.split("\n");
|
|
581
|
+
const linesToShow = detail === "full" ? allLines : allLines.slice(0, 4);
|
|
582
|
+
snippet =
|
|
583
|
+
"\n" +
|
|
584
|
+
linesToShow
|
|
585
|
+
.map((l, i) => `${startLine + i + 1}│${l}`)
|
|
586
|
+
.join("\n");
|
|
587
|
+
}
|
|
557
588
|
}
|
|
558
589
|
const text = line1 +
|
|
559
590
|
(summaryStr ? `\n${summaryStr}` : "") +
|
|
@@ -590,6 +621,31 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
590
621
|
}
|
|
591
622
|
});
|
|
592
623
|
}
|
|
624
|
+
function annotateSkeletonLines(skeleton, sourceContent) {
|
|
625
|
+
const sourceLines = sourceContent.split("\n");
|
|
626
|
+
const skelLines = skeleton.split("\n");
|
|
627
|
+
const used = new Set();
|
|
628
|
+
return skelLines
|
|
629
|
+
.map((skelLine) => {
|
|
630
|
+
const trimmed = skelLine.trim();
|
|
631
|
+
if (!trimmed ||
|
|
632
|
+
trimmed.startsWith("//") ||
|
|
633
|
+
trimmed.startsWith("*") ||
|
|
634
|
+
trimmed.startsWith("/*")) {
|
|
635
|
+
return skelLine;
|
|
636
|
+
}
|
|
637
|
+
// Match against source lines using first 40 chars
|
|
638
|
+
const matchStr = trimmed.slice(0, 40);
|
|
639
|
+
for (let i = 0; i < sourceLines.length; i++) {
|
|
640
|
+
if (!used.has(i) && sourceLines[i].includes(matchStr)) {
|
|
641
|
+
used.add(i);
|
|
642
|
+
return `${String(i + 1).padStart(4)}│${skelLine}`;
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
return skelLine;
|
|
646
|
+
})
|
|
647
|
+
.join("\n");
|
|
648
|
+
}
|
|
593
649
|
function handleCodeSkeleton(args) {
|
|
594
650
|
return __awaiter(this, void 0, void 0, function* () {
|
|
595
651
|
const target = String(args.target || "");
|
|
@@ -630,25 +686,35 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
630
686
|
parts.push(`// ${t} — file not found`);
|
|
631
687
|
continue;
|
|
632
688
|
}
|
|
689
|
+
// Read source for line annotations
|
|
690
|
+
let sourceContent = "";
|
|
691
|
+
try {
|
|
692
|
+
sourceContent = fs.readFileSync(absPath, "utf-8");
|
|
693
|
+
}
|
|
694
|
+
catch (_a) { }
|
|
633
695
|
// Try cached skeleton first
|
|
634
696
|
try {
|
|
635
697
|
const db = getVectorDb();
|
|
636
698
|
const cached = yield (0, retriever_1.getStoredSkeleton)(db, absPath);
|
|
637
699
|
if (cached) {
|
|
638
700
|
const tokens = Math.ceil(cached.length / 4);
|
|
639
|
-
|
|
701
|
+
const annotated = sourceContent
|
|
702
|
+
? annotateSkeletonLines(cached, sourceContent)
|
|
703
|
+
: cached;
|
|
704
|
+
parts.push(`// ${t} (~${tokens} tokens)\n\n${annotated}`);
|
|
640
705
|
continue;
|
|
641
706
|
}
|
|
642
707
|
}
|
|
643
|
-
catch (
|
|
708
|
+
catch (_b) {
|
|
644
709
|
// Index may not exist yet — fall through to live generation
|
|
645
710
|
}
|
|
646
711
|
// Generate live
|
|
647
712
|
try {
|
|
648
|
-
const content = fs.readFileSync(absPath, "utf-8");
|
|
713
|
+
const content = sourceContent || fs.readFileSync(absPath, "utf-8");
|
|
649
714
|
const result = yield skel.skeletonizeFile(absPath, content);
|
|
650
715
|
if (result.success) {
|
|
651
|
-
|
|
716
|
+
const annotated = annotateSkeletonLines(result.skeleton, content);
|
|
717
|
+
parts.push(`// ${t} (~${result.tokenEstimate} tokens)\n\n${annotated}`);
|
|
652
718
|
}
|
|
653
719
|
else {
|
|
654
720
|
parts.push(`// ${t} — skeleton failed: ${result.error}`);
|
|
@@ -732,7 +798,7 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
732
798
|
const table = yield db.ensureTable();
|
|
733
799
|
let query = table
|
|
734
800
|
.query()
|
|
735
|
-
.select(["defined_symbols", "path", "start_line"])
|
|
801
|
+
.select(["defined_symbols", "path", "start_line", "role", "is_exported"])
|
|
736
802
|
.where("array_length(defined_symbols) > 0")
|
|
737
803
|
.limit(pattern ? 10000 : Math.max(limit * 50, 2000));
|
|
738
804
|
if (pathPrefix) {
|
|
@@ -748,6 +814,8 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
748
814
|
const defs = toStringArray(row.defined_symbols);
|
|
749
815
|
const rowPath = String(row.path || "");
|
|
750
816
|
const line = Number(row.start_line || 0);
|
|
817
|
+
const role = String(row.role || "");
|
|
818
|
+
const exported = Boolean(row.is_exported);
|
|
751
819
|
for (const sym of defs) {
|
|
752
820
|
if (pattern && !sym.toLowerCase().includes(pattern.toLowerCase())) {
|
|
753
821
|
continue;
|
|
@@ -762,6 +830,8 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
762
830
|
count: 1,
|
|
763
831
|
path: rowPath,
|
|
764
832
|
line: Math.max(1, line + 1),
|
|
833
|
+
role,
|
|
834
|
+
exported,
|
|
765
835
|
});
|
|
766
836
|
}
|
|
767
837
|
}
|
|
@@ -780,7 +850,9 @@ exports.mcp = new commander_1.Command("mcp")
|
|
|
780
850
|
const rel = e.path.startsWith(projectRoot)
|
|
781
851
|
? e.path.slice(projectRoot.length + 1)
|
|
782
852
|
: e.path;
|
|
783
|
-
|
|
853
|
+
const roleTag = e.role ? ` [${e.role.slice(0, 4)}]` : "";
|
|
854
|
+
const expTag = e.exported ? " exported" : "";
|
|
855
|
+
return `${e.symbol}${roleTag}${expTag}\t${rel}:${e.line}`;
|
|
784
856
|
});
|
|
785
857
|
return ok(lines.join("\n"));
|
|
786
858
|
}
|
package/package.json
CHANGED
|
@@ -40,6 +40,7 @@ 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.
|
|
@@ -70,11 +71,13 @@ Call graph — who calls a symbol and what it calls. Callers and callees include
|
|
|
70
71
|
- `symbol` (required): Function/method/class name
|
|
71
72
|
|
|
72
73
|
### list_symbols
|
|
73
|
-
List indexed symbols with definition locations.
|
|
74
|
+
List indexed symbols with definition locations, role, and export status.
|
|
74
75
|
- `pattern` (optional): Filter by name (case-insensitive substring match)
|
|
75
76
|
- `limit` (optional): Max results (default 20, max 100)
|
|
76
77
|
- `path` (optional): Only symbols under this path prefix
|
|
77
78
|
|
|
79
|
+
Output: `symbolName [ORCH] exported src/path/file.ts:42`
|
|
80
|
+
|
|
78
81
|
### index_status
|
|
79
82
|
Check centralized index health — chunks, files, indexed directories, model info, watcher status.
|
|
80
83
|
|