token-goat 2.6.36 → 2.8.0

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 (34) hide show
  1. package/README.md +31 -5
  2. package/SECURITY.md +46 -17
  3. package/dist/{token-goat-chunk-UFOVM7ZN.mjs → token-goat-chunk-2F6TFBZE.mjs} +1274 -367
  4. package/dist/token-goat-chunk-324QOJYZ.mjs +91 -0
  5. package/dist/{token-goat-chunk-V465YKOR.mjs → token-goat-chunk-44Y77VHR.mjs} +365 -23
  6. package/dist/{token-goat-chunk-CNDOJ3ZP.mjs → token-goat-chunk-4KZILRZN.mjs} +2 -2
  7. package/dist/token-goat-chunk-5CVKO3DA.mjs +185 -0
  8. package/dist/token-goat-chunk-A62K4XW2.mjs +23 -0
  9. package/dist/{token-goat-chunk-VYMGEVZS.mjs → token-goat-chunk-AO6MFFTW.mjs} +317 -11
  10. package/dist/{token-goat-chunk-65BKISIS.mjs → token-goat-chunk-FBGBTICM.mjs} +4 -4
  11. package/dist/{token-goat-chunk-LN6OUHTV.mjs → token-goat-chunk-J35AKWEQ.mjs} +5 -5
  12. package/dist/{token-goat-hook-chunk-BDR6C6IE.mjs → token-goat-chunk-LVCBDJVE.mjs} +318 -51
  13. package/dist/token-goat-chunk-R4SR7MQY.mjs +486 -0
  14. package/dist/{token-goat-chunk-IYTVE6KN.mjs → token-goat-chunk-SRAR6DOK.mjs} +133 -141
  15. package/dist/{token-goat-chunk-MGOUYAA2.mjs → token-goat-chunk-TUPJRK7R.mjs} +1 -1
  16. package/dist/{token-goat-chunk-KYFJC37X.mjs → token-goat-chunk-VXSYZGBA.mjs} +582 -135
  17. package/dist/{token-goat-chunk-DG53MVNJ.mjs → token-goat-chunk-WN5T5EW5.mjs} +212 -212
  18. package/dist/token-goat-hook.mjs +7 -7
  19. package/dist/token-goat.core.mjs +5 -5
  20. package/package.json +9 -7
  21. package/dist/token-goat-chunk-FRTBMRP7.mjs +0 -10048
  22. package/dist/token-goat-hook-chunk-3QYSN4QV.mjs +0 -14764
  23. package/dist/token-goat-hook-chunk-3ZDBWJDF.mjs +0 -13659
  24. package/dist/token-goat-hook-chunk-5UH54CW6.mjs +0 -912
  25. package/dist/token-goat-hook-chunk-6ODM3MP7.mjs +0 -706
  26. package/dist/token-goat-hook-chunk-A77A26A7.mjs +0 -18184
  27. package/dist/token-goat-hook-chunk-BUOCULAM.mjs +0 -29
  28. package/dist/token-goat-hook-chunk-C6GIABOX.mjs +0 -15971
  29. package/dist/token-goat-hook-chunk-E257IGSN.mjs +0 -153
  30. package/dist/token-goat-hook-chunk-MW5HPEGD.mjs +0 -10411
  31. package/dist/token-goat-hook-chunk-QSCYNJ2B.mjs +0 -23
  32. package/dist/token-goat-hook-chunk-RFRLWOQH.mjs +0 -11
  33. package/dist/token-goat-hook-chunk-XUMIVYEN.mjs +0 -109
  34. package/dist/token-goat-hook-chunk-Y2WHX2P3.mjs +0 -6463
