grepmax 0.26.69 → 0.26.71

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.
@@ -0,0 +1,194 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
36
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
37
+ return new (P || (P = Promise))(function (resolve, reject) {
38
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
39
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
40
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
41
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
42
+ });
43
+ };
44
+ Object.defineProperty(exports, "__esModule", { value: true });
45
+ exports.documentFilter = documentFilter;
46
+ exports.handleDocumentSearch = handleDocumentSearch;
47
+ const path = __importStar(require("node:path"));
48
+ const document_contract_1 = require("../mcp/document-contract");
49
+ function sqlString(input) {
50
+ return `'${input.replace(/'/g, "''")}'`;
51
+ }
52
+ function documentFilter(prefixes) {
53
+ return `(${prefixes
54
+ .map((prefix) => {
55
+ const dir = prefix.endsWith(path.sep) ? prefix : prefix + path.sep;
56
+ return `(path = ${sqlString(prefix)} OR (path >= ${sqlString(dir)} AND path < ${sqlString(`${dir}\uffff`)}))`;
57
+ })
58
+ .join(" OR ")}) AND lower(path) LIKE '%.md'`;
59
+ }
60
+ function handleDocumentSearch(deps, cmd, signal) {
61
+ return __awaiter(this, void 0, void 0, function* () {
62
+ var _a, _b;
63
+ var _c, _d;
64
+ try {
65
+ const deadline = performance.now() + document_contract_1.DOCUMENT_LIMITS.deadlineMs;
66
+ signal = AbortSignal.any([
67
+ signal,
68
+ AbortSignal.timeout(document_contract_1.DOCUMENT_LIMITS.deadlineMs),
69
+ ]);
70
+ signal.throwIfAborted();
71
+ if (cmd.contractVersion !== document_contract_1.DOCUMENT_CONTRACT_VERSION)
72
+ return (0, document_contract_1.documentFailure)("unsupported_tool");
73
+ if (deps.state() !== "ready")
74
+ return (0, document_contract_1.documentFailure)(deps.state());
75
+ if (typeof cmd.checkout !== "string")
76
+ return (0, document_contract_1.documentFailure)("no_index");
77
+ const context = (0, document_contract_1.selectDocumentContext)(deps.home, cmd.checkout);
78
+ if (cmd.projectRoot !== context.wireRoot || cmd.store !== context.store)
79
+ return (0, document_contract_1.documentFailure)("store_unavailable");
80
+ const embeddingState = deps.embeddingState(context.wireRoot);
81
+ if (embeddingState !== "ready")
82
+ return (0, document_contract_1.documentFailure)(embeddingState);
83
+ const generation = deps.generation();
84
+ if (!(0, document_contract_1.documentGeneration)(generation))
85
+ return (0, document_contract_1.documentFailure)("index_unavailable");
86
+ if (!(0, document_contract_1.documentGeneration)(cmd.generation) || cmd.generation !== generation)
87
+ return (0, document_contract_1.documentFailure)("embedding_mismatch");
88
+ const recheck = () => {
89
+ signal.throwIfAborted();
90
+ if (performance.now() >= deadline)
91
+ throw new Error("timeout");
92
+ if (deps.state() !== "ready")
93
+ throw new Error(deps.state());
94
+ if (deps.generation() !== generation ||
95
+ deps.embeddingState(context.wireRoot) !== "ready")
96
+ throw new Error("embedding_mismatch");
97
+ };
98
+ const base = {
99
+ ok: true,
100
+ root: context.root,
101
+ store: context.store,
102
+ generation,
103
+ };
104
+ if (cmd.cmd === "documents.status") {
105
+ const { paths, requested } = (0, document_contract_1.documentCoveragePaths)(cmd.paths, context);
106
+ const covered = paths.flatMap((file) => {
107
+ const entry = deps.meta(file);
108
+ return (entry === null || entry === void 0 ? void 0 : entry.hasVectors) === true
109
+ ? [
110
+ Object.assign(Object.assign({ path: file }, (entry.hashVersion === 1 && /^[a-f0-9]{64}$/.test(entry.hash)
111
+ ? { hash: entry.hash, hashAlgorithm: "sha256-bytes" }
112
+ : {})), ((0, document_contract_1.documentMtime)(entry.mtimeMs) !== null
113
+ ? { indexedMtimeMs: entry.mtimeMs }
114
+ : {})),
115
+ ]
116
+ : [];
117
+ });
118
+ recheck();
119
+ const state = (0, document_contract_1.documentQueryState)(deps.queryState());
120
+ return Object.assign(Object.assign({}, base), { embeddingReady: state === "ready", queryState: state, lastIndexed: (_c = (0, document_contract_1.documentIndexedAt)((_a = deps.lastIndexed) === null || _a === void 0 ? void 0 : _a.call(deps, context.wireRoot))) !== null && _c !== void 0 ? _c : context.lastIndexed, indexState: (0, document_contract_1.documentIndexState)(deps.indexState(context.wireRoot)), covered, coverage: {
121
+ requested,
122
+ indexed: covered.length,
123
+ partial: covered.length !== requested,
124
+ } });
125
+ }
126
+ if (cmd.cmd !== "documents.search")
127
+ return (0, document_contract_1.documentFailure)("unsupported_tool");
128
+ if (typeof cmd.query !== "string" ||
129
+ !cmd.query.trim() ||
130
+ cmd.query.length > document_contract_1.DOCUMENT_LIMITS.query)
131
+ return (0, document_contract_1.documentFailure)("search_unavailable");
132
+ const prefixes = (0, document_contract_1.documentPaths)(cmd.prefixes, context, "prefixes");
133
+ const state = deps.queryState();
134
+ if (state !== "ready")
135
+ return (0, document_contract_1.documentFailure)(state);
136
+ recheck();
137
+ const encoded = yield deps.encode(cmd.query, signal);
138
+ recheck();
139
+ if (!encoded.dense.length || !encoded.dense.every(Number.isFinite))
140
+ return (0, document_contract_1.documentFailure)("embedding_unavailable");
141
+ const table = yield deps.table();
142
+ recheck();
143
+ const remainingMs = Math.floor(deadline - performance.now());
144
+ if (remainingMs <= 0)
145
+ throw new Error("timeout");
146
+ // Await the actual native promise, not a JS timeout race. The caller's
147
+ // bridge/signal has its own deadline; shared ownership must remain until
148
+ // native completion, even if the SDK fails to honor its native timeout.
149
+ const rows = (yield table
150
+ .vectorSearch(encoded.dense)
151
+ .distanceType("cosine")
152
+ .where(documentFilter(prefixes))
153
+ .select(["path", "hash", "start_line", "end_line", "_distance"])
154
+ .limit(document_contract_1.DOCUMENT_LIMITS.candidates)
155
+ .toArray({ timeoutMs: remainingMs }));
156
+ recheck();
157
+ const matches = rows.slice(0, document_contract_1.DOCUMENT_LIMITS.candidates).flatMap((row) => {
158
+ if (typeof row.path !== "string" ||
159
+ !prefixes.some((prefix) => row.path === prefix || row.path.startsWith(prefix + path.sep)))
160
+ return [];
161
+ const file = (0, document_contract_1.canonicalPointer)(row.path, context);
162
+ if (!file ||
163
+ !Number.isInteger(row.start_line) ||
164
+ row.start_line < 0 ||
165
+ !Number.isInteger(row.end_line) ||
166
+ row.end_line < row.start_line ||
167
+ !Number.isFinite(row._distance))
168
+ return [];
169
+ const entry = deps.meta(row.path);
170
+ // Only a matching current metadata revision proves this row's digest is bytes.
171
+ const hash = (entry === null || entry === void 0 ? void 0 : entry.hashVersion) === 1 &&
172
+ entry.hasVectors === true &&
173
+ row.hash === entry.hash &&
174
+ /^[a-f0-9]{64}$/.test(row.hash)
175
+ ? { hash: row.hash, hashAlgorithm: "sha256-bytes" }
176
+ : {};
177
+ return [
178
+ Object.assign({ path: file, startLine: row.start_line + 1, endLine: row.end_line + 1, score: 1 / (1 + Math.max(0, row._distance)) }, hash),
179
+ ];
180
+ });
181
+ return Object.assign(Object.assign({}, base), { indexState: (0, document_contract_1.documentIndexState)(deps.indexState(context.wireRoot)), matches, retrieval: "dense", candidateLimit: document_contract_1.DOCUMENT_LIMITS.candidates });
182
+ }
183
+ catch (error) {
184
+ const e = error;
185
+ return (0, document_contract_1.documentFailure)(signal.aborted
186
+ ? ((_b = signal.reason) === null || _b === void 0 ? void 0 : _b.name) === "TimeoutError"
187
+ ? "timeout"
188
+ : "cancelled"
189
+ : e.name === "QueryTimeoutError"
190
+ ? "timeout"
191
+ : ((_d = e.code) !== null && _d !== void 0 ? _d : e.message));
192
+ }
193
+ });
194
+ }
@@ -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),
@@ -133,13 +133,17 @@ function handleCommand(daemon, cmd, conn) {
133
133
  cmd.cmd !== "shutdown" &&
134
134
  (daemon.operationStatus() === "closing" ||
135
135
  daemon.operationStatus() === "closed")) {
136
- return errorResponse(new operation_coordinator_1.OperationClosedError());
136
+ return cmd.cmd === "documents.status" || cmd.cmd === "documents.search"
137
+ ? { ok: false, state: "busy" }
138
+ : errorResponse(new operation_coordinator_1.OperationClosedError());
137
139
  }
