grepmax 0.7.5 → 0.7.6

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.
@@ -61,6 +61,7 @@ const searcher_1 = require("../lib/search/searcher");
61
61
  const retriever_1 = require("../lib/skeleton/retriever");
62
62
  const skeletonizer_1 = require("../lib/skeleton/skeletonizer");
63
63
  const vector_db_1 = require("../lib/store/vector-db");
64
+ const file_utils_1 = require("../lib/utils/file-utils");
64
65
  const filter_builder_1 = require("../lib/utils/filter-builder");
65
66
  const project_registry_1 = require("../lib/utils/project-registry");
66
67
  const project_root_1 = require("../lib/utils/project-root");
@@ -155,13 +156,17 @@ const TOOLS = [
155
156
  },
156
157
  {
157
158
  name: "code_skeleton",
158
- description: "Show the structure of a source fileall function/class/method signatures with bodies collapsed. Useful for understanding large files without reading every line. Returns ~4x fewer tokens than the full file.",
159
+ description: "Show the structure of source files — signatures with bodies collapsed (~4x fewer tokens). Accepts a file path, a directory path, or comma-separated file paths.",
159
160
  inputSchema: {
160
161
  type: "object",
161
162
  properties: {
162
163
  target: {
163
164
  type: "string",
164
- description: "File path relative to project root (e.g. 'src/services/booking.ts')",
165
+ description: "File path, directory path (e.g. 'src/lib/search/'), or comma-separated files (e.g. 'src/a.ts,src/b.ts'). Relative to project root.",
166
+ },
167
+ limit: {
168
+ type: "number",
169
+ description: "Max files for directory mode (default 10, max 20). Ignored for single files.",
165
170
  },
166
171
  },
167
172
  required: ["target"],
@@ -533,36 +538,71 @@ exports.mcp = new commander_1.Command("mcp")
533
538
  const target = String(args.target || "");
534
539
  if (!target)
535
540
  return err("Missing required parameter: target");
536
- const absPath = path.resolve(projectRoot, target);
537
- if (!fs.existsSync(absPath)) {
538
- return err(`File not found: ${target}`);
541
+ const fileLimit = Math.min(Math.max(Number(args.limit) || 10, 1), 20);
542
+ // Determine targets: comma-separated, directory, or single file
543
+ let targets;
544
+ if (target.includes(",")) {
545
+ targets = target
546
+ .split(",")
547
+ .map((t) => t.trim())
548
+ .filter(Boolean);
539
549
  }
540
- // Try cached skeleton first (stored with absolute path)
541
- try {
542
- const db = getVectorDb();
543
- const cached = yield (0, retriever_1.getStoredSkeleton)(db, absPath);
544
- if (cached) {
545
- const tokens = Math.ceil(cached.length / 4);
546
- return ok(`// ${target} (~${tokens} tokens)\n\n${cached}`);
550
+ else {
551
+ const absPath = path.resolve(projectRoot, target);
552
+ if (fs.existsSync(absPath) && fs.statSync(absPath).isDirectory()) {
553
+ const entries = fs.readdirSync(absPath, { withFileTypes: true });
554
+ targets = entries
555
+ .filter((e) => e.isFile() &&
556
+ (0, file_utils_1.isIndexableFile)(path.join(absPath, e.name)))
557
+ .map((e) => path.relative(projectRoot, path.join(absPath, e.name)))
558
+ .slice(0, fileLimit);
559
+ if (targets.length === 0) {
560
+ return err(`No indexable files found in ${target}`);
561
+ }
547
562
  }
548
- }
549
- catch (_a) {
550
- // Index may not exist yet — fall through to live generation
551
- }
552
- // Generate skeleton from file
553
- try {
554
- const content = fs.readFileSync(absPath, "utf-8");
555
- const skel = yield getSkeletonizer();
556
- const result = yield skel.skeletonizeFile(absPath, content);
557
- if (!result.success && result.error) {
558
- return err(`Skeleton generation failed: ${result.error}`);
563
+ else {
564
+ targets = [target];
559
565
  }
560
- return ok(`// ${target} (~${result.tokenEstimate} tokens)\n\n${result.skeleton}`);
561
566
  }
562
- catch (e) {
563
- const msg = e instanceof Error ? e.message : String(e);
564
- return err(`Skeleton failed: ${msg}`);
567
+ // Generate skeletons for all targets
568
+ const parts = [];
569
+ const skel = yield getSkeletonizer();
570
+ for (const t of targets) {
571
+ const absPath = path.resolve(projectRoot, t);
572
+ if (!fs.existsSync(absPath)) {
573
+ parts.push(`// ${t} — file not found`);
574
+ continue;
575
+ }
576
+ // Try cached skeleton first
577
+ try {
578
+ const db = getVectorDb();
579
+ const cached = yield (0, retriever_1.getStoredSkeleton)(db, absPath);
580
+ if (cached) {
581
+ const tokens = Math.ceil(cached.length / 4);
582
+ parts.push(`// ${t} (~${tokens} tokens)\n\n${cached}`);
583
+ continue;
584
+ }
585
+ }
586
+ catch (_a) {
587
+ // Index may not exist yet — fall through to live generation
588
+ }
589
+ // Generate live
590
+ try {
591
+ const content = fs.readFileSync(absPath, "utf-8");
592
+ const result = yield skel.skeletonizeFile(absPath, content);
593
+ if (result.success) {
594
+ parts.push(`// ${t} (~${result.tokenEstimate} tokens)\n\n${result.skeleton}`);
595
+ }
596
+ else {
597
+ parts.push(`// ${t} — skeleton failed: ${result.error}`);
598
+ }
599
+ }
600
+ catch (e) {
601
+ const msg = e instanceof Error ? e.message : String(e);
602
+ parts.push(`// ${t} — error: ${msg}`);
603
+ }
565
604
  }
605
+ return ok(parts.join("\n\n---\n\n"));
566
606
  });
567
607
  }
568
608
  function handleTraceCalls(args) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "grepmax",
3
- "version": "0.7.5",
3
+ "version": "0.7.6",
4
4
  "author": "Robert Owens <robowens@me.com>",
5
5
  "homepage": "https://github.com/reowens/grepmax",
6
6
  "bugs": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "grepmax",
3
- "version": "0.7.5",
3
+ "version": "0.7.6",
4
4
  "description": "Semantic code search for Claude Code. Automatically indexes your project and provides intelligent search capabilities.",
5
5
  "author": {
6
6
  "name": "Robert Owens",
@@ -55,8 +55,9 @@ Search ALL indexed code across every directory. Same parameters as semantic_sear
55
55
  Use sparingly. Prefer `semantic_search` when you know which directory to search.
56
56
 
57
57
  ### code_skeleton
58
- File structure — signatures with bodies collapsed (~4x fewer tokens).
59
- - `target` (required): File path relative to project root
58
+ File or directory structure — signatures with bodies collapsed (~4x fewer tokens).
59
+ - `target` (required): File path, directory path (e.g. "src/lib/search/"), or comma-separated files
60
+ - `limit` (optional): Max files for directory mode (default 10, max 20)
60
61
 
61
62
  ### trace_calls
62
63
  Call graph — who calls a symbol and what it calls. Callers and callees include file:line locations. Unscoped — follows calls across all indexed directories.