@@ -21,6 +21,7 @@ import {
21
21
  formatCsvTable,
22
22
  getFileEntry,
23
23
  indexFileSync,
24
+ isAvailable,
24
25
  isBlobStale,
25
26
  isImagePath,
26
27
  isIndexEmptyForProject,
@@ -50,8 +51,9 @@ import {
50
51
  walkProject,
51
52
  yamlLineClosesQuote,
52
53
  yamlOpenQuoteAfter
53
- } from "./token-goat-chunk-UFOVM7ZN.mjs";
54
+ } from "./token-goat-chunk-2F6TFBZE.mjs";
54
55
  import {
56
+ Database,
55
57
  PER_FILE_COUNTERFACTUAL_CEILING,
56
58
  _detectOpenQuote,
57
59
  _lineClosesQuote,
@@ -101,7 +103,7 @@ import {
101
103
  unsupportedLanguageName,
102
104
  windowsCmdQuoteArg,
103
105
  withExtension
104
- } from "./token-goat-chunk-V465YKOR.mjs";
106
+ } from "./token-goat-chunk-44Y77VHR.mjs";
105
107
  import {
106
108
  registerReset
107
109
  } from "./token-goat-chunk-AO2QD2AG.mjs";
@@ -320,7 +322,15 @@ function resolveHeaderPos(headers, base, ordinal) {
320
322
  const pick2 = ordinal === null ? 0 : ordinal - 1;
321
323
  const headerPos = matches[pick2];
322
324
  if (headerPos === void 0) return null;
323
- return { headerPos, redirectedFrom: null };
325
+ let occurrences = null;
326
+ if (ordinal === null && matches.length > 1) {
327
+ occurrences = [];
328
+ for (const i of matches) {
329
+ const h = headers[i];
330
+ if (h !== void 0) occurrences.push(h.index + 1);
331
+ }
332
+ }
333
+ return { headerPos, redirectedFrom: null, occurrences };
324
334
  }
325
335
  if (ordinal !== null || normalizedTarget.length === 0) return null;
326
336
  let prefixPos = -1;
