token-goat 2.9.11 → 2.9.13

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.
Files changed (25) hide show
  1. package/README.md +7 -1
  2. package/dist/{token-goat-chunk-FDURVZQD.mjs → token-goat-chunk-2WC4ZUXN.mjs} +1 -1
  3. package/dist/{token-goat-chunk-MRZ555B3.mjs → token-goat-chunk-3ESRORNM.mjs} +188 -97
  4. package/dist/token-goat-chunk-4NXUKV7D.mjs +56 -0
  5. package/dist/{token-goat-chunk-Y5VKNLVD.mjs → token-goat-chunk-6B44WLIF.mjs} +5 -5
  6. package/dist/{token-goat-chunk-2ZUPQYLO.mjs → token-goat-chunk-B3CTCQTH.mjs} +1 -1
  7. package/dist/{token-goat-chunk-V53Z47ZH.mjs → token-goat-chunk-FQCNJV4V.mjs} +20 -6
  8. package/dist/{token-goat-chunk-3ZALKJ23.mjs → token-goat-chunk-FZU7GMUS.mjs} +49 -24
  9. package/dist/{token-goat-chunk-AAEYU2U2.mjs → token-goat-chunk-JOXLE672.mjs} +344 -5699
  10. package/dist/{token-goat-chunk-HDL77BN3.mjs → token-goat-chunk-JVNPCQB7.mjs} +10 -7
  11. package/dist/{token-goat-chunk-LHLQFGWQ.mjs → token-goat-chunk-OMNQUUIT.mjs} +9 -27
  12. package/dist/{token-goat-chunk-PJPFOOGM.mjs → token-goat-chunk-P2PU4CR5.mjs} +8 -6
  13. package/dist/{token-goat-chunk-YCKCFYTM.mjs → token-goat-chunk-QKXBGBQR.mjs} +110 -21
  14. package/dist/{token-goat-chunk-MKITQ5RY.mjs → token-goat-chunk-QWSUZWFP.mjs} +44 -33
  15. package/dist/{token-goat-chunk-4NZUXC4F.mjs → token-goat-chunk-RDITECDL.mjs} +7 -5
  16. package/dist/{token-goat-chunk-LKOYKSID.mjs → token-goat-chunk-U7X6LQD2.mjs} +271 -69
  17. package/dist/token-goat-chunk-UM47DRD3.mjs +242 -0
  18. package/dist/token-goat-chunk-UMXJN7DI.mjs +5521 -0
  19. package/dist/token-goat-chunk-YOA4N6WA.mjs +308 -0
  20. package/dist/{token-goat-chunk-SY7WTZMW.mjs → token-goat-chunk-ZZI3IDQZ.mjs} +1016 -995
  21. package/dist/token-goat-hook.mjs +8 -6
  22. package/dist/token-goat.core.mjs +10 -7
  23. package/docs/cli.md +11 -8
  24. package/docs/security.md +1 -1
  25. package/package.json +1 -1
@@ -1,30 +1,5 @@
1
1
  import { createRequire as __cjsRequire } from 'node:module';
2
2
  const require = __cjsRequire(import.meta.url);
