token-goat 2.9.19 → 2.9.20

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 (50) hide show
  1. package/README.md +3 -1
  2. package/dist/token-goat-chunk-2CLWWRFR.mjs +26 -0
  3. package/dist/{token-goat-chunk-WKO5TVNA.mjs → token-goat-chunk-2Q3N5KUQ.mjs} +531 -571
  4. package/dist/{token-goat-chunk-DA6TIDLI.mjs → token-goat-chunk-3OGZOFLS.mjs} +18 -13
  5. package/dist/{token-goat-chunk-PIAESKVU.mjs → token-goat-chunk-3VTJC7KU.mjs} +568 -429
  6. package/dist/{token-goat-chunk-ZGQXRYKE.mjs → token-goat-chunk-6LJNM4ZZ.mjs} +1 -1
  7. package/dist/{token-goat-chunk-SOKAPOOC.mjs → token-goat-chunk-74ADIZZX.mjs} +46 -47
  8. package/dist/{token-goat-chunk-LACH3WKS.mjs → token-goat-chunk-ASTBLE2R.mjs} +3 -3
  9. package/dist/{token-goat-chunk-VJQBYSXG.mjs → token-goat-chunk-AU2K2QHR.mjs} +3 -3
  10. package/dist/token-goat-chunk-BQIC3AVL.mjs +292 -0
  11. package/dist/{token-goat-chunk-P46RTOAQ.mjs → token-goat-chunk-CBXLE54Q.mjs} +10 -7
  12. package/dist/{token-goat-chunk-3W5P673V.mjs → token-goat-chunk-DNAF26L4.mjs} +1 -1
  13. package/dist/{token-goat-chunk-FQYMZASI.mjs → token-goat-chunk-DPHJU3P7.mjs} +789 -4456
  14. package/dist/{token-goat-chunk-FX5DHKGF.mjs → token-goat-chunk-DW4VKU7D.mjs} +4 -4
  15. package/dist/token-goat-chunk-DYUBZZNP.mjs +198 -0
  16. package/dist/{token-goat-chunk-EP7TCWHM.mjs → token-goat-chunk-ERGHDBC6.mjs} +70 -65
  17. package/dist/token-goat-chunk-EUZKG7ZO.mjs +304 -0
  18. package/dist/{token-goat-chunk-AVRD7SBO.mjs → token-goat-chunk-FWYZVS3E.mjs} +270 -29
  19. package/dist/token-goat-chunk-G6SYQQO7.mjs +41 -0
  20. package/dist/{token-goat-chunk-62VJ47WN.mjs → token-goat-chunk-GIPMOGOI.mjs} +5 -5
  21. package/dist/{token-goat-chunk-L2UOJBV4.mjs → token-goat-chunk-H4VC5TR6.mjs} +27 -19
  22. package/dist/{token-goat-chunk-2GTB5RBZ.mjs → token-goat-chunk-I5PQRHFE.mjs} +11 -271
  23. package/dist/{token-goat-chunk-MU6I4IDI.mjs → token-goat-chunk-ITWYDOKP.mjs} +11 -7
  24. package/dist/{token-goat-chunk-IBTFGZBX.mjs → token-goat-chunk-K3ZNBN4U.mjs} +2 -2
  25. package/dist/{token-goat-chunk-S7RFIX4Y.mjs → token-goat-chunk-K5XPIUVB.mjs} +45 -14
  26. package/dist/token-goat-chunk-KT75DZK4.mjs +1989 -0
  27. package/dist/{token-goat-chunk-F24NE3FO.mjs → token-goat-chunk-MNJWG2ZO.mjs} +2 -2
  28. package/dist/{token-goat-chunk-NJKNAC37.mjs → token-goat-chunk-MUJV7BR3.mjs} +1 -1
  29. package/dist/{token-goat-chunk-FJZ5MZK7.mjs → token-goat-chunk-ODF7H7WS.mjs} +2 -2
  30. package/dist/{token-goat-chunk-GYC34EGE.mjs → token-goat-chunk-ONMU7BON.mjs} +2 -2
  31. package/dist/{token-goat-chunk-KWM6KBPA.mjs → token-goat-chunk-P4XBHZXU.mjs} +1 -1
  32. package/dist/{token-goat-chunk-7DGTVBWP.mjs → token-goat-chunk-PAVWB4L4.mjs} +159 -1863
  33. package/dist/{token-goat-chunk-DHIXE6GV.mjs → token-goat-chunk-PTW22MRC.mjs} +1 -1
  34. package/dist/token-goat-chunk-SL454EN5.mjs +1816 -0
  35. package/dist/token-goat-chunk-SP5QR2HN.mjs +1379 -0
  36. package/dist/{token-goat-chunk-BTKDZW7F.mjs → token-goat-chunk-T46UKRFM.mjs} +1 -1
  37. package/dist/{token-goat-chunk-JNIFSVWM.mjs → token-goat-chunk-T63VHOL3.mjs} +5 -1
  38. package/dist/token-goat-chunk-VSJGPEBB.mjs +248 -0
  39. package/dist/{token-goat-chunk-EXLLLIC3.mjs → token-goat-chunk-VYXGHGUY.mjs} +3 -3
  40. package/dist/token-goat-chunk-W6QYCWAT.mjs +128 -0
  41. package/dist/{token-goat-chunk-HPMMLV37.mjs → token-goat-chunk-Z4ALQADF.mjs} +256 -341
  42. package/dist/token-goat-chunk-ZHFM4DHJ.mjs +324 -0
  43. package/dist/token-goat-hook.mjs +17 -11
  44. package/dist/token-goat.core.mjs +27 -19
  45. package/docs/C4_RUNTIME_ARCHITECTURE.md +1 -1
  46. package/docs/cli.md +13 -12
  47. package/docs/install.md +1 -1
  48. package/docs/security.md +2 -2
  49. package/package.json +3 -2
  50. package/dist/token-goat-chunk-NYFYIRG3.mjs +0 -35