@@ -337,7 +347,7 @@ function resolveHeaderPos(headers, base, ordinal) {
337
347
  if (distinct.size === 1 && prefixPos !== -1) {
338
348
  const chosen = headers[prefixPos];
339
349
  if (chosen === void 0) return null;
340
- return { headerPos: prefixPos, redirectedFrom: base };
350
+ return { headerPos: prefixPos, redirectedFrom: base, occurrences: null };
341
351
  }
342
352
  const queryWords = normalizedTarget.split(/\s+/).filter((w) => w.length >= MIN_WIDEN_WORD_LEN);
343
353
  if (queryWords.length === 0) return null;
@@ -352,7 +362,7 @@ function resolveHeaderPos(headers, base, ordinal) {
352
362
  if (widenedMatches.length !== 1) return null;
353
363
  const widenedPos = widenedMatches[0];
354
364
  if (widenedPos === void 0) return null;
355
- return { headerPos: widenedPos, redirectedFrom: base };
365
+ return { headerPos: widenedPos, redirectedFrom: base, occurrences: null };
356
366
  }
357
367
  function buildSectionResult(headers, kind, lines, headerPos, redirectedFrom) {
358
368
  const header = headers[headerPos];
@@ -378,7 +388,9 @@ function resolveSectionFromText(text, headingSpec, language) {
378
388
  const lines = text.split("\n");
379
389
  const resolved = resolveHeaderPos(headers, base, ordinal);
380
390
  if (resolved === null) return null;
381
- return buildSectionResult(headers, kind, lines, resolved.headerPos, resolved.redirectedFrom);
391
+ const built = buildSectionResult(headers, kind, lines, resolved.headerPos, resolved.redirectedFrom);
392
+ if (built === null || resolved.occurrences === null) return built;
393
+ return { ...built, occurrences: resolved.occurrences };
382
394
  }
383
395
  function extractSection(text, headingSpec) {
384
396
  return resolveSectionFromText(text, headingSpec, "unknown");
@@ -3745,7 +3757,6 @@ ${c.body}`).join("\n\n");
3745
3757
 
3746
3758
  // src/sqlite_query.ts
3747
3759
  import * as fs2 from "node:fs";
3748
- import Database from "better-sqlite3";
3749
3760
  var SQLITE_QUERY_ROW_CAP = 5e3;
3750
3761
  var SQLITE_MAGIC = Buffer.from([83, 81, 76, 105, 116, 101, 32, 102, 111, 114, 109, 97, 116, 32, 51, 0]);
3751
3762
  function readMagicBytes(filePath) {
@@ -4930,7 +4941,7 @@ function loadTs() {
4930
4941
  }
4931
4942
  return _ts;
4932
4943
  }
4933
- function isAvailable() {
4944
+ function isAvailable2() {
4934
4945
  return loadTs() !== null;
4935
4946
  }
4936
4947
  function loadError() {
@@ -5094,6 +5105,7 @@ function findIdentifierNearPosition(ts, sourceFile, line0, position, name) {
5094
5105
 
5095
5106
  // src/read_commands.ts
5096
5107
  var DIDYOUMEAN_LIMIT = 5;
5108
+ var AMBIGUOUS_HEADING_LIMIT = 10;
5097
5109
  var TYPO_TWO_EDIT_MIN_LEN = 8;
5098
5110
  var TYPO_MAX_QUERY_LEN = 64;
5099
5111
  var MIN_REVERSE_MATCH_LEN = 3;
@@ -5382,13 +5394,14 @@ function filterSimilarHeadings(available, query) {
5382
5394
  return sortByLengthCloseness(matched, query);
5383
5395
  }
5384
5396
  function didYouMean(candidates) {
5385
- if (candidates.length === 0) return "";
5397
+ const unique = [...new Set(candidates)];
5398
+ if (unique.length === 0) return "";
5386
5399
  const lines = ["Did you mean:"];
5387
- for (const c of candidates.slice(0, DIDYOUMEAN_LIMIT)) {
5400
+ for (const c of unique.slice(0, DIDYOUMEAN_LIMIT)) {
5388
5401
  lines.push(` - ${c}`);
5389
5402
  }
5390
- if (candidates.length > DIDYOUMEAN_LIMIT) {
5391
- lines.push(` (${candidates.length - DIDYOUMEAN_LIMIT} more not shown)`);
5403
+ if (unique.length > DIDYOUMEAN_LIMIT) {
5404
+ lines.push(` (${unique.length - DIDYOUMEAN_LIMIT} more not shown)`);
5392
5405
  }
5393
5406
  return lines.join("\n");
5394
5407
  }
@@ -6018,6 +6031,18 @@ function runSection(opts) {
6018
6031
  if (!fs5.existsSync(filePath)) {
6019
6032
  return { text: `File not found: '${filePath}'`, code: 1 };
6020
6033
  }
6034
+ const ordSpec = /^(.*?)#(\d+)$/.exec(heading);
6035
+ const ordBase = ordSpec?.[1]?.trim();
6036
+ if (ordBase !== void 0 && ordBase.length > 0) {
6037
+ const baseResult = readSection(filePath, ordBase, readFileText);
6038
+ if (baseResult !== null) {
6039
+ const total = baseResult.occurrences?.length ?? 1;
6040
+ return {
6041
+ text: `Heading '${ordBase}' has ${countNoun(total, "occurrence")} in '${specFilePath}'; valid ordinals are #1 to #${total}`,
6042
+ code: 1
6043
+ };
6044
+ }
6045
+ }
6021
6046
  const messages = [`Section '${heading}' not found in '${filePath}'`];
6022
6047
  const allHeadings = listSections(filePath, readFileText);
6023
6048
  const available = filterSimilarHeadings(allHeadings, heading);
@@ -6026,6 +6051,18 @@ function runSection(opts) {
6026
6051
  else messages.push(`Try: token-goat outline ${specFilePath}`);
6027
6052
  return { text: messages.join("\n"), code: 1 };
6028
6053
  }
