grepmax 0.26.69 → 0.26.70

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.
@@ -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.69",
13
+ "version": "0.26.70",
14
14
  "author": {
15
15
  "name": "Robert Owens",
16
16
  "email": "robowens@me.com"
package/README.md CHANGED
@@ -223,6 +223,16 @@ gmax surprises --experimental --exclude generated --top 10
223
223
 
224
224
  The CLI and MCP output include score, max similarity, pair count, representative symbols, directory buckets, top similarities, applied penalties, and `gmax skeleton` follow-up hints. On large monorepos, prefer `--in`/`--exclude`; the default scan is capped at 50,000 rows and user-provided `--max-rows` is capped at 100,000. If a narrow `--in` scope returns no findings, increase `--dir-depth` so subdirectories are compared inside the scope.
225
225
 
226
+ Surprises excludes generated code, bindings, fixtures and GraphQL schema/operation output by default. Use CLI `--include-generated` or MCP `include_generated: true` to include these families; `--include-tests` / `include_tests` controls test files separately.
227
+
228
+ ### Analysis coverage and compact output
229
+
230
+ Project overviews disclose when their language, directory, role and symbol breakdowns cover the first 200,000 chunks. CLI and MCP output label sampled chunk/file counts and show the full project chunk inventory separately. Inventory counting streams only paths in small batches with an execution deadline.
231
+
232
+ Architecture audits omit unresolved same-name definitions from rankings, cycles and dead-code claims, and report the number omitted. Compact CLI audit and MCP cycle rows retain total file/edge counts and show up to eight complete paths within 1,000 characters, with an explicit omitted-file count.
233
+
234
+ CLI `gmax skeleton --agent` and MCP `code_skeleton` text show at most 120 lines / 6,000 characters per file and report omitted lines and characters. CLI human output and JSON structure remain complete.
235
+
226
236
  ## Background Daemon
227
237
 
228
238
  A single daemon watches your projects via native OS file events (FSEvents/inotify). Changes are detected in sub-second and incrementally reindexed. All writes to LanceDB are routed through the daemon via IPC, eliminating lock contention.
@@ -43,8 +43,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
43
43
  };
44
44
  Object.defineProperty(exports, "__esModule", { value: true });
45
45
  exports.audit = void 0;
46
+ exports.formatHuman = formatHuman;
47
+ exports.formatAgent = formatAgent;
46
48
  const commander_1 = require("commander");
47
49
  const graph_handler_1 = require("../lib/daemon/graph-handler");
50
+ const agent_budget_1 = require("../lib/output/agent-budget");
48
51
  const vector_db_1 = require("../lib/store/vector-db");
49
52
  const exit_1 = require("../lib/utils/exit");
50
53
  const project_registry_1 = require("../lib/utils/project-registry");