@@ -5,7 +5,7 @@ import {
5
5
  isTextHeavy,
6
6
  ocrImage,
7
7
  ocrIntegrityFailed
8
- } from "./token-goat-chunk-F24NE3FO.mjs";
8
+ } from "./token-goat-chunk-MNJWG2ZO.mjs";
9
9
  import {
10
10
  formatSqliteQueryTable,
11
11
  formatSqliteSchema,
@@ -20,10 +20,8 @@ import {
20
20
  NOTEBOOK_CELL_LINES_SUFFIX,
21
21
  SKIP_DIRS,
22
22
  canShrinkFormat,
23
- capJsonRows,
24
23
  emptyIndexMessage,
25
24
  enqueueDirtyPathSafe,
26
- estimateTokens,
27
25
  fenceUntrusted,
28
26
  formatSymbolLocation,
29
27
  getEmbeddingCoverage,
@@ -36,16 +34,22 @@ import {
36
34
  isVirtualIndexedPath,
37
35
  parseIpv6Groups,
38
36
  probeImageMeta,
37
+ recordKnownRootThrottled,
39
38
  resolveLineRegions,
40
39
  scanAndRecord,
41
40
  searchEvidenceSemantically,
42
41
  shrinkImage,
43
- trimToBudget,
44
42
  urlPolicyDenialReason,
45
43
  virtualIndexedScopeNote,
46
44
  walkProject
47
- } from "./token-goat-chunk-FQYMZASI.mjs";
45
+ } from "./token-goat-chunk-DPHJU3P7.mjs";
46
+ import {
47
+ capJsonRows,
48
+ estimateTokens,
49
+ trimToBudget
50
+ } from "./token-goat-chunk-ZHFM4DHJ.mjs";
48
51
  import {
52
+ BYTES_PER_TOKEN,
49
53
  colorStdout,
50
54
  isBlobStale,
51
55
  loadBlob,
@@ -53,8 +57,8 @@ import {
53
57
  redactSecrets,
54
58
  savedTokensFromBytes,
55
59
  storeBlob,
56
- stripAnsi
57
- } from "./token-goat-chunk-S7RFIX4Y.mjs";
60
+ stripAnsiEscapes
61
+ } from "./token-goat-chunk-K5XPIUVB.mjs";
58
62
  import {
59
63
  extractPdfMeta,
60
64
  extractPdfOutline,
@@ -68,7 +72,7 @@ import {
68
72
  parseWhereSpecs,
69
73
  profileCsv,
70
74
  queryCsv
71
- } from "./token-goat-chunk-KWM6KBPA.mjs";
75
+ } from "./token-goat-chunk-P4XBHZXU.mjs";
72
76
  import {
73
77
  MAX_ZIP_INPUT_BYTES,
74
78
  MAX_ZIP_OUTPUT_BYTES,
@@ -103,7 +107,7 @@ import {
103
107
  extractSolidity,
104
108
  extractThrift,
105
109
  stripLeadingAttributes
106
- } from "./token-goat-chunk-NJKNAC37.mjs";
110
+ } from "./token-goat-chunk-MUJV7BR3.mjs";
107
111
  import {
108
112
  MAX_OVER_FETCH,
109
113
  OVER_FETCH_FACTOR,
@@ -117,7 +121,7 @@ import {
117
121
  mergeNearbyHits,
118
122
  readSection,
119
123
  searchSemantic
120
- } from "./token-goat-chunk-EP7TCWHM.mjs";
124
+ } from "./token-goat-chunk-ERGHDBC6.mjs";
121
125
  import {
122
126
  DEFAULT_QUERY_LIMIT,
123
127
  countRefs,
@@ -130,7 +134,7 @@ import {
130
134
  queryRefsByContext,
131
135
  querySymbols,
132
136
  searchSymbolsFts
133
- } from "./token-goat-chunk-IBTFGZBX.mjs";
137
+ } from "./token-goat-chunk-K3ZNBN4U.mjs";
134
138
  import {
135
139
  FILENAME_LANGUAGE,
136
140
  TREE_SITTER_LANGUAGES,
@@ -149,7 +153,7 @@ import {
149
153
  partialRefsReason,
150
154
  redactIfDotenv,
151
155
  unsupportedLanguageName
152
- } from "./token-goat-chunk-JNIFSVWM.mjs";
156
+ } from "./token-goat-chunk-T63VHOL3.mjs";
153
157
  import {
154
158
  fileIsAbsent,
155
159
  findProject,
@@ -159,7 +163,7 @@ import {
159
163
  loadConfig,
160
164
  resolveProjectRoot,
161
165
  shortFingerprint
162
- } from "./token-goat-chunk-SOKAPOOC.mjs";
166
+ } from "./token-goat-chunk-74ADIZZX.mjs";
163
167
  import {
164
168
  registerReset
165
169
  } from "./token-goat-chunk-EEIDFMEM.mjs";
@@ -169,6 +173,7 @@ import {
169
173
  atomicWriteBytes,
170
174
  compileGrepMatcher,
171
175
  countNoun,
176
+ dataDir,
172
177
  decodeSource,
173
178
  ensureNewline,
174
179
  escapeRegExp,
@@ -191,7 +196,7 @@ import {
191
196
  supportRequestLine,
192
197
  windowsCmdQuoteArg,
193
198
  withExtension
194
- } from "./token-goat-chunk-ZGQXRYKE.mjs";
199
+ } from "./token-goat-chunk-6LJNM4ZZ.mjs";
195
200
  import {
196
201
  UNTRUSTED_FILE_TAG,
197
202
  UNTRUSTED_GITHUB_TAG,
@@ -881,6 +886,20 @@ function renderContextWindow(displayFile, matchLine, window, matchSuffix = "", i
881
886
  );
882
887
  }
883
888
 
889
+ // src/emit.ts
890
+ init_define_import_meta_env();
891
+ function emit(text) {
892
+ const payload = colorStdout() ? text : stripAnsiEscapes(text);
893
+ process.stdout.write(ensureNewline(payload));
894
+ }
895
+ function emitErr(text) {
896
+ process.stderr.write(ensureNewline(text));
897
+ }
898
+
899
+ // src/query_limits.ts
900
+ init_define_import_meta_env();
901
+ var UNBOUNDED_QUERY_LIMIT = -1;
902
+
884
903
  // src/ref_blindness.ts
885
904
  init_define_import_meta_env();
886
905
  var REF_INDEXED_LANGUAGES = /* @__PURE__ */ new Set([
@@ -935,8 +954,8 @@ import { randomUUID } from "node:crypto";
935
954
  // src/graph_traversal.ts
936
955
  init_define_import_meta_env();
937
956
  var DEFAULT_REF_QUERY_LIMIT = 500;
938
- var ALL_SYMBOLS_IN_FILE_LIMIT = -1;
939
- var UNBOUNDED_REF_LIMIT = -1;
957
+ var ALL_SYMBOLS_IN_FILE_LIMIT = UNBOUNDED_QUERY_LIMIT;
958
+ var UNBOUNDED_REF_LIMIT = UNBOUNDED_QUERY_LIMIT;
940
959
  function enclosingSymbol(symbols, line) {
941
960
  let best = null;
942
961
  for (const s of symbols) {
@@ -1276,13 +1295,6 @@ function findCyclesCapped(graph) {
1276
1295
  init_define_import_meta_env();
1277
1296
  import * as fs from "node:fs";
1278
1297
  import * as path2 from "node:path";
1279
- function emit(text) {
1280
- const payload = colorStdout() ? text : stripAnsi(text);
1281
- process.stdout.write(ensureNewline(payload));
1282
- }
1283
- function emitErr(text) {
1284
- process.stderr.write(ensureNewline(text));
1285
- }
1286
1298
  function runDead(opts) {
1287
1299
  if (opts.top !== void 0 && opts.top <= 0) {
1288
1300
  emitErr(`--top must be a positive number, got: ${opts.top}`);
@@ -1950,21 +1962,14 @@ function renderModules(result, top) {
1950
1962
  }
1951
1963
 
1952
1964
  // src/graph_analysis.ts
1953
- function emit2(text) {
1954
- const payload = colorStdout() ? text : stripAnsi(text);
1955
- process.stdout.write(ensureNewline(payload));
1956
- }
1957
- function emitErr2(text) {
1958
- process.stderr.write(ensureNewline(text));
1959
- }
1960
1965
  function runSimilar(opts) {
1961
1966
  if (opts.top !== void 0 && opts.top <= 0) {
1962
- emitErr2(`--top must be a positive number, got: ${opts.top}`);
1967
+ emitErr(`--top must be a positive number, got: ${opts.top}`);
1963
1968
  return 1;
1964
1969
  }
1965
1970
  const sepIdx = opts.spec.lastIndexOf("::");
1966
1971
  if (sepIdx < 0) {
1967
- emitErr2(`Invalid spec - expected "file::symbol", got: ${opts.spec}`);
1972
+ emitErr(`Invalid spec - expected "file::symbol", got: ${opts.spec}`);
1968
1973
  return 1;
1969
1974
  }
1970
1975
  const top = opts.top ?? 10;
@@ -1977,18 +1982,18 @@ function runSimilar(opts) {
1977
1982
  const matches = hits.filter((h) => !(h.filePath === anchor.filePath && h.name === anchor.name));
1978
1983
  const results = matches.slice(0, top);
1979
1984
  if (matches.length > results.length) {
1980
- emitErr2(`Showing top ${results.length} of ${matches.length} similar symbols (raise --top to see the rest).`);
1985
+ emitErr(`Showing top ${results.length} of ${matches.length} similar symbols (raise --top to see the rest).`);
1981
1986
  }
1982
1987
  if (opts.json === true) {
1983
- emit2(displaySafeJson(results.map((h) => ({ name: h.name, kind: h.kind, file: h.filePath, line: h.lineStart }))));
1988
+ emit(displaySafeJson(results.map((h) => ({ name: h.name, kind: h.kind, file: h.filePath, line: h.lineStart }))));
1984
1989
  return 0;
1985
1990
  }
1986
- for (const h of results) emit2(`${displaySafeText(h.name)} ${displaySafeText(h.kind)} ${formatSymbolLocation(displaySafeText(toDisplayPath(rootDir, h.filePath)), h.lineStart)}`);
1991
+ for (const h of results) emit(`${displaySafeText(h.name)} ${displaySafeText(h.kind)} ${formatSymbolLocation(displaySafeText(toDisplayPath(rootDir, h.filePath)), h.lineStart)}`);
1987
1992
  return 0;
1988
1993
  }
1989
1994
  function runContextFor(opts) {
1990
1995
  if (opts.top !== void 0 && opts.top <= 0) {
1991
- emitErr2(`--top must be a positive number, got: ${opts.top}`);
1996
+ emitErr(`--top must be a positive number, got: ${opts.top}`);
1992
1997
  return 1;
1993
1998
  }
1994
1999
  const top = opts.top ?? 12;
@@ -1998,7 +2003,7 @@ function runContextFor(opts) {
1998
2003
  const moreBeyondTop = fetched.length > top;
1999
2004
  const hits = fetched.slice(0, top);
2000
2005
  if (hits.length === 0) {
2001
- emitErr2(`No matches found for '${opts.task}'`);
2006
+ emitErr(`No matches found for '${opts.task}'`);
2002
2007
  return 1;
2003
2008
  }
2004
2009
  const entries = [];
@@ -2017,19 +2022,19 @@ function runContextFor(opts) {
2017
2022
  );
2018
2023
  }
2019
2024
  if (moreBeyondTop) notices.push(`More matches exist beyond --top ${top} (raise it to see them).`);
2020
- for (const n of notices) emitErr2(n);
2025
+ for (const n of notices) emitErr(n);
2021
2026
  if (opts.json === true) {
2022
- emit2(displaySafeJson(entries));
2027
+ emit(displaySafeJson(entries));
2023
2028
  return 0;
2024
2029
  }
2025
- for (const e of entries) emit2(`token-goat read "${displaySafeText(toDisplayPath(rootDir, e.file))}::${displaySafeText(e.symbol)}@${e.line}"`);
2030
+ for (const e of entries) emit(`token-goat read "${displaySafeText(toDisplayPath(rootDir, e.file))}::${displaySafeText(e.symbol)}@${e.line}"`);
2026
2031
  return 0;
2027
2032
  }
2028
2033
  function runTestFor(opts) {
2029
2034
  const filePath = resolveIndexPath(opts.file);
2030
2035
  const symbols = querySymbols({ filePath, limit: ALL_SYMBOLS_IN_FILE_LIMIT });
2031
2036
  if (!fs3.existsSync(opts.file) && symbols.length === 0) {
2032
- emitErr2(`Could not read: ${opts.file}`);
2037
+ emitErr(`Could not read: ${opts.file}`);
2033
2038
  return 1;
2034
2039
  }
2035
2040
  const rootDir = resolveProjectRoot({ project: process.cwd() });
@@ -2054,22 +2059,22 @@ function runTestFor(opts) {
2054
2059
  }
2055
2060
  if (opts.json === true) {
2056
2061
  const capped = guardJsonRows(results.map((r) => ({ ...r, testFile: toDisplayPath(rootDir, r.testFile) })));
2057
- emit2(displaySafeJson({ items: capped.items, truncated: capped.truncated, totalCount: capped.totalCount }));
2062
+ emit(displaySafeJson({ items: capped.items, truncated: capped.truncated, totalCount: capped.totalCount }));
2058
2063
  return 0;
2059
2064
  }
2060
2065
  if (results.length === 0) {
2061
- emit2(`No test files found referencing symbols in '${displaySafeText(opts.file)}'`);
2066
+ emit(`No test files found referencing symbols in '${displaySafeText(opts.file)}'`);
2062
2067
  return 0;
2063
2068
  }
2064
2069
  for (const r of results) {
2065
- emit2(toDisplayPath(rootDir, r.testFile));
2066
- for (const fn of r.testFunctions) emit2(` ${fn}`);
2070
+ emit(toDisplayPath(rootDir, r.testFile));
2071
+ for (const fn of r.testFunctions) emit(` ${fn}`);
2067
2072
  }
2068
2073
  return 0;
2069
2074
  }
2070
2075
  function runCoverageGaps(opts) {
2071
2076
  if (opts.top !== void 0 && opts.top <= 0) {
2072
- emitErr2(`--top must be a positive number, got: ${opts.top}`);
2077
+ emitErr(`--top must be a positive number, got: ${opts.top}`);
2073
2078
  return 1;
2074
2079
  }
2075
2080
  const top = opts.top ?? 50;
@@ -2087,30 +2092,30 @@ function runCoverageGaps(opts) {
2087
2092
  }
2088
2093
  const sliced = gaps.slice(0, top);
2089
2094
  if (gaps.length > sliced.length) {
2090
- emitErr2(`Showing top ${sliced.length} of ${gaps.length} coverage gaps (raise --top to see the rest).`);
2095
+ emitErr(`Showing top ${sliced.length} of ${gaps.length} coverage gaps (raise --top to see the rest).`);
2091
2096
  }
2092
2097
  if (opts.json === true) {
2093
- emit2(displaySafeJson(sliced));
2098
+ emit(displaySafeJson(sliced));
2094
2099
  return 0;
2095
2100
  }
2096
2101
  if (sliced.length === 0) {
2097
- emit2("No coverage gaps found.");
2098
- if (isIndexEmptyForProject(globalDbPath(), rootDir)) emit2(emptyIndexMessage(rootDir));
2102
+ emit("No coverage gaps found.");
2103
+ if (isIndexEmptyForProject(globalDbPath(), rootDir)) emit(emptyIndexMessage(rootDir));
2099
2104
  return 0;
2100
2105
  }
2101
- for (const g of sliced) emit2(`${displaySafeText(g.name)} ${displaySafeText(g.kind)} ${displaySafeText(toDisplayPath(rootDir, g.file))}:${g.line}`);
2106
+ for (const g of sliced) emit(`${displaySafeText(g.name)} ${displaySafeText(g.kind)} ${displaySafeText(toDisplayPath(rootDir, g.file))}:${g.line}`);
2102
2107
  return 0;
2103
2108
  }
2104
2109
  function runArch(opts) {
2105
2110
  if (opts.top !== void 0 && opts.top <= 0) {
2106
- emitErr2(`--top must be a positive number, got: ${opts.top}`);
2111
+ emitErr(`--top must be a positive number, got: ${opts.top}`);
2107
2112
  return 1;
2108
2113
  }
2109
2114
  const cwd = opts.cwd ?? process.cwd();
2110
2115
  const top = opts.top ?? 10;
2111
2116
  const { files, graph, importedBy, resolve: resolve8 } = buildImportGraph(cwd);
2112
2117
  if (files.length === 0 && opts.json !== true) {
2113
- emit2(`no tracked files found under '${toDisplayPath(getDisplayRoot(cwd), cwd)}' (is it a git repo?). Nothing to analyse.`);
2118
+ emit(`no tracked files found under '${toDisplayPath(getDisplayRoot(cwd), cwd)}' (is it a git repo?). Nothing to analyse.`);
2114
2119
  return 0;
2115
2120
  }
2116
2121
  const allHubs = [...importedBy.entries()].sort((a, b) => b[1].size - a[1].size).map(([f, importers]) => ({ file: f, importedBy: importers.size }));
@@ -2123,22 +2128,22 @@ function runArch(opts) {
2123
2128
  const moduleResult = opts.modules === true ? detectModules({ files, graph, importedBy, resolve: resolve8 }, cwd, top) : null;
2124
2129
  if (opts.json === true) {
2125
2130
  const modulePayload = moduleResult === null ? {} : { modules: moduleResult.modules, modulesTotal: moduleResult.modulesTotal, modulesTruncated: moduleResult.modules.length < moduleResult.modulesTotal, modularity: moduleResult.modularity, isolatedCount: moduleResult.isolatedCount, crossImports: moduleResult.crossImports, crossImportsTotal: moduleResult.crossImportsTotal, crossImportsTruncated: moduleResult.crossImports.length < moduleResult.crossImportsTotal, noImportEdges: moduleResult.noEdges };
2126
- emit2(displaySafeJson({ hubs, hubsTotal, hubsTruncated: hubs.length < hubsTotal, entryPoints, entryPointsTotal, entryPointsTruncated: entryPoints.length < entryPointsTotal, cycles, ...cyclesTruncated ? { cyclesTruncated: true } : {}, ...modulePayload }));
2131
+ emit(displaySafeJson({ hubs, hubsTotal, hubsTruncated: hubs.length < hubsTotal, entryPoints, entryPointsTotal, entryPointsTruncated: entryPoints.length < entryPointsTotal, cycles, ...cyclesTruncated ? { cyclesTruncated: true } : {}, ...modulePayload }));
2127
2132
  return 0;
2128
2133
  }
2129
- emit2(hubs.length < hubsTotal ? `hubs (top ${hubs.length} of ${hubsTotal} most-imported):` : `hubs (${hubsTotal} most-imported):`);
2130
- for (const h of hubs) emit2(` ${h.importedBy} importers ${displaySafeText(toDisplayPath(getDisplayRoot(opts.cwd), h.file))}`);
2131
- emit2(entryPoints.length < entryPointsTotal ? `entry points (imported by nobody, top ${entryPoints.length} of ${entryPointsTotal}):` : `entry points (imported by nobody, ${entryPointsTotal} found):`);
2132
- for (const e of entryPoints) emit2(` ${displaySafeText(toDisplayPath(getDisplayRoot(opts.cwd), e.file))}`);
2133
- emit2(cyclesTruncated ? `cycles (first ${cycles.length}, truncated at the ${MAX_CYCLES}-cycle enumeration limit: more cycles exist):` : `cycles (${cycles.length} found):`);
2134
- for (const c of cycles) emit2(` ${c.map((f) => toDisplayPath(getDisplayRoot(opts.cwd), f)).join(" -> ")}`);
2135
- if (moduleResult !== null) for (const line of renderModules(moduleResult, top)) emit2(line);
2134
+ emit(hubs.length < hubsTotal ? `hubs (top ${hubs.length} of ${hubsTotal} most-imported):` : `hubs (${hubsTotal} most-imported):`);
2135
+ for (const h of hubs) emit(` ${h.importedBy} importers ${displaySafeText(toDisplayPath(getDisplayRoot(opts.cwd), h.file))}`);
2136
+ emit(entryPoints.length < entryPointsTotal ? `entry points (imported by nobody, top ${entryPoints.length} of ${entryPointsTotal}):` : `entry points (imported by nobody, ${entryPointsTotal} found):`);
2137
+ for (const e of entryPoints) emit(` ${displaySafeText(toDisplayPath(getDisplayRoot(opts.cwd), e.file))}`);
2138
+ emit(cyclesTruncated ? `cycles (first ${cycles.length}, truncated at the ${MAX_CYCLES}-cycle enumeration limit: more cycles exist):` : `cycles (${cycles.length} found):`);
2139
+ for (const c of cycles) emit(` ${c.map((f) => toDisplayPath(getDisplayRoot(opts.cwd), f)).join(" -> ")}`);
2140
+ if (moduleResult !== null) for (const line of renderModules(moduleResult, top)) emit(line);
2136
2141
  return 0;
2137
2142
  }
2138
2143
  function runBlame(opts) {
2139
2144
  const sepIdx = opts.spec.lastIndexOf("::");
2140
2145
  if (sepIdx < 0) {
2141
- emitErr2(`Invalid spec - expected "file::symbol", got: ${displaySafeText(opts.spec)}`);
2146
+ emitErr(`Invalid spec - expected "file::symbol", got: ${displaySafeText(opts.spec)}`);
2142
2147
  return 1;
2143
2148
  }
2144
2149
  const cwd = opts.cwd ?? process.cwd();
@@ -2151,12 +2156,12 @@ function runBlame(opts) {
2151
2156
  try {
2152
2157
  const result = runGit(["blame", "-L", `${start},${end}`, "--", filePath], { cwd });
2153
2158
  if (result.exitCode !== 0) {
2154
- emitErr2(`git blame failed: ${displaySafeText(result.stderr)}`);
2159
+ emitErr(`git blame failed: ${displaySafeText(result.stderr)}`);
2155
2160
  return 1;
2156
2161
  }
2157
2162
  raw = result.stdout;
2158
2163
  } catch (e) {
2159
- emitErr2(`git blame failed: ${extractErrorMessage(e)}`);
2164
+ emitErr(`git blame failed: ${extractErrorMessage(e)}`);
2160
2165
  return 1;
2161
2166
  }
2162
2167
  if (opts.json === true) {
@@ -2165,32 +2170,25 @@ function runBlame(opts) {
2165
2170
  if (!m) return { raw: l };
2166
2171
  return { commit: m[2], boundary: m[1] === "^", author: (m[3] ?? "").trim(), date: (m[4] ?? "").trim(), line: Number.parseInt(m[5] ?? "0", 10), content: m[6] };
2167
2172
  });
2168
- emit2(displaySafeJson({ symbol: sym.name, file: filePath, lines }));
2173
+ emit(displaySafeJson({ symbol: sym.name, file: filePath, lines }));
2169
2174
  return 0;
2170
2175
  }
2171
- emit2(`${displaySafeText(sym.name)} ${displaySafeText(toDisplayPath(getDisplayRoot(opts.cwd), filePath))}:${start}-${end}`);
2172
- emit2(fenceUntrusted(raw.trim(), UNTRUSTED_FILE_TAG));
2176
+ emit(`${displaySafeText(sym.name)} ${displaySafeText(toDisplayPath(getDisplayRoot(opts.cwd), filePath))}:${start}-${end}`);
2177
+ emit(fenceUntrusted(raw.trim(), UNTRUSTED_FILE_TAG));
2173
2178
  return 0;
2174
2179
  }
2175
2180
 
2176
2181
  // src/graph_commands.ts
2177
- function emit3(text) {
2178
- const payload = colorStdout() ? text : stripAnsi(text);
2179
- process.stdout.write(ensureNewline(payload));
2180
- }
2181
- function emitErr3(text) {
2182
- process.stderr.write(ensureNewline(text));
2183
- }
2184
2182
  function runCallers(opts) {
2185
2183
  if (opts.limit !== void 0 && opts.limit <= 0) {
2186
- emitErr3(`--limit must be a positive number, got: ${opts.limit}`);
2184
+ emitErr(`--limit must be a positive number, got: ${opts.limit}`);
2187
2185
  return 1;
2188
2186
  }
2189
2187
  const rootDir = resolveProjectRoot({ project: process.cwd() });
2190
2188
  const { name, file } = parseGraphSymbolSpec(opts.symbol);
2191
2189
  const fileHint = file !== void 0 ? resolveIndexPath(file, rootDir) : void 0;
2192
2190
  if (fileHint !== void 0 && querySymbols({ name, filePath: fileHint, limit: 1 }).length === 0) {
2193
- emitErr3(`Symbol '${name}' not found in '${file}'`);
2191
+ emitErr(`Symbol '${name}' not found in '${file}'`);
2194
2192
  return 1;
2195
2193
  }
2196
2194
  const unbounded = opts.excludeTests === true || opts.grep !== void 0 || fileHint !== void 0;
@@ -2207,41 +2205,41 @@ function runCallers(opts) {
2207
2205
  if (entries.length === 0) {
2208
2206
  if (matchesGrep !== void 0 && preGrepCount > 0) {
2209
2207
  if (opts.json === true) {
2210
- emit3(displaySafeJson({ items: [], truncated: false, totalCount: 0, hiddenByGrep: preGrepCount }));
2208
+ emit(displaySafeJson({ items: [], truncated: false, totalCount: 0, hiddenByGrep: preGrepCount }));
2211
2209
  return 0;
2212
2210
  }
2213
- emit3(grepFilteredToEmptyNotice(preGrepCount, opts.grep ?? "", "caller", "callers"));
2211
+ emit(grepFilteredToEmptyNotice(preGrepCount, opts.grep ?? "", "caller", "callers"));
2214
2212
  return 0;
2215
2213
  }
2216
2214
  if (opts.excludeTests === true && suppressed > 0) {
2217
2215
  if (opts.json === true) {
2218
- emit3(displaySafeJson({ items: [], truncated: false, totalCount: 0, hiddenByExcludeTests: suppressed }));
2216
+ emit(displaySafeJson({ items: [], truncated: false, totalCount: 0, hiddenByExcludeTests: suppressed }));
2219
2217
  return 1;
2220
2218
  }
2221
- emitErr3(`No non-test references found for '${opts.symbol}' (${excludeTestsHiddenNote(suppressed)})`);
2219
+ emitErr(`No non-test references found for '${opts.symbol}' (${excludeTestsHiddenNote(suppressed)})`);
2222
2220
  return 1;
2223
2221
  }
2224
2222
  const defRows = querySymbols({ name, rootDir, limit: REF_BLIND_DEF_PROBE_LIMIT });
2225
2223
  if (defRows.length === 0) {
2226
- emitErr3(`Symbol not found: ${opts.symbol}${unknownSymbolSuggestion(name, rootDir)}`);
2227
- if (opts.json !== true && isIndexEmptyForProject(globalDbPath(), rootDir)) emitErr3(emptyIndexMessage(rootDir));
2224
+ emitErr(`Symbol not found: ${opts.symbol}${unknownSymbolSuggestion(name, rootDir)}`);
2225
+ if (opts.json !== true && isIndexEmptyForProject(globalDbPath(), rootDir)) emitErr(emptyIndexMessage(rootDir));
2228
2226
  return 1;
2229
2227
  }
2230
2228
  const defPaths = fileHint !== void 0 ? [fileHint] : defRows.map((r) => r.filePath);
2231
2229
  const firstDefPath = defPaths[0];
2232
2230
  if (firstDefPath !== void 0 && defPaths.every((fp) => !isRefIndexedFile(fp))) {
2233
- emitErr3(refBlindLanguageNotice(name, detectLanguageOfFile(firstDefPath), toDisplayPath(rootDir, firstDefPath)));
2231
+ emitErr(refBlindLanguageNotice(name, detectLanguageOfFile(firstDefPath), toDisplayPath(rootDir, firstDefPath)));
2234
2232
  return 1;
2235
2233
  }
2236
2234
  const kindRows = fileHint !== void 0 ? querySymbols({ name, filePath: fileHint, limit: REF_BLIND_DEF_PROBE_LIMIT }) : defRows;
2237
2235
  const kindVerdict = refBlindKindVerdict(kindRows);
2238
2236
  if (kindVerdict.allBlind) {
2239
- emitErr3(refBlindKindNotice(name, kindVerdict.blindKinds));
2237
+ emitErr(refBlindKindNotice(name, kindVerdict.blindKinds));
2240
2238
  return 1;
2241
2239
  }
2242
- emitErr3(`No references found for '${opts.symbol}'`);
2243
- if (kindVerdict.blindCount > 0) emitErr3(refBlindKindPartialNote(name, kindVerdict.blindKinds, kindVerdict.blindCount, kindRows.length));
2244
- if (opts.json !== true && isIndexEmptyForProject(globalDbPath(), rootDir)) emitErr3(emptyIndexMessage(rootDir));
2240
+ emitErr(`No references found for '${opts.symbol}'`);
2241
+ if (kindVerdict.blindCount > 0) emitErr(refBlindKindPartialNote(name, kindVerdict.blindKinds, kindVerdict.blindCount, kindRows.length));
2242
+ if (opts.json !== true && isIndexEmptyForProject(globalDbPath(), rootDir)) emitErr(emptyIndexMessage(rootDir));
2245
2243
  return 1;
2246
2244
  }
2247
2245
  const contextLines = opts.context ?? 0;
@@ -2254,7 +2252,7 @@ function runCallers(opts) {
2254
2252
  const capped = guardJsonRows(rows);
2255
2253
  const limitTruncated = entries.length < filtered.length || sqlTruncated;
2256
2254
  const hiddenByGrep = preGrepCount - filtered.length;
2257
- emit3(displaySafeJson({
2255
+ emit(displaySafeJson({
2258
2256
  items: capped.items,
2259
2257
  truncated: capped.truncated || limitTruncated,
2260
2258
  totalCount: filtered.length,
@@ -2264,24 +2262,24 @@ function runCallers(opts) {
2264
2262
  return 0;
2265
2263
  }
2266
2264
  if (opts.excludeTests === true && suppressed > 0) {
2267
- emit3(`${countNoun(entries.length, "caller")} found (${excludeTestsHiddenNote(suppressed)})`);
2265
+ emit(`${countNoun(entries.length, "caller")} found (${excludeTestsHiddenNote(suppressed)})`);
2268
2266
  }
2269
2267
  const overflowed = sqlTruncated || entries.length < filtered.length;
2270
2268
  if (overflowed) {
2271
2269
  const totalCallers = sqlTruncated ? countRefs({ name, rootDir }) : filtered.length;
2272
- emitErr3(`Showing the first ${entries.length} of ${countNoun(totalCallers, "caller")} (raise --limit to see the rest).`);
2270
+ emitErr(`Showing the first ${entries.length} of ${countNoun(totalCallers, "caller")} (raise --limit to see the rest).`);
2273
2271
  }
2274
2272
  for (const e of entries) {
2275
2273
  const displayPath = toDisplayPath(rootDir, e.file);
2276
- emit3(`${e.caller} ${displayPath}:${e.line}`);
2274
+ emit(`${e.caller} ${displayPath}:${e.line}`);
2277
2275
  const window = buildContextWindow(e.file, e.line, contextLines);
2278
- if (window !== null) for (const l of renderContextWindow(displayPath, e.line, window, "", " ")) emit3(l);
2276
+ if (window !== null) for (const l of renderContextWindow(displayPath, e.line, window, "", " ")) emit(l);
2279
2277
  }
2280
2278
  return 0;
2281
2279
  }
2282
2280
  function runCallChain(opts) {
2283
2281
  if (opts.depth !== void 0 && opts.depth <= 0) {
2284
- emitErr3(`--depth must be a positive number, got: ${opts.depth}`);
2282
+ emitErr(`--depth must be a positive number, got: ${opts.depth}`);
2285
2283
  return 1;
2286
2284
  }
2287
2285
  const maxDepth = opts.depth ?? 8;
@@ -2290,13 +2288,13 @@ function runCallChain(opts) {
2290
2288
  const fileHint = file !== void 0 ? resolveIndexPath(file, rootDir) : void 0;
2291
2289
  if (fileHint !== void 0) {
2292
2290
  if (querySymbols({ name, filePath: fileHint, limit: 1 }).length === 0) {
2293
- emitErr3(`Symbol '${name}' not found in '${file}'`);
2294
- if (opts.json !== true && isIndexEmptyForProject(globalDbPath(), rootDir)) emitErr3(emptyIndexMessage(rootDir));
2291
+ emitErr(`Symbol '${name}' not found in '${file}'`);
2292
+ if (opts.json !== true && isIndexEmptyForProject(globalDbPath(), rootDir)) emitErr(emptyIndexMessage(rootDir));
2295
2293
  return 1;
2296
2294
  }
2297
2295
  } else if (querySymbols({ name, rootDir, limit: 1 }).length === 0) {
2298
- emitErr3(`Symbol not found: ${opts.symbol}${unknownSymbolSuggestion(name, rootDir)}`);
2299
- if (opts.json !== true && isIndexEmptyForProject(globalDbPath(), rootDir)) emitErr3(emptyIndexMessage(rootDir));
2296
+ emitErr(`Symbol not found: ${opts.symbol}${unknownSymbolSuggestion(name, rootDir)}`);
2297
+ if (opts.json !== true && isIndexEmptyForProject(globalDbPath(), rootDir)) emitErr(emptyIndexMessage(rootDir));
2300
2298
  return 1;
2301
2299
  }
2302
2300
  const refBlindRootPath = () => {
@@ -2334,7 +2332,7 @@ function runCallChain(opts) {
2334
2332
  const refBlindKinds = noCallers ? refBlindRootKinds().blindKinds : [];
2335
2333
  const blindRootPath = noCallers ? refBlindRootPath() : void 0;
2336
2334
  const refBlindLanguage = blindRootPath !== void 0 ? { language: detectLanguageOfFile(blindRootPath), definedIn: toDisplayPath(rootDir, blindRootPath) } : void 0;
2337
- emit3(displaySafeJson({
2335
+ emit(displaySafeJson({
2338
2336
  chains: filteredChains,
2339
2337
  ...hiddenByGrep > 0 ? { hiddenByGrep } : {},
2340
2338
  ...hiddenByExcludeTests > 0 ? { hiddenByExcludeTests } : {},
@@ -2345,37 +2343,37 @@ function runCallChain(opts) {
2345
2343
  }
2346
2344
  if (noCallers) {
2347
2345
  if (opts.excludeTests === true && suppressedCount > 0) {
2348
- emit3(`${name} (no non-test callers; ${excludeTestsHiddenNote(suppressedCount)})`);
2346
+ emit(`${name} (no non-test callers; ${excludeTestsHiddenNote(suppressedCount)})`);
2349
2347
  return 0;
2350
2348
  }
2351
2349
  const blindRoot = refBlindRootPath();
2352
2350
  if (blindRoot !== void 0) {
2353
- emitErr3(refBlindLanguageNotice(name, detectLanguageOfFile(blindRoot), toDisplayPath(rootDir, blindRoot)));
2354
- emit3(`${name} (no callers recorded)`);
2351
+ emitErr(refBlindLanguageNotice(name, detectLanguageOfFile(blindRoot), toDisplayPath(rootDir, blindRoot)));
2352
+ emit(`${name} (no callers recorded)`);
2355
2353
  return 0;
2356
2354
  }
2357
2355
  const rootKinds = refBlindRootKinds();
2358
2356
  if (rootKinds.allBlind) {
2359
- emitErr3(refBlindKindNotice(name, rootKinds.blindKinds));
2360
- emit3(`${name} (no callers recorded)`);
2357
+ emitErr(refBlindKindNotice(name, rootKinds.blindKinds));
2358
+ emit(`${name} (no callers recorded)`);
2361
2359
  return 0;
2362
2360
  }
2363
- emit3(`${name} (no callers)`);
2364
- if (rootKinds.blindCount > 0) emitErr3(refBlindKindPartialNote(name, rootKinds.blindKinds, rootKinds.blindCount, rootKinds.total));
2361
+ emit(`${name} (no callers)`);
2362
+ if (rootKinds.blindCount > 0) emitErr(refBlindKindPartialNote(name, rootKinds.blindKinds, rootKinds.blindCount, rootKinds.total));
2365
2363
  return 0;
2366
2364
  }
2367
2365
  if (matchesGrep !== void 0 && filteredChains.length === 0) {
2368
- emit3(grepFilteredToEmptyNotice(chains.length, opts.grep, "chain", "chains"));
2366
+ emit(grepFilteredToEmptyNotice(chains.length, opts.grep, "chain", "chains"));
2369
2367
  return 0;
2370
2368
  }
2371
2369
  for (const chain of filteredChains) {
2372
- emit3(chain.join(" -> "));
2370
+ emit(chain.join(" -> "));
2373
2371
  }
2374
2372
  return 0;
2375
2373
  }
2376
2374
  function runImpact(opts) {
2377
2375
  if (opts.top !== void 0 && opts.top <= 0) {
2378
- emitErr3(`--top must be a positive number, got: ${opts.top}`);
2376
+ emitErr(`--top must be a positive number, got: ${opts.top}`);
2379
2377
  return 1;
2380
2378
  }
2381
2379
  const top = opts.top ?? 20;
@@ -2384,7 +2382,7 @@ function runImpact(opts) {
2384
2382
  const { name: rootName, file } = parseGraphSymbolSpec(opts.symbol);
2385
2383
  const fileHint = file !== void 0 ? resolveIndexPath(file, rootDir) : void 0;
2386
2384
  if (fileHint !== void 0 && querySymbols({ name: rootName, filePath: fileHint, limit: 1 }).length === 0) {
2387
- emitErr3(`Symbol '${rootName}' not found in '${file}'`);
2385
+ emitErr(`Symbol '${rootName}' not found in '${file}'`);
2388
2386
  return 1;
2389
2387
  }
2390
2388
  const getSyms = buildFileSymCache();
@@ -2429,64 +2427,64 @@ function runImpact(opts) {
2429
2427
  const grepped = matchesGrep !== void 0 ? allSorted.filter(([symbol]) => matchesGrep(symbol)) : allSorted;
2430
2428
  const sorted = grepped.slice(0, top);
2431
2429
  if (depthCapped > 0) {
2432
- emitErr3(`Impact truncated at the ${DEPTH_CAP}-hop depth limit: ${depthCapped} symbol${depthCapped === 1 ? "" : "s"} at that depth ${depthCapped === 1 ? "was" : "were"} not expanded, so callers reachable only beyond ${DEPTH_CAP} hops are missing.`);
2430
+ emitErr(`Impact truncated at the ${DEPTH_CAP}-hop depth limit: ${depthCapped} symbol${depthCapped === 1 ? "" : "s"} at that depth ${depthCapped === 1 ? "was" : "were"} not expanded, so callers reachable only beyond ${DEPTH_CAP} hops are missing.`);
2433
2431
  }
2434
2432
  if (grepped.length > sorted.length) {
2435
- emitErr3(`Showing top ${sorted.length} of ${grepped.length} impacted symbols (raise --top to see the rest).`);
2433
+ emitErr(`Showing top ${sorted.length} of ${grepped.length} impacted symbols (raise --top to see the rest).`);
2436
2434
  }
2437
2435
  if (matchesGrep !== void 0 && sorted.length === 0 && allSorted.length > 0) {
2438
2436
  if (opts.json === true) {
2439
- emitErr3(grepFilteredToEmptyNotice(allSorted.length, opts.grep, "impacted symbol", "impacted symbols"));
2440
- emit3(displaySafeJson([]));
2437
+ emitErr(grepFilteredToEmptyNotice(allSorted.length, opts.grep, "impacted symbol", "impacted symbols"));
2438
+ emit(displaySafeJson([]));
2441
2439
  return 0;
2442
2440
  }
2443
- emit3(grepFilteredToEmptyNotice(allSorted.length, opts.grep, "impacted symbol", "impacted symbols"));
2441
+ emit(grepFilteredToEmptyNotice(allSorted.length, opts.grep, "impacted symbol", "impacted symbols"));
2444
2442
  return 0;
2445
2443
  }
2446
2444
  if (sorted.length === 0) {
2447
2445
  if (opts.excludeTests === true && suppressedCount > 0) {
2448
2446
  if (opts.json === true) {
2449
- emit3(displaySafeJson([]));
2447
+ emit(displaySafeJson([]));
2450
2448
  return 1;
2451
2449
  }
2452
- emitErr3(`No non-test impact found for '${opts.symbol}' (${excludeTestsHiddenNote(suppressedCount)})`);
2450
+ emitErr(`No non-test impact found for '${opts.symbol}' (${excludeTestsHiddenNote(suppressedCount)})`);
2453
2451
  return 1;
2454
2452
  }
2455
2453
  const defRows = querySymbols({ name: rootName, rootDir, limit: REF_BLIND_DEF_PROBE_LIMIT });
2456
2454
  if (defRows.length === 0) {
2457
- emitErr3(`Symbol not found: ${opts.symbol}${unknownSymbolSuggestion(rootName, rootDir)}`);
2455
+ emitErr(`Symbol not found: ${opts.symbol}${unknownSymbolSuggestion(rootName, rootDir)}`);
2458
2456
  return 1;
2459
2457
  }
2460
2458
  const defPaths = fileHint !== void 0 ? [fileHint] : defRows.map((r) => r.filePath);
2461
2459
  const firstDefPath = defPaths[0];
2462
2460
  if (firstDefPath !== void 0 && defPaths.every((fp) => !isRefIndexedFile(fp))) {
2463
- emitErr3(refBlindLanguageNotice(rootName, detectLanguageOfFile(firstDefPath), toDisplayPath(rootDir, firstDefPath)));
2461
+ emitErr(refBlindLanguageNotice(rootName, detectLanguageOfFile(firstDefPath), toDisplayPath(rootDir, firstDefPath)));
2464
2462
  return 1;
2465
2463
  }
2466
2464
  const kindRows = fileHint !== void 0 ? querySymbols({ name: rootName, filePath: fileHint, limit: REF_BLIND_DEF_PROBE_LIMIT }) : defRows;
2467
2465
  const kindVerdict = refBlindKindVerdict(kindRows);
2468
2466
  if (kindVerdict.allBlind) {
2469
- emitErr3(refBlindKindNotice(rootName, kindVerdict.blindKinds));
2467
+ emitErr(refBlindKindNotice(rootName, kindVerdict.blindKinds));
2470
2468
  return 1;
2471
2469
  }
2472
- emitErr3(`No callers found for '${opts.symbol}'`);
2473
- if (kindVerdict.blindCount > 0) emitErr3(refBlindKindPartialNote(rootName, kindVerdict.blindKinds, kindVerdict.blindCount, kindRows.length));
2470
+ emitErr(`No callers found for '${opts.symbol}'`);
2471
+ if (kindVerdict.blindCount > 0) emitErr(refBlindKindPartialNote(rootName, kindVerdict.blindKinds, kindVerdict.blindCount, kindRows.length));
2474
2472
  return 1;
2475
2473
  }
2476
2474
  if (opts.json === true) {
2477
- emit3(displaySafeJson(sorted.map(([symbol, h]) => ({ symbol, hops: h }))));
2475
+ emit(displaySafeJson(sorted.map(([symbol, h]) => ({ symbol, hops: h }))));
2478
2476
  return 0;
2479
2477
  }
2480
2478
  const MODULE_SCOPE_PREFIX = "(module scope) ";
2481
2479
  for (const [symbol, h] of sorted) {
2482
2480
  const displaySymbol = symbol.startsWith(MODULE_SCOPE_PREFIX) ? MODULE_SCOPE_PREFIX + toDisplayPath(rootDir, symbol.slice(MODULE_SCOPE_PREFIX.length)) : symbol;
2483
- emit3(`${displaySymbol} (hops: ${h})`);
2481
+ emit(`${displaySymbol} (hops: ${h})`);
2484
2482
  }
2485
2483
  return 0;
2486
2484
  }
2487
2485
  function runAsk(opts) {
2488
2486
  if (opts.top !== void 0 && opts.top <= 0) {
2489
- emitErr3(`--top must be a positive number, got: ${opts.top}`);
2487
+ emitErr(`--top must be a positive number, got: ${opts.top}`);
2490
2488
  return 1;
2491
2489
  }
2492
2490
  const top = opts.top ?? 8;
@@ -2495,7 +2493,7 @@ function runAsk(opts) {
2495
2493
  const moreBeyondTop = fetched.length > top;
2496
2494
  const hits = fetched.slice(0, top);
2497
2495
  if (moreBeyondTop) {
2498
- emitErr3(`Answer is grounded in the top ${countNoun(top, "match", "matches")}; more matched (raise --top to widen the evidence).`);
2496
+ emitErr(`Answer is grounded in the top ${countNoun(top, "match", "matches")}; more matched (raise --top to widen the evidence).`);
2499
2497
  }
2500
2498
  warnIfFilesStale(hits.map((h) => h.filePath));
2501
2499
  const BACKEND_ENV = "TOKEN_GOAT_ASK_BACKEND";
@@ -2503,12 +2501,12 @@ function runAsk(opts) {
2503
2501
  const entries = hits.map((h) => ({ file: h.filePath, symbol: h.name, kind: h.kind, line: h.lineStart, readCmd: `token-goat read "${h.filePath}::${h.name}@${h.lineStart}"` }));
2504
2502
  const degrade = (reason, extraNote) => {
2505
2503
  if (opts.json === true) {
2506
- emit3(displaySafeJson({ degraded: true, note: reason, ...extraNote !== void 0 ? { hint: extraNote } : {}, context: entries }));
2504
+ emit(displaySafeJson({ degraded: true, note: reason, ...extraNote !== void 0 ? { hint: extraNote } : {}, context: entries }));
2507
2505
  return 0;
2508
2506
  }
2509
- emit3(`[degraded mode - ${reason}]`);
2510
- if (extraNote !== void 0) emit3(extraNote);
2511
- for (const e of entries) emit3(`token-goat read "${displaySafeText(toDisplayPath(rootDir, e.file))}::${displaySafeText(e.symbol)}@${e.line}"`);
2507
+ emit(`[degraded mode - ${reason}]`);
2508
+ if (extraNote !== void 0) emit(extraNote);
2509
+ for (const e of entries) emit(`token-goat read "${displaySafeText(toDisplayPath(rootDir, e.file))}::${displaySafeText(e.symbol)}@${e.line}"`);
2512
2510
  return 0;
2513
2511
  };
2514
2512
  if (!backendLabel) return degrade(`set ${BACKEND_ENV}=claude|codex for LLM synthesis`);
@@ -2555,9 +2553,9 @@ ANSWER:`;
2555
2553
  }
2556
2554
  if (answer) {
2557
2555
  if (opts.json === true) {
2558
- emit3(displaySafeJson({ answer, context: entries }));
2556
+ emit(displaySafeJson({ answer, context: entries }));
2559
2557
  } else {
2560
- emit3(answer);
2558
+ emit(answer);
2561
2559
  }
2562
2560
  return 0;
2563
2561
  }
@@ -3054,6 +3052,17 @@ async function takeScreenshot(url, destPath, opts) {
3054
3052
  return { path: finalPath, originalBytes: buffer.length, finalBytes: finalBuffer.length };
3055
3053
  }
3056
3054
 
3055
+ // src/symbol_scan.ts
3056
+ init_define_import_meta_env();
3057
+ var SYMBOL_SCAN_PAGE = 1e4;
3058
+ function forEachSymbol(queryOpts, visit) {
3059
+ for (let offset = 0; ; offset += SYMBOL_SCAN_PAGE) {
3060
+ const rows = querySymbols({ ...queryOpts, limit: SYMBOL_SCAN_PAGE, offset });
3061
+ for (const row of rows) visit(row);
3062
+ if (rows.length < SYMBOL_SCAN_PAGE) return;
3063
+ }
3064
+ }
3065
+
3057
3066
  // src/ts_refs.ts
3058
3067
  init_define_import_meta_env();
3059
3068
  import { createRequire } from "node:module";
@@ -7376,7 +7385,7 @@ function fenceHtmlText(text) {
7376
7385
  function runCsvQuery(opts) {
7377
7386
  const text = readFileText(opts.file);
7378
7387
  if (text === null) {
7379
- emitErr4(`Could not read: ${opts.file}`);
7388
+ emitErr(`Could not read: ${opts.file}`);
7380
7389
  return 1;
7381
7390
  }
7382
7391
  const columns = opts.columns ? opts.columns.split(",").map((c) => c.trim()).filter(Boolean) : void 0;
@@ -7384,7 +7393,7 @@ function runCsvQuery(opts) {
7384
7393
  try {
7385
7394
  head = opts.head !== void 0 ? requireNonNegativeStrictInt("--head", opts.head) : void 0;
7386
7395
  } catch (e) {
7387
- emitErr4(extractErrorMessage(e));
7396
+ emitErr(extractErrorMessage(e));
7388
7397
  return 1;
7389
7398
  }
7390
7399
  try {
@@ -7397,7 +7406,7 @@ function runCsvQuery(opts) {
7397
7406
  ...opts.noHeader === true ? { noHeader: true } : {}
7398
7407
  });
7399
7408
  if (result.header.length === 0) {
7400
- emit4(`No data rows found in ${displaySafeText(opts.file)}`);
7409
+ emit(`No data rows found in ${displaySafeText(opts.file)}`);
7401
7410
  return 0;
7402
7411
  }
7403
7412
  const fullSourceBytes = sumFileSizes([opts.file]);
@@ -7406,23 +7415,23 @@ function runCsvQuery(opts) {
7406
7415
  const headTruncated = result.rows.length < result.totalRows;
7407
7416
  const capped = guardJsonRows(rowsJson);
7408
7417
  const jsonText = displaySafeJson({ items: capped.items, truncated: capped.truncated || headTruncated, totalCount: result.totalRows, ...result.totalRows === 0 && result.preFilterRows > 0 ? { filteredFromRows: result.preFilterRows } : {} }, 0);
7409
- emit4(jsonText);
7418
+ emit(jsonText);
7410
7419
  recordReadStat("csv_query", fullSourceBytes, jsonText, opts.file);
7411
7420
  } else {
7412
7421
  const tableText = formatCsvTable(result, (opts.where ?? []).map((w) => `--where ${w}`));
7413
- emit4(tableText);
7422
+ emit(tableText);
7414
7423
  recordReadStat("csv_query", fullSourceBytes, tableText, opts.file);
7415
7424
  }
7416
7425
  return 0;
7417
7426
  } catch (e) {
7418
- emitErr4(extractErrorMessage(e));
7427
+ emitErr(extractErrorMessage(e));
7419
7428
  return 1;
7420
7429
  }
7421
7430
  }
7422
7431
  function runCsvProfile(opts) {
7423
7432
  const text = readFileText(opts.file);
7424
7433
  if (text === null) {
7425
- emitErr4(`Could not read: ${opts.file}`);
7434
+ emitErr(`Could not read: ${opts.file}`);
7426
7435
  return 1;
7427
7436
  }
7428
7437
  try {
@@ -7431,41 +7440,41 @@ function runCsvProfile(opts) {
7431
7440
  ...opts.noHeader === true ? { noHeader: true } : {}
7432
7441
  });
7433
7442
  if (profiles.length === 0) {
7434
- emit4(`No data rows found in ${displaySafeText(opts.file)}`);
7443
+ emit(`No data rows found in ${displaySafeText(opts.file)}`);
7435
7444
  return 0;
7436
7445
  }
7437
7446
  const fullSourceBytes = sumFileSizes([opts.file]);
7438
7447
  const profileText = formatCsvProfile(profiles);
7439
- emit4(profileText);
7448
+ emit(profileText);
7440
7449
  recordReadStat("csv_profile", fullSourceBytes, profileText, opts.file);
7441
7450
  return 0;
7442
7451
  } catch (e) {
7443
- emitErr4(extractErrorMessage(e));
7452
+ emitErr(extractErrorMessage(e));
7444
7453
  return 1;
7445
7454
  }
7446
7455
  }
7447
7456
  function runOutlineCommand(opts, parse, formatLabel, kind) {
7448
7457
  const text = readFileText(opts.file);
7449
7458
  if (text === null) {
7450
- emitErr4(`Could not read: ${opts.file}`);
7459
+ emitErr(`Could not read: ${opts.file}`);
7451
7460
  return 1;
7452
7461
  }
7453
7462
  let data;
7454
7463
  try {
7455
7464
  data = parse(text);
7456
7465
  } catch {
7457
- emitErr4(`Failed to parse ${formatLabel}: ${opts.file}`);
7466
+ emitErr(`Failed to parse ${formatLabel}: ${opts.file}`);
7458
7467
  return 1;
7459
7468
  }
7460
7469
  const outline = outlineJson(data);
7461
7470
  const fullSourceBytes = sumFileSizes([opts.file]);
7462
7471
  if (opts.json === true) {
7463
7472
  const jsonText = displaySafeJson(outline, 0);
7464
- emit4(jsonText);
7473
+ emit(jsonText);
7465
7474
  recordReadStat(kind, fullSourceBytes, jsonText, opts.file);
7466
7475
  } else {
7467
7476
  const text2 = formatJsonOutline(outline);
7468
- emit4(text2);
7477
+ emit(text2);
7469
7478
  recordReadStat(kind, fullSourceBytes, text2, opts.file);
7470
7479
  }
7471
7480
  return 0;
@@ -7476,21 +7485,21 @@ function runJsonOutline(opts) {
7476
7485
  function runQueryCommand(opts, parse, formatLabel, guardTag, kind) {
7477
7486
  const text = readFileText(opts.file);
7478
7487
  if (text === null) {
7479
- emitErr4(`Could not read: ${opts.file}`);
7488
+ emitErr(`Could not read: ${opts.file}`);
7480
7489
  return 1;
7481
7490
  }
7482
7491
  let data;
7483
7492
  try {
7484
7493
  data = parse(text);
7485
7494
  } catch {
7486
- emitErr4(`Failed to parse ${formatLabel}: ${opts.file}`);
7495
+ emitErr(`Failed to parse ${formatLabel}: ${opts.file}`);
7487
7496
  return 1;
7488
7497
  }
7489
7498
  let head;
7490
7499
  try {
7491
7500
  head = opts.head !== void 0 ? requireNonNegativeStrictInt("--head", opts.head) : void 0;
7492
7501
  } catch (e) {
7493
- emitErr4(extractErrorMessage(e));
7502
+ emitErr(extractErrorMessage(e));
7494
7503
  return 1;
7495
7504
  }
7496
7505
  try {
@@ -7499,7 +7508,7 @@ function runQueryCommand(opts, parse, formatLabel, guardTag, kind) {
7499
7508
  if (!result.fanned) {
7500
7509
  const value = result.items[0];
7501
7510
  const valueText = opts.json === true ? displaySafeJson(value, 0) : displaySafeJson(value);
7502
- emit4(valueText);
7511
+ emit(valueText);
7503
7512
  recordReadStat(kind, fullSourceBytes, valueText, opts.file);
7504
7513
  return 0;
7505
7514
  }
@@ -7509,7 +7518,7 @@ function runQueryCommand(opts, parse, formatLabel, guardTag, kind) {
7509
7518
  if (opts.json === true) {
7510
7519
  const capped = guardJsonRows(limited);
7511
7520
  const jsonText = displaySafeJson({ items: capped.items, truncated: capped.truncated || headTruncated || result.truncated, totalCount }, 0);
7512
- emit4(jsonText);
7521
+ emit(jsonText);
7513
7522
  recordReadStat(kind, fullSourceBytes, jsonText, opts.file);
7514
7523
  } else {
7515
7524
  const lines = limited.map((item) => displaySafeJson(item, 0));
@@ -7525,7 +7534,7 @@ function runQueryCommand(opts, parse, formatLabel, guardTag, kind) {
7525
7534
  }
7526
7535
  return 0;
7527
7536
  } catch (e) {
7528
- emitErr4(extractErrorMessage(e));
7537
+ emitErr(extractErrorMessage(e));
7529
7538
  return 1;
7530
7539
  }
7531
7540
  }
@@ -7567,21 +7576,21 @@ function runYamlQuery(opts) {
7567
7576
  function runXmlOutline(opts) {
7568
7577
  const text = readFileText(opts.file);
7569
7578
  if (text === null) {
7570
- emitErr4(`Could not read: ${opts.file}`);
7579
+ emitErr(`Could not read: ${opts.file}`);
7571
7580
  return 1;
7572
7581
  }
7573
7582
  let summary;
7574
7583
  try {
7575
7584
  summary = outlineXml(text, { ...opts.maxDepth !== void 0 ? { maxDepth: opts.maxDepth } : {} });
7576
7585
  } catch (e) {
7577
- emitErr4(`Failed to parse XML: ${opts.file}
7586
+ emitErr(`Failed to parse XML: ${opts.file}
7578
7587
  ${extractErrorMessage(e)}`);
7579
7588
  return 1;
7580
7589
  }
7581
7590
  const fullSourceBytes = sumFileSizes([opts.file]);
7582
7591
  if (opts.json === true) {
7583
7592
  const jsonText = displaySafeJson(summary);
7584
- emit4(jsonText);
7593
+ emit(jsonText);
7585
7594
  recordReadStat("xml_outline", fullSourceBytes, jsonText, opts.file);
7586
7595
  } else {
7587
7596
  const outlineText = formatXmlOutline(summary);
@@ -7593,19 +7602,19 @@ ${extractErrorMessage(e)}`);
7593
7602
  function runXmlQuery(opts) {
7594
7603
  const text = readFileText(opts.file);
7595
7604
  if (text === null) {
7596
- emitErr4(`Could not read: ${opts.file}`);
7605
+ emitErr(`Could not read: ${opts.file}`);
7597
7606
  return 1;
7598
7607
  }
7599
7608
  const queryPath = (opts.xpath ?? opts.path ?? "").trim();
7600
7609
  if (!queryPath) {
7601
- emitErr4("Must provide a path or --xpath <expression>");
7610
+ emitErr("Must provide a path or --xpath <expression>");
7602
7611
  return 1;
7603
7612
  }
7604
7613
  let head;
7605
7614
  try {
7606
7615
  head = opts.head !== void 0 ? requireNonNegativeStrictInt("--head", opts.head) : void 0;
7607
7616
  } catch (e) {
7608
- emitErr4(extractErrorMessage(e));
7617
+ emitErr(extractErrorMessage(e));
7609
7618
  return 1;
7610
7619
  }
7611
7620
  try {
@@ -7615,10 +7624,10 @@ function runXmlQuery(opts) {
7615
7624
  if (result.attributeValues.length === 0) {
7616
7625
  if (opts.json === true) {
7617
7626
  const jsonText = displaySafeJson({ items: [], truncated: false, totalCount: 0 }, 0);
7618
- emit4(jsonText);
7627
+ emit(jsonText);
7619
7628
  recordReadStat("xml_query", fullSourceBytes, jsonText, opts.file);
7620
7629
  } else {
7621
- emit4(`No attributes matched path: '${displaySafeText(queryPath)}'`);
7630
+ emit(`No attributes matched path: '${displaySafeText(queryPath)}'`);
7622
7631
  }
7623
7632
  return 0;
7624
7633
  }
@@ -7650,7 +7659,7 @@ ${val}`;
7650
7659
  outText = val;
7651
7660
  }
7652
7661
  }
7653
- emit4(outText);
7662
+ emit(outText);
7654
7663
  recordReadStat("xml_query", fullSourceBytes, outText, opts.file);
7655
7664
  return 0;
7656
7665
  }
@@ -7680,7 +7689,7 @@ ${val}`;
7680
7689
  { items: capped.items, truncated: capped.truncated || headTruncated2, totalCount: totalCount2 },
7681
7690
  0
7682
7691
  );
7683
- emit4(jsonText);
7692
+ emit(jsonText);
7684
7693
  recordReadStat("xml_query", fullSourceBytes, jsonText, opts.file);
7685
7694
  } else {
7686
7695
  const lines = [];
@@ -7710,10 +7719,10 @@ ${val}`);
7710
7719
  if (result.items.length === 0) {
7711
7720
  if (opts.json === true) {
7712
7721
  const jsonText = displaySafeJson({ items: [], truncated: false, totalCount: 0 }, 0);
7713
- emit4(jsonText);
7722
+ emit(jsonText);
7714
7723
  recordReadStat("xml_query", fullSourceBytes, jsonText, opts.file);
7715
7724
  } else {
7716
- emit4(`No elements matched path: '${displaySafeText(queryPath)}'`);
7725
+ emit(`No elements matched path: '${displaySafeText(queryPath)}'`);
7717
7726
  }
7718
7727
  return 0;
7719
7728
  }
@@ -7725,7 +7734,7 @@ ${val}`);
7725
7734
  ...opts.decodeEmbeddedXml ? { decodeEmbedded: true } : {}
7726
7735
  });
7727
7736
  const jsonText = displaySafeJson(jsonVal);
7728
- emit4(jsonText);
7737
+ emit(jsonText);
7729
7738
  recordReadStat("xml_query", fullSourceBytes, jsonText, opts.file);
7730
7739
  } else {
7731
7740
  let xmlText = serializeXmlNode(
@@ -7757,7 +7766,7 @@ ${xmlText}`;
7757
7766
  { items: capped.items, truncated: capped.truncated || headTruncated, totalCount },
7758
7767
  0
7759
7768
  );
7760
- emit4(jsonText);
7769
+ emit(jsonText);
7761
7770
  recordReadStat("xml_query", fullSourceBytes, jsonText, opts.file);
7762
7771
  } else {
7763
7772
  const blocks = limited.map((node) => {
@@ -7781,21 +7790,21 @@ ${block}`;
7781
7790
  }
7782
7791
  return 0;
7783
7792
  } catch (e) {
7784
- emitErr4(extractErrorMessage(e));
7793
+ emitErr(extractErrorMessage(e));
7785
7794
  return 1;
7786
7795
  }
7787
7796
  }
7788
7797
  function runHtmlOutline(opts) {
7789
7798
  const text = readFileText(opts.file);
7790
7799
  if (text === null) {
7791
- emitErr4(`Could not read: ${opts.file}`);
7800
+ emitErr(`Could not read: ${opts.file}`);
7792
7801
  return 1;
7793
7802
  }
7794
7803
  const summary = outlineHtml(text);
7795
7804
  const fullSourceBytes = sumFileSizes([opts.file]);
7796
7805
  if (opts.json === true) {
7797
7806
  const jsonText = displaySafeJson(summary);
7798
- emit4(jsonText);
7807
+ emit(jsonText);
7799
7808
  recordReadStat("html_outline", fullSourceBytes, jsonText, opts.file);
7800
7809
  } else {
7801
7810
  const outlineText = formatHtmlOutline(summary);
@@ -7807,14 +7816,14 @@ function runHtmlOutline(opts) {
7807
7816
  function runHtmlQuery(opts) {
7808
7817
  const text = readFileText(opts.file);
7809
7818
  if (text === null) {
7810
- emitErr4(`Could not read: ${opts.file}`);
7819
+ emitErr(`Could not read: ${opts.file}`);
7811
7820
  return 1;
7812
7821
  }
7813
7822
  let head;
7814
7823
  try {
7815
7824
  head = opts.head !== void 0 ? requireNonNegativeStrictInt("--head", opts.head) : void 0;
7816
7825
  } catch (e) {
7817
- emitErr4(extractErrorMessage(e));
7826
+ emitErr(extractErrorMessage(e));
7818
7827
  return 1;
7819
7828
  }
7820
7829
  try {
@@ -7825,10 +7834,10 @@ function runHtmlQuery(opts) {
7825
7834
  if (result.attributeValues.length === 0) {
7826
7835
  if (opts.json === true) {
7827
7836
  const jsonText = displaySafeJson({ items: [], truncated: false, totalCount: 0 }, 0);
7828
- emit4(jsonText);
7837
+ emit(jsonText);
7829
7838
  recordReadStat("html_query", fullSourceBytes, jsonText, opts.file);
7830
7839
  } else {
7831
- emit4(`No attributes matched selector: '${displaySafeText(opts.selector)}'`);
7840
+ emit(`No attributes matched selector: '${displaySafeText(opts.selector)}'`);
7832
7841
  }
7833
7842
  return 0;
7834
7843
  }
@@ -7838,7 +7847,7 @@ function runHtmlQuery(opts) {
7838
7847
  if (opts.json === true) {
7839
7848
  const capped = guardJsonRows(limited2);
7840
7849
  const jsonText = displaySafeJson({ items: capped.items, truncated: capped.truncated || headTruncated2, totalCount: totalCount2 }, 0);
7841
- emit4(jsonText);
7850
+ emit(jsonText);
7842
7851
  recordReadStat("html_query", fullSourceBytes, jsonText, opts.file);
7843
7852
  } else {
7844
7853
  const lines = limited2.map((item) => item);
@@ -7854,10 +7863,10 @@ function runHtmlQuery(opts) {
7854
7863
  if (result.elements.length === 0) {
7855
7864
  if (opts.json === true) {
7856
7865
  const jsonText = displaySafeJson({ items: [], truncated: false, totalCount: 0 }, 0);
7857
- emit4(jsonText);
7866
+ emit(jsonText);
7858
7867
  recordReadStat("html_query", fullSourceBytes, jsonText, opts.file);
7859
7868
  } else {
7860
- emit4(`No elements matched selector: '${displaySafeText(opts.selector)}'`);
7869
+ emit(`No elements matched selector: '${displaySafeText(opts.selector)}'`);
7861
7870
  }
7862
7871
  return 0;
7863
7872
  }
@@ -7874,7 +7883,7 @@ function runHtmlQuery(opts) {
7874
7883
  }));
7875
7884
  const capped = guardJsonRows(jsonItems);
7876
7885
  const jsonText = displaySafeJson({ items: capped.items, truncated: capped.truncated || headTruncated, totalCount });
7877
- emit4(jsonText);
7886
+ emit(jsonText);
7878
7887
  recordReadStat("html_query", fullSourceBytes, jsonText, opts.file);
7879
7888
  } else if (opts.text === true) {
7880
7889
  const textLines = limited.map((n) => extractNodeText(n, text)).filter(Boolean);
@@ -7895,24 +7904,24 @@ function runHtmlQuery(opts) {
7895
7904
  }
7896
7905
  return 0;
7897
7906
  } catch (e) {
7898
- emitErr4(extractErrorMessage(e));
7907
+ emitErr(extractErrorMessage(e));
7899
7908
  return 1;
7900
7909
  }
7901
7910
  }
7902
7911
  function runHtmlLint(opts) {
7903
7912
  const text = readFileText(opts.file);
7904
7913
  if (text === null) {
7905
- emitErr4(`Could not read: ${opts.file}`);
7914
+ emitErr(`Could not read: ${opts.file}`);
7906
7915
  return 1;
7907
7916
  }
7908
7917
  const report = lintHtml(text);
7909
7918
  const isClean = opts.strict ? report.errors.length === 0 && report.warnings.length === 0 : report.errors.length === 0;
7910
7919
  if (opts.json === true) {
7911
- emit4(displaySafeJson(report));
7920
+ emit(displaySafeJson(report));
7912
7921
  return isClean ? 0 : 1;
7913
7922
  }
7914
7923
  if (report.errors.length === 0 && report.warnings.length === 0) {
7915
- emit4(`\u2713 ${displaySafeText(opts.file)}: HTML structure is valid (all tags balanced, no duplicate IDs, void elements respected).`);
7924
+ emit(`\u2713 ${displaySafeText(opts.file)}: HTML structure is valid (all tags balanced, no duplicate IDs, void elements respected).`);
7916
7925
  return 0;
7917
7926
  }
7918
7927
  const lines = [];
@@ -7936,20 +7945,20 @@ function runHtmlLint(opts) {
7936
7945
  lines.push(` <${tag}>: open=${counts.open}, close=${counts.close}, diff=${counts.diff}`);
7937
7946
  }
7938
7947
  }
7939
- emit4(lines.join("\n"));
7948
+ emit(lines.join("\n"));
7940
7949
  return isClean ? 0 : 1;
7941
7950
  }
7942
7951
  function loadOpenApiOperations(file) {
7943
7952
  const text = readFileText(file);
7944
7953
  if (text === null) {
7945
- emitErr4(`Could not read: ${file}`);
7954
+ emitErr(`Could not read: ${file}`);
7946
7955
  return null;
7947
7956
  }
7948
7957
  let spec;
7949
7958
  try {
7950
7959
  spec = parseOpenApiSpec(text, file);
7951
7960
  } catch {
7952
- emitErr4(`Failed to parse OpenAPI spec (not valid JSON or YAML): ${file}`);
7961
+ emitErr(`Failed to parse OpenAPI spec (not valid JSON or YAML): ${file}`);
7953
7962
  return null;
7954
7963
  }
7955
7964
  return extractOperations(spec);
@@ -7960,7 +7969,7 @@ function runOpenApiOutline(opts) {
7960
7969
  const fullSourceBytes = sumFileSizes([opts.file]);
7961
7970
  if (opts.json === true) {
7962
7971
  const jsonText = displaySafeJson(operations, 0);
7963
- emit4(jsonText);
7972
+ emit(jsonText);
7964
7973
  recordReadStat("openapi_outline", fullSourceBytes, jsonText, opts.file);
7965
7974
  } else {
7966
7975
  const text = formatOpenApiOutline(operations);
@@ -7978,13 +7987,13 @@ function runOpenApiOp(opts) {
7978
7987
  const closes = rankSimilarNames(operations.map(operationLabel), opts.operation);
7979
7988
  if (closes.length > 0) messages.push(didYouMean(closes));
7980
7989
  else if (operations.length > 0) messages.push(`Try: token-goat openapi-outline ${opts.file}`);
7981
- emitErr4(messages.join("\n"));
7990
+ emitErr(messages.join("\n"));
7982
7991
  return 1;
7983
7992
  }
7984
7993
  const fullSourceBytes = sumFileSizes([opts.file]);
7985
7994
  if (opts.json === true) {
7986
7995
  const jsonText = displaySafeJson(match, 0);
7987
- emit4(jsonText);
7996
+ emit(jsonText);
7988
7997
  recordReadStat("openapi_op", fullSourceBytes, jsonText, opts.operation);
7989
7998
  } else {
7990
7999
  const text = formatOperationDetail(match);
@@ -8003,7 +8012,6 @@ var MIN_WORD_SIMILARITY_LEN = 3;
8003
8012
  var STRUCTURED_MISS_MAX_BYTES = 128 * 1024;
8004
8013
  var STRUCTURED_MISS_MAX_FILES = 12;
8005
8014
  var STRUCTURED_MISS_MAX_NODES = 2e4;
8006
- var FIND_SCAN_LIMIT = 2e4;
8007
8015
  function endsWithPathBoundary(full, suffix) {
8008
8016
  if (!full.endsWith(suffix)) return false;
8009
8017
  if (full.length === suffix.length) return true;
@@ -8084,8 +8092,9 @@ function didYouMean(candidates) {
8084
8092
  return lines.join("\n");
8085
8093
  }
8086
8094
  function unknownSymbolSuggestion(name, rootDir) {
8087
- const rawSymbols = querySymbols({ limit: FIND_SCAN_LIMIT, rootDir });
8088
- const candidates = rankSimilarNames(rawSymbols.map((s) => s.name), name);
8095
+ const names = /* @__PURE__ */ new Set();
8096
+ forEachSymbol({ rootDir }, (s) => names.add(s.name));
8097
+ const candidates = rankSimilarNames([...names], name);
8089
8098
  return candidates.length > 0 ? `
8090
8099
  ${didYouMean(candidates)}` : "";
8091
8100
  }
@@ -8572,14 +8581,14 @@ ${sub.text}`);
8572
8581
  }
8573
8582
  function runBrief(opts) {
8574
8583
  if (opts.limit !== void 0 && opts.limit <= 0) {
8575
- emitErr4(`--limit must be a positive number, got: ${opts.limit}`);
8584
+ emitErr(`--limit must be a positive number, got: ${opts.limit}`);
8576
8585
  return 1;
8577
8586
  }
8578
8587
  const crossFilePairs = parseCrossFileMultiSpec(opts.spec);
8579
8588
  if (crossFilePairs !== null) {
8580
8589
  const { text: text2, code: code2 } = runBriefCrossFile(crossFilePairs, opts);
8581
- if (code2 === 0) emit4(text2);
8582
- else emitErr4(text2);
8590
+ if (code2 === 0) emit(text2);
8591
+ else emitErr(text2);
8583
8592
  return code2;
8584
8593
  }
8585
8594
  const { file, symbol } = parseReadSpec(opts.spec);
@@ -8587,14 +8596,14 @@ function runBrief(opts) {
8587
8596
  const multiSymbols = symbol.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
8588
8597
  if (multiSymbols.length > 1) {
8589
8598
  const { text: text2, code: code2 } = runBriefMulti(file, multiSymbols, opts);
8590
- if (code2 === 0) emit4(text2);
8591
- else emitErr4(text2);
8599
+ if (code2 === 0) emit(text2);
8600
+ else emitErr(text2);
8592
8601
  return code2;
8593
8602
  }
8594
8603
  }
8595
8604
  const { text, code } = runBriefCore(opts);
8596
- if (code === 0) emit4(text);
8597
- else emitErr4(text);
8605
+ if (code === 0) emit(text);
8606
+ else emitErr(text);
8598
8607
  return code;
8599
8608
  }
8600
8609
 
@@ -8609,7 +8618,7 @@ var OURS_RE = /^<{7}(?:\s+(.*))?$/;
8609
8618
  var BASE_RE = /^\|{7}(?:\s+(.*))?$/;
8610
8619
  var SEP_RE = /^={7}\s*$/;
8611
8620
  var THEIRS_RE = /^>{7}(?:\s+(.*))?$/;
8612
- function parseConflicts(filePath, text) {
8621
+ function parseConflicts(filePath, text, contextLines = 3) {
8613
8622
  const lines = text.split(/\r?\n/);
8614
8623
  const regions = [];
8615
8624
  const warnings = [];
@@ -8672,13 +8681,29 @@ function parseConflicts(filePath, text) {
8672
8681
  const theirsMatch = THEIRS_RE.exec(line);
8673
8682
  if (theirsMatch !== null) {
8674
8683
  const theirsLabel = (theirsMatch[1] ?? "").trim();
8684
+ const beforeContext = [];
8685
+ if (contextLines > 0) {
8686
+ const ctxStart = Math.max(0, startLine - 1 - contextLines);
8687
+ for (let c = ctxStart; c < startLine - 1; c++) {
8688
+ beforeContext.push({ line: c + 1, text: lines[c] ?? "" });
8689
+ }
8690
+ }
8691
+ const afterContext = [];
8692
+ if (contextLines > 0) {
8693
+ const ctxEnd = Math.min(lines.length, lineNo + contextLines);
8694
+ for (let c = lineNo; c < ctxEnd; c++) {
8695
+ afterContext.push({ line: c + 1, text: lines[c] ?? "" });
8696
+ }
8697
+ }
8675
8698
  regions.push({
8676
8699
  filePath,
8677
8700
  lineStart: startLine,
8678
8701
  lineEnd: lineNo,
8679
8702
  ours: { label: oursLabel, content: oursLines.join("\n") },
8680
8703
  base: sawBase ? { label: baseLabel, content: baseLines.join("\n") } : null,
8681
- theirs: { label: theirsLabel, content: theirsLines.join("\n") }
8704
+ theirs: { label: theirsLabel, content: theirsLines.join("\n") },
8705
+ ...beforeContext.length > 0 ? { beforeContext } : {},
8706
+ ...afterContext.length > 0 ? { afterContext } : {}
8682
8707
  });
8683
8708
  resetRegion();
8684
8709
  continue;
@@ -8721,6 +8746,11 @@ function formatSingleFileConflicts(result) {
8721
8746
  lines.push(`${displaySafeText(result.filePath)} -- ${result.regions.length} conflict${result.regions.length === 1 ? "" : "s"}`);
8722
8747
  for (const r of result.regions) {
8723
8748
  lines.push(` lines ${r.lineStart}-${r.lineEnd}`);
8749
+ if (r.beforeContext && r.beforeContext.length > 0) {
8750
+ for (const c of r.beforeContext) {
8751
+ lines.push(` ${c.line} | ${displaySafeText(c.text)}`);
8752
+ }
8753
+ }
8724
8754
  lines.push(` <<<<<<< ${displaySafeText(r.ours.label || "(ours)")}`);
8725
8755
  lines.push(indentBlock(r.ours.content));
8726
8756
  if (r.base !== null) {
@@ -8730,6 +8760,11 @@ function formatSingleFileConflicts(result) {
8730
8760
  lines.push(" =======");
8731
8761
  lines.push(indentBlock(r.theirs.content));
8732
8762
  lines.push(` >>>>>>> ${displaySafeText(r.theirs.label || "(theirs)")}`);
8763
+ if (r.afterContext && r.afterContext.length > 0) {
8764
+ for (const c of r.afterContext) {
8765
+ lines.push(` ${c.line} | ${displaySafeText(c.text)}`);
8766
+ }
8767
+ }
8733
8768
  }
8734
8769
  } else {
8735
8770
  lines.push(`${displaySafeText(result.filePath)} -- no conflicts`);
@@ -8779,23 +8814,24 @@ function runConflicts(opts) {
8779
8814
  try {
8780
8815
  stat = fs8.statSync(abs);
8781
8816
  } catch {
8782
- emitErr4(`Could not read: ${opts.path}`);
8817
+ emitErr(`Could not read: ${opts.path}`);
8783
8818
  return 1;
8784
8819
  }
8785
8820
  files = stat.isDirectory() ? walkProject(abs).files : [abs];
8786
8821
  }
8822
+ const contextLines = opts.context !== void 0 ? opts.context : 3;
8787
8823
  const results = [];
8788
8824
  for (const f of files) {
8789
8825
  const text = readFileText(f);
8790
8826
  if (text === null) continue;
8791
- const parsed = parseConflicts(f, text);
8827
+ const parsed = parseConflicts(f, text, contextLines);
8792
8828
  if (parsed.regions.length > 0 || parsed.warnings.length > 0) results.push(parsed);
8793
8829
  }
8794
8830
  const fullSourceBytes = sumFileSizes(files);
8795
8831
  const detail = opts.path ?? ".";
8796
8832
  if (opts.json === true) {
8797
8833
  const jsonText = displaySafeJson(opts.summary === true ? results.map(summarizeFileConflicts) : results, 0);
8798
- emit4(jsonText);
8834
+ emit(jsonText);
8799
8835
  recordReadStat("conflicts", fullSourceBytes, jsonText, detail);
8800
8836
  } else if (opts.summary === true) {
8801
8837
  const text = formatConflictSummaries(results.map(summarizeFileConflicts));
@@ -8873,7 +8909,7 @@ function refIsSafe(ref) {
8873
8909
  return !ref.startsWith("-");
8874
8910
  }
8875
8911
  function emitUnsafeRef(ref) {
8876
- emitErr4(`Refusing a git ref that starts with '-': ${ref}`);
8912
+ emitErr(`Refusing a git ref that starts with '-': ${ref}`);
8877
8913
  }
8878
8914
  function changedDiffBaselineBytes(cwd, ref, files) {
8879
8915
  if (files.length === 0) return 0;
@@ -8896,25 +8932,25 @@ function runChanged(opts = {}) {
8896
8932
  try {
8897
8933
  const result = runGit(["diff", ref, "--name-only"], { cwd });
8898
8934
  if (result.exitCode !== 0) {
8899
- emitErr4(`git diff failed: ${result.stderr}`);
8935
+ emitErr(`git diff failed: ${result.stderr}`);
8900
8936
  const hint = buildChangedRefHint(cwd, ref);
8901
8937
  if (hint !== null) {
8902
- emitErr4(hint);
8938
+ emitErr(hint);
8903
8939
  }
8904
8940
  return 1;
8905
8941
  }
8906
8942
  changedFiles = result.stdout.trim().split(/\r?\n/).filter(Boolean);
8907
8943
  } catch {
8908
- emitErr4(`Could not run git diff against '${ref}'`);
8944
+ emitErr(`Could not run git diff against '${ref}'`);
8909
8945
  return 1;
8910
8946
  }
8911
8947
  const emptyEnvelope = () => {
8912
- emit4(displaySafeJson({ items: [], truncated: false, totalCount: 0 }));
8948
+ emit(displaySafeJson({ items: [], truncated: false, totalCount: 0 }));
8913
8949
  return 0;
8914
8950
  };
8915
8951
  if (changedFiles.length === 0) {
8916
8952
  if (opts.json === true) return emptyEnvelope();
8917
- emit4("No files changed.");
8953
+ emit("No files changed.");
8918
8954
  return 0;
8919
8955
  }
8920
8956
  const preGrepFileCount = changedFiles.length;
@@ -8922,7 +8958,7 @@ function runChanged(opts = {}) {
8922
8958
  if (matchesGrep !== void 0) changedFiles = changedFiles.filter((f) => matchesGrep(f));
8923
8959
  if (matchesGrep !== void 0 && changedFiles.length === 0) {
8924
8960
  if (opts.json === true) return emptyEnvelope();
8925
- emit4(grepFilteredToEmptyNotice(preGrepFileCount, opts.grep ?? "", "changed file", "changed files"));
8961
+ emit(grepFilteredToEmptyNotice(preGrepFileCount, opts.grep ?? "", "changed file", "changed files"));
8926
8962
  return 0;
8927
8963
  }
8928
8964
  const postGrepFileCount = changedFiles.length;
@@ -8936,12 +8972,12 @@ function runChanged(opts = {}) {
8936
8972
  if (opts.json === true) return emptyEnvelope();
8937
8973
  const grepRemoved = preGrepFileCount - postGrepFileCount;
8938
8974
  if (matchesGrep !== void 0 && grepRemoved > 0) {
8939
- emit4(
8975
+ emit(
8940
8976
  `No non-test files matched --grep ${opts.grep ?? ""} (${excludeTestsHiddenNote(hiddenTestFiles)}; ${countNoun(grepRemoved, "other changed file")} did not match the filter)`
8941
8977
  );
8942
8978
  return 0;
8943
8979
  }
8944
- emit4(`No non-test files changed (${excludeTestsHiddenNote(hiddenTestFiles)})`);
8980
+ emit(`No non-test files changed (${excludeTestsHiddenNote(hiddenTestFiles)})`);
8945
8981
  return 0;
8946
8982
  }
8947
8983
  if (opts.symbolMode === true) {
@@ -8957,27 +8993,27 @@ function runChanged(opts = {}) {
8957
8993
  }
8958
8994
  const allSymbols = [];
8959
8995
  for (const f of changedFiles) {
8960
- const fileSymbols = querySymbols({ filePath: resolveIndexPath(f, projectRoot), limit: FIND_SCAN_LIMIT2 });
8996
+ const fileSymbols = querySymbols({ filePath: resolveIndexPath(f, projectRoot), limit: FIND_SCAN_LIMIT });
8961
8997
  const hunks = hunksByFile.get(f);
8962
8998
  const scoped = hunks === void 0 || isVirtualIndexedPath(f) ? fileSymbols : fileSymbols.filter((s) => hunks.some((h) => h.start <= s.lineEnd && h.end >= s.lineStart));
8963
8999
  allSymbols.push(...scoped);
8964
9000
  }
8965
9001
  if (allSymbols.length === 0) {
8966
9002
  if (opts.json === true) return emptyEnvelope();
8967
- emit4("No symbols changed.");
9003
+ emit("No symbols changed.");
8968
9004
  return 0;
8969
9005
  }
8970
9006
  const symbolFullBytes = symbolDiffBaselineBytes;
8971
9007
  if (opts.json === true) {
8972
9008
  const capped = guardJsonRows(allSymbols);
8973
9009
  const text = displaySafeJson({ items: capped.items, truncated: capped.truncated, totalCount: capped.totalCount });
8974
- emit4(text);
9010
+ emit(text);
8975
9011
  recordReadStat("changed_lookup", symbolFullBytes, text, ref);
8976
9012
  return 0;
8977
9013
  }
8978
9014
  const symbolText = allSymbols.map((s) => `${s.name} (${s.kind}) \u2014 ${formatSymbolLocation(toDisplayPath(projectRoot, s.filePath), s.lineStart)}`).join("\n");
8979
9015
  for (const s of allSymbols) {
8980
- emit4(`${displaySafeText(s.name)} (${displaySafeText(s.kind)}) \u2014 ${formatSymbolLocation(displaySafeText(toDisplayPath(projectRoot, s.filePath)), s.lineStart)}`);
9016
+ emit(`${displaySafeText(s.name)} (${displaySafeText(s.kind)}) \u2014 ${formatSymbolLocation(displaySafeText(toDisplayPath(projectRoot, s.filePath)), s.lineStart)}`);
8981
9017
  }
8982
9018
  recordReadStat("changed_lookup", symbolFullBytes, symbolText, ref);
8983
9019
  return 0;
@@ -8986,12 +9022,12 @@ function runChanged(opts = {}) {
8986
9022
  if (opts.json === true) {
8987
9023
  const capped = guardJsonRows(changedFiles);
8988
9024
  const text = displaySafeJson({ items: capped.items, truncated: capped.truncated, totalCount: capped.totalCount });
8989
- emit4(text);
9025
+ emit(text);
8990
9026
  recordReadStat("changed_lookup", fullBytes, text, ref);
8991
9027
  return 0;
8992
9028
  }
8993
9029
  for (const f of changedFiles) {
8994
- emit4(f);
9030
+ emit(f);
8995
9031
  }
8996
9032
  recordReadStat("changed_lookup", fullBytes, changedFiles.join("\n"), ref);
8997
9033
  return 0;
@@ -9041,27 +9077,27 @@ function runDiff(opts) {
9041
9077
  try {
9042
9078
  diffResult = runGit(diffArgs, { cwd });
9043
9079
  } catch {
9044
- emitErr4(`Could not run git diff for '${match.filePath}'`);
9080
+ emitErr(`Could not run git diff for '${match.filePath}'`);
9045
9081
  return 1;
9046
9082
  }
9047
9083
  if (diffResult.exitCode !== 0) {
9048
- emitErr4(`git diff failed: ${diffResult.stderr}`);
9084
+ emitErr(`git diff failed: ${diffResult.stderr}`);
9049
9085
  return 1;
9050
9086
  }
9051
9087
  if (diffResult.stdout.trim() === "") {
9052
- emit4(`No changes to '${displaySafeText(match.name)}' in '${displaySafeText(toDisplayPath(getDisplayRoot(opts.projectRoot), match.filePath))}'.`);
9088
+ emit(`No changes to '${displaySafeText(match.name)}' in '${displaySafeText(toDisplayPath(getDisplayRoot(opts.projectRoot), match.filePath))}'.`);
9053
9089
  return 0;
9054
9090
  }
9055
9091
  const { hunks } = splitDiffHunks(diffResult.stdout);
9056
9092
  const diffFileScoped = isVirtualIndexedPath(match.filePath);
9057
9093
  const overlapping = diffFileScoped ? hunks : hunks.filter((h) => h.start <= match.lineEnd && h.end >= match.lineStart);
9058
9094
  if (overlapping.length === 0) {
9059
- emit4(`No changes to '${displaySafeText(match.name)}' (lines ${match.lineStart}-${match.lineEnd}) in '${displaySafeText(toDisplayPath(getDisplayRoot(opts.projectRoot), match.filePath))}'.`);
9095
+ emit(`No changes to '${displaySafeText(match.name)}' (lines ${match.lineStart}-${match.lineEnd}) in '${displaySafeText(toDisplayPath(getDisplayRoot(opts.projectRoot), match.filePath))}'.`);
9060
9096
  return 0;
9061
9097
  }
9062
9098
  if (opts.json === true) {
9063
9099
  const capped = guardJsonRows(overlapping.map((h) => ({ start: h.start, end: h.end, text: h.text })));
9064
- emit4(
9100
+ emit(
9065
9101
  displaySafeJson(
9066
9102
  {
9067
9103
  symbol: match.name,
@@ -9078,7 +9114,7 @@ function runDiff(opts) {
9078
9114
  }
9079
9115
  const header = `# ${displaySafeText(match.name)} (${displaySafeText(match.kind)}) \u2014 ${formatSymbolLocation(displaySafeText(toDisplayPath(getDisplayRoot(opts.projectRoot), match.filePath)), match.lineStart, match.lineEnd)}`;
9080
9116
  const diffNote = diffFileScoped ? [virtualIndexedScopeNote(displaySafeText(toDisplayPath(getDisplayRoot(opts.projectRoot), match.filePath)), "these hunks cover the whole file rather than this symbol alone")] : [];
9081
- emit4(guardText([header, ...diffNote, ...overlapping.map((h) => h.text)].join("\n"), "diff"));
9117
+ emit(guardText([header, ...diffNote, ...overlapping.map((h) => h.text)].join("\n"), "diff"));
9082
9118
  return 0;
9083
9119
  }
9084
9120
  var DEFAULT_LOG_MAX_COUNT = 20;
@@ -9139,20 +9175,20 @@ function runLog(opts) {
9139
9175
  try {
9140
9176
  logResult = runGit(logArgs, { cwd });
9141
9177
  } catch {
9142
- emitErr4(`Could not run git log for '${match.filePath}'`);
9178
+ emitErr(`Could not run git log for '${match.filePath}'`);
9143
9179
  return 1;
9144
9180
  }
9145
9181
  if (logResult.exitCode !== 0) {
9146
- emitErr4(`git log failed: ${displaySafeText(logResult.stderr)}`);
9182
+ emitErr(`git log failed: ${displaySafeText(logResult.stderr)}`);
9147
9183
  return 1;
9148
9184
  }
9149
9185
  if (logResult.stdout.trim() === "") {
9150
- emit4(`No history for '${displaySafeText(match.name)}' (lines ${match.lineStart}-${match.lineEnd}) in '${displaySafeText(toDisplayPath(getDisplayRoot(opts.projectRoot), match.filePath))}'.`);
9186
+ emit(`No history for '${displaySafeText(match.name)}' (lines ${match.lineStart}-${match.lineEnd}) in '${displaySafeText(toDisplayPath(getDisplayRoot(opts.projectRoot), match.filePath))}'.`);
9151
9187
  return 0;
9152
9188
  }
9153
9189
  if (opts.json === true) {
9154
9190
  const capped = guardJsonRows(parseLogDashLOutput(logResult.stdout));
9155
- emit4(
9191
+ emit(
9156
9192
  displaySafeJson(
9157
9193
  {
9158
9194
  symbol: match.name,
@@ -9169,7 +9205,7 @@ function runLog(opts) {
9169
9205
  }
9170
9206
  const header = `# ${displaySafeText(match.name)} (${displaySafeText(match.kind)}) \u2014 ${formatSymbolLocation(displaySafeText(toDisplayPath(getDisplayRoot(opts.projectRoot), match.filePath)), match.lineStart, match.lineEnd)}`;
9171
9207
  const logNote = fileScoped ? [virtualIndexedScopeNote(displaySafeText(toDisplayPath(getDisplayRoot(opts.projectRoot), match.filePath)), "this history covers the whole file rather than this symbol alone")] : [];
9172
- emit4(guardText([header, ...logNote, logResult.stdout].join("\n"), "diff"));
9208
+ emit(guardText([header, ...logNote, logResult.stdout].join("\n"), "diff"));
9173
9209
  return 0;
9174
9210
  }
9175
9211
 
@@ -9619,26 +9655,26 @@ async function runZipList(opts) {
9619
9655
  data = readFileBytes(opts.file);
9620
9656
  } catch (err) {
9621
9657
  if (err instanceof ZipInputTooLargeError) {
9622
- emitErr4(err.message);
9658
+ emitErr(err.message);
9623
9659
  return 1;
9624
9660
  }
9625
9661
  throw err;
9626
9662
  }
9627
9663
  if (data === null) {
9628
- emitErr4(`Could not read: ${opts.file}`);
9664
+ emitErr(`Could not read: ${opts.file}`);
9629
9665
  return 1;
9630
9666
  }
9631
9667
  let entries;
9632
9668
  try {
9633
9669
  entries = await listZipEntries(data);
9634
9670
  } catch (err) {
9635
- emitErr4(archiveReadFailure(err, opts.file));
9671
+ emitErr(archiveReadFailure(err, opts.file));
9636
9672
  return 1;
9637
9673
  }
9638
9674
  const fullSourceBytes = sumFileSizes([opts.file]);
9639
9675
  if (opts.json === true) {
9640
9676
  const jsonText = displaySafeJson(entries, 0);
9641
- emit4(jsonText);
9677
+ emit(jsonText);
9642
9678
  recordReadStat("zip_list", fullSourceBytes, jsonText, opts.file);
9643
9679
  } else {
9644
9680
  const text = formatZipList(entries);
@@ -9653,13 +9689,13 @@ async function runZipRead(opts) {
9653
9689
  data = readFileBytes(opts.file);
9654
9690
  } catch (err) {
9655
9691
  if (err instanceof ZipInputTooLargeError) {
9656
- emitErr4(err.message);
9692
+ emitErr(err.message);
9657
9693
  return 1;
9658
9694
  }
9659
9695
  throw err;
9660
9696
  }
9661
9697
  if (data === null) {
9662
- emitErr4(`Could not read: ${opts.file}`);
9698
+ emitErr(`Could not read: ${opts.file}`);
9663
9699
  return 1;
9664
9700
  }
9665
9701
  let entries;
@@ -9668,12 +9704,12 @@ async function runZipRead(opts) {
9668
9704
  entries = await listZipEntries(data);
9669
9705
  content = await extractZipEntry(data, opts.entry);
9670
9706
  } catch (err) {
9671
- emitErr4(archiveReadFailure(err, opts.file));
9707
+ emitErr(archiveReadFailure(err, opts.file));
9672
9708
  return 1;
9673
9709
  }
9674
9710
  const matchedEntry = entries.find((e) => e.path === opts.entry);
9675
9711
  if (matchedEntry?.isDirectory === true) {
9676
- emitErr4(`Entry '${opts.entry}' is a directory, not a file, in '${opts.file}'`);
9712
+ emitErr(`Entry '${opts.entry}' is a directory, not a file, in '${opts.file}'`);
9677
9713
  return 1;
9678
9714
  }
9679
9715
  if (content === void 0) {
@@ -9681,7 +9717,7 @@ async function runZipRead(opts) {
9681
9717
  const closes = rankSimilarNames(entries.map((e) => e.path), opts.entry);
9682
9718
  if (closes.length > 0) messages.push(didYouMean(closes));
9683
9719
  else if (entries.length > 0) messages.push(`Try: token-goat zip-list ${opts.file}`);
9684
- emitErr4(messages.join("\n"));
9720
+ emitErr(messages.join("\n"));
9685
9721
  return 1;
9686
9722
  }
9687
9723
  const buf = Buffer.from(content);
@@ -9689,7 +9725,7 @@ async function runZipRead(opts) {
9689
9725
  const fullSourceBytes = sumFileSizes([opts.file]);
9690
9726
  if (opts.json === true) {
9691
9727
  const jsonText = displaySafeJson({ path: opts.entry, text }, 0);
9692
- emit4(jsonText);
9728
+ emit(jsonText);
9693
9729
  recordReadStat("zip_read", fullSourceBytes, jsonText, opts.entry);
9694
9730
  } else {
9695
9731
  emitGuarded(text, "zip-read");
@@ -9703,16 +9739,16 @@ function runSqliteSchema(opts) {
9703
9739
  const fullSourceBytes = sumFileSizes([opts.file]);
9704
9740
  if (opts.json === true) {
9705
9741
  const jsonText = displaySafeJson(schema, 0);
9706
- emit4(jsonText);
9742
+ emit(jsonText);
9707
9743
  recordReadStat("sqlite_schema", fullSourceBytes, jsonText, opts.file);
9708
9744
  } else {
9709
9745
  const text = formatSqliteSchema(schema);
9710
- emit4(text);
9746
+ emit(text);
9711
9747
  recordReadStat("sqlite_schema", fullSourceBytes, text, opts.file);
9712
9748
  }
9713
9749
  return 0;
9714
9750
  } catch (e) {
9715
- emitErr4(extractErrorMessage(e));
9751
+ emitErr(extractErrorMessage(e));
9716
9752
  return 1;
9717
9753
  }
9718
9754
  }
@@ -9722,16 +9758,16 @@ function runSqliteTables(opts) {
9722
9758
  const fullSourceBytes = sumFileSizes([opts.file]);
9723
9759
  if (opts.json === true) {
9724
9760
  const jsonText = displaySafeJson(tables, 0);
9725
- emit4(jsonText);
9761
+ emit(jsonText);
9726
9762
  recordReadStat("sqlite_tables", fullSourceBytes, jsonText, opts.file);
9727
9763
  } else {
9728
9764
  const text = formatSqliteTables(tables);
9729
- emit4(text);
9765
+ emit(text);
9730
9766
  recordReadStat("sqlite_tables", fullSourceBytes, text, opts.file);
9731
9767
  }
9732
9768
  return 0;
9733
9769
  } catch (e) {
9734
- emitErr4(extractErrorMessage(e));
9770
+ emitErr(extractErrorMessage(e));
9735
9771
  return 1;
9736
9772
  }
9737
9773
  }
@@ -9740,7 +9776,7 @@ function runSqliteQuery(opts) {
9740
9776
  try {
9741
9777
  head = opts.head !== void 0 ? requireNonNegativeStrictInt("--head", opts.head) : void 0;
9742
9778
  } catch (e) {
9743
- emitErr4(extractErrorMessage(e));
9779
+ emitErr(extractErrorMessage(e));
9744
9780
  return 1;
9745
9781
  }
9746
9782
  try {
@@ -9757,7 +9793,7 @@ function runSqliteQuery(opts) {
9757
9793
  totalCount,
9758
9794
  rowCapped: result.rowCapped
9759
9795
  }, 0);
9760
- emit4(jsonText);
9796
+ emit(jsonText);
9761
9797
  const uncappedFull = guardJsonRows(result.rows);
9762
9798
  const baselineJsonText = displaySafeJson({
9763
9799
  columns: result.columns,
@@ -9769,27 +9805,27 @@ function runSqliteQuery(opts) {
9769
9805
  recordReadStat("sqlite_query", Buffer.byteLength(baselineJsonText, "utf8"), jsonText, opts.file);
9770
9806
  } else {
9771
9807
  const text = formatSqliteQueryTable({ ...result, rows }, { headTruncated });
9772
- emit4(text);
9808
+ emit(text);
9773
9809
  const baselineText = formatSqliteQueryTable({ ...result, rows: result.rows }, { headTruncated: false });
9774
9810
  recordReadStat("sqlite_query", Buffer.byteLength(baselineText, "utf8"), text, opts.file);
9775
9811
  }
9776
9812
  return 0;
9777
9813
  } catch (e) {
9778
- emitErr4(extractErrorMessage(e));
9814
+ emitErr(extractErrorMessage(e));
9779
9815
  return 1;
9780
9816
  }
9781
9817
  }
9782
9818
  function runCoverageReportGaps(opts) {
9783
9819
  const text = readFileText(opts.file);
9784
9820
  if (text === null) {
9785
- emitErr4(`Could not read: ${opts.file}`);
9821
+ emitErr(`Could not read: ${opts.file}`);
9786
9822
  return 1;
9787
9823
  }
9788
9824
  let report;
9789
9825
  try {
9790
9826
  report = parseCoverageReport(text);
9791
9827
  } catch (e) {
9792
- emitErr4(`Failed to parse coverage report (not valid LCOV or Istanbul JSON): ${opts.file}
9828
+ emitErr(`Failed to parse coverage report (not valid LCOV or Istanbul JSON): ${opts.file}
9793
9829
  ${extractErrorMessage(e)}`);
9794
9830
  return 1;
9795
9831
  }
@@ -9797,7 +9833,7 @@ ${extractErrorMessage(e)}`);
9797
9833
  const fullSourceBytes = sumFileSizes([opts.file]);
9798
9834
  if (opts.json === true) {
9799
9835
  const jsonText = displaySafeJson(scoped, 0);
9800
- emit4(jsonText);
9836
+ emit(jsonText);
9801
9837
  recordReadStat("coverage_report_gaps", fullSourceBytes, jsonText, opts.file);
9802
9838
  } else {
9803
9839
  const text2 = formatCoverageGaps(scoped);
@@ -9875,17 +9911,17 @@ function extractFrontmatter(lines) {
9875
9911
  function runConfigGet(opts) {
9876
9912
  const text = readFileText(opts.file);
9877
9913
  if (text === null) {
9878
- emitErr4(`Could not read: ${opts.file}`);
9914
+ emitErr(`Could not read: ${opts.file}`);
9879
9915
  return 1;
9880
9916
  }
9881
9917
  const frontmatterLines = extractFrontmatter(text.split(/\r?\n/));
9882
9918
  if (frontmatterLines !== null) {
9883
9919
  const value = lookupYaml(frontmatterLines, opts.key);
9884
9920
  if (value === null) {
9885
- emitErr4(`Key '${opts.key}' not found in ${opts.file}`);
9921
+ emitErr(`Key '${opts.key}' not found in ${opts.file}`);
9886
9922
  return 1;
9887
9923
  }
9888
- emit4(value);
9924
+ emit(value);
9889
9925
  return 0;
9890
9926
  }
9891
9927
  const ext = path10.extname(opts.file).toLowerCase();
@@ -9894,29 +9930,29 @@ function runConfigGet(opts) {
9894
9930
  let obj = JSON.parse(text);
9895
9931
  for (const part of opts.key.split(".")) {
9896
9932
  if (typeof obj !== "object" || obj === null) {
9897
- emitErr4(`Key '${opts.key}' not found in ${opts.file}`);
9933
+ emitErr(`Key '${opts.key}' not found in ${opts.file}`);
9898
9934
  return 1;
9899
9935
  }
9900
9936
  obj = obj[part];
9901
9937
  if (obj === void 0) {
9902
- emitErr4(`Key '${opts.key}' not found in ${opts.file}`);
9938
+ emitErr(`Key '${opts.key}' not found in ${opts.file}`);
9903
9939
  return 1;
9904
9940
  }
9905
9941
  }
9906
- emit4(displaySafeJson(obj, 0));
9942
+ emit(displaySafeJson(obj, 0));
9907
9943
  return 0;
9908
9944
  } catch {
9909
- emitErr4(`Failed to parse JSON: ${opts.file}`);
9945
+ emitErr(`Failed to parse JSON: ${opts.file}`);
9910
9946
  return 1;
9911
9947
  }
9912
9948
  }
9913
9949
  if (ext === ".yaml" || ext === ".yml") {
9914
9950
  const value = lookupYaml(text.split(/\r?\n/), opts.key);
9915
9951
  if (value === null) {
9916
- emitErr4(`Key '${opts.key}' not found in ${opts.file}`);
9952
+ emitErr(`Key '${opts.key}' not found in ${opts.file}`);
9917
9953
  return 1;
9918
9954
  }
9919
- emit4(value);
9955
+ emit(value);
9920
9956
  return 0;
9921
9957
  }
9922
9958
  const keyParts = opts.key.split(".");
@@ -9937,18 +9973,18 @@ function runConfigGet(opts) {
9937
9973
  if (new RegExp(`^${escapeRegExp(leafKey)}\\s*=`).test(trimmed)) {
9938
9974
  const eqIdx = trimmed.indexOf("=");
9939
9975
  const rawValue = stripInlineComment(trimmed.slice(eqIdx + 1)).trim();
9940
- emit4(stripPairedQuotes(rawValue));
9976
+ emit(stripPairedQuotes(rawValue));
9941
9977
  return 0;
9942
9978
  }
9943
9979
  }
9944
- emitErr4(`Key '${opts.key}' not found in ${opts.file}`);
9980
+ emitErr(`Key '${opts.key}' not found in ${opts.file}`);
9945
9981
  return 1;
9946
9982
  }
9947
9983
  function runPerFileEmitting(files, label, run) {
9948
9984
  let anyOk = false;
9949
9985
  files.forEach((file, i) => {
9950
- if (i > 0) emit4("");
9951
- emit4(`# ${label}: ${file}`);
9986
+ if (i > 0) emit("");
9987
+ emit(`# ${label}: ${file}`);
9952
9988
  if (run(file) === 0) anyOk = true;
9953
9989
  });
9954
9990
  return anyOk ? 0 : 1;
@@ -9958,7 +9994,7 @@ function runExports(opts) {
9958
9994
  if (multiFiles.length > 1) return runPerFileEmitting(multiFiles, "Exports", (file) => runExports({ ...opts, file }));
9959
9995
  const confined = fileConfinementRefusal("This file", opts.file, opts.projectRoot);
9960
9996
  if (confined !== null) {
9961
- emitErr4(confined);
9997
+ emitErr(confined);
9962
9998
  return 1;
9963
9999
  }
9964
10000
  const diskPath = resolveAgainstProjectRoot(opts.file, opts.projectRoot);
@@ -9977,7 +10013,7 @@ function runExports(opts) {
9977
10013
  const ext = path10.extname(opts.file).toLowerCase();
9978
10014
  const text = readFileText(diskPath);
9979
10015
  if (text === null && symbols.length === 0) {
9980
- emitErr4(`Could not read: ${opts.file}`);
10016
+ emitErr(`Could not read: ${opts.file}`);
9981
10017
  return 1;
9982
10018
  }
9983
10019
  if (text !== null) {
@@ -9987,7 +10023,7 @@ function runExports(opts) {
9987
10023
  for (const n of extractExportNames(text, ext)) if (!names.includes(n)) names.push(n);
9988
10024
  }
9989
10025
  if (names.length === 0) {
9990
- emit4(`No exported symbols found in '${displaySafeText(opts.file)}'`);
10026
+ emit(`No exported symbols found in '${displaySafeText(opts.file)}'`);
9991
10027
  return 0;
9992
10028
  }
9993
10029
  const preFilterCount = names.length;
@@ -9997,12 +10033,12 @@ function runExports(opts) {
9997
10033
  if (filteredNames.length === 0) {
9998
10034
  if (opts.json === true) {
9999
10035
  const jsonText = displaySafeJson([]);
10000
- emit4(jsonText);
10036
+ emit(jsonText);
10001
10037
  recordReadStat("exports", fullSourceBytes, jsonText, opts.file);
10002
10038
  return 0;
10003
10039
  }
10004
10040
  const textOut = grepFilteredToEmptyNotice(preFilterCount, opts.grep ?? "", "exported symbol", "exported symbols");
10005
- emit4(textOut);
10041
+ emit(textOut);
10006
10042
  recordReadStat("exports", fullSourceBytes, textOut, opts.file);
10007
10043
  return 0;
10008
10044
  }
@@ -10013,7 +10049,7 @@ function runExports(opts) {
10013
10049
  return { name: n, kind: kindOf(n), lineStart: loc?.lineStart ?? null, lineEnd: loc?.lineEnd ?? null };
10014
10050
  })
10015
10051
  );
10016
- emit4(jsonText);
10052
+ emit(jsonText);
10017
10053
  recordReadStat("exports", fullSourceBytes, jsonText, opts.file);
10018
10054
  return 0;
10019
10055
  }
@@ -10023,7 +10059,7 @@ function runExports(opts) {
10023
10059
  return `${kindOf(n).padEnd(10)} ${n}${locSuffix}`;
10024
10060
  });
10025
10061
  for (const line of outLines) {
10026
- emit4(line);
10062
+ emit(line);
10027
10063
  }
10028
10064
  recordReadStat("exports", fullSourceBytes, outLines.join("\n"), opts.file);
10029
10065
  return 0;
@@ -10034,12 +10070,12 @@ function runImports(opts) {
10034
10070
  const diskPath = resolveAgainstProjectRoot(opts.file, opts.projectRoot);
10035
10071
  const text = readFileText(diskPath);
10036
10072
  if (text === null) {
10037
- emitErr4(`Could not read: ${opts.file}`);
10073
+ emitErr(`Could not read: ${opts.file}`);
10038
10074
  return 1;
10039
10075
  }
10040
10076
  const imports = extractImports(text, importsExtensionFor(opts.file));
10041
10077
  if (imports.length === 0) {
10042
- emit4(`No imports found in '${displaySafeText(opts.file)}'`);
10078
+ emit(`No imports found in '${displaySafeText(opts.file)}'`);
10043
10079
  return 0;
10044
10080
  }
10045
10081
  const preFilterCount = imports.length;
@@ -10049,25 +10085,25 @@ function runImports(opts) {
10049
10085
  if (filteredImports.length === 0) {
10050
10086
  if (opts.json === true) {
10051
10087
  const jsonText = displaySafeJson({ items: [], truncated: false, totalCount: 0 });
10052
- emit4(jsonText);
10088
+ emit(jsonText);
10053
10089
  recordReadStat("imports", fullSourceBytes, jsonText, opts.file);
10054
10090
  return 0;
10055
10091
  }
10056
10092
  const text2 = grepFilteredToEmptyNotice(preFilterCount, opts.grep ?? "", "import", "imports");
10057
- emit4(text2);
10093
+ emit(text2);
10058
10094
  recordReadStat("imports", fullSourceBytes, text2, opts.file);
10059
10095
  return 0;
10060
10096
  }
10061
10097
  if (opts.json === true) {
10062
10098
  const capped = guardJsonRows(filteredImports);
10063
10099
  const jsonText = displaySafeJson({ items: capped.items, truncated: capped.truncated, totalCount: capped.totalCount });
10064
- emit4(jsonText);
10100
+ emit(jsonText);
10065
10101
  recordReadStat("imports", fullSourceBytes, jsonText, opts.file);
10066
10102
  return 0;
10067
10103
  }
10068
10104
  const outLines = filteredImports.map((imp) => `import ${imp}`);
10069
10105
  for (const line of outLines) {
10070
- emit4(line);
10106
+ emit(line);
10071
10107
  }
10072
10108
  recordReadStat("imports", fullSourceBytes, outLines.join("\n"), opts.file);
10073
10109
  return 0;
@@ -10165,50 +10201,55 @@ function runNoteList(opts = {}) {
10165
10201
  }
10166
10202
  function runFind(opts) {
10167
10203
  if (opts.limit !== void 0 && opts.limit <= 0) {
10168
- emitErr4(`--limit must be a positive number, got: ${opts.limit}`);
10204
+ emitErr(`--limit must be a positive number, got: ${opts.limit}`);
10169
10205
  return 1;
10170
10206
  }
10171
10207
  const rootDir = resolveProjectRoot({ project: process.cwd() });
10172
10208
  const patternLower = opts.pattern.toLowerCase();
10173
- const rawSymbols = querySymbols({ limit: FIND_SCAN_LIMIT2, rootDir });
10174
- const symbols = rawSymbols.filter(
10175
- (s) => s.name.toLowerCase().includes(patternLower)
10176
- );
10209
+ const matchedFiles = /* @__PURE__ */ new Set();
10210
+ const allNames = /* @__PURE__ */ new Set();
10211
+ forEachSymbol({ rootDir }, (s) => {
10212
+ allNames.add(s.name);
10213
+ if (s.name.toLowerCase().includes(patternLower)) matchedFiles.add(s.filePath);
10214
+ });
10177
10215
  let fuzzyNames = [];
10178
- if (symbols.length === 0) {
10179
- fuzzyNames = rankSimilarNames(rawSymbols.map((s) => s.name), opts.pattern);
10216
+ if (matchedFiles.size === 0) {
10217
+ fuzzyNames = rankSimilarNames([...allNames], opts.pattern);
10218
+ if (fuzzyNames.length > 0) {
10219
+ const byName = new Map(fuzzyNames.map((n) => [n, []]));
10220
+ forEachSymbol({ rootDir }, (s) => {
10221
+ byName.get(s.name)?.push(s.filePath);
10222
+ });
10223
+ for (const n of fuzzyNames) for (const f of byName.get(n) ?? []) matchedFiles.add(f);
10224
+ }
10180
10225
  }
10181
- const matched = fuzzyNames.length > 0 ? fuzzyNames.flatMap((n) => rawSymbols.filter((s) => s.name === n)) : symbols;
10182
- const allFiles = [...new Set(matched.map((s) => s.filePath))];
10226
+ const allFiles = [...matchedFiles];
10183
10227
  const files = allFiles.slice(0, opts.limit ?? 50);
10184
10228
  const limitDropped = allFiles.length - files.length;
10185
- const truncated = rawSymbols.length === FIND_SCAN_LIMIT2 || limitDropped > 0;
10229
+ const truncated = limitDropped > 0;
10186
10230
  if (files.length === 0) {
10187
- emitErr4(`No indexed files match '${opts.pattern}'`);
10231
+ emitErr(`No indexed files match '${opts.pattern}'`);
10188
10232
  return 1;
10189
10233
  }
10190
10234
  if (opts.json === true) {
10191
10235
  const fuzzyPayload = fuzzyNames.length > 0 ? { fuzzy: true, matchedNames: fuzzyNames } : {};
10192
- emit4(displaySafeJson({ files, truncated, totalCount: allFiles.length, ...fuzzyPayload }));
10236
+ emit(displaySafeJson({ files, truncated, totalCount: allFiles.length, ...fuzzyPayload }));
10193
10237
  return 0;
10194
10238
  }
10195
10239
  if (fuzzyNames.length > 0) {
10196
- emitErr4(`No symbol name contains '${opts.pattern}'; showing files for the nearest indexed ${fuzzyNames.length === 1 ? "name" : "names"}: ${fuzzyNames.join(", ")}`);
10240
+ emitErr(`No symbol name contains '${opts.pattern}'; showing files for the nearest indexed ${fuzzyNames.length === 1 ? "name" : "names"}: ${fuzzyNames.join(", ")}`);
10197
10241
  }
10198
10242
  for (const f of files) {
10199
- emit4(toDisplayPath(rootDir, f));
10243
+ emit(toDisplayPath(rootDir, f));
10200
10244
  }
10201
10245
  if (limitDropped > 0) {
10202
- emitErr4(`Showing ${files.length} of ${allFiles.length} matching files; rerun with --limit ${allFiles.length} to see them all`);
10203
- }
10204
- if (rawSymbols.length === FIND_SCAN_LIMIT2) {
10205
- emitErr4(`Results may be incomplete; index scan hit limit of ${FIND_SCAN_LIMIT2} symbols`);
10246
+ emitErr(`Showing ${files.length} of ${allFiles.length} matching files; rerun with --limit ${allFiles.length} to see them all`);
10206
10247
  }
10207
10248
  return 0;
10208
10249
  }
10209
10250
  function runLocate(opts) {
10210
10251
  if (opts.limit !== void 0 && opts.limit <= 0) {
10211
- emitErr4(`--limit must be a positive number, got: ${opts.limit}`);
10252
+ emitErr(`--limit must be a positive number, got: ${opts.limit}`);
10212
10253
  return 1;
10213
10254
  }
10214
10255
  const rootDir = opts.projectRoot ?? resolveProjectRoot({ project: process.cwd() });
@@ -10219,35 +10260,55 @@ function runLocate(opts) {
10219
10260
  targetFile = targetSpec.slice(0, colonIdx);
10220
10261
  targetSpec = targetSpec.slice(colonIdx + 2);
10221
10262
  }
10222
- const queryOpts = {
10223
- limit: FIND_SCAN_LIMIT2
10224
- };
10263
+ const scanOpts = {};
10225
10264
  if (targetFile !== void 0) {
10226
- queryOpts.filePath = resolveIndexPath(targetFile, rootDir);
10227
- healStaleIndex(queryOpts.filePath);
10265
+ scanOpts.filePath = resolveIndexPath(targetFile, rootDir);
10266
+ healStaleIndex(scanOpts.filePath);
10228
10267
  } else {
10229
- queryOpts.rootDir = rootDir;
10268
+ scanOpts.rootDir = rootDir;
10230
10269
  }
10231
- let rawSymbols = querySymbols(queryOpts);
10270
+ const limit = opts.limit ?? 25;
10271
+ const specLower = targetSpec.toLowerCase();
10272
+ const scan = () => {
10273
+ const found2 = { exact: [], exactCount: 0, partial: [], partialCount: 0, names: /* @__PURE__ */ new Set(), files: /* @__PURE__ */ new Set() };
10274
+ forEachSymbol(scanOpts, (s) => {
10275
+ found2.names.add(s.name);
10276
+ found2.files.add(s.filePath);
10277
+ const nameLower = s.name.toLowerCase();
10278
+ if (nameLower === specLower) {
10279
+ found2.exactCount++;
10280
+ if (found2.exact.length < limit) found2.exact.push(s);
10281
+ } else if (nameLower.includes(specLower)) {
10282
+ found2.partialCount++;
10283
+ if (found2.partial.length < limit) found2.partial.push(s);
10284
+ }
10285
+ });
10286
+ return found2;
10287
+ };
10288
+ let found = scan();
10232
10289
  if (targetFile === void 0) {
10233
- const heal = healStaleResultFiles(rawSymbols.map((s) => s.filePath));
10234
- if (heal.healed) rawSymbols = querySymbols(queryOpts);
10290
+ const heal = healStaleResultFiles([...found.files]);
10291
+ if (heal.healed) found = scan();
10235
10292
  }
10236
- const specLower = targetSpec.toLowerCase();
10237
- const exactMatches = rawSymbols.filter((s) => s.name.toLowerCase() === specLower);
10238
- const partialMatches = rawSymbols.filter(
10239
- (s) => s.name.toLowerCase() !== specLower && s.name.toLowerCase().includes(specLower)
10240
- );
10241
- const combined = [...exactMatches, ...partialMatches];
10293
+ let matchCount = found.exactCount + found.partialCount;
10294
+ let combined = [...found.exact, ...found.partial];
10242
10295
  let fuzzyNames = [];
10243
- if (combined.length === 0) {
10244
- fuzzyNames = rankSimilarNames(rawSymbols.map((s) => s.name), targetSpec);
10296
+ if (matchCount === 0) {
10297
+ fuzzyNames = rankSimilarNames([...found.names], targetSpec);
10298
+ if (fuzzyNames.length > 0) {
10299
+ const byName = new Map(fuzzyNames.map((n) => [n, []]));
10300
+ forEachSymbol(scanOpts, (s) => {
10301
+ const bucket = byName.get(s.name);
10302
+ if (bucket === void 0) return;
10303
+ matchCount++;
10304
+ if (bucket.length < limit) bucket.push(s);
10305
+ });
10306
+ combined = fuzzyNames.flatMap((n) => byName.get(n) ?? []);
10307
+ }
10245
10308
  }
10246
- const matched = fuzzyNames.length > 0 ? fuzzyNames.flatMap((n) => rawSymbols.filter((s) => s.name === n)) : combined;
10247
- const limit = opts.limit ?? 25;
10248
- const shown = matched.slice(0, limit);
10309
+ const shown = combined.slice(0, limit);
10249
10310
  if (shown.length === 0) {
10250
- emitErr4(`No landmark or symbol located for '${targetSpec}'`);
10311
+ emitErr(`No landmark or symbol located for '${targetSpec}'`);
10251
10312
  return 1;
10252
10313
  }
10253
10314
  const hits = shown.map((s) => ({
@@ -10259,22 +10320,22 @@ function runLocate(opts) {
10259
10320
  span: `${s.lineStart}-${s.lineEnd}`
10260
10321
  }));
10261
10322
  if (opts.json === true) {
10262
- emit4(displaySafeJson({
10323
+ emit(displaySafeJson({
10263
10324
  items: hits,
10264
- totalCount: matched.length,
10265
- truncated: matched.length > limit,
10325
+ totalCount: matchCount,
10326
+ truncated: matchCount > limit,
10266
10327
  ...fuzzyNames.length > 0 ? { fuzzy: true, matchedNames: fuzzyNames } : {}
10267
10328
  }));
10268
10329
  return 0;
10269
10330
  }
10270
10331
  if (fuzzyNames.length > 0) {
10271
- emitErr4(`No exact landmark for '${targetSpec}'; nearest matches: ${fuzzyNames.join(", ")}`);
10332
+ emitErr(`No exact landmark for '${targetSpec}'; nearest matches: ${fuzzyNames.join(", ")}`);
10272
10333
  }
10273
10334
  for (const hit of hits) {
10274
- emit4(`${displaySafeText(hit.filePath)}:${hit.span} [${displaySafeText(hit.kind)}] ${displaySafeText(hit.name)}`);
10335
+ emit(`${displaySafeText(hit.filePath)}:${hit.span} [${displaySafeText(hit.kind)}] ${displaySafeText(hit.name)}`);
10275
10336
  }
10276
- if (matched.length > limit) {
10277
- emitErr4(`Showing ${limit} of ${matched.length} locations; rerun with --limit ${matched.length} to see them all`);
10337
+ if (matchCount > limit) {
10338
+ emitErr(`Showing ${limit} of ${matchCount} locations; rerun with --limit ${matchCount} to see them all`);
10278
10339
  }
10279
10340
  return 0;
10280
10341
  }
@@ -10282,10 +10343,10 @@ function runListSections(opts) {
10282
10343
  const sections = listSections(opts.file);
10283
10344
  if (sections.length === 0) {
10284
10345
  if (!fileExists(opts.file)) {
10285
- emitErr4(`Could not read: ${opts.file}`);
10346
+ emitErr(`Could not read: ${opts.file}`);
10286
10347
  return 1;
10287
10348
  }
10288
- emitErr4(`No sections found in '${opts.file}'`);
10349
+ emitErr(`No sections found in '${opts.file}'`);
10289
10350
  return 1;
10290
10351
  }
10291
10352
  const preFilterCount = sections.length;
@@ -10301,19 +10362,19 @@ function runListSections(opts) {
10301
10362
  const filtered = matchesGrep !== void 0 ? labelled.filter((_, i) => matchesGrep(sections[i] ?? "")) : labelled;
10302
10363
  if (filtered.length === 0) {
10303
10364
  if (opts.json === true) {
10304
- emit4(displaySafeJson({ items: [], truncated: false, totalCount: 0 }));
10365
+ emit(displaySafeJson({ items: [], truncated: false, totalCount: 0 }));
10305
10366
  return 0;
10306
10367
  }
10307
- emit4(grepFilteredToEmptyNotice(preFilterCount, opts.grep ?? "", "section", "sections"));
10368
+ emit(grepFilteredToEmptyNotice(preFilterCount, opts.grep ?? "", "section", "sections"));
10308
10369
  return 0;
10309
10370
  }
10310
10371
  if (opts.json === true) {
10311
10372
  const capped = guardJsonRows(filtered);
10312
- emit4(displaySafeJson({ items: capped.items, truncated: capped.truncated, totalCount: capped.totalCount }));
10373
+ emit(displaySafeJson({ items: capped.items, truncated: capped.truncated, totalCount: capped.totalCount }));
10313
10374
  return 0;
10314
10375
  }
10315
10376
  for (const heading of filtered) {
10316
- emit4(heading);
10377
+ emit(heading);
10317
10378
  }
10318
10379
  return 0;
10319
10380
  }
@@ -10392,15 +10453,38 @@ function runSection(opts) {
10392
10453
  }
10393
10454
  const kind = result.redirectedFrom !== void 0 ? "section_replacement" : "section_read";
10394
10455
  const fullSourceBytes = sumFileSizes([filePath]);
10456
+ let content = result.content;
10457
+ let lineEnd = result.lineEnd;
10458
+ let truncatedNotice = "";
10459
+ if (opts.maxLines !== void 0 && opts.maxLines > 0) {
10460
+ const lines = content.split("\n");
10461
+ if (lines.length > opts.maxLines) {
10462
+ const remaining = lines.length - opts.maxLines;
10463
+ content = lines.slice(0, opts.maxLines).join("\n");
10464
+ lineEnd = Math.min(result.lineEnd, result.lineStart + opts.maxLines - 1);
10465
+ truncatedNotice = `
10466
+ ... (${countNoun(remaining, "more line")} not shown; pass a larger --max-lines or omit to read full section)`;
10467
+ }
10468
+ }
10395
10469
  if (opts.json === true) {
10396
- const text2 = displaySafeJson(result);
10470
+ const jsonPayload = {
10471
+ ...result,
10472
+ content,
10473
+ lineEnd,
10474
+ ...opts.maxLines !== void 0 && opts.maxLines > 0 ? {
10475
+ totalLines: result.content.split("\n").length,
10476
+ shownLines: content.split("\n").length,
10477
+ truncated: truncatedNotice.length > 0
10478
+ } : {}
10479
+ };
10480
+ const text2 = displaySafeJson(jsonPayload);
10397
10481
  if (opts.suppressStat !== true) recordReadStat(kind, fullSourceBytes, text2, heading);
10398
10482
  return { text: text2, code: 0 };
10399
10483
  }
10400
10484
  const redirectNote = result.redirectedFrom !== void 0 ? ` (redirected from: '${result.redirectedFrom}')` : "";
10401
10485
  const text = guardText(
10402
- `# ${result.heading} \u2014 ${filePath}:${result.lineStart}-${result.lineEnd}${redirectNote}
10403
- ${result.content}`,
10486
+ `# ${result.heading} \u2014 ${filePath}:${result.lineStart}-${lineEnd}${redirectNote}
10487
+ ${content}${truncatedNotice}`,
10404
10488
  "heading"
10405
10489
  );
10406
10490
  if (opts.suppressStat !== true) recordReadStat(kind, fullSourceBytes, text, heading);
@@ -10521,8 +10605,7 @@ ${sub.text}`);
10521
10605
  // src/read_commands.ts
10522
10606
  var SYMBOL_PREVIEW_LINES = 5;
10523
10607
  var GREP_MAX_LINES = 200;
10524
- var FIND_SCAN_LIMIT2 = 2e4;
10525
- var REFS_TOP_SCAN_LIMIT = 2e4;
10608
+ var FIND_SCAN_LIMIT = 2e4;
10526
10609
  function fileExists2(p) {
10527
10610
  try {
10528
10611
  fs12.statSync(p);
@@ -10597,6 +10680,7 @@ function verifyPin(p, pinned) {
10597
10680
  verifyPinnedIdentity(p, pinned);
10598
10681
  }
10599
10682
  function indexFileSyncPinned(resolvedPath, dbPath) {
10683
+ recordKnownRootThrottled(resolvedPath, dataDir(), dbPath);
10600
10684
  const pinned = activePins?.get(pinKey(path12.resolve(resolvedPath)));
10601
10685
  if (pinned === void 0) {
10602
10686
  indexFileSync(resolvedPath, dbPath);
@@ -10737,15 +10821,8 @@ function warnIfFilesStale(filePaths) {
10737
10821
  );
10738
10822
  }
10739
10823
  }
10740
- function emit4(text) {
10741
- const out = colorStdout() ? text : stripAnsi(text);
10742
- process.stdout.write(ensureNewline(out));
10743
- }
10744
- function emitErr4(text) {
10745
- process.stderr.write(ensureNewline(text));
10746
- }
10747
10824
  function emitGuarded(text, command) {
10748
- emit4(guardText(text, command));
10825
+ emit(guardText(text, command));
10749
10826
  }
10750
10827
  function guardText(text, command) {
10751
10828
  const cfg = loadConfig();
@@ -10800,6 +10877,11 @@ function resolveEnclosingSymbol(filePath, chunkStartLine) {
10800
10877
  }
10801
10878
  return best === null ? null : { name: best.name, kind: best.kind, lineStart: best.lineStart };
10802
10879
  }
10880
+ var IMPORT_BIND_BODY_RE = /^\s*(?:const|let|var)\s*\{[^}]*\}\s*=\s*(?:await\s+)?(?:import|require)\s*\(/;
10881
+ function stableSortImportBindsLast(rows) {
10882
+ const isBind = (r) => typeof r.body === "string" && IMPORT_BIND_BODY_RE.test(r.body) ? 1 : 0;
10883
+ return [...rows].sort((a, b) => isBind(a) - isBind(b));
10884
+ }
10803
10885
  function runSymbol(opts) {
10804
10886
  if (opts.limit !== void 0 && opts.limit <= 0) {
10805
10887
  return { text: `--limit must be a positive number, got: ${opts.limit}`, code: 1 };
@@ -10834,27 +10916,42 @@ function runSymbol(opts) {
10834
10916
  }
10835
10917
  if (opts.name !== void 0) queryOpts.name = queryOpts.filePath !== void 0 ? stripHtmlIdSpelling(opts.name, queryOpts.filePath) : opts.name;
10836
10918
  if (opts.kind !== void 0) queryOpts.kind = opts.kind;
10837
- if (matchesGrep !== void 0 || excludeTests || excludeVendored) {
10838
- queryOpts.limit = FIND_SCAN_LIMIT2;
10839
- } else if (opts.limit !== void 0) {
10919
+ const anyClientFilter = matchesGrep !== void 0 || excludeTests || excludeVendored;
10920
+ const effectiveLimit = opts.limit ?? DEFAULT_QUERY_LIMIT;
10921
+ if (!anyClientFilter && opts.limit !== void 0) {
10840
10922
  queryOpts.limit = opts.limit;
10841
10923
  }
10842
10924
  if (opts.file === void 0 && opts.projectRoot !== void 0) queryOpts.rootDir = opts.projectRoot;
10843
10925
  if (opts.file === void 0 && queryOpts.rootDir === void 0 && confinedRoot !== null) queryOpts.rootDir = confinedRoot;
10844
- let rawResults = querySymbols(queryOpts);
10926
+ const runSweep = () => {
10927
+ const found = { kept: [], keptCount: 0, scanned: 0, hiddenByExcludeTests: 0, files: /* @__PURE__ */ new Set() };
10928
+ const take = (s) => {
10929
+ found.scanned++;
10930
+ found.files.add(s.filePath);
10931
+ const nameKept = matchesGrep === void 0 || matchesGrep(s.name);
10932
+ if (nameKept && !(excludeTests && isTestFile(s.filePath)) && !(excludeVendored && isIgnoredIndexPath(s.filePath))) {
10933
+ found.keptCount++;
10934
+ if (found.kept.length < effectiveLimit) found.kept.push(s);
10935
+ } else if (excludeTests && nameKept && isTestFile(s.filePath)) {
10936
+ found.hiddenByExcludeTests++;
10937
+ }
10938
+ };
10939
+ if (anyClientFilter) forEachSymbol(queryOpts, take);
10940
+ else for (const row of querySymbols(queryOpts)) take(row);
10941
+ return found;
10942
+ };
10943
+ let sweep = runSweep();
10845
10944
  let stillStale = EMPTY_PATH_SET;
10846
10945
  if (opts.file === void 0) {
10847
- const heal = healStaleResultFiles(rawResults.map((s) => s.filePath));
10946
+ const heal = healStaleResultFiles([...sweep.files]);
10848
10947
  stillStale = heal.stillStale;
10849
- if (heal.healed) rawResults = querySymbols(queryOpts);
10948
+ if (heal.healed) sweep = runSweep();
10850
10949
  }
10851
- const preFilterCount = rawResults.length;
10852
- const effectiveLimit = opts.limit ?? 100;
10853
- const anyClientFilter = matchesGrep !== void 0 || excludeTests || excludeVendored;
10854
- const filtered = anyClientFilter ? rawResults.filter((s) => (matchesGrep === void 0 || matchesGrep(s.name)) && !(excludeTests && isTestFile(s.filePath)) && !(excludeVendored && isIgnoredIndexPath(s.filePath))) : rawResults;
10855
- const results = anyClientFilter ? filtered.slice(0, effectiveLimit) : filtered;
10856
- const hiddenByExcludeTests = excludeTests ? rawResults.filter((s) => (matchesGrep === void 0 || matchesGrep(s.name)) && isTestFile(s.filePath)).length : 0;
10857
- if (excludeTests && filtered.length === 0 && hiddenByExcludeTests > 0) {
10950
+ const preFilterCount = sweep.scanned;
10951
+ const unordered = sweep.kept.slice(0, effectiveLimit);
10952
+ const results = opts.name === void 0 ? unordered : stableSortImportBindsLast(unordered);
10953
+ const hiddenByExcludeTests = sweep.hiddenByExcludeTests;
10954
+ if (excludeTests && sweep.keptCount === 0 && hiddenByExcludeTests > 0) {
10858
10955
  const label = opts.name ?? opts.grep ?? "*";
10859
10956
  const notice = `no non-test matches for '${label}' (${excludeTestsHiddenNote(hiddenByExcludeTests)})`;
10860
10957
  if (opts.json === true) {
@@ -10862,7 +10959,7 @@ function runSymbol(opts) {
10862
10959
  }
10863
10960
  return { text: `token-goat: ${notice}`, code: 0 };
10864
10961
  }
10865
- if (matchesGrep !== void 0 && filtered.length === 0 && preFilterCount > 0) {
10962
+ if (matchesGrep !== void 0 && sweep.keptCount === 0 && preFilterCount > 0) {
10866
10963
  if (opts.json === true) {
10867
10964
  const text2 = displaySafeJson({ items: [], truncated: false, totalCount: 0 });
10868
10965
  return { text: text2, code: 0 };
@@ -10875,8 +10972,14 @@ function runSymbol(opts) {
10875
10972
  const indexEmpty = emptyIndexRoot !== null && isIndexEmptyForProject(globalDbPath(), emptyIndexRoot);
10876
10973
  if (opts.name !== void 0 && emptyIndexRoot !== null) {
10877
10974
  const rootDir = emptyIndexRoot;
10878
- const rawSymbols = querySymbols({ limit: FIND_SCAN_LIMIT2, rootDir });
10879
- const exactMatches = rawSymbols.filter((s) => s.name === opts.name);
10975
+ const exactMatches = [];
10976
+ const allNames = /* @__PURE__ */ new Set();
10977
+ const structuredFileSet = /* @__PURE__ */ new Set();
10978
+ forEachSymbol({ rootDir }, (s) => {
10979
+ allNames.add(s.name);
10980
+ structuredFileSet.add(s.filePath);
10981
+ if (s.name === opts.name) exactMatches.push(s);
10982
+ });
10880
10983
  if (exactMatches.length > 0) {
10881
10984
  const shown = exactMatches.slice(0, DIDYOUMEAN_LIMIT);
10882
10985
  const where = shown.map((s) => `${s.kind} at ${formatSymbolLocation(toDisplayPath(rootDir, s.filePath), s.lineStart)}`).join("; ");
@@ -10886,12 +10989,12 @@ function runSymbol(opts) {
10886
10989
  text2 += `
10887
10990
  '${opts.name}' IS indexed (${where}${more}) -- ${widen}`;
10888
10991
  } else {
10889
- const candidates = rankSimilarNames(rawSymbols.map((s) => s.name), opts.name);
10992
+ const candidates = rankSimilarNames([...allNames], opts.name);
10890
10993
  text2 += candidates.length > 0 ? `
10891
10994
  ${didYouMean(candidates)}` : indexEmpty ? "" : `
10892
10995
  Try: token-goat semantic "${opts.name}"`;
10893
10996
  }
10894
- const structuredFiles = [...new Set(rawSymbols.map((s) => s.filePath))].sort();
10997
+ const structuredFiles = [...structuredFileSet].sort();
10895
10998
  const hit = findStructuredKeyPath(opts.name, structuredFiles);
10896
10999
  if (hit !== null) {
10897
11000
  const display = toDisplayPath(rootDir, hit.filePath);
@@ -10917,8 +11020,8 @@ ${emptyIndexMessage(emptyIndexRoot)}`;
10917
11020
  let trueTotal;
10918
11021
  let truncatedFlag;
10919
11022
  if (anyClientFilter) {
10920
- trueTotal = filtered.length;
10921
- truncatedFlag = capped.truncated || results.length < filtered.length;
11023
+ trueTotal = sweep.keptCount;
11024
+ truncatedFlag = capped.truncated || results.length < sweep.keptCount;
10922
11025
  } else {
10923
11026
  trueTotal = countSymbols(queryOpts);
10924
11027
  truncatedFlag = capped.truncated || trueTotal > results.length;
@@ -10954,7 +11057,7 @@ ${preview}${elided}` : header;
10954
11057
  const warning = opts.file !== void 0 ? staleWarning(resolveIndexPath(opts.file, opts.projectRoot ?? process.cwd())) : "";
10955
11058
  const text = guardText(warning + blocks.join("\n\n"), "symbol");
10956
11059
  recordReadStat("symbol_lookup", fullSourceBytes, text, opts.name ?? opts.file ?? opts.grep);
10957
- const symbolTotal = () => anyClientFilter ? { count: filtered.length, exact: rawResults.length < FIND_SCAN_LIMIT2 } : { count: countSymbols(queryOpts), exact: true };
11060
+ const symbolTotal = () => anyClientFilter ? { count: sweep.keptCount, exact: true } : { count: countSymbols(queryOpts), exact: true };
10958
11061
  return { text: text + truncationFooter(results.length, effectiveLimit, symbolTotal, "matches", "--limit"), code: 0 };
10959
11062
  }
10960
11063
  function truncationFooter(shown, limit, total, plural, flag) {
@@ -10965,6 +11068,7 @@ token-goat: ${notice}`;
10965
11068
  }
10966
11069
  function refsTotal(clientFiltered, filteredTotal, shown, countExact, preScanCount, scanLimit) {
10967
11070
  if (!clientFiltered) return { count: countExact(), exact: true };
11071
+ if (scanLimit < 0) return { count: filteredTotal ?? shown, exact: true };
10968
11072
  return { count: filteredTotal ?? shown, exact: preScanCount < scanLimit };
10969
11073
  }
10970
11074
  function truncationNotice(shown, limit, total, plural, flag) {
@@ -11017,7 +11121,7 @@ function runRead(opts) {
11017
11121
  const crossFileLead = formatCrossFileLead("read", symbol, file, opts.projectRoot);
11018
11122
  if (crossFileLead !== "") messages.push(crossFileLead);
11019
11123
  const resolved = resolveIndexPath(file, opts.projectRoot ?? process.cwd());
11020
- const scanned = querySymbols({ filePath: resolved, limit: FIND_SCAN_LIMIT2 }).map((s) => s.name);
11124
+ const scanned = querySymbols({ filePath: resolved, limit: FIND_SCAN_LIMIT }).map((s) => s.name);
11021
11125
  const closes = rankSimilarNames(scanned, symbol);
11022
11126
  if (closes.length > 0) messages.push(didYouMean(closes));
11023
11127
  else if (scanned.length > 0) {
@@ -11186,9 +11290,9 @@ function renderRefsTargets(targets, opts, {
11186
11290
  const refRows = [];
11187
11291
  for (const { file, symbol, key } of targets) {
11188
11292
  const queryOpts = { name: symbol };
11189
- if (opts.excludeTests === true || opts.grep !== void 0) queryOpts.limit = REFS_TOP_SCAN_LIMIT;
11293
+ if (opts.excludeTests === true || opts.grep !== void 0) queryOpts.limit = UNBOUNDED_QUERY_LIMIT;
11190
11294
  else if (opts.limit !== void 0) queryOpts.limit = opts.limit;
11191
- else if (opts.top !== void 0) queryOpts.limit = REFS_TOP_SCAN_LIMIT;
11295
+ else if (opts.top !== void 0) queryOpts.limit = UNBOUNDED_QUERY_LIMIT;
11192
11296
  const rootDir = refsRootDir(opts);
11193
11297
  if (rootDir !== void 0) queryOpts.rootDir = rootDir;
11194
11298
  const scanned = queryRefs(queryOpts);
@@ -11258,7 +11362,7 @@ function renderRefsTargets(targets, opts, {
11258
11362
  const fullSourceBytes = refsSearchBaselineBytes(refRows);
11259
11363
  if (opts.json === true) {
11260
11364
  const text2 = displaySafeJson(jsonOut);
11261
- emit4(text2);
11365
+ emit(text2);
11262
11366
  if (anyFound) recordReadStat("symbol_read", fullSourceBytes, text2, opts.spec);
11263
11367
  return anyFound ? 0 : 1;
11264
11368
  }
@@ -11269,11 +11373,11 @@ function renderRefsTargets(targets, opts, {
11269
11373
  }
11270
11374
  function runRefs(opts) {
11271
11375
  if (opts.limit !== void 0 && opts.limit <= 0) {
11272
- emitErr4(`--limit must be a positive number, got: ${opts.limit}`);
11376
+ emitErr(`--limit must be a positive number, got: ${opts.limit}`);
11273
11377
  return 1;
11274
11378
  }
11275
11379
  if (opts.top !== void 0 && opts.top <= 0) {
11276
- emitErr4(`--top must be a positive number, got: ${opts.top}`);
11380
+ emitErr(`--top must be a positive number, got: ${opts.top}`);
11277
11381
  return 1;
11278
11382
  }
11279
11383
  const baseConfined = confinedProjectRoot();
@@ -11282,13 +11386,13 @@ function runRefs(opts) {
11282
11386
  const requested = opts.projectRoot;
11283
11387
  const projectDenial = requested === void 0 || confinedRoot !== baseConfined ? null : confinementRefusal("--project", requested, baseConfined);
11284
11388
  if (projectDenial !== null) {
11285
- emitErr4(projectDenial);
11389
+ emitErr(projectDenial);
11286
11390
  return 1;
11287
11391
  }
11288
11392
  for (const file2 of refsSpecFiles(opts.spec)) {
11289
11393
  const denial = confinementRefusal("This file", resolveIndexPath(file2, opts.projectRoot ?? process.cwd()), confinedRoot);
11290
11394
  if (denial !== null) {
11291
- emitErr4(denial);
11395
+ emitErr(denial);
11292
11396
  return 1;
11293
11397
  }
11294
11398
  }
@@ -11319,9 +11423,9 @@ function runRefsSingle(opts) {
11319
11423
  const symName = symbol ?? file;
11320
11424
  const queryOpts = { name: symName };
11321
11425
  const defFileHint = symbol !== void 0 ? resolveIndexPath(file, opts.projectRoot ?? process.cwd()) : void 0;
11322
- if (opts.excludeTests === true || opts.grep !== void 0) queryOpts.limit = REFS_TOP_SCAN_LIMIT;
11426
+ if (opts.excludeTests === true || opts.grep !== void 0) queryOpts.limit = UNBOUNDED_QUERY_LIMIT;
11323
11427
  else if (opts.limit !== void 0) queryOpts.limit = opts.limit;
11324
- else if (opts.top !== void 0) queryOpts.limit = REFS_TOP_SCAN_LIMIT;
11428
+ else if (opts.top !== void 0) queryOpts.limit = UNBOUNDED_QUERY_LIMIT;
11325
11429
  const rootDir = refsRootDir(opts);
11326
11430
  if (rootDir !== void 0) queryOpts.rootDir = rootDir;
11327
11431
  const scanned = queryRefs(queryOpts);
@@ -11347,39 +11451,39 @@ function runRefsSingle(opts) {
11347
11451
  if (results.length === 0) {
11348
11452
  if (matchesGrep !== void 0 && preGrepCount > 0) {
11349
11453
  if (opts.json === true) {
11350
- emit4(displaySafeJson({ items: [], truncated: false, totalCount: 0, hiddenByGrep: preGrepCount }));
11454
+ emit(displaySafeJson({ items: [], truncated: false, totalCount: 0, hiddenByGrep: preGrepCount }));
11351
11455
  return 0;
11352
11456
  }
11353
- emit4(grepFilteredToEmptyNotice(preGrepCount, opts.grep ?? "", "reference", "references"));
11457
+ emit(grepFilteredToEmptyNotice(preGrepCount, opts.grep ?? "", "reference", "references"));
11354
11458
  return 0;
11355
11459
  }
11356
11460
  if (opts.excludeTests === true && suppressed > 0) {
11357
- emitErr4(`No non-test references found for '${symName}' (${excludeTestsHiddenNote(suppressed)})`);
11461
+ emitErr(`No non-test references found for '${symName}' (${excludeTestsHiddenNote(suppressed)})`);
11358
11462
  return 1;
11359
11463
  }
11360
11464
  const rootDir2 = opts.projectRoot ?? resolveProjectRoot({ project: process.cwd() });
11361
11465
  const defRows = querySymbols({ name: symName, rootDir: rootDir2, limit: REF_BLIND_DEF_PROBE_LIMIT });
11362
11466
  if (defRows.length === 0) {
11363
- emitErr4(`Symbol not found: ${symName}${unknownSymbolSuggestion(symName, rootDir2)}`);
11364
- if (opts.json !== true && isIndexEmptyForProject(globalDbPath(), rootDir2)) emitErr4(emptyIndexMessage(rootDir2));
11467
+ emitErr(`Symbol not found: ${symName}${unknownSymbolSuggestion(symName, rootDir2)}`);
11468
+ if (opts.json !== true && isIndexEmptyForProject(globalDbPath(), rootDir2)) emitErr(emptyIndexMessage(rootDir2));
11365
11469
  return 1;
11366
11470
  }
11367
11471
  const defPaths = defFileHint !== void 0 ? [defFileHint] : defRows.map((r) => r.filePath);
11368
11472
  const firstDefPath = defPaths[0];
11369
11473
  if (firstDefPath !== void 0 && defPaths.every((fp) => !isRefIndexedFile(fp))) {
11370
- emitErr4(refBlindLanguageNotice(symName, detectLanguageOfFile(firstDefPath), refsDisplayPath(firstDefPath)));
11474
+ emitErr(refBlindLanguageNotice(symName, detectLanguageOfFile(firstDefPath), refsDisplayPath(firstDefPath)));
11371
11475
  return 1;
11372
11476
  }
11373
11477
  const kindRows = defFileHint !== void 0 ? querySymbols({ name: symName, filePath: defFileHint, rootDir: rootDir2, limit: REF_BLIND_DEF_PROBE_LIMIT }) : defRows;
11374
11478
  const kindVerdict = refBlindKindVerdict(kindRows);
11375
11479
  if (kindVerdict.allBlind) {
11376
- emitErr4(refBlindKindNotice(symName, kindVerdict.blindKinds));
11480
+ emitErr(refBlindKindNotice(symName, kindVerdict.blindKinds));
11377
11481
  return 1;
11378
11482
  }
11379
- emitErr4(`No references found for '${symName}'`);
11380
- if (kindVerdict.blindCount > 0) emitErr4(refBlindKindPartialNote(symName, kindVerdict.blindKinds, kindVerdict.blindCount, kindRows.length));
11483
+ emitErr(`No references found for '${symName}'`);
11484
+ if (kindVerdict.blindCount > 0) emitErr(refBlindKindPartialNote(symName, kindVerdict.blindKinds, kindVerdict.blindCount, kindRows.length));
11381
11485
  if (opts.json !== true) {
11382
- if (isIndexEmptyForProject(globalDbPath(), rootDir2)) emitErr4(emptyIndexMessage(rootDir2));
11486
+ if (isIndexEmptyForProject(globalDbPath(), rootDir2)) emitErr(emptyIndexMessage(rootDir2));
11383
11487
  }
11384
11488
  return 1;
11385
11489
  }
@@ -11396,14 +11500,14 @@ function runRefsSingle(opts) {
11396
11500
  }
11397
11501
  const hiddenByGrep = matchesGrep !== void 0 ? preGrepCount - (filteredTotal ?? results.length) : 0;
11398
11502
  const text2 = displaySafeJson({ ...payload, ...hiddenByGrep > 0 ? { hiddenByGrep } : {} });
11399
- emit4(text2);
11503
+ emit(text2);
11400
11504
  recordReadStat("symbol_read", fullSourceBytes, text2, symName);
11401
11505
  return 0;
11402
11506
  }
11403
11507
  const lines = opts.top !== void 0 ? renderTopFilesSummary(results, opts.top, suppressed) : opts.callers === true ? [...opts.excludeTests === true && suppressed > 0 ? [`${countNoun(results.length, "reference")} (${excludeTestsHiddenNote(suppressed)})`] : [], ...renderCallerGroups(results, opts.context ?? 0)] : [...opts.excludeTests === true && suppressed > 0 ? [`${countNoun(results.length, "reference")} (${excludeTestsHiddenNote(suppressed)})`] : [], ...results.flatMap((ref) => renderRefLines(ref, opts.context ?? 0, ""))];
11404
11508
  const refsFooter = opts.top !== void 0 ? "" : truncationFooter(results.length, opts.limit ?? 100, () => refsTotal(clientFiltered, filteredTotal, results.length, () => countRefs(queryOpts), preScanCount, scanLimit), "references", "--limit");
11405
11509
  const text = lines.join("\n");
11406
- emit4(guardText(text, "symbol") + refsFooter);
11510
+ emit(guardText(text, "symbol") + refsFooter);
11407
11511
  recordReadStat("symbol_read", fullSourceBytes, text + refsFooter, symName);
11408
11512
  return 0;
11409
11513
  }
@@ -11459,11 +11563,11 @@ function renderCallerGroups(refs, contextLines = 0) {
11459
11563
  function runPrSlice(opts) {
11460
11564
  const parsed = parsePrSliceArg(opts.slice);
11461
11565
  if (parsed === null) {
11462
- emitErr4(`Invalid slice '${opts.slice}' -- expected one of: files, diff:<path>, comments, description`);
11566
+ emitErr(`Invalid slice '${opts.slice}' -- expected one of: files, diff:<path>, comments, description`);
11463
11567
  return 1;
11464
11568
  }
11465
11569
  if (!isGhAvailable()) {
11466
- emitErr4("gh (GitHub CLI) not found on PATH -- install it from https://cli.github.com and run `gh auth login`");
11570
+ emitErr("gh (GitHub CLI) not found on PATH -- install it from https://cli.github.com and run `gh auth login`");
11467
11571
  return 1;
11468
11572
  }
11469
11573
  let repo = opts.repo;
@@ -11477,21 +11581,21 @@ function runPrSlice(opts) {
11477
11581
  }
11478
11582
  const resolved = remoteUrl.length > 0 ? parseGithubRepoFromRemoteUrl(remoteUrl) : null;
11479
11583
  if (resolved === null) {
11480
- emitErr4("Could not resolve a GitHub repo from the current directory's git remote 'origin' -- pass --repo owner/repo");
11584
+ emitErr("Could not resolve a GitHub repo from the current directory's git remote 'origin' -- pass --repo owner/repo");
11481
11585
  return 1;
11482
11586
  }
11483
11587
  repo = resolved;
11484
11588
  }
11485
11589
  if (!isSafeRepoSlug(repo)) {
11486
- emitErr4(`"${repo}" is not a plain owner/name repository slug -- pass --repo owner/repo`);
11590
+ emitErr(`"${repo}" is not a plain owner/name repository slug -- pass --repo owner/repo`);
11487
11591
  return 1;
11488
11592
  }
11489
11593
  if (!isSafePrNumber(opts.pr)) {
11490
- emitErr4(`"${opts.pr}" is not a pull request number`);
11594
+ emitErr(`"${opts.pr}" is not a pull request number`);
11491
11595
  return 1;
11492
11596
  }
11493
11597
  if (!isGhAuthenticated()) {
11494
- emitErr4("gh is not authenticated -- run `gh auth login`");
11598
+ emitErr("gh is not authenticated -- run `gh auth login`");
11495
11599
  return 1;
11496
11600
  }
11497
11601
  try {
@@ -11502,7 +11606,7 @@ function runPrSlice(opts) {
11502
11606
  if (opts.json === true) {
11503
11607
  const capped = guardJsonRows(files);
11504
11608
  const jsonText = displaySafeJson({ items: capped.items, truncated: capped.truncated, totalCount: capped.totalCount }, 0);
11505
- emit4(jsonText);
11609
+ emit(jsonText);
11506
11610
  recordReadStat("pr_slice", fullSourceBytes, jsonText, `${repo}#${opts.pr} files`);
11507
11611
  } else {
11508
11612
  const text = formatFilesSlice(files);
@@ -11515,14 +11619,14 @@ function runPrSlice(opts) {
11515
11619
  const diffText = fetchPrDiff(opts.pr, repo);
11516
11620
  const rawFileDiff = extractFileDiff(diffText, parsed.path);
11517
11621
  if (rawFileDiff === null) {
11518
- emitErr4(`No diff found for '${parsed.path}' in PR #${opts.pr}`);
11622
+ emitErr(`No diff found for '${parsed.path}' in PR #${opts.pr}`);
11519
11623
  return 1;
11520
11624
  }
11521
11625
  const fileDiff = redactSecrets(rawFileDiff).text;
11522
11626
  const fullSourceBytes = Buffer.byteLength(diffText, "utf8");
11523
11627
  if (opts.json === true) {
11524
11628
  const jsonText = displaySafeJson({ path: parsed.path, diff: fenceGithubFieldIfMatched(fileDiff) }, 0);
11525
- emit4(jsonText);
11629
+ emit(jsonText);
11526
11630
  recordReadStat("pr_slice", fullSourceBytes, jsonText, `${repo}#${opts.pr} diff:${parsed.path}`);
11527
11631
  } else {
11528
11632
  emitGuarded(fenceGithubText(fileDiff), "pr-slice");
@@ -11542,7 +11646,7 @@ function runPrSlice(opts) {
11542
11646
  const fencedComments = comments.map((c) => ({ ...c, body: fenceGithubFieldIfMatched(c.body) }));
11543
11647
  const capped = guardJsonRows(fencedComments);
11544
11648
  const jsonText = displaySafeJson({ items: capped.items, truncated: capped.truncated, totalCount: capped.totalCount }, 0);
11545
- emit4(jsonText);
11649
+ emit(jsonText);
11546
11650
  recordReadStat("pr_slice", fullSourceBytes, jsonText, `${repo}#${opts.pr} comments`);
11547
11651
  } else {
11548
11652
  const text = formatCommentsSlice(comments);
@@ -11566,7 +11670,7 @@ function runPrSlice(opts) {
11566
11670
  body: desc.body !== null ? fenceGithubFieldIfMatched(desc.body) : null
11567
11671
  };
11568
11672
  const jsonText = displaySafeJson(fencedDesc, 0);
11569
- emit4(jsonText);
11673
+ emit(jsonText);
11570
11674
  recordReadStat("pr_slice", fullSourceBytes, jsonText, `${repo}#${opts.pr} description`);
11571
11675
  } else {
11572
11676
  const text = formatDescriptionSlice(desc);
@@ -11577,7 +11681,7 @@ function runPrSlice(opts) {
11577
11681
  }
11578
11682
  }
11579
11683
  } catch (e) {
11580
- emitErr4(extractErrorMessage(e));
11684
+ emitErr(extractErrorMessage(e));
11581
11685
  return 1;
11582
11686
  }
11583
11687
  }
@@ -11676,7 +11780,7 @@ function runGrep(opts) {
11676
11780
  const contextLines = opts.context ?? 0;
11677
11781
  const guarded = compileGuardedRegex(opts.pattern);
11678
11782
  if (!guarded.ok) {
11679
- emitErr4(`Invalid regex: ${opts.pattern} -- ${guarded.reason}`);
11783
+ emitErr(`Invalid regex: ${opts.pattern} -- ${guarded.reason}`);
11680
11784
  return 1;
11681
11785
  }
11682
11786
  const regex = guarded.re;
@@ -11762,7 +11866,7 @@ function runGrep(opts) {
11762
11866
  }
11763
11867
  for (const searchPath of searchPaths) {
11764
11868
  if (!fileExists2(searchPath)) {
11765
- emitErr4(`Path not found: ${searchPath}`);
11869
+ emitErr(`Path not found: ${searchPath}`);
11766
11870
  return 1;
11767
11871
  }
11768
11872
  const stat = fs12.statSync(searchPath);
@@ -11789,7 +11893,7 @@ function runGrep(opts) {
11789
11893
  }
11790
11894
  }
11791
11895
  if (hits.length === 0) {
11792
- emitErr4(`No matches for '${opts.pattern}'`);
11896
+ emitErr(`No matches for '${opts.pattern}'`);
11793
11897
  return 1;
11794
11898
  }
11795
11899
  const truncated = hits.slice(0, maxLines);
@@ -11805,32 +11909,44 @@ function runGrep(opts) {
11805
11909
  hit.symbol = enc === null ? null : { name: enc.name, kind: enc.kind, lineStart: enc.lineStart, lineEnd: enc.lineEnd };
11806
11910
  }
11807
11911
  for (const file of new Set(truncated.map((h) => h.file).filter(isVirtualIndexedPath))) {
11808
- emit4(virtualIndexedScopeNote(displaySafeText(file), "a match in it cannot be attributed to a symbol and these hits carry no label"));
11912
+ emit(virtualIndexedScopeNote(displaySafeText(file), "a match in it cannot be attributed to a symbol and these hits carry no label"));
11809
11913
  }
11810
11914
  }
11811
11915
  if (opts.json === true) {
11812
11916
  const payload = { items: truncated, truncated: hits.length > maxLines, totalCount: hits.length };
11813
- emit4(displaySafeJson(payload));
11917
+ emit(displaySafeJson(payload));
11814
11918
  return 0;
11815
11919
  }
11816
11920
  for (const hit of truncated) {
11817
11921
  const symbolTag = opts.symbol === true && hit.symbol != null ? ` [${hit.symbol.name} (${hit.symbol.kind})]` : "";
11818
11922
  if (hit.context !== void 0) {
11819
- for (const line of renderContextWindow(hit.file, hit.line, hit.context, symbolTag)) emit4(line);
11923
+ for (const line of renderContextWindow(hit.file, hit.line, hit.context, symbolTag)) emit(line);
11820
11924
  } else {
11821
- emit4(`${displaySafeText(hit.file)}:${hit.line}: ${hit.text}${symbolTag}`);
11925
+ emit(`${displaySafeText(hit.file)}:${hit.line}: ${hit.text}${symbolTag}`);
11822
11926
  }
11823
11927
  }
11824
11928
  if (hits.length > maxLines) {
11825
- emitErr4(`... (${hits.length - maxLines} more lines omitted)`);
11826
- emitErr4(`Tip: To avoid broad grepping and reduce token expenditure, locate specific symbols with:`);
11827
- emitErr4(` token-goat symbol <name>`);
11828
- emitErr4(` token-goat locate <name>`);
11829
- emitErr4(` token-goat outline <file> / token-goat skeleton <file>`);
11929
+ emitErr(`... (${hits.length - maxLines} more lines omitted)`);
11930
+ emitErr(`Tip: To avoid broad grepping and reduce token expenditure, locate specific symbols with:`);
11931
+ emitErr(` token-goat symbol <name>`);
11932
+ emitErr(` token-goat locate <name>`);
11933
+ emitErr(` token-goat outline <file> / token-goat skeleton <file>`);
11830
11934
  }
11831
11935
  return 0;
11832
11936
  }
11833
11937
  var RRF_K = 60;
11938
+ function applyRelevanceFloor(hits, floor) {
11939
+ const kept = [];
11940
+ let nearestRejected = null;
11941
+ for (const h of hits) {
11942
+ if (h.distance <= floor) {
11943
+ kept.push(h);
11944
+ } else if (nearestRejected === null || h.distance < nearestRejected) {
11945
+ nearestRejected = h.distance;
11946
+ }
11947
+ }
11948
+ return { kept, nearestRejected };
11949
+ }
11834
11950
  async function runSemantic(query, opts) {
11835
11951
  if (opts.limit !== void 0 && opts.limit <= 0) {
11836
11952
  const message = `--limit must be a positive number, got: ${opts.limit}`;
@@ -11919,7 +12035,19 @@ async function runSemantic(query, opts) {
11919
12035
  }
11920
12036
  }
11921
12037
  }
11922
- if (rawHits.length === 0 && isAvailable() && preflight.status === "ready" && !searchSemanticError) {
12038
+ let floorNearestRejected = null;
12039
+ if (rawHits.length > 0) {
12040
+ const floor = loadConfig().semantic.max_distance;
12041
+ const { kept, nearestRejected } = applyRelevanceFloor(rawHits, floor);
12042
+ floorNearestRejected = nearestRejected;
12043
+ if (kept.length === 0 && nearestRejected !== null) {
12044
+ console.warn(
12045
+ `Matching on meaning found nothing within ${floor} (closest was ${nearestRejected.toFixed(3)}); these results come from keyword search alone. Raise semantic.max_distance to see weaker matches.`
12046
+ );
12047
+ }
12048
+ rawHits = kept;
12049
+ }
12050
+ if (rawHits.length === 0 && floorNearestRejected === null && isAvailable() && preflight.status === "ready" && !searchSemanticError) {
11923
12051
  try {
11924
12052
  const enabled = loadConfig().indexing.embeddings_enabled;
11925
12053
  const { indexedFiles, embeddedFiles } = enabled ? getEmbeddingCoverage(globalDbPath(), rootDir) : { indexedFiles: 0, embeddedFiles: 0 };
@@ -11947,7 +12075,9 @@ async function runSemantic(query, opts) {
11947
12075
  kind: enclosing?.kind ?? null,
11948
12076
  distance: h.distance,
11949
12077
  previewText: h.text,
11950
- rrf: 1 / (RRF_K + denseRank)
12078
+ rrf: 1 / (RRF_K + denseRank),
12079
+ inDense: true,
12080
+ inLexical: false
11951
12081
  });
11952
12082
  });
11953
12083
  ftsRows.forEach((s, ftsRank) => {
@@ -11955,6 +12085,7 @@ async function runSemantic(query, opts) {
11955
12085
  const existing = fused.get(key);
11956
12086
  if (existing !== void 0) {
11957
12087
  existing.rrf += 1 / (RRF_K + ftsRank);
12088
+ existing.inLexical = true;
11958
12089
  } else {
11959
12090
  fused.set(key, {
11960
12091
  filePath: s.filePath,
@@ -11964,7 +12095,9 @@ async function runSemantic(query, opts) {
11964
12095
  kind: s.kind,
11965
12096
  distance: null,
11966
12097
  previewText: s.body,
11967
- rrf: 1 / (RRF_K + ftsRank)
12098
+ rrf: 1 / (RRF_K + ftsRank),
12099
+ inDense: false,
12100
+ inLexical: true
11968
12101
  });
11969
12102
  }
11970
12103
  });
@@ -11987,12 +12120,15 @@ async function runSemantic(query, opts) {
11987
12120
  warnIfFilesStale(hits.map((h) => h.filePath));
11988
12121
  if (hits.length > 0) {
11989
12122
  if (opts.json === true) {
11990
- const items = hits.map((h) => ({
12123
+ const items = hits.map((h, i) => ({
11991
12124
  filePath: toDisplayPath(rootDir, h.filePath),
11992
12125
  name: h.name,
11993
12126
  kind: h.kind,
11994
12127
  startLine: h.startLine,
11995
12128
  endLine: h.endLine,
12129
+ rank: i + 1,
12130
+ rrf: h.rrf,
12131
+ retrieval: h.inDense && h.inLexical ? "both" : h.inDense ? "dense" : "lexical",
11996
12132
  distance: h.distance,
11997
12133
  preview: previewLines(h.previewText, 3)
11998
12134
  }));
@@ -12016,18 +12152,19 @@ async function runSemantic(query, opts) {
12016
12152
  recordReadStat("semantic_search", sumFileSizes(hits.map((h) => h.filePath)), text3, query);
12017
12153
  return { text: text3, code: 0 };
12018
12154
  }
12019
- const blocks = hits.map((h) => {
12155
+ const blocks = hits.map((h, i) => {
12156
+ const mark = h.inDense && h.inLexical ? ", +keyword" : "";
12020
12157
  if (h.distance !== null) {
12021
12158
  const suffix = h.name !== null ? ` \u2014 inside ${h.name} (${h.kind})` : "";
12022
- return `# ${toDisplayPath(rootDir, h.filePath)}:${h.startLine}-${h.endLine} (distance ${h.distance.toFixed(3)})${suffix}
12159
+ return `# ${i + 1}. ${toDisplayPath(rootDir, h.filePath)}:${h.startLine}-${h.endLine} (distance ${h.distance.toFixed(3)}${mark})${suffix}
12023
12160
  ${previewLines(h.previewText, 3)}`;
12024
12161
  }
12025
- return `# ${h.name} (${h.kind}) \u2014 ${toDisplayPath(rootDir, h.filePath)}:${h.startLine}-${h.endLine}
12162
+ return `# ${i + 1}. ${h.name} (${h.kind}) \u2014 ${toDisplayPath(rootDir, h.filePath)}:${h.startLine}-${h.endLine} (keyword)
12026
12163
  ${previewLines(h.previewText, 3)}`;
12027
12164
  });
12028
12165
  const text2 = guardText(blocks.join("\n\n"), "semantic");
12029
12166
  if (hits.length < eligibleCount) {
12030
- emitErr4(`Showing ${hits.length} of ${candidatesClipped ? "at least " : ""}${countNoun(eligibleCount, "match", "matches")} (raise --limit to see the rest).`);
12167
+ emitErr(`Showing ${hits.length} of ${candidatesClipped ? "at least " : ""}${countNoun(eligibleCount, "match", "matches")} (raise --limit to see the rest).`);
12031
12168
  }
12032
12169
  recordReadStat("semantic_search", sumFileSizes(hits.map((h) => h.filePath)), text2, query);
12033
12170
  return { text: text2, code: 0 };
@@ -12127,7 +12264,7 @@ function fileExists3(p) {
12127
12264
  return false;
12128
12265
  }
12129
12266
  }
12130
- var FIND_SCAN_LIMIT3 = 2e4;
12267
+ var FIND_SCAN_LIMIT2 = FIND_SCAN_LIMIT;
12131
12268
  var PARENT_IDENTIFIER_RE2 = /^[\w$]+$/;
12132
12269
  function parseReadSpec(spec) {
12133
12270
  const colonIdx = findSpecSeparator(spec);
@@ -12264,7 +12401,7 @@ function runLineRegion(range, opts) {
12264
12401
  } else {
12265
12402
  healStaleIndex(resolved);
12266
12403
  }
12267
- const symbols = querySymbols({ filePath: resolved, limit: FIND_SCAN_LIMIT3 });
12404
+ const symbols = querySymbols({ filePath: resolved, limit: FIND_SCAN_LIMIT2 });
12268
12405
  const regions = resolveLineRegions(symbols, allLines.length, start, end);
12269
12406
  const asked = start === end ? `${start}` : `${start}-${end}`;
12270
12407
  if (regions.length === 0) {
@@ -12328,7 +12465,7 @@ function formatAmbiguity(symbol, file, candidates, explicitRoot, commandName = "
12328
12465
  const getFileSyms = (filePath) => {
12329
12466
  let fileSyms = fileSymCache.get(filePath);
12330
12467
  if (fileSyms === void 0) {
12331
- fileSyms = querySymbols({ filePath, limit: FIND_SCAN_LIMIT3 });
12468
+ fileSyms = querySymbols({ filePath, limit: FIND_SCAN_LIMIT2 });
12332
12469
  fileSymCache.set(filePath, fileSyms);
12333
12470
  }
12334
12471
  return fileSyms;
@@ -12456,16 +12593,16 @@ function resolveSymbolSpec(spec, forceRefresh, projectRoot) {
12456
12593
  function resolveSymbolSpecOrEmitError(commandName, spec, projectRoot) {
12457
12594
  const { file, symbol } = parseReadSpec(spec);
12458
12595
  if (symbol === void 0 || symbol === "") {
12459
- emitErr4(`'token-goat ${commandName}' requires a 'file::symbol' spec (got '${spec}')`);
12596
+ emitErr(`'token-goat ${commandName}' requires a 'file::symbol' spec (got '${spec}')`);
12460
12597
  return null;
12461
12598
  }
12462
12599
  const resolution = resolveSymbolSpec(spec, void 0, projectRoot);
12463
12600
  if (resolution.kind === "confined") {
12464
- emitErr4(resolution.message);
12601
+ emitErr(resolution.message);
12465
12602
  return null;
12466
12603
  }
12467
12604
  if (resolution.kind === "ambiguous") {
12468
- emitErr4(
12605
+ emitErr(
12469
12606
  formatAmbiguity(
12470
12607
  resolution.symbol,
12471
12608
  resolution.file,
@@ -12481,11 +12618,11 @@ function resolveSymbolSpecOrEmitError(commandName, spec, projectRoot) {
12481
12618
  const crossFileLead = formatCrossFileLead(commandName, symbol, file, projectRoot);
12482
12619
  if (crossFileLead !== "") messages.push(crossFileLead);
12483
12620
  const resolved = resolveIndexPath(file, projectRoot ?? process.cwd());
12484
- const scanned = querySymbols({ filePath: resolved, limit: FIND_SCAN_LIMIT3 }).map((s) => s.name);
12621
+ const scanned = querySymbols({ filePath: resolved, limit: FIND_SCAN_LIMIT2 }).map((s) => s.name);
12485
12622
  const closes = rankSimilarNames(scanned, symbol);
12486
12623
  if (closes.length > 0) messages.push(didYouMean(closes));
12487
12624
  else if (scanned.length > 0) messages.push(`Try: token-goat outline ${file}`);
12488
- emitErr4(messages.join("\n"));
12625
+ emitErr(messages.join("\n"));
12489
12626
  return null;
12490
12627
  }
12491
12628
  return resolution.entry;
@@ -12500,13 +12637,13 @@ var CONTENT_MAX_ITEMS = 256;
12500
12637
  var CONTENT_MAX_BYTES = 32 * 1024 * 1024;
12501
12638
  var CONTENT_MAX_ITEM_BYTES = CONTENT_MAX_INPUT_CHARS * 7;
12502
12639
  var CONTENT_SUBDIR = "content";
12503
- var TEXT_BYTES_PER_TOKEN = 4;
12504
- var BASE64URL_BYTES_PER_TOKEN = 1.45;
12640
+ var TEXT_BYTES_PER_TOKEN = BYTES_PER_TOKEN.text;
12641
+ var BASE64URL_BYTES_PER_TOKEN = BYTES_PER_TOKEN.dense;
12505
12642
  function estimateTextTokens(bytes) {
12506
- return Math.round(bytes / TEXT_BYTES_PER_TOKEN);
12643
+ return savedTokensFromBytes(bytes, "text");
12507
12644
  }
12508
12645
  function estimateBase64urlTokens(bytes) {
12509
- return Math.round(bytes / BASE64URL_BYTES_PER_TOKEN);
12646
+ return savedTokensFromBytes(bytes, "dense");
12510
12647
  }
12511
12648
  function assertInput(text) {
12512
12649
  if (text.length > CONTENT_MAX_INPUT_CHARS) {
@@ -12617,6 +12754,8 @@ function resolveHandoff(name, opts = {}) {
12617
12754
  export {
12618
12755
  isAvailable2 as isAvailable,
12619
12756
  loadError,
12757
+ emit,
12758
+ emitErr,
12620
12759
  ALL_SYMBOLS_IN_FILE_LIMIT,
12621
12760
  enclosingSymbol,
12622
12761
  runDead,