6054
+ if (result.occurrences !== void 0) {
6055
+ const lines = [
6056
+ `Ambiguous heading '${heading}' in '${specFilePath}': ${countNoun(result.occurrences.length, "heading")} match. Retry with one of the qualified commands below to pick one:`
6057
+ ];
6058
+ for (const [i, line] of result.occurrences.slice(0, AMBIGUOUS_HEADING_LIMIT).entries()) {
6059
+ lines.push(` - line ${line} -> token-goat section "${specFilePath}::${heading}#${i + 1}"`);
6060
+ }
6061
+ if (result.occurrences.length > AMBIGUOUS_HEADING_LIMIT) {
6062
+ lines.push(` (${result.occurrences.length - AMBIGUOUS_HEADING_LIMIT} more not shown)`);
6063
+ }
6064
+ return { text: lines.join("\n"), code: 1 };
6065
+ }
6029
6066
  const kind = result.redirectedFrom !== void 0 ? "section_replacement" : "section_read";
6030
6067
  const fullSourceBytes = sumFileSizes([filePath]);
6031
6068
  if (opts.json === true) {
@@ -6145,40 +6182,15 @@ function refsSpecFiles(spec) {
6145
6182
  const { file } = parseMultiRefsSpec(spec);
6146
6183
  return file === void 0 ? [] : [file];
6147
6184
  }
6148
- function runRefs(opts) {
6149
- if (opts.limit !== void 0 && opts.limit <= 0) {
6150
- emitErr(`--limit must be a positive number, got: ${opts.limit}`);
6151
- return 1;
6152
- }
6153
- if (opts.top !== void 0 && opts.top <= 0) {
6154
- emitErr(`--top must be a positive number, got: ${opts.top}`);
6155
- return 1;
6156
- }
6157
- const confinedRoot = confinedProjectRoot();
6158
- if (confinedRoot !== null) {
6159
- const projectDenial = opts.projectRoot === void 0 ? null : confinementRefusal("--project", opts.projectRoot, confinedRoot);
6160
- if (projectDenial !== null) {
6161
- emitErr(projectDenial);
6162
- return 1;
6163
- }
6164
- for (const file2 of refsSpecFiles(opts.spec)) {
6165
- const denial = confinementRefusal("This file", resolveIndexPath(file2, opts.projectRoot ?? process.cwd()), confinedRoot);
6166
- if (denial !== null) {
6167
- emitErr(denial);
6168
- return 1;
6169
- }
6170
- }
6171
- }
6172
- const crossFilePairs = parseCrossFileMultiSpec(opts.spec);
6173
- if (crossFilePairs !== null) return runRefsCrossFile(crossFilePairs, opts);
6174
- const { file, symbols } = parseMultiRefsSpec(opts.spec);
6175
- if (symbols.length <= 1) return runRefsSingle(opts);
6185
+ function renderRefsTargets(targets, opts, {
6186
+ annotateHiddenByGrep
6187
+ }) {
6176
6188
  const jsonOut = {};
6177
6189
  let anyFound = false;
6178
6190
  const lines = [];
6179
6191
  const refFilePaths = [];
6180
- for (const sym of symbols) {
6181
- const queryOpts = { name: sym };
6192
+ for (const { file, symbol, key } of targets) {
6193
+ const queryOpts = { name: symbol };
6182
6194
  if (opts.excludeTests === true || opts.grep !== void 0) queryOpts.limit = REFS_TOP_SCAN_LIMIT;
6183
6195
  else if (opts.limit !== void 0) queryOpts.limit = opts.limit;
6184
6196
  else if (opts.top !== void 0) queryOpts.limit = REFS_TOP_SCAN_LIMIT;
@@ -6186,7 +6198,7 @@ function runRefs(opts) {
6186
6198
  if (rootDir !== void 0) queryOpts.rootDir = rootDir;
6187
6199
  const scanned = queryRefs(queryOpts);
6188
6200
  const preScanCount = scanned.length;
6189
- let results = applyTypedRefsTier(sym, file, scanned);
6201
+ let results = applyTypedRefsTier(symbol, file, scanned);
6190
6202
  let suppressed = 0;
6191
6203
  if (opts.excludeTests === true) {
6192
6204
  const f = applyExcludeTestsFilter(results);
@@ -6205,25 +6217,25 @@ function runRefs(opts) {
6205
6217
  refFilePaths.push(...results.map((r) => r.filePath));
6206
6218
  if (opts.json === true) {
6207
6219
  const hiddenByGrep = matchesGrep !== void 0 ? preGrepCount - (filteredTotal ?? results.length) : 0;
6208
- const withHidden = (payload) => ({ ...payload, ...hiddenByGrep > 0 ? { hiddenByGrep } : {} });
6220
+ const withHidden = (payload) => ({ ...payload, ...annotateHiddenByGrep && hiddenByGrep > 0 ? { hiddenByGrep } : {} });
6209
6221
  if (opts.top !== void 0) {
6210
- jsonOut[sym] = withHidden(topFilesJsonPayload(results, opts.top));
6222
+ jsonOut[key] = withHidden(topFilesJsonPayload(results, opts.top));
6211
6223
  } else {
6212
6224
  const capped = guardJsonRows(results);
6213
6225
  const trueTotal = opts.excludeTests === true || matchesGrep !== void 0 ? filteredTotal ?? results.length : countRefs(queryOpts);
6214
- jsonOut[sym] = withHidden({ items: refsJsonItems(capped.items, opts.context ?? 0), truncated: capped.truncated || trueTotal > results.length, totalCount: trueTotal });
6226
+ jsonOut[key] = withHidden({ items: refsJsonItems(capped.items, opts.context ?? 0), truncated: capped.truncated || trueTotal > results.length, totalCount: trueTotal });
6215
6227
  }
6216
6228
  continue;
6217
6229
  }
6218
6230
  if (results.length === 0) {
6219
6231
  if (matchesGrep !== void 0 && preGrepCount > 0) {
6220
- lines.push(`${sym}: ${grepFilteredToEmptyNotice(preGrepCount, opts.grep ?? "", "reference", "references").trim()}`);
6232
+ lines.push(`${key}: ${grepFilteredToEmptyNotice(preGrepCount, opts.grep ?? "", "reference", "references").trim()}`);
6221
6233
  continue;
6222
6234
  }
6223
- lines.push(opts.excludeTests === true && suppressed > 0 ? `${sym}: (no non-test references found; ${excludeTestsHiddenNote(suppressed)})` : `${sym}: (no references found)`);
6235
+ lines.push(opts.excludeTests === true && suppressed > 0 ? `${key}: (no non-test references found; ${excludeTestsHiddenNote(suppressed)})` : `${key}: (no references found)`);
6224
6236
  continue;
6225
6237
  }
6226
- lines.push(`${sym}:`);
6238
+ lines.push(`${key}:`);
6227
6239
  if (opts.top !== void 0) {
6228
6240
  lines.push(...renderTopFilesSummary(results, opts.top, suppressed));
6229
6241
  } else if (opts.callers === true) {
@@ -6256,90 +6268,50 @@ function runRefs(opts) {
6256
6268
  if (anyFound) recordReadStat("symbol_read", fullSourceBytes, text, opts.spec);
6257
6269
  return anyFound ? 0 : 1;
6258
6270
  }
6259
- function runRefsCrossFile(pairs, opts) {
6260
- const distinctFiles = new Set(pairs.map((p) => p.file));
6261
- const keyFor = (p) => distinctFiles.size === 1 ? p.symbol : `${p.file}::${p.symbol}`;
6262
- const jsonOut = {};
6263
- let anyFound = false;
6264
- const lines = [];
6265
- const refFilePaths = [];
6266
- for (const { file, symbol } of pairs) {
6267
- const key = keyFor({ file, symbol });
6268
- const queryOpts = { name: symbol };
6269
- if (opts.excludeTests === true || opts.grep !== void 0) queryOpts.limit = REFS_TOP_SCAN_LIMIT;
6270
- else if (opts.limit !== void 0) queryOpts.limit = opts.limit;
6271
- else if (opts.top !== void 0) queryOpts.limit = REFS_TOP_SCAN_LIMIT;
6272
- const rootDir = refsRootDir(opts);
6273
- if (rootDir !== void 0) queryOpts.rootDir = rootDir;
6274
- const scanned = queryRefs(queryOpts);
6275
- const preScanCount = scanned.length;
6276
- let results = applyTypedRefsTier(symbol, file, scanned);
6277
- let suppressed = 0;
6278
- if (opts.excludeTests === true) {
6279
- const f = applyExcludeTestsFilter(results);
6280
- suppressed = f.suppressed;
6281
- results = f.refs;
6282
- }
6283
- const preGrepCount = results.length;
6284
- const matchesGrep = refGrepFilter(opts.grep);
6285
- if (matchesGrep !== void 0) results = results.filter(matchesGrep);
6286
- let filteredTotal;
6287
- if (opts.excludeTests === true || matchesGrep !== void 0) filteredTotal = results.length;
6288
- if ((opts.excludeTests === true || matchesGrep !== void 0) && opts.top === void 0) {
6289
- results = results.slice(0, opts.limit ?? 100);
6290
- }
6291
- if (results.length > 0) anyFound = true;
6292
- refFilePaths.push(...results.map((r) => r.filePath));
6293
- if (opts.json === true) {
6294
- if (opts.top !== void 0) {
6295
- jsonOut[key] = topFilesJsonPayload(results, opts.top);
6296
- } else {
6297
- const capped = guardJsonRows(results);
6298
- const trueTotal = opts.excludeTests === true || matchesGrep !== void 0 ? filteredTotal ?? results.length : countRefs(queryOpts);
6299
- jsonOut[key] = { items: refsJsonItems(capped.items, opts.context ?? 0), truncated: capped.truncated || trueTotal > results.length, totalCount: trueTotal };
6300
- }
6301
- continue;
6271
+ function runRefs(opts) {
6272
+ if (opts.limit !== void 0 && opts.limit <= 0) {
6273
+ emitErr(`--limit must be a positive number, got: ${opts.limit}`);
6274
+ return 1;
6275
+ }
6276
+ if (opts.top !== void 0 && opts.top <= 0) {
6277
+ emitErr(`--top must be a positive number, got: ${opts.top}`);
6278
+ return 1;
6279
+ }
6280
+ const confinedRoot = confinedProjectRoot();
6281
+ if (confinedRoot !== null) {
6282
+ const projectDenial = opts.projectRoot === void 0 ? null : confinementRefusal("--project", opts.projectRoot, confinedRoot);
6283
+ if (projectDenial !== null) {
6284
+ emitErr(projectDenial);
6285
+ return 1;
6302
6286
  }
6303
- if (results.length === 0) {
6304
- if (matchesGrep !== void 0 && preGrepCount > 0) {
6305
- lines.push(`${key}: ${grepFilteredToEmptyNotice(preGrepCount, opts.grep ?? "", "reference", "references").trim()}`);
6306
- continue;
6287
+ for (const file2 of refsSpecFiles(opts.spec)) {
6288
+ const denial = confinementRefusal("This file", resolveIndexPath(file2, opts.projectRoot ?? process.cwd()), confinedRoot);
6289
+ if (denial !== null) {
6290
+ emitErr(denial);
6291
+ return 1;
6307
6292
  }
6308
- lines.push(opts.excludeTests === true && suppressed > 0 ? `${key}: (no non-test references found; ${excludeTestsHiddenNote(suppressed)})` : `${key}: (no references found)`);
6309
- continue;
6310
- }
6311
- lines.push(`${key}:`);
6312
- if (opts.top !== void 0) {
6313
- lines.push(...renderTopFilesSummary(results, opts.top, suppressed));
6314
- } else if (opts.callers === true) {
6315
- if (opts.excludeTests === true && suppressed > 0) lines.push(` ${countNoun(results.length, "reference")} (${excludeTestsHiddenNote(suppressed)})`);
6316
- lines.push(...renderCallerGroups(results, opts.context ?? 0));
6317
- } else {
6318
- if (opts.excludeTests === true && suppressed > 0) lines.push(` ${countNoun(results.length, "reference")} (${excludeTestsHiddenNote(suppressed)})`);
6319
- for (const ref of results) lines.push(...renderRefLines(ref, opts.context ?? 0));
6320
- }
6321
- if (opts.top === void 0) {
6322
- const notice = truncationNotice(
6323
- results.length,
6324
- opts.limit ?? 100,
6325
- () => refsTotal(opts.excludeTests === true || matchesGrep !== void 0, filteredTotal, results.length, () => countRefs(queryOpts), preScanCount),
6326
- "references",
6327
- "--limit"
6328
- );
6329
- if (notice !== null) lines.push(` token-goat: ${notice}`);
6330
6293
  }
6331
6294
  }
6332
- const fullSourceBytes = sumFileSizes(refFilePaths);
6333
- if (opts.json === true) {
6334
- const text2 = JSON.stringify(jsonOut, null, 2);
6335
- emit(text2);
6336
- if (anyFound) recordReadStat("symbol_read", fullSourceBytes, text2, opts.spec);
6337
- return anyFound ? 0 : 1;
6338
- }
6339
- const text = lines.join("\n");
6340
- emitGuarded(text, "symbol");
6341
- if (anyFound) recordReadStat("symbol_read", fullSourceBytes, text, opts.spec);
6342
- return anyFound ? 0 : 1;
6295
+ const crossFilePairs = parseCrossFileMultiSpec(opts.spec);
6296
+ if (crossFilePairs !== null) return runRefsCrossFile(crossFilePairs, opts);
6297
+ const { file, symbols } = parseMultiRefsSpec(opts.spec);
6298
+ if (symbols.length <= 1) return runRefsSingle(opts);
6299
+ return renderRefsTargets(
6300
+ symbols.map((symbol) => ({ file, symbol, key: symbol })),
6301
+ opts,
6302
+ { annotateHiddenByGrep: true }
6303
+ );
6304
+ }
6305
+ function runRefsCrossFile(pairs, opts) {
6306
+ const distinctFiles = new Set(pairs.map((p) => p.file));
6307
+ const keyFor = (p) => distinctFiles.size === 1 ? p.symbol : `${p.file}::${p.symbol}`;
6308
+ return renderRefsTargets(
6309
+ pairs.map((p) => ({ file: p.file, symbol: p.symbol, key: keyFor(p) })),
6310
+ opts,
6311
+ // Not annotated today; renderRefsTargets's own option doc explains why that is a preserved
6312
+ // divergence rather than a decision.
6313
+ { annotateHiddenByGrep: false }
6314
+ );
6343
6315
  }
6344
6316
  function runRefsSingle(opts) {
6345
6317
  const { file, symbol } = parseReadSpec(opts.spec);
@@ -7569,7 +7541,15 @@ function runListSections(opts) {
7569
7541
  }
7570
7542
  const preFilterCount = sections.length;
7571
7543
  const matchesGrep = opts.grep !== void 0 ? compileGrepMatcher(opts.grep) : void 0;
7572
- const filtered = matchesGrep !== void 0 ? sections.filter((s) => matchesGrep(s)) : sections;
7544
+ const totals = /* @__PURE__ */ new Map();
7545
+ for (const heading of sections) totals.set(heading, (totals.get(heading) ?? 0) + 1);
7546
+ const seen = /* @__PURE__ */ new Map();
7547
+ const labelled = sections.map((heading) => {
7548
+ const nth = (seen.get(heading) ?? 0) + 1;
7549
+ seen.set(heading, nth);
7550
+ return (totals.get(heading) ?? 1) > 1 ? `${heading}#${nth}` : heading;
7551
+ });
7552
+ const filtered = matchesGrep !== void 0 ? labelled.filter((_, i) => matchesGrep(sections[i] ?? "")) : labelled;
7573
7553
  if (filtered.length === 0) {
7574
7554
  if (opts.json === true) {
7575
7555
  emit(JSON.stringify({ items: [], truncated: false, totalCount: 0 }, null, 2));
@@ -7583,8 +7563,8 @@ function runListSections(opts) {
7583
7563
  emit(JSON.stringify({ items: capped.items, truncated: capped.truncated, totalCount: capped.totalCount }, null, 2));
7584
7564
  return 0;
7585
7565
  }
7586
- for (const s of filtered) {
7587
- emit(s);
7566
+ for (const heading of filtered) {
7567
+ emit(heading);
7588
7568
  }
7589
7569
  return 0;
7590
7570
  }
@@ -8781,15 +8761,27 @@ async function runSemantic(query, opts) {
8781
8761
  }
8782
8762
  }
8783
8763
  const rootDir = opts.projectRoot ?? resolveProjectRoot({ project: process.cwd() });
8764
+ if (!isAvailable()) {
8765
+ console.warn(
8766
+ "Matching on meaning is off (onnxruntime-node is not installed); these results come from keyword search alone. Install it with: npm install -g onnxruntime-node (drop -g if token-goat is a project dependency)"
8767
+ );
8768
+ }
8784
8769
  const overFetchForMerge = Math.min(MAX_OVER_FETCH, n * OVER_FETCH_FACTOR);
8785
- const rawHits = await searchSemantic(
8786
- getDb(globalDbPath()),
8787
- query,
8788
- overFetchForMerge,
8789
- void 0,
8790
- void 0,
8791
- rootDir
8792
- );
8770
+ let rawHits = [];
8771
+ try {
8772
+ rawHits = await searchSemantic(
8773
+ getDb(globalDbPath()),
8774
+ query,
8775
+ overFetchForMerge,
8776
+ void 0,
8777
+ void 0,
8778
+ rootDir
8779
+ );
8780
+ } catch (e) {
8781
+ console.warn(
8782
+ `Matching on meaning is off (${extractErrorMessage(e)}); these results come from keyword search alone.`
8783
+ );
8784
+ }
8793
8785
  const mergedHits = mergeNearbyHits(rawHits);
8794
8786
  const overFetchFts = Math.min(MAX_OVER_FETCH, n * OVER_FETCH_FACTOR);
8795
8787
  const ftsRows = searchSymbolsFts(query, overFetchFts, void 0, rootDir);
@@ -10340,7 +10332,7 @@ export {
10340
10332
  symbolNamesInFile,
10341
10333
  computeFileFingerprint,
10342
10334
  upsertNote,
10343
- isAvailable,
10335
+ isAvailable2 as isAvailable,
10344
10336
  loadError,
10345
10337
  ConfinementIdentityError,
10346
10338
  ABSENT_PIN,
@@ -4,7 +4,7 @@ import {
4
4
  loadConfig,
5
5
  redactSecrets,
6
6
  stripAnsiCodes
7
- } from "./token-goat-chunk-V465YKOR.mjs";
7
+ } from "./token-goat-chunk-44Y77VHR.mjs";
8
8
 
9
9
  // src/tool_filters/helpers.ts
10
10
  import * as fs from "node:fs";