3
- import {
4
- IMPORT_RE,
5
- extractAbap,
6
- extractAbl,
7
- extractAsm,
8
- extractBatch,
9
- extractCShader,
10
- extractCmake,
11
- extractCobol,
12
- extractErlang,
13
- extractFortran,
14
- extractGroovy,
15
- extractJcl,
16
- extractMatlab,
17
- extractNatural,
18
- extractObjc,
19
- extractPascal,
20
- extractPerl,
21
- extractPli,
22
- extractRpg,
23
- extractSas,
24
- extractSolidity,
25
- extractThrift,
26
- stripLeadingAttributes
27
- } from "./token-goat-chunk-2ZUPQYLO.mjs";
28
3
  import {
29
4
  DEFAULT_QUERY_LIMIT,
30
5
  ImageDecodeError,
@@ -53,20 +28,14 @@ import {
53
28
  getTrackedFiles,
54
29
  indexFileSync,
55
30
  isAvailable,
56
- isBlobStale,
57
31
  isImagePath,
58
32
  isIndexEmptyForProject,
59
- isOcrEngineAvailable,
60
33
  isPrivateIpv4Octets,
61
34
  isPrivateIpv6Groups,
62
- isTextHeavy,
63
35
  isTreeSitterAvailable,
64
36
  listSections,
65
- loadBlob,
66
37
  locatePdfPages,
67
38
  mergeNearbyHits,
68
- ocrImage,
69
- ocrIntegrityFailed,
70
39
  parseIpv6Groups,
71
40
  parseWhereSpecs,
72
41
  pathEqClause,
@@ -84,21 +53,34 @@ import {
84
53
  searchSemantic,
85
54
  searchSymbolsFts,
86
55
  shrinkImage,
87
- storeBlob,
88
56
  unzipBounded,
89
57
  urlPolicyDenialReason,
90
58
  walkProject
91
- } from "./token-goat-chunk-SY7WTZMW.mjs";
59
+ } from "./token-goat-chunk-ZZI3IDQZ.mjs";
60
+ import {
61
+ capJsonRows,
62
+ estimateTokens,
63
+ trimToBudget
64
+ } from "./token-goat-chunk-JOXLE672.mjs";
65
+ import {
66
+ isOcrEngineAvailable,
67
+ isTextHeavy,
68
+ ocrImage,
69
+ ocrIntegrityFailed
70
+ } from "./token-goat-chunk-YOA4N6WA.mjs";
71
+ import {
72
+ isBlobStale,
73
+ loadBlob,
74
+ storeBlob
75
+ } from "./token-goat-chunk-UM47DRD3.mjs";
92
76
  import {
93
77
  Database,
94
78
  FILENAME_LANGUAGE,
95
79
  TREE_SITTER_LANGUAGES,
96
80
  basenameImportsExtension,
97
- capJsonRows,
98
81
  colorStdout,
99
82
  detectLanguage,
100
83
  detectLanguageOfFile,
101
- estimateTokens,
102
84
  fileIsAbsent,
103
85
  findProject,
104
86
  fingerprintContent,
@@ -115,13 +97,38 @@ import {
115
97
  savedTokensFromBytes,
116
98
  shortFingerprint,
117
99
  stripAnsi,
118
- trimToBudget,
119
100
  unsupportedLanguageName
120
- } from "./token-goat-chunk-AAEYU2U2.mjs";
101
+ } from "./token-goat-chunk-UMXJN7DI.mjs";
121
102
  import {
122
103
  registerReset
123
104
  } from "./token-goat-chunk-EEIDFMEM.mjs";
124
105
  import {
106
+ IMPORT_RE,
107
+ extractAbap,
108
+ extractAbl,
109
+ extractAsm,
110
+ extractBatch,
111
+ extractCShader,
112
+ extractCmake,
113
+ extractCobol,
114
+ extractErlang,
115
+ extractFortran,
116
+ extractGroovy,
117
+ extractJcl,
118
+ extractMatlab,
119
+ extractNatural,
120
+ extractObjc,
121
+ extractPascal,
122
+ extractPerl,
123
+ extractPli,
124
+ extractRpg,
125
+ extractSas,
126
+ extractSolidity,
127
+ extractThrift,
128
+ stripLeadingAttributes
129
+ } from "./token-goat-chunk-B3CTCQTH.mjs";
130
+ import {
131
+ NOTEBOOK_CELL_LINES_SUFFIX,
125
132
  PER_FILE_COUNTERFACTUAL_CEILING,
126
133
  UNTRUSTED_FILE_TAG,
127
134
  UNTRUSTED_GITHUB_TAG,
@@ -143,8 +150,10 @@ import {
143
150
  filtersFilteredToEmptyNotice,
144
151
  foldCaseForContainment,
145
152
  foldPath,
153
+ formatSymbolLocation,
146
154
  globalDbPath,
147
155
  grepFilteredToEmptyNotice,
156
+ indexedSourceText,
148
157
  isAblSource,
149
158
  isInsideRoot,
150
159
  isMatlabSource,
@@ -154,6 +163,7 @@ import {
154
163
  isPerlSource,
155
164
  isPrologSource,
156
165
  isTestFile,
166
+ isVirtualIndexedPath,
157
167
  normalizePath,
158
168
  pushAll,
159
169
  redactUrlQuery,
@@ -166,9 +176,10 @@ import {
166
176
  stripBom,
167
177
  supportRequestLine,
168
178
  toDisplayPath,
179
+ virtualIndexedScopeNote,
169
180
  windowsCmdQuoteArg,
170
181
  withExtension
171
- } from "./token-goat-chunk-YCKCFYTM.mjs";
182
+ } from "./token-goat-chunk-QKXBGBQR.mjs";
172
183
  import {
173
184
  init_define_import_meta_env
174
185
  } from "./token-goat-chunk-A37V4PBF.mjs";
@@ -285,18 +296,101 @@ function formatJsonOutline(outline) {
285
296
  }
286
297
  return lines.join("\n");
287
298
  }
299
+ var MAX_RECURSIVE_NODES = 5e4;
300
+ var MAX_RECURSIVE_DEPTH = 100;
301
+ function collectRecursiveKey(root, keyName, out, budget) {
302
+ const seen = /* @__PURE__ */ new Set();
303
+ function walk(val, depth) {
304
+ if (depth > MAX_RECURSIVE_DEPTH) {
305
+ budget.exhausted = true;
306
+ return;
307
+ }
308
+ if (val === null || typeof val !== "object") return;
309
+ if (seen.has(val)) return;
310
+ seen.add(val);
311
+ if (budget.nodesLeft <= 0) {
312
+ budget.exhausted = true;
313
+ return;
314
+ }
315
+ budget.nodesLeft--;
316
+ if (Array.isArray(val)) {
317
+ for (let i = 0; i < val.length; i++) {
318
+ walk(val[i], depth + 1);
319
+ if (budget.nodesLeft <= 0) {
320
+ if (i < val.length - 1) budget.exhausted = true;
321
+ return;
322
+ }
323
+ }
324
+ } else {
325
+ const obj = val;
326
+ if (Object.prototype.hasOwnProperty.call(obj, keyName)) {
327
+ out.push(obj[keyName]);
328
+ }
329
+ const keys = Object.keys(obj);
330
+ for (let i = 0; i < keys.length; i++) {
331
+ walk(obj[keys[i]], depth + 1);
332
+ if (budget.nodesLeft <= 0) {
333
+ if (i < keys.length - 1) budget.exhausted = true;
334
+ return;
335
+ }
336
+ }
337
+ }
338
+ }
339
+ walk(root, 0);
340
+ }
341
+ function getNestedField(obj, fieldPath) {
342
+ if (obj === null || typeof obj !== "object") return void 0;
343
+ if (Object.prototype.hasOwnProperty.call(obj, fieldPath)) {
344
+ return obj[fieldPath];
345
+ }
346
+ const parts = fieldPath.split(".");
347
+ let cur = obj;
348
+ for (const part of parts) {
349
+ if (cur === null || typeof cur !== "object") return void 0;
350
+ if (!Object.prototype.hasOwnProperty.call(cur, part)) return void 0;
351
+ cur = cur[part];
352
+ }
353
+ return cur;
354
+ }
288
355
  function parseJsonPath(spec) {
289
356
  const ops = [];
290
357
  const n = spec.length;
291
358
  let i = 0;
292
359
  while (i < n) {
360
+ if (spec[i] === "." && i + 1 < n && spec[i + 1] === ".") {
361
+ i += 2;
362
+ let j2 = i;
363
+ while (j2 < n && spec[j2] !== "." && spec[j2] !== "[") j2++;
364
+ if (j2 === i) throw new Error(`invalid path spec: expected property name after '..' in '${spec}'`);
365
+ ops.push({ kind: "recursive_key", name: spec.slice(i, j2) });
366
+ i = j2;
367
+ continue;
368
+ }
293
369
  const ch = spec[i];
294
370
  if (ch === ".") {
295
371
  i++;
296
372
  continue;
297
373
  }
298
374
  if (ch === "[") {
299
- const close = spec.indexOf("]", i);
375
+ let inQuote = null;
376
+ let close = -1;
377
+ for (let k = i + 1; k < n; k++) {
378
+ const c = spec[k];
379
+ if (inQuote !== null) {
380
+ if (c === "\\") {
381
+ k++;
382
+ continue;
383
+ }
384
+ if (c === inQuote) {
385
+ inQuote = null;
386
+ }
387
+ } else if (c === '"' || c === "'") {
388
+ inQuote = c;
389
+ } else if (c === "]") {
390
+ close = k;
391
+ break;
392
+ }
393
+ }
300
394
  if (close === -1) throw new Error(`invalid path spec: unterminated '[' in '${spec}'`);
301
395
  const inner = spec.slice(i + 1, close);
302
396
  if (inner === "*") {
@@ -304,9 +398,34 @@ function parseJsonPath(spec) {
304
398
  } else if (/^-?\d+$/.test(inner)) {
305
399
  ops.push({ kind: "index", index: Number(inner) });
306
400
  } else {
307
- const m = /^([^=]+)=(.*)$/.exec(inner);
308
- if (!m) throw new Error(`invalid bracket expression '[${inner}]' in path spec: '${spec}' (expected [n], [*], or [field=value])`);
309
- ops.push({ kind: "filter", field: m[1].trim(), value: m[2] });
401
+ let expr = inner.trim();
402
+ if (expr.startsWith("?(") && expr.endsWith(")")) {
403
+ expr = expr.slice(2, -1).trim();
404
+ }
405
+ if (expr.startsWith("@.")) {
406
+ expr = expr.slice(2).trim();
407
+ }
408
+ const m = /^([^=]+)==?(.*)$/.exec(expr);
409
+ if (!m) {
410
+ const bareOperator = /[<>]/.exec(expr);
411
+ if (bareOperator !== null) {
412
+ throw new Error(`unsupported comparison operator '${bareOperator[0]}' in '[${inner}]' of path spec '${spec}': this grammar filters by equality only ([field=value])`);
413
+ }
414
+ throw new Error(`invalid bracket expression '[${inner}]' in path spec: '${spec}' (expected [n], [*], or [field=value])`);
415
+ }
416
+ let field = m[1].trim();
417
+ if (field.startsWith("@.")) field = field.slice(2).trim();
418
+ const swallowedOperator = /[!<>]$/.exec(field);
419
+ if (swallowedOperator !== null) {
420
+ throw new Error(`unsupported comparison operator '${swallowedOperator[0]}=' in '[${inner}]' of path spec '${spec}': this grammar filters by equality only ([field=value])`);
421
+ }
422
+ let rawVal = m[2].trim();
423
+ if (rawVal.startsWith('"') && rawVal.endsWith('"') || rawVal.startsWith("'") && rawVal.endsWith("'")) {
424
+ if (rawVal.length >= 2) {
425
+ rawVal = rawVal.slice(1, -1).replace(/\\(["'\\])/g, "$1");
426
+ }
427
+ }
428
+ ops.push({ kind: "filter", field, value: rawVal });
310
429
  }
311
430
  i = close + 1;
312
431
  continue;
@@ -322,6 +441,7 @@ function parseJsonPath(spec) {
322
441
  function evalJsonPath(data, ops) {
323
442
  let current = [data];
324
443
  let fanned = false;
444
+ const budget = { nodesLeft: MAX_RECURSIVE_NODES, exhausted: false };
325
445
  for (const op of ops) {
326
446
  const next = [];
327
447
  for (const item of current) {
@@ -331,6 +451,9 @@ function evalJsonPath(data, ops) {
331
451
  } else if (!fanned) {
332
452
  throw new Error(`path not found: key '${op.name}' does not exist on ${jsonType(item)} value`);
333
453
  }
454
+ } else if (op.kind === "recursive_key") {
455
+ fanned = true;
456
+ collectRecursiveKey(item, op.name, next, budget);
334
457
  } else if (op.kind === "index") {
335
458
  if (Array.isArray(item)) {
336
459
  const idx = op.index < 0 ? item.length + op.index : op.index;
@@ -353,8 +476,11 @@ function evalJsonPath(data, ops) {
353
476
  fanned = true;
354
477
  if (Array.isArray(item)) {
355
478
  for (const el of item) {
356
- if (typeof el === "object" && el !== null && !Array.isArray(el) && String(el[op.field]) === op.value) {
357
- next.push(el);
479
+ if (typeof el === "object" && el !== null && !Array.isArray(el)) {
480
+ const val = getNestedField(el, op.field);
481
+ if (val !== void 0 && String(val) === op.value) {
482
+ next.push(el);
483
+ }
358
484
  }
359
485
  }
360
486
  }
@@ -362,7 +488,7 @@ function evalJsonPath(data, ops) {
362
488
  }
363
489
  current = next;
364
490
  }
365
- return { fanned, items: current };
491
+ return { fanned, items: current, truncated: budget.exhausted };
366
492
  }
367
493
  function queryJson(data, spec) {
368
494
  return evalJsonPath(data, parseJsonPath(spec));
@@ -4406,7 +4532,7 @@ function quoteIdent(name) {
4406
4532
  function getSqliteSchema(filePath) {
4407
4533
  const db = openReadonlySqlite(filePath);
4408
4534
  try {
4409
- const objects = db.prepare("SELECT name, type FROM sqlite_master WHERE type IN ('table','view') AND name NOT LIKE 'sqlite_%' ORDER BY name").all();
4535
+ const objects = db.prepare("SELECT name, type FROM sqlite_master WHERE type IN ('table','view') AND name NOT LIKE 'sqlite\\_%' ESCAPE '\\' ORDER BY name").all();
4410
4536
  const tables = objects.map((o) => {
4411
4537
  const columns = db.prepare(`PRAGMA table_info(${quoteIdent(o.name)})`).all().map(
4412
4538
  (c) => ({
@@ -4461,6 +4587,50 @@ function formatSqliteSchema(result) {
4461
4587
  return lines.join("\n");
4462
4588
  }).join("\n\n");
4463
4589
  }
4590
+ function getSqliteTables(filePath) {
4591
+ const db = openReadonlySqlite(filePath);
4592
+ try {
4593
+ const objects = db.prepare(
4594
+ // ESCAPE makes every `_` literal; see getSqliteSchema above. Here it costs three tables rather than one, since `%_fts_%` and `%_vec0_%` exist to hide the shadow tables FTS5 and sqlite-vec create beside a virtual table, and unescaped they also hide anything of the shape `my_ftsx_cache`.
4595
+ "SELECT name, type FROM sqlite_master WHERE type IN ('table','view') AND name NOT LIKE 'sqlite\\_%' ESCAPE '\\' AND name NOT LIKE '%\\_fts\\_%' ESCAPE '\\' AND name NOT LIKE '%\\_vec0\\_%' ESCAPE '\\' ORDER BY name"
4596
+ ).all();
4597
+ return objects.map((o) => {
4598
+ let columnCount;
4599
+ try {
4600
+ const cols = db.prepare(`PRAGMA table_info(${quoteIdent(o.name)})`).all();
4601
+ columnCount = cols.length;
4602
+ } catch {
4603
+ columnCount = 0;
4604
+ }
4605
+ let rowCount;
4606
+ try {
4607
+ const row = db.prepare(`SELECT COUNT(*) AS c FROM ${quoteIdent(o.name)}`).get();
4608
+ rowCount = row.c;
4609
+ } catch {
4610
+ rowCount = null;
4611
+ }
4612
+ return {
4613
+ name: o.name,
4614
+ kind: o.type === "view" ? "view" : "table",
4615
+ rowCount,
4616
+ columnCount
4617
+ };
4618
+ });
4619
+ } finally {
4620
+ db.close();
4621
+ }
4622
+ }
4623
+ function formatSqliteTables(tables) {
4624
+ if (tables.length === 0) return "(no tables or views found)";
4625
+ return tables.map((t) => {
4626
+ const parts = [t.kind];
4627
+ if (t.rowCount !== null) {
4628
+ parts.push(`${t.rowCount.toLocaleString()} row${t.rowCount === 1 ? "" : "s"}`);
4629
+ }
4630
+ parts.push(`${t.columnCount} col${t.columnCount === 1 ? "" : "s"}`);
4631
+ return `${displaySafeText(t.name)} (${parts.join(", ")})`;
4632
+ }).join("\n");
4633
+ }
4464
4634
  var FORBIDDEN_KEYWORDS = [
4465
4635
  "INSERT",
4466
4636
  "UPDATE",
@@ -5420,7 +5590,7 @@ function resolveSymbolMatch(filePath, symbolName, dbPath = globalDbPath()) {
5420
5590
  }
5421
5591
  function bodyFromSource(entry) {
5422
5592
  try {
5423
- return fs3.readFileSync(entry.filePath, "utf8").split(/\r?\n/).slice(Math.max(0, entry.lineStart - 1), entry.lineEnd).join("\n");
5593
+ return indexedSourceText(entry.filePath, fs3.readFileSync(entry.filePath, "utf8")).split(/\r?\n/).slice(Math.max(0, entry.lineStart - 1), entry.lineEnd).join("\n");
5424
5594
  } catch {
5425
5595
  return "";
5426
5596
  }
@@ -5617,7 +5787,7 @@ function refMatchesDefinition(ts, checker, sourceFile, ref, symbolName, defSymbo
5617
5787
  }
5618
5788
  const node = findIdentifierNearPosition(ts, sourceFile, line0, position, symbolName);
5619
5789
  if (node === null) return null;
5620
- let symbol = checker.getSymbolAtLocation(node);
5790
+ let symbol = ts.isShorthandPropertyAssignment(node.parent) ? checker.getShorthandAssignmentValueSymbol(node.parent) : checker.getSymbolAtLocation(node);
5621
5791
  if (symbol === void 0) return null;
5622
5792
  if (symbol.flags & ts.SymbolFlags.Alias) {
5623
5793
  try {
@@ -5835,7 +6005,7 @@ function resolveBody(entry) {
5835
6005
  if (entry.body !== "") return entry.body;
5836
6006
  const source = readFileText(entry.filePath);
5837
6007
  if (source === null) return entry.body;
5838
- return source.split(/\r?\n/).slice(Math.max(0, entry.lineStart - 1), entry.lineEnd).join("\n");
6008
+ return indexedSourceText(entry.filePath, source).split(/\r?\n/).slice(Math.max(0, entry.lineStart - 1), entry.lineEnd).join("\n");
5839
6009
  }
5840
6010
  var STALE_WARNING = "\u26A0 STALE: index is older than the file on disk (worker hasn't reindexed yet \u2014 retry shortly, or read the file directly)";
5841
6011
  var DELETED_WARNING = "\u26A0 DELETED: this file is no longer on disk \u2014 what follows is what the index last saw of it";
@@ -6240,7 +6410,7 @@ function runSymbol(opts) {
6240
6410
  const exactMatches = rawSymbols.filter((s) => s.name === opts.name);
6241
6411
  if (exactMatches.length > 0) {
6242
6412
  const shown = exactMatches.slice(0, DIDYOUMEAN_LIMIT);
6243
- const where = shown.map((s) => `${s.kind} at ${toDisplayPath(rootDir, s.filePath)}:${s.lineStart}`).join("; ");
6413
+ const where = shown.map((s) => `${s.kind} at ${formatSymbolLocation(toDisplayPath(rootDir, s.filePath), s.lineStart)}`).join("; ");
6244
6414
  const more = exactMatches.length > shown.length ? ` (+${exactMatches.length - shown.length} more)` : "";
6245
6415
  const flags = [opts.kind !== void 0 ? "--kind" : null, opts.file !== void 0 ? "--file" : null].filter((f) => f !== null);
6246
6416
  const widen = flags.length > 0 ? `drop ${flags.join("/")} to see it` : "widen the search scope to see it";
@@ -6300,7 +6470,7 @@ ${emptyIndexMessage(emptyIndexRoot)}`;
6300
6470
  const blocks = results.map((sym) => {
6301
6471
  const statsStr = formatStatsSuffix(refCounts, sym);
6302
6472
  const goneTag = fileIsGone(sym.filePath) ? ` ${DELETED_TAG}` : "";
6303
- const header = `# ${sym.name} (${sym.kind}) \u2014 ${toDisplayPath(symbolDisplayRoot, sym.filePath)}:${sym.lineStart}-${sym.lineEnd}${statsStr}${goneTag}`;
6473
+ const header = `# ${sym.name} (${sym.kind}) \u2014 ${formatSymbolLocation(toDisplayPath(symbolDisplayRoot, sym.filePath), sym.lineStart, sym.lineEnd)}${statsStr}${goneTag}`;
6304
6474
  const body = resolveBody(sym);
6305
6475
  const bodyLines = body.split(/\r?\n/);
6306
6476
  const preview = bodyLines.slice(0, SYMBOL_PREVIEW_LINES).join("\n");
@@ -7332,7 +7502,8 @@ function runOutline(opts) {
7332
7502
  const bodyLen = sym.lineEnd - sym.lineStart + 1;
7333
7503
  const docFirst = hasRealDocstring(sym.docstring) ? ` # ${clipDocSummary(sym.docstring.split("\n")[0] ?? "")}` : "";
7334
7504
  const statsStr = formatStatsSuffix(refCounts, sym);
7335
- lines.push(` ${rangeStr} ${kindStr} ${sym.name} (${bodyLen}\u2113)${docFirst}${statsStr}`);
7505
+ const notebookSuffix = isVirtualIndexedPath(sym.filePath) ? NOTEBOOK_CELL_LINES_SUFFIX : "";
7506
+ lines.push(` ${rangeStr} ${kindStr} ${sym.name} (${bodyLen}\u2113)${docFirst}${statsStr}${notebookSuffix}`);
7336
7507
  }
7337
7508
  const text = guardText(staleWarning(resolved) + lines.join("\n"), "symbol");
7338
7509
  recordReadStat("outline", fullSourceBytes, text, opts.file);
@@ -7473,7 +7644,7 @@ function runQueryCommand(opts, parse, formatLabel, guardTag, kind) {
7473
7644
  const headTruncated = limited.length < totalCount;
7474
7645
  if (opts.json === true) {
7475
7646
  const capped = guardJsonRows(limited);
7476
- const jsonText = displaySafeJson({ items: capped.items, truncated: capped.truncated || headTruncated, totalCount }, 0);
7647
+ const jsonText = displaySafeJson({ items: capped.items, truncated: capped.truncated || headTruncated || result.truncated, totalCount }, 0);
7477
7648
  emit(jsonText);
7478
7649
  recordReadStat(kind, fullSourceBytes, jsonText, opts.file);
7479
7650
  } else {
@@ -7481,6 +7652,9 @@ function runQueryCommand(opts, parse, formatLabel, guardTag, kind) {
7481
7652
  if (headTruncated) {
7482
7653
  lines.push(`...(${totalCount - limited.length} more items elided; use --head to see more)`);
7483
7654
  }
7655
+ if (result.truncated) {
7656
+ lines.push(`...(the search stopped early at this tool's traversal limit; these are not necessarily all the matches. Narrow the path to search less of the document.)`);
7657
+ }
7484
7658
  const plainText = lines.join("\n");
7485
7659
  emitGuarded(plainText, guardTag);
7486
7660
  recordReadStat(kind, fullSourceBytes, plainText, opts.file);
@@ -8093,6 +8267,25 @@ function runSqliteSchema(opts) {
8093
8267
  return 1;
8094
8268
  }
8095
8269
  }
8270
+ function runSqliteTables(opts) {
8271
+ try {
8272
+ const tables = getSqliteTables(opts.file);
8273
+ const fullSourceBytes = sumFileSizes([opts.file]);
8274
+ if (opts.json === true) {
8275
+ const jsonText = displaySafeJson(tables, 0);
8276
+ emit(jsonText);
8277
+ recordReadStat("sqlite_tables", fullSourceBytes, jsonText, opts.file);
8278
+ } else {
8279
+ const text = formatSqliteTables(tables);
8280
+ emit(text);
8281
+ recordReadStat("sqlite_tables", fullSourceBytes, text, opts.file);
8282
+ }
8283
+ return 0;
8284
+ } catch (e) {
8285
+ emitErr(extractErrorMessage(e));
8286
+ return 1;
8287
+ }
8288
+ }
8096
8289
  function runSqliteQuery(opts) {
8097
8290
  let head;
8098
8291
  try {
@@ -8254,7 +8447,7 @@ async function runImageMeta(file) {
8254
8447
  shrunkBytes: shrink !== null ? shrink.shrunkBytes : null
8255
8448
  };
8256
8449
  }
8257
- async function runImageText(file) {
8450
+ async function runImageText(file, lang) {
8258
8451
  if (!fileExists(file)) {
8259
8452
  throw new Error(`Could not read: ${file}`);
8260
8453
  }
@@ -8262,7 +8455,7 @@ async function runImageText(file) {
8262
8455
  throw new Error(`Not an image file: ${file}`);
8263
8456
  }
8264
8457
  const data = fs4.readFileSync(file);
8265
- const ocr = await ocrImage(data);
8458
+ const ocr = await ocrImage(data, lang);
8266
8459
  if (ocr === null) {
8267
8460
  if (ocrIntegrityFailed()) {
8268
8461
  throw new Error(`${file} was not OCRed: the cached language model failed its checksum and was discarded, so the next run re-downloads it`);
@@ -8349,7 +8542,7 @@ ${emptyIndexMessage(rootDir2)}`, code: 1 };
8349
8542
  const bodyLen = match.lineEnd - match.lineStart + 1;
8350
8543
  const lines = [
8351
8544
  // This header is token-goat's own line quoting a repo-chosen name, kind and path, so it is escaped. `body` below it is the source the reader asked for and stays byte-for-byte.
8352
- `# ${displaySafeText(match.name)} ${displaySafeText(match.kind)} ${displaySafeText(toDisplayPath(rootDir, match.filePath))}:${match.lineStart}-${match.lineEnd}`,
8545
+ `# ${displaySafeText(match.name)} ${displaySafeText(match.kind)} ${formatSymbolLocation(displaySafeText(toDisplayPath(rootDir, match.filePath)), match.lineStart, match.lineEnd)}`,
8353
8546
  `# ${countNoun(bodyLen, "line")} (~${Math.ceil(body.length / 4)} tok)`,
8354
8547
  body,
8355
8548
  ""
@@ -8669,7 +8862,7 @@ function runChanged(opts = {}) {
8669
8862
  for (const f of changedFiles) {
8670
8863
  const fileSymbols = querySymbols({ filePath: resolveIndexPath(f, projectRoot), limit: FIND_SCAN_LIMIT });
8671
8864
  const hunks = hunksByFile.get(f);
8672
- const scoped = hunks === void 0 ? fileSymbols : fileSymbols.filter((s) => hunks.some((h) => h.start <= s.lineEnd && h.end >= s.lineStart));
8865
+ const scoped = hunks === void 0 || isVirtualIndexedPath(f) ? fileSymbols : fileSymbols.filter((s) => hunks.some((h) => h.start <= s.lineEnd && h.end >= s.lineStart));
8673
8866
  allSymbols.push(...scoped);
8674
8867
  }
8675
8868
  if (allSymbols.length === 0) {
@@ -8685,9 +8878,9 @@ function runChanged(opts = {}) {
8685
8878
  recordReadStat("changed_lookup", symbolFullBytes, text, ref);
8686
8879
  return 0;
8687
8880
  }
8688
- const symbolText = allSymbols.map((s) => `${s.name} (${s.kind}) \u2014 ${toDisplayPath(projectRoot, s.filePath)}:${s.lineStart}`).join("\n");
8881
+ const symbolText = allSymbols.map((s) => `${s.name} (${s.kind}) \u2014 ${formatSymbolLocation(toDisplayPath(projectRoot, s.filePath), s.lineStart)}`).join("\n");
8689
8882
  for (const s of allSymbols) {
8690
- emit(`${displaySafeText(s.name)} (${displaySafeText(s.kind)}) \u2014 ${displaySafeText(toDisplayPath(projectRoot, s.filePath))}:${s.lineStart}`);
8883
+ emit(`${displaySafeText(s.name)} (${displaySafeText(s.kind)}) \u2014 ${formatSymbolLocation(displaySafeText(toDisplayPath(projectRoot, s.filePath)), s.lineStart)}`);
8691
8884
  }
8692
8885
  recordReadStat("changed_lookup", symbolFullBytes, symbolText, ref);
8693
8886
  return 0;
@@ -8800,7 +8993,8 @@ function runDiff(opts) {
8800
8993
  return 0;
8801
8994
  }
8802
8995
  const { hunks } = splitDiffHunks(diffResult.stdout);
8803
- const overlapping = hunks.filter((h) => h.start <= match.lineEnd && h.end >= match.lineStart);
8996
+ const diffFileScoped = isVirtualIndexedPath(match.filePath);
8997
+ const overlapping = diffFileScoped ? hunks : hunks.filter((h) => h.start <= match.lineEnd && h.end >= match.lineStart);
8804
8998
  if (overlapping.length === 0) {
8805
8999
  emit(`No changes to '${displaySafeText(match.name)}' (lines ${match.lineStart}-${match.lineEnd}) in '${displaySafeText(toDisplayPath(getDisplayRoot(opts.projectRoot), match.filePath))}'.`);
8806
9000
  return 0;
@@ -8822,8 +9016,9 @@ function runDiff(opts) {
8822
9016
  );
8823
9017
  return 0;
8824
9018
  }
8825
- const header = `# ${displaySafeText(match.name)} (${displaySafeText(match.kind)}) \u2014 ${displaySafeText(toDisplayPath(getDisplayRoot(opts.projectRoot), match.filePath))}:${match.lineStart}-${match.lineEnd}`;
8826
- emit(guardText([header, ...overlapping.map((h) => h.text)].join("\n"), "diff"));
9019
+ const header = `# ${displaySafeText(match.name)} (${displaySafeText(match.kind)}) \u2014 ${formatSymbolLocation(displaySafeText(toDisplayPath(getDisplayRoot(opts.projectRoot), match.filePath)), match.lineStart, match.lineEnd)}`;
9020
+ const diffNote = diffFileScoped ? [virtualIndexedScopeNote(displaySafeText(toDisplayPath(getDisplayRoot(opts.projectRoot), match.filePath)), "these hunks cover the whole file rather than this symbol alone")] : [];
9021
+ emit(guardText([header, ...diffNote, ...overlapping.map((h) => h.text)].join("\n"), "diff"));
8827
9022
  return 0;
8828
9023
  }
8829
9024
  var DEFAULT_LOG_MAX_COUNT = 20;
@@ -8873,7 +9068,8 @@ function runLog(opts) {
8873
9068
  if (match === null) return 1;
8874
9069
  const cwd = opts.projectRoot ?? process.cwd();
8875
9070
  const maxCount = opts.maxCount ?? DEFAULT_LOG_MAX_COUNT;
8876
- const logArgs = [
9071
+ const fileScoped = isVirtualIndexedPath(match.filePath);
9072
+ const logArgs = fileScoped ? ["log", `--max-count=${maxCount}`, ...opts.ref !== void 0 ? [opts.ref] : [], "--", match.filePath] : [
8877
9073
  "log",
8878
9074
  `-L${match.lineStart},${match.lineEnd}:${match.filePath}`,
8879
9075
  `--max-count=${maxCount}`,
@@ -8911,8 +9107,9 @@ function runLog(opts) {
8911
9107
  );
8912
9108
  return 0;
8913
9109
  }
8914
- const header = `# ${displaySafeText(match.name)} (${displaySafeText(match.kind)}) \u2014 ${displaySafeText(toDisplayPath(getDisplayRoot(opts.projectRoot), match.filePath))}:${match.lineStart}-${match.lineEnd}`;
8915
- emit(guardText([header, logResult.stdout].join("\n"), "diff"));
9110
+ const header = `# ${displaySafeText(match.name)} (${displaySafeText(match.kind)}) \u2014 ${formatSymbolLocation(displaySafeText(toDisplayPath(getDisplayRoot(opts.projectRoot), match.filePath)), match.lineStart, match.lineEnd)}`;
9111
+ const logNote = fileScoped ? [virtualIndexedScopeNote(displaySafeText(toDisplayPath(getDisplayRoot(opts.projectRoot), match.filePath)), "this history covers the whole file rather than this symbol alone")] : [];
9112
+ emit(guardText([header, ...logNote, logResult.stdout].join("\n"), "diff"));
8916
9113
  return 0;
8917
9114
  }
8918
9115
  function foldRealpath(p) {
@@ -9051,9 +9248,12 @@ function runGrep(opts) {
9051
9248
  syms = querySymbols({ filePath: resolveIndexPath(hit.file), limit: ALL_SYMBOLS_IN_FILE_LIMIT });
9052
9249
  symbolsByFile.set(hit.file, syms);
9053
9250
  }
9054
- const enc = enclosingSymbol(syms, hit.line);
9251
+ const enc = isVirtualIndexedPath(hit.file) ? null : enclosingSymbol(syms, hit.line);
9055
9252
  hit.symbol = enc === null ? null : { name: enc.name, kind: enc.kind, lineStart: enc.lineStart, lineEnd: enc.lineEnd };
9056
9253
  }
9254
+ for (const file of new Set(truncated.map((h) => h.file).filter(isVirtualIndexedPath))) {
9255
+ emit(virtualIndexedScopeNote(displaySafeText(file), "a match in it cannot be attributed to a symbol and these hits carry no label"));
9256
+ }
9057
9257
  }
9058
9258
  if (opts.json === true) {
9059
9259
  const payload = { items: truncated, truncated: hits.length > maxLines, totalCount: hits.length };
@@ -11142,7 +11342,7 @@ function runTypes(opts) {
11142
11342
  emit2(`${countNoun(filtered.length, "type declaration")} (${excludeTestsHiddenNote(suppressed)})`);
11143
11343
  }
11144
11344
  for (const r of filtered) {
11145
- emit2(`${displaySafeText(r.name)} ${displaySafeText(r.kind)} ${displaySafeText(toDisplayPath(rootDir, r.filePath))}:${r.lineStart}`);
11345
+ emit2(`${displaySafeText(r.name)} ${displaySafeText(r.kind)} ${formatSymbolLocation(displaySafeText(toDisplayPath(rootDir, r.filePath)), r.lineStart)}`);
11146
11346
  }
11147
11347
  if (cappedOut > 0) {
11148
11348
  emitErr2(`Showing ${filtered.length} of ${eligibleCount} type declarations (--limit is per kind; raise it to see the rest).`);
@@ -11197,7 +11397,7 @@ function runScope(opts) {
11197
11397
  return 0;
11198
11398
  }
11199
11399
  for (const s of enclosing) {
11200
- emit2(`${displaySafeText(s.name)} ${displaySafeText(s.kind)} ${displaySafeText(toDisplayPath(scopeDisplayRoot, s.filePath))}:${s.lineStart}-${s.lineEnd}`);
11400
+ emit2(`${displaySafeText(s.name)} ${displaySafeText(s.kind)} ${formatSymbolLocation(displaySafeText(toDisplayPath(scopeDisplayRoot, s.filePath)), s.lineStart, s.lineEnd)}`);
11201
11401
  }
11202
11402
  return 0;
11203
11403
  }
@@ -11330,7 +11530,7 @@ function runSimilar(opts) {
11330
11530
  emit2(displaySafeJson(results.map((h) => ({ name: h.name, kind: h.kind, file: h.filePath, line: h.lineStart }))));
11331
11531
  return 0;
11332
11532
  }
11333
- for (const h of results) emit2(`${displaySafeText(h.name)} ${displaySafeText(h.kind)} ${displaySafeText(toDisplayPath(rootDir, h.filePath))}:${h.lineStart}`);
11533
+ for (const h of results) emit2(`${displaySafeText(h.name)} ${displaySafeText(h.kind)} ${formatSymbolLocation(displaySafeText(toDisplayPath(rootDir, h.filePath)), h.lineStart)}`);
11334
11534
  return 0;
11335
11535
  }
11336
11536
  function runContextFor(opts) {
@@ -11766,6 +11966,7 @@ export {
11766
11966
  resolveBody,
11767
11967
  healStaleIndex,
11768
11968
  warnIfFilesStale,
11969
+ guardJsonRows,
11769
11970
  findSpecSeparator,
11770
11971
  rankSimilarNames,
11771
11972
  filterSimilarHeadings,
@@ -11795,6 +11996,7 @@ export {
11795
11996
  runZipRead,
11796
11997
  runPrSlice,
11797
11998
  runSqliteSchema,
11999
+ runSqliteTables,
11798
12000
  runSqliteQuery,
11799
12001
  runCoverageReportGaps,
11800
12002
  runConflicts,