@@ -67,6 +70,8 @@ function formatCycle(files) {
67
70
  function formatHuman(r) {
68
71
  const out = [];
69
72
  out.push(`${style.bold("Audit")} ${style.dim(`— ${r.scannedChunks} chunks across ${r.scannedFiles} files`)}`);
73
+ if (r.ambiguousSymbols)
74
+ out.push(`Unresolved symbol names omitted: ${r.ambiguousSymbols}`);
70
75
  out.push("");
71
76
  out.push(style.bold("God nodes") + style.dim(" (most depended-upon symbols)"));
72
77
  if (r.godNodes.length === 0) {
@@ -122,8 +127,10 @@ function formatHuman(r) {
122
127
  return out.join("\n");
123
128
  }
124
129
  function formatAgent(r) {
130
+ var _a;
125
131
  const lines = [];
126
132
  lines.push(`scanned\t${r.scannedChunks}\t${r.scannedFiles}`);
133
+ lines.push(`ambiguous_symbols_omitted\t${(_a = r.ambiguousSymbols) !== null && _a !== void 0 ? _a : 0}`);
127
134
  for (const g of r.godNodes) {
128
135
  const ambiguous = g.defFiles > 1 ? `\tdefs=${g.defFiles}` : "";
129
136
  lines.push(`god\t${g.symbol}\t${g.file}:${g.line + 1}\t${g.inboundFiles}\t${g.totalRefs}${ambiguous}`);
@@ -132,7 +139,8 @@ function formatAgent(r) {
132
139
  lines.push(`hub\t${h.file}\t${h.dependents}\t${h.defines}\t${h.fanOut}`);
133
140
  }
134
141
  for (const c of r.fileCycles) {
135
- lines.push(`cycle\t${c.files.join(",")}\t${c.files.length}\t${c.edgeCount}`);
142
+ const shown = (0, agent_budget_1.boundedAgentList)(c.files);
143
+ lines.push(`cycle\t${shown.text}\t${c.files.length}\t${c.edgeCount}\tomitted_files=${shown.omitted}`);
136
144
  }
137
145
  for (const d of r.deadCandidates) {
138
146
  lines.push(`dead\t${d.symbol}\t${d.file}:${d.line + 1}`);
@@ -83,9 +83,11 @@ const embedding_generation_1 = require("../lib/index/embedding-generation");
83
83
  const embedding_status_1 = require("../lib/index/embedding-status");
84
84
  const index_config_1 = require("../lib/index/index-config");
85
85
  const syncer_1 = require("../lib/index/syncer");
86
+ const agent_budget_1 = require("../lib/output/agent-budget");
86
87
  const agent_search_formatter_1 = require("../lib/output/agent-search-formatter");
87
88
  const index_state_footer_1 = require("../lib/output/index-state-footer");
88
89
  const mcp_results_1 = require("../lib/output/mcp-results");
90
+ const project_coverage_1 = require("../lib/output/project-coverage");
89
91
  const searcher_1 = require("../lib/search/searcher");
90
92
  const annotator_1 = require("../lib/skeleton/annotator");
91
93
  const skeletonizer_1 = require("../lib/skeleton/skeletonizer");
@@ -1133,7 +1135,7 @@ exports.mcp = new commander_1.Command("mcp")
1133
1135
  const annotated = sourceContent
1134
1136
  ? (0, annotator_1.annotateSkeletonLines)(skeleton, sourceContent)
1135
1137
  : skeleton;
1136
- parts.push(`// ${t} (~${tokenEstimate} tokens)\n\n${annotated}`);
1138
+ parts.push(`// ${t} (~${tokenEstimate} tokens)\n\n${(0, agent_budget_1.boundedAgentText)(annotated)}`);
1137
1139
  }
1138
1140
  }
1139
1141
  if (fmt === "json") {
@@ -1518,6 +1520,8 @@ exports.mcp = new commander_1.Command("mcp")
1518
1520
  }
1519
1521
  const lines = [];
1520
1522
  lines.push(`Audit — ${audit.scannedChunks} chunks across ${audit.scannedFiles} files`);
1523
+ if (audit.ambiguousSymbols)
1524
+ lines.push(`Unresolved symbol names omitted: ${audit.ambiguousSymbols}`);
1521
1525
  lines.push("");
1522
1526
  lines.push("God nodes (most depended-upon symbols):");
1523
1527
  for (const g of audit.godNodes) {
@@ -1535,7 +1539,8 @@ exports.mcp = new commander_1.Command("mcp")
1535
1539
  lines.push("");
1536
1540
  lines.push("File dependency cycles (symbol-derived):");
1537
1541
  for (const c of audit.fileCycles) {
1538
- lines.push(` ${c.files.join(", ")} - ${c.files.length} files, ${c.edgeCount} internal edges`);
1542
+ const shown = (0, agent_budget_1.boundedAgentList)(c.files);
1543
+ lines.push(` ${shown.text} - ${c.files.length} files, ${c.edgeCount} internal edges; omitted_files=${shown.omitted}`);
1539
1544
  }
1540
1545
  if (audit.fileCycles.length === 0)
1541
1546
  lines.push(" none");
@@ -1581,6 +1586,7 @@ exports.mcp = new commander_1.Command("mcp")
1581
1586
  maxRows,
1582
1587
  includeTests: Boolean(args.include_tests),
1583
1588
  includeEval: Boolean(args.include_eval),
1589
+ includeGenerated: Boolean(args.include_generated),
1584
1590
  in: typeof args.in === "string" ? [args.in] : undefined,
1585
1591
  exclude: typeof args.exclude === "string" ? [args.exclude] : undefined,
1586
1592
  };
@@ -1990,7 +1996,10 @@ exports.mcp = new commander_1.Command("mcp")
1990
1996
  const pct = (count) => Math.round((count / overview.chunks) * 100);
1991
1997
  const lines = [];
1992
1998
  lines.push(`Project: ${projectName} (${root})`);
1993
- lines.push(`Last indexed: ${(_a = proj.lastIndexed) !== null && _a !== void 0 ? _a : "unknown"} • ${overview.chunks} chunks • ${overview.files} files`);
1999
+ lines.push(`Last indexed: ${(_a = proj.lastIndexed) !== null && _a !== void 0 ? _a : "unknown"} • ${(0, project_coverage_1.projectCounts)(overview)}`);
2000
+ const coverage = (0, project_coverage_1.projectCoverageNotice)(overview);
2001
+ if (coverage)
2002
+ lines.push(`Coverage: ${coverage}`);
1994
2003
  lines.push("");
1995
2004
  lines.push(`Languages: ${overview.extEntries
1996
2005
  .map(([ext, count]) => `${ext} (${pct(count)}%)`)
@@ -2976,6 +2985,10 @@ exports.mcp = new commander_1.Command("mcp")
2976
2985
  .boolean()
2977
2986
  .describe("Include eval/experiment/script files")
2978
2987
  .optional(),
2988
+ include_generated: zod_1.z
2989
+ .boolean()
2990
+ .describe("Include generated code, bindings and fixtures")
2991
+ .optional(),
2979
2992
  },
2980
2993
  }, handleSurprisingConnections);
2981
2994
  tool("get_neighbors", {
@@ -46,6 +46,7 @@ exports.project = void 0;
46
46
  const path = __importStar(require("node:path"));
47
47
  const commander_1 = require("commander");
48
48
  const rows_handler_1 = require("../lib/daemon/rows-handler");
49
+ const project_coverage_1 = require("../lib/output/project-coverage");
49
50
  const daemon_client_1 = require("../lib/utils/daemon-client");
50
51
  const exit_1 = require("../lib/utils/exit");
51
52
  const project_registry_1 = require("../lib/utils/project-registry");
@@ -80,9 +81,12 @@ exports.project = new commander_1.Command("project")
80
81
  const projects = (0, project_registry_1.listProjects)();
81
82
  const proj = projects.find((p) => p.root === root);
82
83
  const { chunks, files, extEntries, dirEntries, roleEntries, topSymbols, entryPoints, } = overview;
84
+ const coverage = (0, project_coverage_1.projectCoverageNotice)(overview);
83
85
  if (opts.agent) {
84
86
  console.log(`name\t${projectName}`);
85
87
  console.log(`root\t${root}`);
88
+ if (coverage)
89
+ console.log(`coverage\t${coverage}`);
86
90
  console.log(`chunks\t${chunks}`);
87
91
  console.log(`files\t${files}`);
88
92
  console.log(`last_indexed\t${(_b = proj === null || proj === void 0 ? void 0 : proj.lastIndexed) !== null && _b !== void 0 ? _b : "unknown"}`);
@@ -100,7 +104,9 @@ exports.project = new commander_1.Command("project")
100
104
  }
101
105
  else {
102
106
  console.log(`Project: ${projectName} (${root})`);
103
- console.log(`Last indexed: ${(_c = proj === null || proj === void 0 ? void 0 : proj.lastIndexed) !== null && _c !== void 0 ? _c : "unknown"} • ${chunks} chunks • ${files} files\n`);
107
+ console.log(`Last indexed: ${(_c = proj === null || proj === void 0 ? void 0 : proj.lastIndexed) !== null && _c !== void 0 ? _c : "unknown"} • ${(0, project_coverage_1.projectCounts)(overview)}\n`);
108
+ if (coverage)
109
+ console.log(`Coverage: ${coverage}\n`);
104
110
  console.log(`Languages: ${extEntries.map(([ext, count]) => `${ext} (${Math.round((count / chunks) * 100)}%)`).join(", ")}\n`);
105
111
  console.log("Directory structure:");
106
112
  for (const [dir, data] of dirEntries) {
@@ -1,12 +1,4 @@
1
1
  "use strict";
2
- /**
3
- * gmax skeleton - Show code skeleton (signatures without implementation)
4
- *
5
- * Usage:
6
- * gmax skeleton <file> # Skeleton of a file
7
- * gmax skeleton <symbol> # Find symbol and skeleton its file
8
- * gmax skeleton "query" # Search and skeleton top results
9
- */
10
2
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
11
3
  if (k2 === undefined) k2 = k;
12
4
  var desc = Object.getOwnPropertyDescriptor(m, k);
@@ -51,6 +43,15 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
51
43
  };
52
44
  Object.defineProperty(exports, "__esModule", { value: true });
53
45
  exports.skeleton = void 0;
46
+ const agent_budget_1 = require("../lib/output/agent-budget");
47
+ /**
48
+ * gmax skeleton - Show code skeleton (signatures without implementation)
49
+ *
50
+ * Usage:
51
+ * gmax skeleton <file> # Skeleton of a file
52
+ * gmax skeleton <symbol> # Find symbol and skeleton its file
53
+ * gmax skeleton "query" # Search and skeleton top results
54
+ */
54
55
  const fs = __importStar(require("node:fs"));
55
56
  const commander_1 = require("commander");
56
57
  const config_1 = require("../config");
@@ -392,7 +393,9 @@ Examples:
392
393
  }
393
394
  else {
394
395
  for (const result of results) {
395
- console.log(result.skeleton);
396
+ console.log(options.agent
397
+ ? (0, agent_budget_1.boundedAgentText)(result.skeleton)
398
+ : result.skeleton);
396
399
  console.log(""); // Blank line between files
397
400
  }
398
401
  }
@@ -423,6 +426,6 @@ function outputResult(result, options) {
423
426
  }, null, 2));
424
427
  }
425
428
  else {
426
- console.log(result.skeleton);
429
+ console.log(options.agent ? (0, agent_budget_1.boundedAgentText)(result.skeleton) : result.skeleton);
427
430
  }
428
431
  }
@@ -132,6 +132,7 @@ exports.surprises = new commander_1.Command("surprises")
132
132
  .option("--min-sim <n>", "Minimum similarity 0-1", String(surprising_connections_1.DEFAULT_SURPRISE_OPTIONS.minSimilarity))
133
133
  .option("--max-rows <n>", `Maximum indexed rows to scan (capped at ${surprising_connections_1.MAX_SURPRISE_ROWS})`, String(surprising_connections_1.DEFAULT_SURPRISE_OPTIONS.maxRows))
134
134
  .option("--include-tests", "Include test files", false)
135
+ .option("--include-generated", "Include generated code, bindings and fixtures", false)
135
136
  .option("--include-eval", "Include eval/experiment/script files", false)
136
137
  .option("--in <subpath>", "Restrict to a sub-path of the project (repeatable)", (value, prev) => prev ? [...prev, value] : [value])
137
138
  .option("--exclude <subpath>", "Exclude a sub-path of the project (repeatable)", (value, prev) => prev ? [...prev, value] : [value])
@@ -180,6 +181,7 @@ exports.surprises = new commander_1.Command("surprises")
180
181
  maxRows: parseIntOption(opts.maxRows, surprising_connections_1.DEFAULT_SURPRISE_OPTIONS.maxRows, surprising_connections_1.MAX_SURPRISE_ROWS),
181
182
  includeTests: Boolean(opts.includeTests),
182
183
  includeEval: Boolean(opts.includeEval),
184
+ includeGenerated: Boolean(opts.includeGenerated),
183
185
  in: analysisIn,
184
186
  exclude: analysisExclude,
185
187
  };
@@ -45,6 +45,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
45
45
  exports.SURPRISE_COLUMNS = exports.MAX_SURPRISE_ROWS = exports.DEFAULT_SURPRISE_OPTIONS = void 0;
46
46
  exports.normalizeSurpriseOptions = normalizeSurpriseOptions;
47
47
  exports.isTestPath = isTestPath;
48
+ exports.isGeneratedPath = isGeneratedPath;
48
49
  exports.isEvalPath = isEvalPath;
49
50
  exports.relPath = relPath;
50
51
  exports.lineLabel = lineLabel;
@@ -73,6 +74,7 @@ exports.DEFAULT_SURPRISE_OPTIONS = {
73
74
  maxRows: 50000,
74
75
  includeTests: false,
75
76
  includeEval: false,
77
+ includeGenerated: false,
76
78
  };
77
79
  exports.MAX_SURPRISE_ROWS = 100000;
78
80
  /**
@@ -152,8 +154,8 @@ const TEST_FILE_RE = /\.(test|spec)\.[cm]?[jt]sx?$/i;
152
154
  const NATIVE_TEST_DIR_RE = /(^|\/)\w+Tests?(\/|$)/;
153
155
  const NATIVE_TEST_FILE_RE = /Tests?\.(swift|kt|java)$/;
154
156
  function normalizeSurpriseOptions(opts = {}) {
155
- var _a, _b, _c, _d, _e, _f, _g;
156
- return Object.assign(Object.assign(Object.assign({}, exports.DEFAULT_SURPRISE_OPTIONS), opts), { sample: Math.max(1, Math.floor((_a = opts.sample) !== null && _a !== void 0 ? _a : exports.DEFAULT_SURPRISE_OPTIONS.sample)), neighbors: Math.max(1, Math.floor((_b = opts.neighbors) !== null && _b !== void 0 ? _b : exports.DEFAULT_SURPRISE_OPTIONS.neighbors)), dirDepth: Math.max(1, Math.floor((_c = opts.dirDepth) !== null && _c !== void 0 ? _c : exports.DEFAULT_SURPRISE_OPTIONS.dirDepth)), minSimilarity: Math.max(0, (_d = opts.minSimilarity) !== null && _d !== void 0 ? _d : exports.DEFAULT_SURPRISE_OPTIONS.minSimilarity), maxRows: Math.max(1, Math.min(exports.MAX_SURPRISE_ROWS, Math.floor((_e = opts.maxRows) !== null && _e !== void 0 ? _e : exports.DEFAULT_SURPRISE_OPTIONS.maxRows))), includeTests: (_f = opts.includeTests) !== null && _f !== void 0 ? _f : exports.DEFAULT_SURPRISE_OPTIONS.includeTests, includeEval: (_g = opts.includeEval) !== null && _g !== void 0 ? _g : exports.DEFAULT_SURPRISE_OPTIONS.includeEval });
157
+ var _a, _b, _c, _d, _e, _f, _g, _h;
158
+ return Object.assign(Object.assign(Object.assign({}, exports.DEFAULT_SURPRISE_OPTIONS), opts), { sample: Math.max(1, Math.floor((_a = opts.sample) !== null && _a !== void 0 ? _a : exports.DEFAULT_SURPRISE_OPTIONS.sample)), neighbors: Math.max(1, Math.floor((_b = opts.neighbors) !== null && _b !== void 0 ? _b : exports.DEFAULT_SURPRISE_OPTIONS.neighbors)), dirDepth: Math.max(1, Math.floor((_c = opts.dirDepth) !== null && _c !== void 0 ? _c : exports.DEFAULT_SURPRISE_OPTIONS.dirDepth)), minSimilarity: Math.max(0, (_d = opts.minSimilarity) !== null && _d !== void 0 ? _d : exports.DEFAULT_SURPRISE_OPTIONS.minSimilarity), maxRows: Math.max(1, Math.min(exports.MAX_SURPRISE_ROWS, Math.floor((_e = opts.maxRows) !== null && _e !== void 0 ? _e : exports.DEFAULT_SURPRISE_OPTIONS.maxRows))), includeTests: (_f = opts.includeTests) !== null && _f !== void 0 ? _f : exports.DEFAULT_SURPRISE_OPTIONS.includeTests, includeEval: (_g = opts.includeEval) !== null && _g !== void 0 ? _g : exports.DEFAULT_SURPRISE_OPTIONS.includeEval, includeGenerated: (_h = opts.includeGenerated) !== null && _h !== void 0 ? _h : false });
157
159
  }
158
160
  function isTestPath(filePath) {
159
161
  return (TEST_DIR_RE.test(filePath) ||
@@ -161,6 +163,11 @@ function isTestPath(filePath) {
161
163
  NATIVE_TEST_DIR_RE.test(filePath) ||
162
164
  NATIVE_TEST_FILE_RE.test(filePath));
163
165
  }
166
+ function isGeneratedPath(filePath) {
167
+ return (/(^|\/)(?:generated|__generated__|bindings|fixtures|__fixtures__)(\/|$)/i.test(filePath) ||
168
+ /\.generated\.[^.]+$/i.test(filePath) ||
169
+ /\/[^/]*GraphQL\/Sources\/(?:Schema|Operations)\//i.test(filePath));
170
+ }
164
171
  function isEvalPath(filePath) {
165
172
  return (/(^|\/)src\/eval[^/]*\.ts$/i.test(filePath) ||
166
173
  /(^|\/)(benchmarks?|experiments|scripts)(\/|$)/i.test(filePath));
@@ -477,6 +484,8 @@ function filterableCodeMeta(row, opts) {
477
484
  return false;
478
485
  if (!opts.includeEval && isEvalPath(row.relPath))
479
486
  return false;
487
+ if (!opts.includeGenerated && isGeneratedPath(row.relPath))
488
+ return false;
480
489
  return row.definedSymbols.length > 0;
481
490
  }
482
491
  function hasCodeContent(content) {
@@ -633,6 +642,7 @@ function analyzeSurprisingConnections(table_1, projectRoot_1) {
633
642
  weakCode: 0,
634
643
  tests: 0,
635
644
  evalHarness: 0,
645
+ generated: 0,
636
646
  sameDirBucket: 0,
637
647
  graphEdge: 0,
638
648
  belowThreshold: 0,
@@ -671,6 +681,10 @@ function analyzeSurprisingConnections(table_1, projectRoot_1) {
671
681
  filters.tests++;
672
682
  continue;
673
683
  }
684
+ if (!opts.includeGenerated && isGeneratedPath(target.relPath)) {
685
+ filters.generated++;
686
+ continue;
687
+ }
674
688
  if (!opts.includeEval && isEvalPath(target.relPath)) {
675
689
  filters.evalHarness++;
676
690
  continue;
@@ -537,13 +537,15 @@ function findFileCycles(deps, prefix, top) {
537
537
  * `top` caps each list; `deadTotal` reports the full pre-cap dead count.
538
538
  */
539
539
  function computeAudit(rows, prefix, top) {
540
- var _a;
541
- var _b;
542
- // First definition of a symbol wins (matches GraphBuilder semantics).
540
+ var _a, _b, _c, _d, _e, _f;
541
+ var _g;
542
+ var _h;
543
+ // Only a uniquely defined name can establish an architectural edge.
543
544
  const defs = new Map();
544
545
  // Distinct files defining each name — name-based edges can't tell same-name
545
546
  // symbols apart, so multi-file definitions get flagged in the output.
546
547
  const defFileCounts = new Map();
548
+ const defLocations = new Map();
547
549
  // Distinct files that reference a symbol (cross-file inbound edges).
548
550
  const inboundFiles = new Map();
549
551
  const inboundTotal = new Map();
@@ -562,9 +564,15 @@ function computeAudit(rows, prefix, top) {
562
564
  if (!defs.has(s)) {
563
565
  defs.set(s, { file, line, exported, complexity: 0 });
564
566
  }
567
+ else {
568
+ (_h = defs.get(s)).exported || (_h.exported = exported);
569
+ }
565
570
  if (!defFileCounts.has(s))
566
571
  defFileCounts.set(s, new Set());
567
572
  defFileCounts.get(s).add(file);
573
+ if (!defLocations.has(s))
574
+ defLocations.set(s, new Set());
575
+ defLocations.get(s).add(`${file}:${line}`);
568
576
  if (!fileDefs.has(file))
569
577
  fileDefs.set(file, new Set());
570
578
  fileDefs.get(file).add(s);
@@ -586,7 +594,7 @@ function computeAudit(rows, prefix, top) {
586
594
  continue;
587
595
  // Builtin method names (get, set, push, …) leak in via prototype/member
588
596
  // definitions and their inbound counts are meaningless name collisions.
589
- if ((0, callsites_1.isBuiltinCallee)(symbol))
597
+ if ((0, callsites_1.isBuiltinCallee)(symbol) || ((_a = defLocations.get(symbol)) === null || _a === void 0 ? void 0 : _a.size) !== 1)
590
598
  continue;
591
599
  const refFiles = inboundFiles.get(symbol);
592
600
  if (!refFiles)
@@ -603,7 +611,7 @@ function computeAudit(rows, prefix, top) {
603
611
  line: info.line,
604
612
  inboundFiles: external,
605
613
  totalRefs: inboundTotal.get(symbol) || 0,
606
- defFiles: (_b = (_a = defFileCounts.get(symbol)) === null || _a === void 0 ? void 0 : _a.size) !== null && _b !== void 0 ? _b : 1,
614
+ defFiles: (_g = (_b = defFileCounts.get(symbol)) === null || _b === void 0 ? void 0 : _b.size) !== null && _g !== void 0 ? _g : 1,
607
615
  });
608
616
  }
609
617
  godNodes.sort((a, b) => b.inboundFiles - a.inboundFiles || b.totalRefs - a.totalRefs);
@@ -613,6 +621,8 @@ function computeAudit(rows, prefix, top) {
613
621
  for (const [file, syms] of fileDefs) {
614
622
  const dependents = new Set();
615
623
  for (const s of syms) {
624
+ if ((0, callsites_1.isBuiltinCallee)(s) || ((_c = defLocations.get(s)) === null || _c === void 0 ? void 0 : _c.size) !== 1)
625
+ continue;
616
626
  const refFiles = inboundFiles.get(s);
617
627
  if (!refFiles)
618
628
  continue;
@@ -626,7 +636,9 @@ function computeAudit(rows, prefix, top) {
626
636
  const out = fileOutRefs.get(file);
627
637
  if (out)
628
638
  for (const s of out)
629
- if (defs.has(s))
639
+ if (defs.has(s) &&
640
+ !(0, callsites_1.isBuiltinCallee)(s) &&
641
+ ((_d = defLocations.get(s)) === null || _d === void 0 ? void 0 : _d.size) === 1)
630
642
  fanOut++;
631
643
  hubFiles.push({
632
644
  file: rel(file, prefix),
@@ -639,7 +651,7 @@ function computeAudit(rows, prefix, top) {
639
651
  const fileDeps = new Map();
640
652
  for (const [file, refs] of fileOutRefs) {
641
653
  for (const s of refs) {
642
- if ((0, callsites_1.isBuiltinCallee)(s))
654
+ if ((0, callsites_1.isBuiltinCallee)(s) || ((_e = defLocations.get(s)) === null || _e === void 0 ? void 0 : _e.size) !== 1)
643
655
  continue;
644
656
  const defFiles = defFileCounts.get(s);
645
657
  if (!defFiles || defFiles.size !== 1)
@@ -657,7 +669,9 @@ function computeAudit(rows, prefix, top) {
657
669
  // references anywhere (including their own file).
658
670
  const deadAll = [];
659
671
  for (const [symbol, info] of defs) {
660
- if (info.exported)
672
+ if (info.exported ||
673
+ ((_f = defLocations.get(symbol)) === null || _f === void 0 ? void 0 : _f.size) !== 1 ||
674
+ (0, callsites_1.isBuiltinCallee)(symbol))
661
675
  continue;
662
676
  if ((inboundTotal.get(symbol) || 0) > 0)
663
677
  continue;
@@ -665,6 +679,7 @@ function computeAudit(rows, prefix, top) {
665
679
  }
666
680
  deadAll.sort((a, b) => a.file.localeCompare(b.file) || a.line - b.line);
667
681
  return {
682
+ ambiguousSymbols: [...defLocations.values()].filter((locations) => locations.size > 1).length,
668
683
  scannedChunks: rows.length,
669
684
  scannedFiles: files.size,
670
685
  godNodes: godNodes.slice(0, top),
@@ -41,8 +41,15 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
41
41
  step((generator = generator.apply(thisArg, _arguments || [])).next());
42
42
  });
43
43
  };
44
+ var __asyncValues = (this && this.__asyncValues) || function (o) {
45
+ if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
46
+ var m = o[Symbol.asyncIterator], i;
47
+ return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
48
+ function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
49
+ function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
50
+ };
44
51
  Object.defineProperty(exports, "__esModule", { value: true });
45
- exports.MAX_LOCATE_ROWS = exports.ReadVerbError = void 0;
52
+ exports.MAX_LOCATE_ROWS = exports.MAX_PROJECT_ROWS = exports.ReadVerbError = void 0;
46
53
  exports.withLocalStore = withLocalStore;
47
54
  exports.scopeToWire = scopeToWire;
48
55
  exports.assertReadableProject = assertReadableProject;
@@ -51,6 +58,7 @@ exports.clampInt = clampInt;
51
58
  exports.asReadVerbResponse = asReadVerbResponse;
52
59
  exports.runSymbols = runSymbols;
53
60
  exports.handleRowsSymbols = handleRowsSymbols;
61
+ exports.countProjectRows = countProjectRows;
54
62
  exports.runProject = runProject;
55
63
  exports.handleRowsProject = handleRowsProject;
56
64
  exports.runLocate = runLocate;
@@ -270,15 +278,42 @@ function handleRowsSymbols(deps, payload) {
270
278
  }));
271
279
  });
272
280
  }
281
+ // --- rows.project -----------------------------------------------------------
282
+ exports.MAX_PROJECT_ROWS = 200000;
283
+ /** Count a path-only stream in bounded Arrow batches with a native deadline.
284
+ * The SDK's countRows API has no execution timeout. */
285
+ function countProjectRows(query, timeoutMs) {
286
+ return __awaiter(this, void 0, void 0, function* () {
287
+ var _a, e_1, _b, _c;
288
+ let count = 0;
289
+ try {
290
+ for (var _d = true, _e = __asyncValues((0, query_timeout_1.streamQueryRows)(query, "project inventory count", timeoutMs)), _f; _f = yield _e.next(), _a = _f.done, !_a; _d = true) {
291
+ _c = _f.value;
292
+ _d = false;
293
+ const _row = _c;
294
+ count++;
295
+ }
296
+ }
297
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
298
+ finally {
299
+ try {
300
+ if (!_d && !_a && (_b = _e.return)) yield _b.call(_e);
301
+ }
302
+ finally { if (e_1) throw e_1.error; }
303
+ }
304
+ return count;
305
+ });
306
+ }
273
307
  /**
274
308
  * The `project` scan and its aggregation. Returns the finished overview rather
275
309
  * than the (up to 200 000) rows it was computed from — see the file header.
276
310
  */
277
311
  function runProject(deps, projectRoot) {
278
312
  return __awaiter(this, void 0, void 0, function* () {
313
+ var _a;
279
314
  const table = yield tableOf(deps);
280
315
  const prefix = projectRoot.endsWith("/") ? projectRoot : `${projectRoot}/`;
281
- const rows = yield table
316
+ const scanned = yield table
282
317
  .query()
283
318
  .select([
284
319
  "path",
@@ -289,8 +324,15 @@ function runProject(deps, projectRoot) {
289
324
  "referenced_symbols",
290
325
  ])
291
326
  .where((0, filter_builder_1.pathStartsWith)(prefix))
292
- .limit(200000)
293
- .toArray(query_timeout_1.QUERY_EXECUTION_OPTIONS);
327
+ .limit(exports.MAX_PROJECT_ROWS + 1)
328
+ .toArray({
329
+ timeoutMs: (_a = deps.queryTimeoutMs) !== null && _a !== void 0 ? _a : query_timeout_1.QUERY_EXECUTION_OPTIONS.timeoutMs,
330
+ });
331
+ const sampled = scanned.length > exports.MAX_PROJECT_ROWS;
332
+ const rows = sampled ? scanned.slice(0, exports.MAX_PROJECT_ROWS) : scanned;
333
+ const totalChunks = sampled
334
+ ? yield countProjectRows(table.query().select(["path"]).where((0, filter_builder_1.pathStartsWith)(prefix)), deps.queryTimeoutMs)
335
+ : rows.length;
294
336
  const nodePath = yield Promise.resolve().then(() => __importStar(require("node:path")));
295
337
  const files = new Set();
296
338
  const extCounts = new Map();
@@ -343,6 +385,8 @@ function runProject(deps, projectRoot) {
343
385
  }
344
386
  }
345
387
  return {
388
+ sampled,
389
+ totalChunks,
346
390
  chunks: rows.length,
347
391
  files: files.size,
348
392
  extEntries: Array.from(extCounts.entries())
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.boundedAgentText = boundedAgentText;
4
+ exports.boundedAgentList = boundedAgentList;
5
+ /** A bounded source excerpt with explicit loss counts. Full/JSON output stays exact. */
6
+ function boundedAgentText(text, maxChars = 6000, maxLines = 120) {
7
+ var _a;
8
+ const lines = text.split("\n");
9
+ const lineLimited = lines.slice(0, maxLines).join("\n");
10
+ let end = Math.min(lineLimited.length, maxChars);
11
+ // Do not emit half of a UTF-16 surrogate pair at the character boundary.
12
+ if (end > 0 &&
13
+ /[\uD800-\uDBFF]/.test(lineLimited[end - 1]) &&
14
+ /[\uDC00-\uDFFF]/.test((_a = lineLimited[end]) !== null && _a !== void 0 ? _a : ""))
15
+ end--;
16
+ const excerpt = lineLimited.slice(0, end);
17
+ if (excerpt.length === text.length)
18
+ return text;
19
+ const shownLines = excerpt ? excerpt.split("\n").length : 0;
20
+ return `${excerpt}\n… omitted ${Math.max(0, lines.length - shownLines)} lines, ${text.length - excerpt.length} characters`;
21
+ }
22
+ /** Preserve complete fields so loss counts describe files, not partial names. */
23
+ function boundedAgentList(items, maxItems = 8, maxChars = 1000) {
24
+ const shown = [];
25
+ let length = 0;
26
+ for (const item of items.slice(0, maxItems)) {
27
+ const field = item
28
+ .replace(/\\/g, "\\\\")
29
+ .replace(/\t/g, "\\t")
30
+ .replace(/\r/g, "\\r")
31
+ .replace(/\n/g, "\\n");
32
+ const nextLength = length + field.length + (shown.length ? 1 : 0);
33
+ if (nextLength > maxChars)
34
+ break;
35
+ shown.push(field);
36
+ length = nextLength;
37
+ }
38
+ return { text: shown.join(","), omitted: items.length - shown.length };
39
+ }
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.projectCounts = projectCounts;
4
+ exports.projectCoverageNotice = projectCoverageNotice;
5
+ function projectCounts(overview) {
6
+ const qualifier = overview.sampled ? "sampled " : "";
7
+ return `${overview.chunks} ${qualifier}chunks • ${overview.files} ${qualifier}files`;
8
+ }
9
+ function projectCoverageNotice(overview) {
10
+ if (!overview.sampled)
11
+ return null;
12
+ const total = overview.totalChunks === undefined
13
+ ? "total chunk count unavailable"
14
+ : `${overview.totalChunks} total chunks`;
15
+ return `partial: ${overview.chunks} sampled chunks, ${overview.files} sampled files; ${total}; all breakdowns below describe the sample`;
16
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "grepmax",
3
- "version": "0.26.69",
3
+ "version": "0.26.70",
4
4
  "author": "Robert Owens <78518764+reowens@users.noreply.github.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.26.69",
3
+ "version": "0.26.70",
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",