138
140
  // The socket listens before LanceDB/MetaCache are open so liveness probes
139
141
  // succeed during slow startup. Gate resource-dependent commands until those
140
142
  // stores exist; ping/shutdown must always work (probes + restart).
141
143
  if (cmd.cmd !== "ping" && cmd.cmd !== "shutdown" && !daemon.isReady()) {
142
- return { ok: false, error: "daemon initializing" };
144
+ return cmd.cmd === "documents.status" || cmd.cmd === "documents.search"
145
+ ? { ok: false, state: "index_unavailable" }
146
+ : { ok: false, error: "daemon initializing" };
143
147
  }
144
148
  switch (cmd.cmd) {
145
149
  case "ping":
@@ -157,6 +161,7 @@ function handleCommand(daemon, cmd, conn) {
157
161
  exclusiveGenerationRebuild: exports.EXCLUSIVE_GENERATION_REBUILD_PROTOCOL,
158
162
  readVerbs: read_verbs_1.READ_VERBS_PROTOCOL,
159
163
  searchDiagnostics: 1,
164
+ existingIndexOnlySearch: 1,
160
165
  perFileSearch: 1,
161
166
  // `watch`/`unwatch` accept holder/pid/ttlMs. A daemon without this
162
167
  // treats `unwatch` as unwatch-for-everyone, so clients releasing a
@@ -225,6 +230,28 @@ function handleCommand(daemon, cmd, conn) {
225
230
  setImmediate(() => daemon.shutdown());
226
231
  return { ok: true };
227
232
  }
233
+ case "documents.status":
234
+ case "documents.search": {
235
+ const ac = new AbortController();
236
+ const close = () => ac.abort();
237
+ conn.once("close", close);
238
+ try {
239
+ return yield daemon.documentSearch(cmd, ac.signal);
240
+ }
241
+ catch (error) {
242
+ return {
243
+ ok: false,
244
+ state: ac.signal.aborted
245
+ ? "cancelled"
246
+ : error instanceof operation_coordinator_1.OperationBusyError
247
+ ? "busy"
248
+ : "index_unavailable",
249
+ };
250
+ }
251
+ finally {
252
+ conn.off("close", close);
253
+ }
254
+ }
228
255
  case "search":
229
256
  case "search-v2": {
230
257
  const isV2 = cmd.cmd === "search-v2";
@@ -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())