token-goat 2.9.30 → 2.9.31

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 (172) hide show
  1. package/README.md +24 -7
  2. package/SECURITY.md +10 -2
  3. package/THIRD_PARTY_NOTICES.md +1 -1
  4. package/dist/native/linux-arm64/tg-hook +0 -0
  5. package/dist/native/linux-x64/tg-hook +0 -0
  6. package/dist/native/win32-arm64/tg-hook.exe +0 -0
  7. package/dist/native/win32-x64/tg-hook.exe +0 -0
  8. package/dist/{token-goat-chunk-QSBRTGM2.mjs → token-goat-chunk-25TRAWET.mjs} +17 -7
  9. package/dist/token-goat-chunk-2KXO6V2B.mjs +203 -0
  10. package/dist/{token-goat-chunk-IVKIZWAB.mjs → token-goat-chunk-2M7E4PF7.mjs} +41 -12
  11. package/dist/{token-goat-chunk-SMVRN2HU.mjs → token-goat-chunk-2UPZGKKY.mjs} +2 -2
  12. package/dist/token-goat-chunk-2WLPWKHV.mjs +135 -0
  13. package/dist/token-goat-chunk-2XBMMDBD.mjs +126 -0
  14. package/dist/token-goat-chunk-32ZOY4N5.mjs +23 -0
  15. package/dist/token-goat-chunk-3EZRNKTK.mjs +188 -0
  16. package/dist/token-goat-chunk-4ADZHI7J.mjs +63 -0
  17. package/dist/token-goat-chunk-4GBVPH3D.mjs +242 -0
  18. package/dist/{token-goat-chunk-KWPNJBDH.mjs → token-goat-chunk-4GILLLWY.mjs} +7 -4
  19. package/dist/{token-goat-chunk-67TQJ76B.mjs → token-goat-chunk-4NAPX7BA.mjs} +36 -3
  20. package/dist/{token-goat-chunk-PU7V3FD6.mjs → token-goat-chunk-4SC7UJYV.mjs} +3354 -2553
  21. package/dist/token-goat-chunk-4SMRO4TO.mjs +366 -0
  22. package/dist/{token-goat-chunk-AFLYLHDH.mjs → token-goat-chunk-4ZBFWLXF.mjs} +283 -427
  23. package/dist/{token-goat-chunk-JDWCRD6M.mjs → token-goat-chunk-57BIAXJL.mjs} +73 -40
  24. package/dist/token-goat-chunk-5AC66HNP.mjs +115 -0
  25. package/dist/token-goat-chunk-5IMLKSOP.mjs +145 -0
  26. package/dist/token-goat-chunk-646E6U44.mjs +398 -0
  27. package/dist/token-goat-chunk-65N4RHP4.mjs +33 -0
  28. package/dist/{token-goat-chunk-JN4XMLSD.mjs → token-goat-chunk-6DG6HWP3.mjs} +8 -2
  29. package/dist/token-goat-chunk-6ENQSNRZ.mjs +573 -0
  30. package/dist/token-goat-chunk-6ZY4GNF2.mjs +91 -0
  31. package/dist/{token-goat-chunk-VPBBTSJR.mjs → token-goat-chunk-76FGDLRO.mjs} +262 -255
  32. package/dist/{token-goat-chunk-7IN2MKDS.mjs → token-goat-chunk-7EZTZOMC.mjs} +121 -289
  33. package/dist/{token-goat-chunk-OJBNYTJP.mjs → token-goat-chunk-7MAOA6X4.mjs} +640 -80
  34. package/dist/token-goat-chunk-7R2ZVVAX.mjs +218 -0
  35. package/dist/{token-goat-chunk-PD5VKH46.mjs → token-goat-chunk-AUNGYYQX.mjs} +2 -2
  36. package/dist/{token-goat-chunk-HG45AF2B.mjs → token-goat-chunk-AUQYRMMH.mjs} +794 -37
  37. package/dist/token-goat-chunk-B3PEKBYG.mjs +128 -0
  38. package/dist/{token-goat-chunk-A3CK6N5Z.mjs → token-goat-chunk-BA4HI6BW.mjs} +1309 -110
  39. package/dist/{token-goat-chunk-JB6QN6VF.mjs → token-goat-chunk-BFCWY73P.mjs} +59 -23
  40. package/dist/{token-goat-chunk-B45VMIIH.mjs → token-goat-chunk-BWGFUZZE.mjs} +7 -5
  41. package/dist/{token-goat-chunk-P4QMM4WK.mjs → token-goat-chunk-C75NA7PL.mjs} +50 -23
  42. package/dist/token-goat-chunk-CBIQ7WTD.mjs +87 -0
  43. package/dist/token-goat-chunk-CETM74KC.mjs +307 -0
  44. package/dist/{token-goat-chunk-H2PHHGM5.mjs → token-goat-chunk-CIMQ2BB3.mjs} +57 -12
  45. package/dist/{token-goat-chunk-N2NMER56.mjs → token-goat-chunk-CJLS3CDL.mjs} +46 -4
  46. package/dist/{token-goat-chunk-VES7EL7O.mjs → token-goat-chunk-CO3UYX6G.mjs} +1 -1
  47. package/dist/token-goat-chunk-COPNXRJM.mjs +154 -0
  48. package/dist/token-goat-chunk-CSJ5L3NL.mjs +479 -0
  49. package/dist/{token-goat-chunk-4LCCNRTG.mjs → token-goat-chunk-CVCEVUGK.mjs} +8 -6
  50. package/dist/{token-goat-chunk-B2RZZCSS.mjs → token-goat-chunk-CXHOFN7R.mjs} +37 -20
  51. package/dist/token-goat-chunk-D735C4QM.mjs +603 -0
  52. package/dist/{token-goat-chunk-APGZXSPS.mjs → token-goat-chunk-DGS2LVNA.mjs} +47 -30
  53. package/dist/{token-goat-chunk-54K3EUV3.mjs → token-goat-chunk-DOWRSMWO.mjs} +1 -1
  54. package/dist/token-goat-chunk-E45INMY3.mjs +71 -0
  55. package/dist/token-goat-chunk-EC5F37F4.mjs +244 -0
  56. package/dist/{token-goat-chunk-XTQAOTSO.mjs → token-goat-chunk-EDBDRVH5.mjs} +4 -1
  57. package/dist/{token-goat-chunk-5BCIJXMO.mjs → token-goat-chunk-EELTBKDM.mjs} +14 -10
  58. package/dist/{token-goat-chunk-W3QCJS6G.mjs → token-goat-chunk-F4HYL64R.mjs} +8 -6
  59. package/dist/token-goat-chunk-F6PAUIEK.mjs +624 -0
  60. package/dist/token-goat-chunk-FDSREWLX.mjs +692 -0
  61. package/dist/token-goat-chunk-GGGG7RWB.mjs +236 -0
  62. package/dist/{token-goat-chunk-C63JQV5K.mjs → token-goat-chunk-GL3ETKSC.mjs} +233 -15
  63. package/dist/token-goat-chunk-GVB2MUST.mjs +1298 -0
  64. package/dist/token-goat-chunk-GWFLAUMQ.mjs +307 -0
  65. package/dist/{token-goat-chunk-ZEJVMUQH.mjs → token-goat-chunk-HLPW63A7.mjs} +2 -2
  66. package/dist/{token-goat-chunk-GOLEOXZP.mjs → token-goat-chunk-HU4TORC5.mjs} +44 -26
  67. package/dist/{token-goat-chunk-Z57YODA2.mjs → token-goat-chunk-I7VKZZAW.mjs} +2 -2
  68. package/dist/{token-goat-chunk-NYKZLXMK.mjs → token-goat-chunk-IA6XSPE3.mjs} +6 -6
  69. package/dist/{token-goat-chunk-E3OQX2XT.mjs → token-goat-chunk-IAGXMHIK.mjs} +81 -42
  70. package/dist/{token-goat-chunk-HYBFA5X3.mjs → token-goat-chunk-IK2DRMFX.mjs} +24 -68
  71. package/dist/{token-goat-chunk-COBQGL5S.mjs → token-goat-chunk-INNPTRUX.mjs} +249 -299
  72. package/dist/{token-goat-chunk-7NADEDKJ.mjs → token-goat-chunk-JJ5BX4F4.mjs} +6 -1
  73. package/dist/{token-goat-chunk-PEPTHRFF.mjs → token-goat-chunk-JVFSHVFJ.mjs} +6 -6
  74. package/dist/token-goat-chunk-KGEFFSHD.mjs +50 -0
  75. package/dist/token-goat-chunk-KQBLRPBN.mjs +433 -0
  76. package/dist/{token-goat-chunk-Q5VTGRH7.mjs → token-goat-chunk-LCNQ2CNN.mjs} +55 -319
  77. package/dist/token-goat-chunk-M3LFJDPU.mjs +58 -0
  78. package/dist/token-goat-chunk-M52KPT3C.mjs +87 -0
  79. package/dist/token-goat-chunk-MBEG42H7.mjs +150 -0
  80. package/dist/{token-goat-chunk-EVC4TOLE.mjs → token-goat-chunk-METECDOH.mjs} +3 -12
  81. package/dist/{token-goat-chunk-T4FK7VOV.mjs → token-goat-chunk-MHX7XCC3.mjs} +2 -1
  82. package/dist/token-goat-chunk-N5LSOVSU.mjs +137 -0
  83. package/dist/{token-goat-chunk-LOBGHXPB.mjs → token-goat-chunk-N5MMR2IW.mjs} +1 -1
  84. package/dist/token-goat-chunk-N7B3JQ2C.mjs +160 -0
  85. package/dist/{token-goat-chunk-RHXKCZX3.mjs → token-goat-chunk-NISNMD7T.mjs} +2182 -2959
  86. package/dist/token-goat-chunk-NMD42SFQ.mjs +434 -0
  87. package/dist/token-goat-chunk-NOSS5VWY.mjs +174 -0
  88. package/dist/{token-goat-chunk-KQNZDCBD.mjs → token-goat-chunk-NSNSPPBG.mjs} +25 -3
  89. package/dist/token-goat-chunk-OBOFIHKN.mjs +38 -0
  90. package/dist/token-goat-chunk-OBRFJ5O5.mjs +76 -0
  91. package/dist/{token-goat-chunk-JTQQGXZH.mjs → token-goat-chunk-ODBT2USM.mjs} +124 -57
  92. package/dist/token-goat-chunk-OS5EM5PP.mjs +107 -0
  93. package/dist/token-goat-chunk-OUKDTVNU.mjs +1178 -0
  94. package/dist/token-goat-chunk-OXFMP75N.mjs +566 -0
  95. package/dist/{token-goat-chunk-DZX2YDPT.mjs → token-goat-chunk-OYIYKDDT.mjs} +2 -2
  96. package/dist/{token-goat-chunk-QCLDAQTS.mjs → token-goat-chunk-P6HQSWQ3.mjs} +50 -53
  97. package/dist/token-goat-chunk-P6VGNTQT.mjs +71 -0
  98. package/dist/{token-goat-chunk-7BXSNBY5.mjs → token-goat-chunk-PFWIMH2E.mjs} +23 -15
  99. package/dist/token-goat-chunk-PJZXIS3G.mjs +39 -0
  100. package/dist/token-goat-chunk-PUO5INXP.mjs +606 -0
  101. package/dist/{token-goat-chunk-GFBSN7BD.mjs → token-goat-chunk-PX5PQWTY.mjs} +22 -250
  102. package/dist/token-goat-chunk-Q5QDBC6O.mjs +111 -0
  103. package/dist/token-goat-chunk-QFNQXSDT.mjs +40 -0
  104. package/dist/{token-goat-chunk-FBNQNSJK.mjs → token-goat-chunk-QH7YVYOY.mjs} +2198 -2782
  105. package/dist/{token-goat-chunk-64FBPDTK.mjs → token-goat-chunk-QLMUHEPB.mjs} +12 -9
  106. package/dist/{token-goat-chunk-RZRTDST7.mjs → token-goat-chunk-QQOJIHL3.mjs} +37 -11
  107. package/dist/{token-goat-chunk-XKI4SEMX.mjs → token-goat-chunk-QQTWJY2O.mjs} +19 -0
  108. package/dist/{token-goat-chunk-U4N3BN2W.mjs → token-goat-chunk-QYHO5CPH.mjs} +3 -2
  109. package/dist/token-goat-chunk-RELAVWAD.mjs +27 -0
  110. package/dist/{token-goat-chunk-ETBHVDB6.mjs → token-goat-chunk-RSLPOBKQ.mjs} +22 -11
  111. package/dist/token-goat-chunk-SAMFDIS2.mjs +712 -0
  112. package/dist/token-goat-chunk-SDELXLDM.mjs +48 -0
  113. package/dist/{token-goat-chunk-4JJS54TR.mjs → token-goat-chunk-SOAFZNNZ.mjs} +161 -38
  114. package/dist/{token-goat-chunk-664RTTUV.mjs → token-goat-chunk-SRTHT7KV.mjs} +21 -16
  115. package/dist/{token-goat-chunk-4FVIAHSI.mjs → token-goat-chunk-T5P5ACNQ.mjs} +7 -6
  116. package/dist/token-goat-chunk-T5YGG4V3.mjs +45 -0
  117. package/dist/token-goat-chunk-TAUZ4OFS.mjs +110 -0
  118. package/dist/{token-goat-chunk-COTXZHTS.mjs → token-goat-chunk-TM6MC754.mjs} +4 -3
  119. package/dist/token-goat-chunk-TWUKBOMP.mjs +72 -0
  120. package/dist/{token-goat-chunk-3CHUNJ2O.mjs → token-goat-chunk-U2KSB4SG.mjs} +8 -5
  121. package/dist/{token-goat-chunk-3Z5S4KGM.mjs → token-goat-chunk-U4WHMG6Y.mjs} +29 -49
  122. package/dist/{token-goat-chunk-PY533T7F.mjs → token-goat-chunk-UGJHGR5A.mjs} +21 -15
  123. package/dist/{token-goat-chunk-CYCEYAEO.mjs → token-goat-chunk-UOUDVA5U.mjs} +1 -1
  124. package/dist/{token-goat-chunk-JDHE26RP.mjs → token-goat-chunk-URRJ33GR.mjs} +16 -5
  125. package/dist/{token-goat-chunk-56EIMS3E.mjs → token-goat-chunk-UZOROKIS.mjs} +23 -17
  126. package/dist/{token-goat-chunk-CZ3LUXYZ.mjs → token-goat-chunk-VIHGGGEI.mjs} +427 -308
  127. package/dist/token-goat-chunk-VTJLAA7P.mjs +21 -0
  128. package/dist/token-goat-chunk-VWDXLT4F.mjs +678 -0
  129. package/dist/{token-goat-chunk-YARZFCZS.mjs → token-goat-chunk-VWZA2H4P.mjs} +62 -53
  130. package/dist/{token-goat-chunk-SQSSNQPE.mjs → token-goat-chunk-VXEXMJDL.mjs} +3979 -4745
  131. package/dist/token-goat-chunk-WBA5SKT4.mjs +547 -0
  132. package/dist/{token-goat-chunk-SJHWVNDQ.mjs → token-goat-chunk-WDH44VAU.mjs} +7 -4
  133. package/dist/token-goat-chunk-X2SUP3EI.mjs +107 -0
  134. package/dist/token-goat-chunk-X3BELZSJ.mjs +125 -0
  135. package/dist/{token-goat-chunk-FZ3NEW5O.mjs → token-goat-chunk-XLRBNZCC.mjs} +13 -8
  136. package/dist/{token-goat-chunk-Z44YO3QZ.mjs → token-goat-chunk-XRKUX6CM.mjs} +1 -1
  137. package/dist/token-goat-chunk-XX6O25RN.mjs +82 -0
  138. package/dist/token-goat-chunk-XZSUHBVS.mjs +65 -0
  139. package/dist/{token-goat-chunk-WY3L4DVT.mjs → token-goat-chunk-Y2ZTQOCL.mjs} +13 -8
  140. package/dist/{token-goat-chunk-UQ5UK2T7.mjs → token-goat-chunk-YB4VMGK2.mjs} +1 -1
  141. package/dist/token-goat-chunk-YBIIY3HR.mjs +51 -0
  142. package/dist/{token-goat-chunk-ZQSJMO2R.mjs → token-goat-chunk-YHVDKQBR.mjs} +105 -105
  143. package/dist/{token-goat-chunk-H2K3QP6H.mjs → token-goat-chunk-YJB5XLWI.mjs} +8 -6
  144. package/dist/{token-goat-chunk-ZCDTCVIS.mjs → token-goat-chunk-YKB6AQG3.mjs} +5 -2
  145. package/dist/token-goat-chunk-YMTG2YA5.mjs +35 -0
  146. package/dist/token-goat-chunk-YPBZYQRV.mjs +40 -0
  147. package/dist/{token-goat-chunk-HOJLCGDP.mjs → token-goat-chunk-YY6AVUFL.mjs} +2033 -2251
  148. package/dist/token-goat-chunk-Z7N5OMMP.mjs +98 -0
  149. package/dist/token-goat-chunk-ZNMNUPAZ.mjs +938 -0
  150. package/dist/token-goat-hook-client.cjs +1 -1
  151. package/dist/token-goat-hook-client.mjs +3 -3
  152. package/dist/token-goat-hook.mjs +67 -38
  153. package/dist/token-goat.core.mjs +4 -4
  154. package/docs/C4_RUNTIME_ARCHITECTURE.md +1 -1
  155. package/docs/cli.md +40 -21
  156. package/docs/install.md +19 -9
  157. package/docs/security.md +5 -3
  158. package/package.json +2 -1
  159. package/dist/token-goat-chunk-5KDMCMF2.mjs +0 -362
  160. package/dist/token-goat-chunk-6QMAS7AB.mjs +0 -42
  161. package/dist/token-goat-chunk-7F2UBPD3.mjs +0 -397
  162. package/dist/token-goat-chunk-ARDNEC2U.mjs +0 -248
  163. package/dist/token-goat-chunk-ATCPY7EQ.mjs +0 -134
  164. package/dist/token-goat-chunk-EFHMMIGP.mjs +0 -68
  165. package/dist/token-goat-chunk-IVALLT3S.mjs +0 -48
  166. package/dist/token-goat-chunk-JDU3EXSU.mjs +0 -65
  167. package/dist/token-goat-chunk-MKPF4CL5.mjs +0 -37
  168. package/dist/token-goat-chunk-RC35RBUL.mjs +0 -312
  169. package/dist/token-goat-chunk-USILZ3T3.mjs +0 -53
  170. package/dist/token-goat-chunk-VL3YIFHZ.mjs +0 -2975
  171. package/dist/token-goat-chunk-XU4P6Z24.mjs +0 -133
  172. package/dist/token-goat-chunk-Y776AENC.mjs +0 -1597
@@ -7,28 +7,35 @@ import {
7
7
  getSqliteSchema,
8
8
  getSqliteTables,
9
9
  runReadOnlySqliteQuery
10
- } from "./token-goat-chunk-ZCDTCVIS.mjs";
10
+ } from "./token-goat-chunk-YKB6AQG3.mjs";
11
11
  import {
12
+ WHOLE_FILE_NOTE_SYMBOL,
13
+ getNote,
14
+ isNoteStale,
15
+ listNotes
16
+ } from "./token-goat-chunk-COPNXRJM.mjs";
17
+ import {
18
+ CORE_SYMBOL_KINDS,
12
19
  DELETED_TAG,
13
20
  DIDYOUMEAN_LIMIT,
14
21
  FIND_SCAN_LIMIT,
15
22
  FirstRows,
16
23
  REF_BLIND_DEF_PROBE_LIMIT,
17
24
  UNBOUNDED_QUERY_LIMIT,
18
- WHOLE_FILE_NOTE_SYMBOL,
19
25
  buildContextWindow,
20
26
  compareBinary,
21
27
  confinedProjectRoot,
22
28
  confinementRefusal,
29
+ couldNotReadError,
23
30
  didYouMean,
24
- emit,
25
- emitErr,
31
+ docCommentLines,
26
32
  emitGuarded,
27
33
  extractExportNames,
28
34
  extractImports,
29
35
  fileConfinementRefusal,
30
36
  fileExists,
31
37
  fileIsGone,
38
+ fileNotFoundError,
32
39
  filterSimilarHeadings,
33
40
  findSpecSeparator,
34
41
  findStructuredKeyPath,
@@ -37,7 +44,6 @@ import {
37
44
  formatAmbiguity,
38
45
  formatBareNameSpecError,
39
46
  formatStatsSuffix,
40
- getNote,
41
47
  guardJsonRows,
42
48
  guardText,
43
49
  hasRealDocstring,
@@ -46,17 +52,17 @@ import {
46
52
  importsExtensionFor,
47
53
  indexFileSyncPinned,
48
54
  indexFreshness,
49
- isNoteStale,
50
55
  isRefIndexedFile,
51
56
  isValidUtf8,
52
57
  largestFileSize,
53
- listNotes,
54
58
  nearNamesSkippedNote,
55
59
  nearSymbolNames,
56
60
  noSymbolsMessage,
57
61
  parseCrossFileMultiSpec,
58
62
  parseMultiFileSpec,
59
63
  parseReadSpec,
64
+ parseYamlDocument,
65
+ parseYamlDocumentAsWritten,
60
66
  previewLines,
61
67
  projectStructuredFiles,
62
68
  rankSimilarNames,
@@ -90,10 +96,27 @@ import {
90
96
  typedRefsForDef,
91
97
  unknownSymbolSuggestion,
92
98
  warnIfFilesStale
93
- } from "./token-goat-chunk-PU7V3FD6.mjs";
99
+ } from "./token-goat-chunk-4SC7UJYV.mjs";
94
100
  import {
101
+ emit,
102
+ emitErr,
95
103
  parseJsonOrJsonc
96
- } from "./token-goat-chunk-XKI4SEMX.mjs";
104
+ } from "./token-goat-chunk-QQTWJY2O.mjs";
105
+ import {
106
+ emptyIndexMessage,
107
+ getEmbeddingCoverage,
108
+ isIgnoredIndexPath,
109
+ isIndexEmptyForProject,
110
+ walkProject
111
+ } from "./token-goat-chunk-ZNMNUPAZ.mjs";
112
+ import {
113
+ capListField,
114
+ guardAndFenceFileText
115
+ } from "./token-goat-chunk-M52KPT3C.mjs";
116
+ import {
117
+ filtersFilteredToEmptyNotice,
118
+ grepFilteredToEmptyNotice
119
+ } from "./token-goat-chunk-CJLS3CDL.mjs";
97
120
  import {
98
121
  MODEL_DOWNLOAD_HOST,
99
122
  RUNTIME_DOWNLOAD_HOST,
@@ -101,34 +124,42 @@ import {
101
124
  isExplicitDownload,
102
125
  lastDownloadFailure,
103
126
  withExplicitDownload
104
- } from "./token-goat-chunk-SMVRN2HU.mjs";
127
+ } from "./token-goat-chunk-2UPZGKKY.mjs";
105
128
  import {
106
129
  commentSyntaxFor
107
130
  } from "./token-goat-chunk-5RG5SBL6.mjs";
108
131
  import {
109
132
  deliveredOutputBytes
110
- } from "./token-goat-chunk-54K3EUV3.mjs";
133
+ } from "./token-goat-chunk-DOWRSMWO.mjs";
111
134
  import {
112
135
  NOTEBOOK_CELL_LINES_SUFFIX,
113
- emptyIndexMessage,
114
136
  formatSymbolLocation,
115
- getEmbeddingCoverage,
116
- isIgnoredIndexPath,
117
- isIndexEmptyForProject,
137
+ indexedSourceText,
118
138
  isVirtualIndexedPath,
119
- searchEvidenceSemantically,
120
- virtualIndexedScopeNote,
121
- walkProject
122
- } from "./token-goat-chunk-FBNQNSJK.mjs";
139
+ virtualIndexedScopeNote
140
+ } from "./token-goat-chunk-QH7YVYOY.mjs";
141
+ import {
142
+ searchEvidenceSemantically
143
+ } from "./token-goat-chunk-NOSS5VWY.mjs";
123
144
  import {
124
145
  enqueueDirtyPathSafe
125
- } from "./token-goat-chunk-H2PHHGM5.mjs";
146
+ } from "./token-goat-chunk-CIMQ2BB3.mjs";
126
147
  import {
127
- ensureWorkerAlive,
128
- fetchBypassesProxy,
129
- nodeFetchHonoursEnvProxy,
130
- proxyConfigured
131
- } from "./token-goat-chunk-5KDMCMF2.mjs";
148
+ isBlobStale,
149
+ loadBlob,
150
+ storeBlob
151
+ } from "./token-goat-chunk-4ZBFWLXF.mjs";
152
+ import {
153
+ CliError,
154
+ formatCommandError,
155
+ formatFailedResultText,
156
+ formatGitFailure
157
+ } from "./token-goat-chunk-CBIQ7WTD.mjs";
158
+ import {
159
+ findContainingSection,
160
+ listSections,
161
+ readSection
162
+ } from "./token-goat-chunk-OXFMP75N.mjs";
132
163
  import {
133
164
  MAX_OVER_FETCH,
134
165
  NATIVE_RUNTIME_INSTALL,
@@ -139,15 +170,12 @@ import {
139
170
  checkEmbeddingPreflight,
140
171
  eachUnfencedLine,
141
172
  embeddingBackendLoadError,
142
- findContainingSection,
143
173
  isAvailable,
144
- listSections,
145
174
  modelDir,
146
175
  modelFilesPresent,
147
- readSection,
148
176
  searchSemantic,
149
177
  wasmBinaryPresent
150
- } from "./token-goat-chunk-RHXKCZX3.mjs";
178
+ } from "./token-goat-chunk-NISNMD7T.mjs";
151
179
  import {
152
180
  ATX_CLASS_BREAK_RE,
153
181
  matchAtxHeading
@@ -156,48 +184,61 @@ import {
156
184
  DEFAULT_QUERY_LIMIT,
157
185
  countRefs,
158
186
  countSymbols,
187
+ distinctSymbolKinds,
159
188
  queryRefCounts,
160
189
  queryRefs,
161
190
  querySymbols,
162
191
  searchSymbolsFts
163
- } from "./token-goat-chunk-HYBFA5X3.mjs";
192
+ } from "./token-goat-chunk-IK2DRMFX.mjs";
164
193
  import {
165
- isBlobStale,
166
- loadBlob,
167
- storeBlob
168
- } from "./token-goat-chunk-ARDNEC2U.mjs";
194
+ fenceFileFieldIfMatched,
195
+ fenceJsonStrings
196
+ } from "./token-goat-chunk-4NAPX7BA.mjs";
169
197
  import {
170
- BYTES_PER_TOKEN,
171
- getGlobalDb,
198
+ readGlobalDb,
172
199
  recordStat,
173
200
  savedTokensFromBytes,
174
201
  withTelemetryWriteDb
175
- } from "./token-goat-chunk-3Z5S4KGM.mjs";
202
+ } from "./token-goat-chunk-U4WHMG6Y.mjs";
176
203
  import {
177
204
  detectLanguage,
178
205
  detectLanguageOfFile,
179
- getDb
180
- } from "./token-goat-chunk-VL3YIFHZ.mjs";
206
+ getReadDb
207
+ } from "./token-goat-chunk-GVB2MUST.mjs";
208
+ import {
209
+ forClient
210
+ } from "./token-goat-chunk-KGEFFSHD.mjs";
211
+ import {
212
+ BYTES_PER_TOKEN
213
+ } from "./token-goat-chunk-XX6O25RN.mjs";
214
+ import {
215
+ ensureWorkerAlive,
216
+ fetchBypassesProxy,
217
+ nodeFetchHonoursEnvProxy,
218
+ proxyConfigured
219
+ } from "./token-goat-chunk-F6PAUIEK.mjs";
181
220
  import {
182
221
  redactSecrets
183
- } from "./token-goat-chunk-4FVIAHSI.mjs";
222
+ } from "./token-goat-chunk-T5P5ACNQ.mjs";
184
223
  import {
185
- findProject,
186
- getDisplayRoot,
187
224
  getProjectConfigInfo,
188
225
  loadConfig,
189
226
  parse,
227
+ resolveConfigKeyLayer
228
+ } from "./token-goat-chunk-7EZTZOMC.mjs";
229
+ import {
230
+ findProject,
231
+ getDisplayRoot,
190
232
  projectHash,
191
- resolveConfigKeyLayer,
192
233
  resolveProjectRoot,
193
234
  shortFingerprint
194
- } from "./token-goat-chunk-7IN2MKDS.mjs";
235
+ } from "./token-goat-chunk-4GBVPH3D.mjs";
195
236
  import {
196
237
  MAX_ZIP_OUTPUT_BYTES,
197
238
  ZipInputTooLargeError,
198
239
  ZipOutputTooLargeError,
199
240
  unzipBounded
200
- } from "./token-goat-chunk-XTQAOTSO.mjs";
241
+ } from "./token-goat-chunk-EDBDRVH5.mjs";
201
242
  import {
202
243
  createLazyModuleLoader
203
244
  } from "./token-goat-chunk-AH6QILZM.mjs";
@@ -207,13 +248,17 @@ import {
207
248
  escapeRegExp,
208
249
  excludeTestsHiddenNote,
209
250
  extractErrorMessage,
210
- filtersFilteredToEmptyNotice,
211
- grepFilteredToEmptyNotice,
212
251
  isTestFile,
213
252
  requireNonNegativeStrictInt,
214
253
  runGit,
215
254
  stripBom
216
- } from "./token-goat-chunk-GOLEOXZP.mjs";
255
+ } from "./token-goat-chunk-HU4TORC5.mjs";
256
+ import {
257
+ canQuoteArg,
258
+ echoedValue,
259
+ fencedCommand,
260
+ quotedArg
261
+ } from "./token-goat-chunk-GGGG7RWB.mjs";
217
262
  import {
218
263
  foldPath
219
264
  } from "./token-goat-chunk-AM5V6GSX.mjs";
@@ -227,7 +272,7 @@ import {
227
272
  import {
228
273
  SKELETON_SYMBOL_CAP,
229
274
  globalDbPath
230
- } from "./token-goat-chunk-VES7EL7O.mjs";
275
+ } from "./token-goat-chunk-CO3UYX6G.mjs";
231
276
  import {
232
277
  init_define_import_meta_env
233
278
  } from "./token-goat-chunk-A37V4PBF.mjs";
@@ -301,7 +346,7 @@ function explainModelDownload(result, now = Date.now()) {
301
346
  }
302
347
  if (result.status === "load_error" || !modelMissing) return result;
303
348
  if (result.status === "no_embeddings") {
304
- const message = `The embedding model (about ${MODEL_MB} MB, once) is not downloaded yet. It downloads by itself in the background, and this project's ${result.indexedFiles} indexed file(s) are embedded after it.`;
349
+ const message = `The embedding model (about ${MODEL_MB} MB, once) is not downloaded yet. It downloads by itself in the background, and this project's ${countNoun(result.indexedFiles, "indexed file")} are embedded after it.`;
305
350
  return rebuild("missing_model_files", false, message, `Nothing to do. To download it now instead, run \`${WARM_COMMAND}\`.`, void 0);
306
351
  }
307
352
  return rebuild("ready", true, `Semantic search is ready. The embedding model (about ${MODEL_MB} MB) is not downloaded yet; it is fetched on first use.`, void 0, void 0);
@@ -314,7 +359,7 @@ function offlineEmbedNotice(fileCount, rootDir) {
314
359
  if (!cfg.network.offline) return null;
315
360
  const state = resolveConfigKeyLayer("network.offline", cfg.network.offline, cfg, getProjectConfigInfo(rootDir));
316
361
  const holder = state.layer === "env" || state.layer === "env-invalid" ? `${state.envVar} is set in your environment` : state.layer === "project" ? `${displaySafeText(state.path)} sets network.offline` : "network.offline is on in config.toml";
317
- return `token-goat: index: ${fileCount} not embedded: the embedding model is not downloaded and ${holder}, so nothing will download it. symbol, read, outline and section work now; semantic falls back to keyword search. To embed them, unset it so the worker can download the model, or copy the pinned model files into ${modelDir()}; then run \`token-goat index\` again.`;
362
+ return `token-goat: index: ${fileCount} not embedded: the embedding model is not downloaded and ${holder}, so nothing will download it. symbol, read, outline and section work now; semantic falls back to keyword search. To embed them, unset it so the model can be downloaded, or copy the pinned model files into ${modelDir()}; then run \`token-goat index\` again.`;
318
363
  }
319
364
 
320
365
  // src/read_symbol.ts
@@ -329,7 +374,7 @@ function stableSortImportBindsLast(rows) {
329
374
  }
330
375
  function runSymbol(opts) {
331
376
  if (opts.limit !== void 0 && opts.limit <= 0) {
332
- return { text: `--limit must be a positive number, got: ${opts.limit}`, code: 1 };
377
+ return { text: `--limit must be a positive number, got: ${echoedValue(String(opts.limit))}`, code: 1 };
333
378
  }
334
379
  if (opts.name !== void 0 && opts.grep !== void 0) {
335
380
  return {
@@ -429,7 +474,7 @@ function runSymbol(opts) {
429
474
  const hiddenByExcludeTests = sweep.hiddenByExcludeTests;
430
475
  if (excludeTests && sweep.keptCount === 0 && hiddenByExcludeTests > 0) {
431
476
  const label = opts.name ?? opts.grep ?? "*";
432
- const notice = `no non-test matches for '${label}' (${excludeTestsHiddenNote(hiddenByExcludeTests)})`;
477
+ const notice = `no non-test matches for ${echoedValue(label)} (${excludeTestsHiddenNote(hiddenByExcludeTests)})`;
433
478
  if (opts.json === true) {
434
479
  return { text: displaySafeJson({ items: [], truncated: false, totalCount: 0 }), code: 0 };
435
480
  }
@@ -446,7 +491,19 @@ function runSymbol(opts) {
446
491
  if (opts.json === true) {
447
492
  return { text: displaySafeJson({ items: [], truncated: false, totalCount: 0 }), code: 0 };
448
493
  }
449
- let text2 = `No matches for '${opts.name ?? opts.grep ?? "*"}'`;
494
+ let text2 = `No matches for ${echoedValue(opts.name ?? opts.grep ?? "*")}`;
495
+ if (opts.kind !== void 0 && !CORE_SYMBOL_KINDS.includes(opts.kind)) {
496
+ const storedKinds = distinctSymbolKinds(opts.projectRoot);
497
+ if (!storedKinds.includes(opts.kind)) {
498
+ text2 += `
499
+ no indexed symbol has kind ${echoedValue(opts.kind)}`;
500
+ const lower = opts.kind.toLowerCase();
501
+ const recased = [.../* @__PURE__ */ new Set([...storedKinds, ...CORE_SYMBOL_KINDS])].filter((k) => k.toLowerCase() === lower);
502
+ const closes = recased.length > 0 ? recased : rankSimilarNames(storedKinds, opts.kind);
503
+ if (closes.length > 0) text2 += `
504
+ ${didYouMean(closes)}`;
505
+ }
506
+ }
450
507
  const emptyIndexRoot = opts.projectRoot ?? resolveProjectRoot({ project: process.cwd() });
451
508
  const indexEmpty = isIndexEmptyForProject(globalDbPath(), emptyIndexRoot);
452
509
  if (opts.name !== void 0) {
@@ -459,11 +516,11 @@ function runSymbol(opts) {
459
516
  const flags = [opts.kind !== void 0 ? "--kind" : null, opts.file !== void 0 ? "--file" : null].filter((f) => f !== null);
460
517
  const widen = flags.length > 0 ? `drop ${flags.join("/")} to see it` : "widen the search scope to see it";
461
518
  text2 += `
462
- '${opts.name}' IS indexed (${where}${more}) -- ${widen}`;
519
+ ${echoedValue(opts.name)} IS indexed (${where}${more}) -- ${widen}`;
463
520
  } else {
464
521
  const near = nearSymbolNames(opts.name, rootDir);
465
- const semanticHint = indexEmpty ? "" : `
466
- Try: token-goat semantic "${opts.name}"`;
522
+ const semanticHint = indexEmpty || !canQuoteArg(opts.name) ? "" : `
523
+ Try: token-goat semantic ${quotedArg(opts.name)}`;
467
524
  if (near.skipped) text2 += `
468
525
  ${nearNamesSkippedNote()}${semanticHint}`;
469
526
  else text2 += near.candidates.length > 0 ? `
@@ -474,7 +531,7 @@ ${didYouMean(near.candidates)}` : semanticHint;
474
531
  if (hit !== null) {
475
532
  const display = toDisplayPath(rootDir, hit.filePath);
476
533
  text2 += `
477
- '${opts.name}' is a key in ${display} at ${hit.dotPath} -- JSON/YAML keys below the top level are not symbols; read it with: token-goat ${hit.command} ${display} '${hit.dotPath}'`;
534
+ ${echoedValue(opts.name)} is a key in ${display} at ${hit.dotPath} -- JSON/YAML keys below the top level are not symbols; read it with: ${fencedCommand(`token-goat ${hit.command} ${quotedArg(display)} ${quotedArg(hit.dotPath)}`)}`;
478
535
  }
479
536
  }
480
537
  if (indexEmpty) {
@@ -519,13 +576,15 @@ ${emptyIndexMessage(emptyIndexRoot)}`;
519
576
  const statsStr = formatStatsSuffix(refCounts, sym);
520
577
  const goneTag = fileIsGone(sym.filePath) ? ` ${DELETED_TAG}` : "";
521
578
  const staleTag = stillStale.has(sym.filePath) ? ` ${STALE_TAG}` : "";
522
- const header = `# ${sym.name} (${sym.kind}) \u2014 ${formatSymbolLocation(toDisplayPath(symbolDisplayRoot, sym.filePath), sym.lineStart, sym.lineEnd)}${statsStr}${goneTag}${staleTag}`;
579
+ const doc = docCommentLines(sym);
580
+ const docLabel = doc.length > 0 ? ` + ${doc.length}-line doc comment` : "";
581
+ const header = `# ${displaySafeText(sym.name)} (${sym.kind}) \u2014 ${formatSymbolLocation(displaySafeText(toDisplayPath(symbolDisplayRoot, sym.filePath)), sym.lineStart, sym.lineEnd)}${docLabel}${statsStr}${goneTag}${staleTag}`;
523
582
  const body = resolveBody(sym);
524
583
  const bodyLines = body.split(/\r?\n/);
525
- const preview = bodyLines.slice(0, SYMBOL_PREVIEW_LINES).join("\n");
584
+ const preview = [...doc, ...bodyLines.slice(0, SYMBOL_PREVIEW_LINES)].join("\n");
526
585
  const dropped = bodyLines.length - SYMBOL_PREVIEW_LINES;
527
- const elided = dropped > 0 ? `
528
- ...(${countNoun(dropped, "more line")}; full body: token-goat read "${toDisplayPath(symbolDisplayRoot, sym.filePath)}::${sym.name}")` : "";
586
+ const elided = dropped > 0 ? forClient(`
587
+ ...(${countNoun(dropped, "more line")}; full body: ${fencedCommand("token-goat read " + quotedArg(`${displaySafeText(toDisplayPath(symbolDisplayRoot, sym.filePath))}::${displaySafeText(sym.name)}`))})`) : "";
529
588
  return preview.trim() !== "" ? `${header}
530
589
  ${preview}${elided}` : header;
531
590
  });
@@ -570,11 +629,11 @@ function runBriefCore(opts) {
570
629
  if (opts.json !== true) {
571
630
  const rootDir2 = resolveProjectRoot({ project: opts.projectRoot ?? process.cwd() });
572
631
  if (isIndexEmptyForProject(globalDbPath(), rootDir2)) {
573
- return { text: `Symbol not found: ${opts.spec}
632
+ return { text: `Symbol not found: ${echoedValue(opts.spec)}
574
633
  ${emptyIndexMessage(rootDir2)}`, code: 1 };
575
634
  }
576
635
  }
577
- return { text: `Symbol not found: ${opts.spec}`, code: 1 };
636
+ return { text: `Symbol not found: ${echoedValue(opts.spec)}`, code: 1 };
578
637
  }
579
638
  const match = resolution.entry;
580
639
  const rootDir = specScopeRoot(opts.spec, resolveProjectRoot({ project: opts.projectRoot ?? process.cwd() })).root;
@@ -627,8 +686,8 @@ ${emptyIndexMessage(rootDir2)}`, code: 1 };
627
686
  lines.push(callers.length === 0 && hiddenNote !== "" ? `Callers (0): no non-test callers${hiddenNote}` : `Callers (${totalCallers}):${hiddenNote}`);
628
687
  }
629
688
  for (const c of shown) {
630
- const callerDisplayPath = toDisplayPath(rootDir, c.file);
631
- lines.push(` ${c.caller} ${callerDisplayPath}:${c.line}`);
689
+ const callerDisplayPath = displaySafeText(toDisplayPath(rootDir, c.file));
690
+ lines.push(` ${displaySafeText(c.caller)} ${callerDisplayPath}:${c.line}`);
632
691
  const window = buildContextWindow(c.file, c.line, opts.context ?? 0);
633
692
  if (window !== null) lines.push(...renderContextWindow(callerDisplayPath, c.line, window, "", " "));
634
693
  }
@@ -686,14 +745,14 @@ ${sub.text}`);
686
745
  }
687
746
  function runBrief(opts) {
688
747
  if (opts.limit !== void 0 && opts.limit <= 0) {
689
- emitErr(`--limit must be a positive number, got: ${opts.limit}`);
748
+ emitErr(formatCommandError(`--limit must be a positive number, got: ${echoedValue(String(opts.limit))}`));
690
749
  return 1;
691
750
  }
692
751
  const crossFilePairs = parseCrossFileMultiSpec(opts.spec);
693
752
  if (crossFilePairs !== null) {
694
753
  const { text: text2, code: code2 } = runBriefCrossFile(crossFilePairs, opts);
695
754
  if (code2 === 0) emit(text2);
696
- else emitErr(text2);
755
+ else emitErr(formatFailedResultText(text2));
697
756
  return code2;
698
757
  }
699
758
  const { file, symbol } = parseReadSpec(opts.spec);
@@ -702,13 +761,13 @@ function runBrief(opts) {
702
761
  if (multiSymbols.length > 1) {
703
762
  const { text: text2, code: code2 } = runBriefMulti(file, multiSymbols, opts);
704
763
  if (code2 === 0) emit(text2);
705
- else emitErr(text2);
764
+ else emitErr(formatFailedResultText(text2));
706
765
  return code2;
707
766
  }
708
767
  }
709
768
  const { text, code } = runBriefCore(opts);
710
769
  if (code === 0) emit(text);
711
- else emitErr(text);
770
+ else emitErr(formatFailedResultText(text));
712
771
  return code;
713
772
  }
714
773
 
@@ -785,7 +844,7 @@ function runSection(opts) {
785
844
  const result = readSection(filePath, heading, readFileText) ?? htmlIdSectionFallback(filePath, heading);
786
845
  if (result === null) {
787
846
  if (!fs.existsSync(filePath)) {
788
- return { text: `File not found: '${filePath}'`, code: 1 };
847
+ return { text: fileNotFoundError(filePath).message, code: 1 };
789
848
  }
790
849
  const ordSpec = /^(.*?)#(\d+)$/.exec(heading);
791
850
  const ordBase = ordSpec?.[1]?.trim();
@@ -794,25 +853,25 @@ function runSection(opts) {
794
853
  if (baseResult !== null) {
795
854
  const total = baseResult.occurrences?.length ?? 1;
796
855
  return {
797
- text: `Heading '${ordBase}' has ${countNoun(total, "occurrence")} in '${specFilePath}'; valid ordinals are #1 to #${total}`,
856
+ text: `Heading ${quotedArg(ordBase)} has ${countNoun(total, "occurrence")} in ${quotedArg(specFilePath)}; valid ordinals are #1 to #${total}`,
798
857
  code: 1
799
858
  };
800
859
  }
801
860
  }
802
- const messages = [`Section '${heading}' not found in '${filePath}'`];
861
+ const messages = [`Section ${quotedArg(heading)} not found in ${quotedArg(filePath)}`];
803
862
  const allHeadings = listSections(filePath, readFileText);
804
863
  const available = filterSimilarHeadings(allHeadings, heading);
805
864
  if (available.length > 0) messages.push(didYouMean(available));
806
- else if (allHeadings.length === 0) messages.push(`'${specFilePath}' has no headings`);
807
- else messages.push(`Try: token-goat outline ${specFilePath}`);
865
+ else if (allHeadings.length === 0) messages.push(`${quotedArg(specFilePath)} has no headings`);
866
+ else messages.push(`Try: token-goat outline ${quotedArg(specFilePath)}`);
808
867
  return { text: messages.join("\n"), code: 1 };
809
868
  }
810
869
  if (result.occurrences !== void 0) {
811
870
  const lines = [
812
- `Ambiguous heading '${heading}' in '${specFilePath}': ${countNoun(result.occurrences.length, "heading")} match. Retry with one of the qualified commands below to pick one:`
871
+ `Ambiguous heading ${quotedArg(heading)} in ${quotedArg(specFilePath)}: ${countNoun(result.occurrences.length, "heading")} match. Retry with one of the qualified commands below to pick one:`
813
872
  ];
814
873
  for (const [i, line] of result.occurrences.slice(0, AMBIGUOUS_HEADING_LIMIT).entries()) {
815
- lines.push(` - line ${line} -> token-goat section "${specFilePath}::${heading}#${i + 1}"`);
874
+ lines.push(` - line ${line} -> token-goat section ${quotedArg(`${specFilePath}::${heading}#${i + 1}`)}`);
816
875
  }
817
876
  if (result.occurrences.length > AMBIGUOUS_HEADING_LIMIT) {
818
877
  lines.push(` (${result.occurrences.length - AMBIGUOUS_HEADING_LIMIT} more not shown)`);
@@ -860,7 +919,7 @@ ${filtered.matched} of ${filtered.total} lines matched`;
860
919
  if (opts.suppressStat !== true) recordReadStat(kind, fullSourceBytes, text2, heading);
861
920
  return { text: text2, code: 0 };
862
921
  }
863
- const redirectNote = result.redirectedFrom !== void 0 ? ` (redirected from: '${result.redirectedFrom}')` : "";
922
+ const redirectNote = result.redirectedFrom !== void 0 ? ` (redirected from: ${echoedValue(result.redirectedFrom)})` : "";
864
923
  const text = guardText(
865
924
  `# ${result.heading} \u2014 ${filePath}:${result.lineStart}-${lineEnd}${redirectNote}${content.length > 0 ? `
866
925
  ${content}` : ""}${truncatedNotice}${grepNote}`,
@@ -882,7 +941,7 @@ function runSectionMulti(specFilePath, resolvedFilePath, headings, opts) {
882
941
  );
883
942
  if (parent !== void 0) {
884
943
  anyFound = true;
885
- const notice = `(already included in section '${parent.heading}', lines ${sectionResult.lineStart}-${sectionResult.lineEnd})`;
944
+ const notice = `(already included in section ${quotedArg(parent.heading)}, lines ${sectionResult.lineStart}-${sectionResult.lineEnd})`;
886
945
  if (opts.json === true) {
887
946
  jsonOut[heading] = {
888
947
  heading: sectionResult.heading,
@@ -938,7 +997,7 @@ function runSectionCrossFile(pairs, opts) {
938
997
  );
939
998
  if (parent !== void 0) {
940
999
  anyFound = true;
941
- const notice = `(already included in section '${parent.heading}', lines ${sectionResult.lineStart}-${sectionResult.lineEnd})`;
1000
+ const notice = `(already included in section ${quotedArg(parent.heading)}, lines ${sectionResult.lineStart}-${sectionResult.lineEnd})`;
942
1001
  if (opts.json === true) {
943
1002
  jsonOut[key] = {
944
1003
  heading: sectionResult.heading,
@@ -1331,9 +1390,10 @@ function formatCoverageGaps(report) {
1331
1390
  }
1332
1391
 
1333
1392
  // src/read_inspect.ts
1393
+ var BINARY_ENTRY_ELIDED = "[binary content elided by token-goat]";
1334
1394
  function archiveReadFailure(err, file) {
1335
1395
  if (err instanceof ArchiveDependencyMissingError || err instanceof ZipOutputTooLargeError) return err.message;
1336
- return `Failed to read archive (not a valid zip-format file): ${file}`;
1396
+ return `Failed to read archive (not a valid zip-format file): ${echoedValue(file)}`;
1337
1397
  }
1338
1398
  async function runZipList(opts) {
1339
1399
  let data;
@@ -1341,30 +1401,30 @@ async function runZipList(opts) {
1341
1401
  data = readFileBytes(opts.file);
1342
1402
  } catch (err) {
1343
1403
  if (err instanceof ZipInputTooLargeError) {
1344
- emitErr(err.message);
1404
+ emitErr(formatCommandError(err.message));
1345
1405
  return 1;
1346
1406
  }
1347
1407
  throw err;
1348
1408
  }
1349
1409
  if (data === null) {
1350
- emitErr(`Could not read: ${opts.file}`);
1410
+ emitErr(formatCommandError(couldNotReadError(opts.file)));
1351
1411
  return 1;
1352
1412
  }
1353
1413
  let entries;
1354
1414
  try {
1355
1415
  entries = await listZipEntries(data);
1356
1416
  } catch (err) {
1357
- emitErr(archiveReadFailure(err, opts.file));
1417
+ emitErr(formatCommandError(archiveReadFailure(err, opts.file)));
1358
1418
  return 1;
1359
1419
  }
1360
1420
  const fullSourceBytes = sumFileSizes([opts.file]);
1361
1421
  if (opts.json === true) {
1362
- const jsonText = displaySafeJson(entries, 0);
1422
+ const jsonText = displaySafeJson(entries.map((e) => ({ ...e, path: fenceFileFieldIfMatched(e.path) })), 0);
1363
1423
  emit(jsonText);
1364
1424
  recordReadStat("zip_list", fullSourceBytes, jsonText, opts.file);
1365
1425
  } else {
1366
- const text = formatZipList(entries);
1367
- emitGuarded(text, "zip-list");
1426
+ const text = guardAndFenceFileText(formatZipList(entries), "zip-list");
1427
+ emit(text);
1368
1428
  recordReadStat("zip_list", fullSourceBytes, text, opts.file);
1369
1429
  }
1370
1430
  return 0;
@@ -1375,13 +1435,13 @@ async function runZipRead(opts) {
1375
1435
  data = readFileBytes(opts.file);
1376
1436
  } catch (err) {
1377
1437
  if (err instanceof ZipInputTooLargeError) {
1378
- emitErr(err.message);
1438
+ emitErr(formatCommandError(err.message));
1379
1439
  return 1;
1380
1440
  }
1381
1441
  throw err;
1382
1442
  }
1383
1443
  if (data === null) {
1384
- emitErr(`Could not read: ${opts.file}`);
1444
+ emitErr(formatCommandError(couldNotReadError(opts.file)));
1385
1445
  return 1;
1386
1446
  }
1387
1447
  let entries;
@@ -1390,32 +1450,33 @@ async function runZipRead(opts) {
1390
1450
  entries = await listZipEntries(data);
1391
1451
  content = await extractZipEntry(data, opts.entry);
1392
1452
  } catch (err) {
1393
- emitErr(archiveReadFailure(err, opts.file));
1453
+ emitErr(formatCommandError(archiveReadFailure(err, opts.file)));
1394
1454
  return 1;
1395
1455
  }
1396
1456
  const matchedEntry = entries.find((e) => e.path === opts.entry);
1397
1457
  if (matchedEntry?.isDirectory === true) {
1398
- emitErr(`Entry '${opts.entry}' is a directory, not a file, in '${opts.file}'`);
1458
+ emitErr(formatCommandError(`Entry ${echoedValue(opts.entry)} is a directory, not a file, in ${echoedValue(opts.file)}`));
1399
1459
  return 1;
1400
1460
  }
1401
1461
  if (content === void 0) {
1402
- const messages = [`Entry '${opts.entry}' not found in '${opts.file}'`];
1462
+ const messages = [`Entry ${echoedValue(opts.entry)} not found in ${echoedValue(opts.file)}`];
1403
1463
  const closes = rankSimilarNames(entries.map((e) => e.path), opts.entry);
1404
1464
  if (closes.length > 0) messages.push(didYouMean(closes));
1405
- else if (entries.length > 0) messages.push(`Try: token-goat zip-list ${opts.file}`);
1406
- emitErr(messages.join("\n"));
1465
+ else if (entries.length > 0) messages.push(`Try: token-goat zip-list ${quotedArg(opts.file)}`);
1466
+ emitErr(formatCommandError(new CliError(messages)));
1407
1467
  return 1;
1408
1468
  }
1409
1469
  const buf = Buffer.from(content);
1410
- const text = isValidUtf8(buf) ? buf.toString("utf-8") : "[binary content elided by token-goat]";
1470
+ const text = isValidUtf8(buf) ? buf.toString("utf-8") : null;
1411
1471
  const fullSourceBytes = sumFileSizes([opts.file]);
1412
1472
  if (opts.json === true) {
1413
- const jsonText = displaySafeJson({ path: opts.entry, text }, 0);
1473
+ const jsonText = displaySafeJson({ path: opts.entry, text: text === null ? BINARY_ENTRY_ELIDED : fenceFileFieldIfMatched(text) }, 0);
1414
1474
  emit(jsonText);
1415
1475
  recordReadStat("zip_read", fullSourceBytes, jsonText, opts.entry);
1416
1476
  } else {
1417
- emitGuarded(text, "zip-read");
1418
- recordReadStat("zip_read", fullSourceBytes, text, opts.entry);
1477
+ const printed = text === null ? BINARY_ENTRY_ELIDED : guardAndFenceFileText(text, "zip-read");
1478
+ emit(printed);
1479
+ recordReadStat("zip_read", fullSourceBytes, printed, opts.entry);
1419
1480
  }
1420
1481
  return 0;
1421
1482
  }
@@ -1424,17 +1485,17 @@ function runSqliteSchema(opts) {
1424
1485
  const schema = getSqliteSchema(opts.file);
1425
1486
  const fullSourceBytes = sumFileSizes([opts.file]);
1426
1487
  if (opts.json === true) {
1427
- const jsonText = displaySafeJson(schema, 0);
1488
+ const jsonText = capListField(schema, "tables", (o) => displaySafeJson(fenceJsonStrings(o, fenceFileFieldIfMatched), 0));
1428
1489
  emit(jsonText);
1429
1490
  recordReadStat("sqlite_schema", fullSourceBytes, jsonText, opts.file);
1430
1491
  } else {
1431
- const text = formatSqliteSchema(schema);
1492
+ const text = guardAndFenceFileText(formatSqliteSchema(schema), "sqlite-schema");
1432
1493
  emit(text);
1433
1494
  recordReadStat("sqlite_schema", fullSourceBytes, text, opts.file);
1434
1495
  }
1435
1496
  return 0;
1436
1497
  } catch (e) {
1437
- emitErr(extractErrorMessage(e));
1498
+ emitErr(formatCommandError(e));
1438
1499
  return 1;
1439
1500
  }
1440
1501
  }
@@ -1443,17 +1504,21 @@ function runSqliteTables(opts) {
1443
1504
  const tables = getSqliteTables(opts.file);
1444
1505
  const fullSourceBytes = sumFileSizes([opts.file]);
1445
1506
  if (opts.json === true) {
1446
- const jsonText = displaySafeJson(tables, 0);
1507
+ const jsonText = capListField({ items: tables }, "items", (o) => displaySafeJson(fenceJsonStrings(o.truncated === true ? o : o.items, fenceFileFieldIfMatched), 0));
1508
+ if (jsonText.startsWith("{")) {
1509
+ const cut = JSON.parse(jsonText);
1510
+ emitErr(`token-goat: sqlite-tables --json shows ${cut.items.length} of ${cut.totalCount} tables, the most that fit overflow_guard.max_tokens; list fewer with sqlite-query.`);
1511
+ }
1447
1512
  emit(jsonText);
1448
1513
  recordReadStat("sqlite_tables", fullSourceBytes, jsonText, opts.file);
1449
1514
  } else {
1450
- const text = formatSqliteTables(tables);
1515
+ const text = guardAndFenceFileText(formatSqliteTables(tables), "sqlite-tables");
1451
1516
  emit(text);
1452
1517
  recordReadStat("sqlite_tables", fullSourceBytes, text, opts.file);
1453
1518
  }
1454
1519
  return 0;
1455
1520
  } catch (e) {
1456
- emitErr(extractErrorMessage(e));
1521
+ emitErr(formatCommandError(e));
1457
1522
  return 1;
1458
1523
  }
1459
1524
  }
@@ -1462,7 +1527,7 @@ function runSqliteQuery(opts) {
1462
1527
  try {
1463
1528
  head = opts.head !== void 0 ? requireNonNegativeStrictInt("--head", opts.head) : void 0;
1464
1529
  } catch (e) {
1465
- emitErr(extractErrorMessage(e));
1530
+ emitErr(formatCommandError(e));
1466
1531
  return 1;
1467
1532
  }
1468
1533
  try {
@@ -1471,9 +1536,9 @@ function runSqliteQuery(opts) {
1471
1536
  const headTruncated = head !== void 0 && result.rows.length > head;
1472
1537
  const rows = head !== void 0 ? result.rows.slice(0, head) : result.rows;
1473
1538
  if (opts.json === true) {
1474
- const capped = guardJsonRows(rows);
1539
+ const capped = guardJsonRows(rows.map((r) => fenceJsonStrings(r, fenceFileFieldIfMatched)));
1475
1540
  const jsonText = displaySafeJson({
1476
- columns: result.columns,
1541
+ columns: result.columns.map(fenceFileFieldIfMatched),
1477
1542
  items: capped.items,
1478
1543
  truncated: capped.truncated || headTruncated || result.rowCapped,
1479
1544
  totalCount,
@@ -1490,29 +1555,28 @@ function runSqliteQuery(opts) {
1490
1555
  }, 0);
1491
1556
  recordReadStat("sqlite_query", Buffer.byteLength(baselineJsonText, "utf8"), jsonText, opts.file);
1492
1557
  } else {
1493
- const text = formatSqliteQueryTable({ ...result, rows }, { headTruncated });
1558
+ const text = guardAndFenceFileText(formatSqliteQueryTable({ ...result, rows }, { headTruncated }), "sqlite-query");
1494
1559
  emit(text);
1495
1560
  const baselineText = formatSqliteQueryTable({ ...result, rows: result.rows }, { headTruncated: false });
1496
1561
  recordReadStat("sqlite_query", Buffer.byteLength(baselineText, "utf8"), text, opts.file);
1497
1562
  }
1498
1563
  return 0;
1499
1564
  } catch (e) {
1500
- emitErr(extractErrorMessage(e));
1565
+ emitErr(formatCommandError(e));
1501
1566
  return 1;
1502
1567
  }
1503
1568
  }
1504
1569
  function runCoverageReportGaps(opts) {
1505
1570
  const text = readFileText(opts.file);
1506
1571
  if (text === null) {
1507
- emitErr(`Could not read: ${opts.file}`);
1572
+ emitErr(formatCommandError(couldNotReadError(opts.file)));
1508
1573
  return 1;
1509
1574
  }
1510
1575
  let report;
1511
1576
  try {
1512
1577
  report = parseCoverageReport(text);
1513
1578
  } catch (e) {
1514
- emitErr(`Failed to parse coverage report (not valid LCOV or Istanbul JSON): ${opts.file}
1515
- ${extractErrorMessage(e)}`);
1579
+ emitErr(formatCommandError(new CliError([`Failed to parse coverage report (not valid LCOV or Istanbul JSON): ${opts.file}`, extractErrorMessage(e)])));
1516
1580
  return 1;
1517
1581
  }
1518
1582
  const scoped = opts.fileFilter !== void 0 ? filterCoverageGapsByFile(report, opts.fileFilter) : report;
@@ -1560,30 +1624,22 @@ function stripPairedQuotes(s) {
1560
1624
  }
1561
1625
  return s;
1562
1626
  }
1563
- function lookupYaml(lines, key) {
1564
- const parts = key.split(".");
1565
- let depth = 0;
1566
- let parentIndent = -1;
1567
- let childIndent = -1;
1568
- for (const line of lines) {
1569
- const trimmed = line.trim();
1570
- if (trimmed === "" || trimmed.startsWith("#")) continue;
1571
- const indent = line.length - line.trimStart().length;
1572
- if (depth > 0 && indent <= parentIndent) return null;
1573
- if (childIndent !== -1 && indent !== childIndent) continue;
1574
- const colon = trimmed.indexOf(":");
1575
- if (colon < 0) continue;
1576
- if (childIndent === -1) childIndent = indent;
1577
- const k = trimmed.slice(0, colon).trim();
1578
- if (k !== parts[depth]) continue;
1579
- if (depth === parts.length - 1) {
1580
- return stripPairedQuotes(trimmed.slice(colon + 1).trim());
1581
- }
1582
- parentIndent = indent;
1583
- childIndent = -1;
1584
- depth++;
1627
+ function lookupYaml(text, key) {
1628
+ let typed;
1629
+ let written;
1630
+ try {
1631
+ typed = parseYamlDocument(text);
1632
+ written = parseYamlDocumentAsWritten(text);
1633
+ } catch {
1634
+ return void 0;
1585
1635
  }
1586
- return null;
1636
+ const parts = key.split(".").map((name) => ({ name, joinable: true }));
1637
+ const found = resolveConfigKey(typed, parts);
1638
+ if (found === void 0) return null;
1639
+ if (found === null) return "null";
1640
+ if (typeof found === "object" && !(found instanceof Date)) return displaySafeJson(found, 0);
1641
+ const asWritten = resolveConfigKey(written, parts);
1642
+ return typeof asWritten === "string" ? asWritten : String(found);
1587
1643
  }
1588
1644
  function extractFrontmatter(lines) {
1589
1645
  if (lines[0]?.trim() !== "---") return null;
@@ -1597,14 +1653,18 @@ function extractFrontmatter(lines) {
1597
1653
  function runConfigGet(opts) {
1598
1654
  const text = readFileText(opts.file);
1599
1655
  if (text === null) {
1600
- emitErr(`Could not read: ${opts.file}`);
1656
+ emitErr(formatCommandError(couldNotReadError(opts.file)));
1601
1657
  return 1;
1602
1658
  }
1603
1659
  const frontmatterLines = extractFrontmatter(text.split(/\r?\n/));
1604
1660
  if (frontmatterLines !== null) {
1605
- const value = lookupYaml(frontmatterLines, opts.key);
1661
+ const value = lookupYaml(frontmatterLines.join("\n"), opts.key);
1662
+ if (value === void 0) {
1663
+ emitErr(formatCommandError(`Failed to parse YAML frontmatter: ${echoedValue(opts.file)}`));
1664
+ return 1;
1665
+ }
1606
1666
  if (value === null) {
1607
- emitErr(`Key '${opts.key}' not found in ${opts.file}`);
1667
+ emitErr(formatCommandError(`Key ${echoedValue(opts.key)} not found in ${echoedValue(opts.file)}`));
1608
1668
  return 1;
1609
1669
  }
1610
1670
  emit(value);
@@ -1616,26 +1676,30 @@ function runConfigGet(opts) {
1616
1676
  let obj = parseJsonOrJsonc(text);
1617
1677
  for (const part of opts.key.split(".")) {
1618
1678
  if (typeof obj !== "object" || obj === null) {
1619
- emitErr(`Key '${opts.key}' not found in ${opts.file}`);
1679
+ emitErr(formatCommandError(`Key ${echoedValue(opts.key)} not found in ${echoedValue(opts.file)}`));
1620
1680
  return 1;
1621
1681
  }
1622
1682
  obj = obj[part];
1623
1683
  if (obj === void 0) {
1624
- emitErr(`Key '${opts.key}' not found in ${opts.file}`);
1684
+ emitErr(formatCommandError(`Key ${echoedValue(opts.key)} not found in ${echoedValue(opts.file)}`));
1625
1685
  return 1;
1626
1686
  }
1627
1687
  }
1628
1688
  emit(displaySafeJson(obj, 0));
1629
1689
  return 0;
1630
1690
  } catch {
1631
- emitErr(`Failed to parse JSON: ${opts.file}`);
1691
+ emitErr(formatCommandError(`Failed to parse JSON: ${echoedValue(opts.file)}`));
1632
1692
  return 1;
1633
1693
  }
1634
1694
  }
1635
1695
  if (ext === ".yaml" || ext === ".yml") {
1636
- const value = lookupYaml(text.split(/\r?\n/), opts.key);
1696
+ const value = lookupYaml(text, opts.key);
1697
+ if (value === void 0) {
1698
+ emitErr(formatCommandError(`Failed to parse YAML: ${echoedValue(opts.file)}`));
1699
+ return 1;
1700
+ }
1637
1701
  if (value === null) {
1638
- emitErr(`Key '${opts.key}' not found in ${opts.file}`);
1702
+ emitErr(formatCommandError(`Key ${echoedValue(opts.key)} not found in ${echoedValue(opts.file)}`));
1639
1703
  return 1;
1640
1704
  }
1641
1705
  emit(value);
@@ -1645,7 +1709,7 @@ function runConfigGet(opts) {
1645
1709
  const toml = lookupToml(text, opts.key);
1646
1710
  if (toml !== void 0) {
1647
1711
  if (toml === null) {
1648
- emitErr(`Key '${opts.key}' not found in ${opts.file}`);
1712
+ emitErr(formatCommandError(`Key ${echoedValue(opts.key)} not found in ${echoedValue(opts.file)}`));
1649
1713
  return 1;
1650
1714
  }
1651
1715
  emit(toml);
@@ -1661,14 +1725,14 @@ function runConfigGet(opts) {
1661
1725
  const value = lookupFlatKey(lines, attempt.section, attempt.leaf, flavour);
1662
1726
  if (value !== null) {
1663
1727
  if (ext === ".toml" && isTomlFragment(value)) {
1664
- emitErr(`Key '${opts.key}' in ${opts.file} spans several lines and the file is not valid TOML, so it cannot be read whole`);
1728
+ emitErr(formatCommandError(`Key ${echoedValue(opts.key)} in ${echoedValue(opts.file)} spans several lines and the file is not valid TOML, so it cannot be read whole`));
1665
1729
  return 1;
1666
1730
  }
1667
1731
  emit(value);
1668
1732
  return 0;
1669
1733
  }
1670
1734
  }
1671
- emitErr(`Key '${opts.key}' not found in ${opts.file}`);
1735
+ emitErr(formatCommandError(`Key ${echoedValue(opts.key)} not found in ${echoedValue(opts.file)}`));
1672
1736
  return 1;
1673
1737
  }
1674
1738
  function isTomlFragment(v) {
@@ -1698,7 +1762,7 @@ function tomlProbePath(key, value) {
1698
1762
  return null;
1699
1763
  }
1700
1764
  }
1701
- function resolveTomlKey(node, parts) {
1765
+ function resolveConfigKey(node, parts) {
1702
1766
  if (parts.length === 0) return node;
1703
1767
  if (typeof node !== "object" || node === null || Array.isArray(node) || node instanceof Date) return void 0;
1704
1768
  const table = node;
@@ -1706,7 +1770,7 @@ function resolveTomlKey(node, parts) {
1706
1770
  if (n > 1 && !(parts[0].joinable && parts[n - 1].joinable)) break;
1707
1771
  const head = parts.slice(0, n).map((p) => p.name).join(".");
1708
1772
  if (!Object.hasOwn(table, head)) continue;
1709
- const found = resolveTomlKey(table[head], parts.slice(n));
1773
+ const found = resolveConfigKey(table[head], parts.slice(n));
1710
1774
  if (found !== void 0) return found;
1711
1775
  }
1712
1776
  return void 0;
@@ -1718,7 +1782,7 @@ function lookupToml(text, key) {
1718
1782
  } catch {
1719
1783
  return void 0;
1720
1784
  }
1721
- const found = resolveTomlKey(doc, splitTomlKeyPath(key));
1785
+ const found = resolveConfigKey(doc, splitTomlKeyPath(key));
1722
1786
  if (found === void 0) return null;
1723
1787
  if (typeof found === "string") return found;
1724
1788
  if (typeof found === "object" && found !== null && !(found instanceof Date)) {
@@ -1766,7 +1830,7 @@ function runExports(opts) {
1766
1830
  if (multiFiles.length > 1) return runPerFileEmitting(multiFiles, "Exports", (file) => runExports({ ...opts, file }));
1767
1831
  const confined = fileConfinementRefusal("This file", opts.file, opts.projectRoot);
1768
1832
  if (confined !== null) {
1769
- emitErr(confined);
1833
+ emitErr(formatCommandError(confined));
1770
1834
  return 1;
1771
1835
  }
1772
1836
  const diskPath = resolveAgainstProjectRoot(opts.file, opts.projectRoot);
@@ -1785,7 +1849,7 @@ function runExports(opts) {
1785
1849
  const ext = path.extname(opts.file).toLowerCase();
1786
1850
  const text = readFileText(diskPath);
1787
1851
  if (text === null && symbols.length === 0) {
1788
- emitErr(`Could not read: ${opts.file}`);
1852
+ emitErr(formatCommandError(couldNotReadError(opts.file)));
1789
1853
  return 1;
1790
1854
  }
1791
1855
  if (text !== null) {
@@ -1795,7 +1859,7 @@ function runExports(opts) {
1795
1859
  for (const n of extractExportNames(text, ext)) if (!names.includes(n)) names.push(n);
1796
1860
  }
1797
1861
  if (names.length === 0) {
1798
- emit(`No exported symbols found in '${displaySafeText(opts.file)}'`);
1862
+ emit(`No exported symbols found in ${echoedValue(opts.file)}`);
1799
1863
  return 0;
1800
1864
  }
1801
1865
  const preFilterCount = names.length;
@@ -1828,7 +1892,7 @@ function runExports(opts) {
1828
1892
  const outLines = filteredNames.map((n) => {
1829
1893
  const loc = locOf(n);
1830
1894
  const locSuffix = loc === null ? "" : ` (${loc.lineStart}-${loc.lineEnd})`;
1831
- return `${kindOf(n).padEnd(10)} ${n}${locSuffix}`;
1895
+ return `${kindOf(n).padEnd(10)} ${displaySafeText(n)}${locSuffix}`;
1832
1896
  });
1833
1897
  for (const line of outLines) {
1834
1898
  emit(line);
@@ -1842,12 +1906,12 @@ function runImports(opts) {
1842
1906
  const diskPath = resolveAgainstProjectRoot(opts.file, opts.projectRoot);
1843
1907
  const text = readFileText(diskPath);
1844
1908
  if (text === null) {
1845
- emitErr(`Could not read: ${opts.file}`);
1909
+ emitErr(formatCommandError(couldNotReadError(opts.file)));
1846
1910
  return 1;
1847
1911
  }
1848
1912
  const imports = extractImports(text, importsExtensionFor(opts.file));
1849
1913
  if (imports.length === 0) {
1850
- emit(`No imports found in '${displaySafeText(opts.file)}'`);
1914
+ emit(`No imports found in ${echoedValue(opts.file)}`);
1851
1915
  return 0;
1852
1916
  }
1853
1917
  const preFilterCount = imports.length;
@@ -1918,8 +1982,8 @@ function runNoteGet(opts) {
1918
1982
  const symbol = opts.symbol ?? WHOLE_FILE_NOTE_SYMBOL;
1919
1983
  const note = getNote(resolvedPath, symbol);
1920
1984
  if (note === null) {
1921
- const where = opts.symbol !== void 0 ? ` for symbol '${opts.symbol}'` : " (whole-file note)";
1922
- return { text: `No note found for '${opts.file}'${where}`, code: 1 };
1985
+ const where = opts.symbol !== void 0 ? ` for symbol ${echoedValue(opts.symbol)}` : " (whole-file note)";
1986
+ return { text: `No note found for ${echoedValue(opts.file)}${where}`, code: 1 };
1923
1987
  }
1924
1988
  const stale = isNoteStale(note);
1925
1989
  if (opts.json === true) {
@@ -1973,7 +2037,7 @@ function runNoteList(opts = {}) {
1973
2037
  }
1974
2038
  function runFind(opts) {
1975
2039
  if (opts.limit !== void 0 && opts.limit <= 0) {
1976
- emitErr(`--limit must be a positive number, got: ${opts.limit}`);
2040
+ emitErr(formatCommandError(`--limit must be a positive number, got: ${echoedValue(String(opts.limit))}`));
1977
2041
  return 1;
1978
2042
  }
1979
2043
  const rootDir = resolveProjectRoot({ project: process.cwd() });
@@ -2001,7 +2065,7 @@ function runFind(opts) {
2001
2065
  const limitDropped = allFiles.length - files.length;
2002
2066
  const truncated = limitDropped > 0;
2003
2067
  if (files.length === 0) {
2004
- emitErr(`No indexed files match '${opts.pattern}'`);
2068
+ emitErr(formatCommandError(`No indexed files match ${echoedValue(opts.pattern)}`));
2005
2069
  return 1;
2006
2070
  }
2007
2071
  if (opts.json === true) {
@@ -2010,10 +2074,10 @@ function runFind(opts) {
2010
2074
  return 0;
2011
2075
  }
2012
2076
  if (fuzzyNames.length > 0) {
2013
- emitErr(`No symbol name contains '${opts.pattern}'; showing files for the nearest indexed ${fuzzyNames.length === 1 ? "name" : "names"}: ${fuzzyNames.join(", ")}`);
2077
+ emitErr(`No symbol name contains ${echoedValue(opts.pattern)}; showing files for the nearest indexed ${fuzzyNames.length === 1 ? "name" : "names"}: ${fuzzyNames.map(displaySafeText).join(", ")}`);
2014
2078
  }
2015
2079
  for (const f of files) {
2016
- emit(toDisplayPath(rootDir, f));
2080
+ emit(displaySafeText(toDisplayPath(rootDir, f)));
2017
2081
  }
2018
2082
  if (limitDropped > 0) {
2019
2083
  emitErr(`Showing ${files.length} of ${allFiles.length} matching files; rerun with --limit ${allFiles.length} to see them all`);
@@ -2022,7 +2086,7 @@ function runFind(opts) {
2022
2086
  }
2023
2087
  function runLocate(opts) {
2024
2088
  if (opts.limit !== void 0 && opts.limit <= 0) {
2025
- emitErr(`--limit must be a positive number, got: ${opts.limit}`);
2089
+ emitErr(formatCommandError(`--limit must be a positive number, got: ${echoedValue(String(opts.limit))}`));
2026
2090
  return 1;
2027
2091
  }
2028
2092
  const rootDir = opts.projectRoot ?? resolveProjectRoot({ project: process.cwd() });
@@ -2081,7 +2145,7 @@ function runLocate(opts) {
2081
2145
  }
2082
2146
  const shown = sinkGoneRows(combined, (s) => s.filePath).slice(0, limit);
2083
2147
  if (shown.length === 0) {
2084
- emitErr(`No landmark or symbol located for '${targetSpec}'`);
2148
+ emitErr(formatCommandError(`No landmark or symbol located for ${echoedValue(targetSpec)}`));
2085
2149
  return 1;
2086
2150
  }
2087
2151
  warnIfFilesStale(shown.map((s) => s.filePath), "locate");
@@ -2104,7 +2168,7 @@ function runLocate(opts) {
2104
2168
  return 0;
2105
2169
  }
2106
2170
  if (fuzzyNames.length > 0) {
2107
- emitErr(`No exact landmark for '${targetSpec}'; nearest matches: ${fuzzyNames.join(", ")}`);
2171
+ emitErr(`No exact landmark for ${echoedValue(targetSpec)}; nearest matches: ${fuzzyNames.map(displaySafeText).join(", ")}`);
2108
2172
  }
2109
2173
  for (const hit of hits) {
2110
2174
  emit(`${displaySafeText(hit.filePath)}:${hit.span} [${displaySafeText(hit.kind)}] ${displaySafeText(hit.name)}${hit.deleted === true ? ` ${DELETED_TAG}` : ""}`);
@@ -2118,10 +2182,10 @@ function runListSections(opts) {
2118
2182
  const sections = listSections(opts.file);
2119
2183
  if (sections.length === 0) {
2120
2184
  if (!fileExists(opts.file)) {
2121
- emitErr(`Could not read: ${opts.file}`);
2185
+ emitErr(formatCommandError(couldNotReadError(opts.file)));
2122
2186
  return 1;
2123
2187
  }
2124
- emitErr(`No sections found in '${opts.file}'`);
2188
+ emitErr(formatCommandError(`No sections found in ${echoedValue(opts.file)}`));
2125
2189
  return 1;
2126
2190
  }
2127
2191
  const preFilterCount = sections.length;
@@ -2156,6 +2220,7 @@ function runListSections(opts) {
2156
2220
 
2157
2221
  // src/read_outline.ts
2158
2222
  init_define_import_meta_env();
2223
+ import * as fs2 from "node:fs";
2159
2224
  var DOC_SUMMARY_MAX_CHARS = 140;
2160
2225
  function firstSentenceEnd(line) {
2161
2226
  const MIN_SENTENCE_CHARS = 30;
@@ -2169,12 +2234,24 @@ function firstSentenceEnd(line) {
2169
2234
  }
2170
2235
  return null;
2171
2236
  }
2172
- function clipDocSummary(firstLine) {
2237
+ function fileLineCount(resolved, symbolExtent) {
2238
+ try {
2239
+ const text = indexedSourceText(resolved, fs2.readFileSync(resolved, "utf8"));
2240
+ if (text === "") return symbolExtent;
2241
+ const lines = text.split("\n");
2242
+ return Math.max(symbolExtent, text.endsWith("\n") ? lines.length - 1 : lines.length);
2243
+ } catch {
2244
+ return symbolExtent;
2245
+ }
2246
+ }
2247
+ function clipDocSummary(docstring) {
2248
+ const [firstLine = "", ...rest] = docstring.split("\n");
2249
+ const more = rest.some((l) => l.trim() !== "") ? "\u2026" : "";
2173
2250
  const sentence = firstSentenceEnd(firstLine);
2174
2251
  if (sentence !== null && sentence <= DOC_SUMMARY_MAX_CHARS) {
2175
- return sentence === firstLine.length ? firstLine : `${firstLine.slice(0, sentence)}\u2026`;
2252
+ return sentence === firstLine.length ? `${firstLine}${more}` : `${firstLine.slice(0, sentence)}\u2026`;
2176
2253
  }
2177
- if (firstLine.length <= DOC_SUMMARY_MAX_CHARS) return firstLine;
2254
+ if (firstLine.length <= DOC_SUMMARY_MAX_CHARS) return `${firstLine}${more}`;
2178
2255
  const cut = firstLine.lastIndexOf(" ", DOC_SUMMARY_MAX_CHARS);
2179
2256
  return `${firstLine.slice(0, cut > 40 ? cut : DOC_SUMMARY_MAX_CHARS).trimEnd()}\u2026`;
2180
2257
  }
@@ -2222,7 +2299,7 @@ function prepareSymbolListing(file, opts) {
2222
2299
  const symbolsTruncated = matchesTruncated;
2223
2300
  const refCounts = opts.stats === true ? queryRefCounts(filtered.map((s) => s.name), globalDbPath(), resolveProjectRoot({ project: opts.projectRoot ?? process.cwd() })) : void 0;
2224
2301
  const fullSourceBytes = sumFileSizes([resolved]);
2225
- return { kind: "ok", resolved, displayRoot: getDisplayRoot(opts.projectRoot), filtered, preFilterCount: scanned, refCounts, fullSourceBytes, symbolsTruncated, trueSymbolCount, totalLines };
2302
+ return { kind: "ok", resolved, displayRoot: getDisplayRoot(opts.projectRoot), filtered, preFilterCount: scanned, refCounts, fullSourceBytes, symbolsTruncated, trueSymbolCount, totalLines: fileLineCount(resolved, totalLines) };
2226
2303
  }
2227
2304
  function runPerFileListing(files, run, json = false) {
2228
2305
  const blocks = [];
@@ -2292,12 +2369,12 @@ function runSkeleton(opts) {
2292
2369
  recordReadStat("stub_view", fullSourceBytes, text2, opts.file);
2293
2370
  return { text: text2, code: 0 };
2294
2371
  }
2295
- const lines = [`# Skeleton: ${opts.file} (${symbolCountLabel(filtered.length, symbolsTruncated, trueSymbolCount)}, ${countNoun(totalLines, "line")})`];
2372
+ const lines = [`# Skeleton: ${displaySafeText(opts.file)} (${symbolCountLabel(filtered.length, symbolsTruncated, trueSymbolCount)}, ${countNoun(totalLines, "line")})`];
2296
2373
  if (filtered.length === 0 && preFilterCount > 0) lines.push(filteredToEmptyNotice(preFilterCount, opts.minLines, opts.grep));
2297
2374
  for (const sym of filtered) {
2298
2375
  const lineStr = sym.lineStart.toString().padStart(6);
2299
2376
  const statsStr = formatStatsSuffix(refCounts, sym);
2300
- lines.push(` ${lineStr} ${sym.kind.padEnd(10)} ${sym.name} ${firstBodyLine(sym.body)}${statsStr}`);
2377
+ lines.push(` ${lineStr} ${sym.kind.padEnd(10)} ${displaySafeText(sym.name)} ${displaySafeText(firstBodyLine(sym.body))}${statsStr}`);
2301
2378
  }
2302
2379
  const text = guardText(staleWarning(resolved, "skeleton") + lines.join("\n"), "symbol");
2303
2380
  recordReadStat("stub_view", fullSourceBytes, text, opts.file);
@@ -2334,16 +2411,16 @@ function runOutline(opts) {
2334
2411
  recordReadStat("outline", fullSourceBytes, text2, opts.file);
2335
2412
  return { text: text2, code: 0 };
2336
2413
  }
2337
- const lines = [`# Outline: ${opts.file} (${symbolCountLabel(filtered.length, symbolsTruncated, trueSymbolCount)})`];
2414
+ const lines = [`# Outline: ${displaySafeText(opts.file)} (${symbolCountLabel(filtered.length, symbolsTruncated, trueSymbolCount)})`];
2338
2415
  if (filtered.length === 0 && preFilterCount > 0) lines.push(filteredToEmptyNotice(preFilterCount, opts.minLines, opts.grep));
2339
2416
  for (const sym of filtered) {
2340
2417
  const rangeStr = `${sym.lineStart.toString().padStart(4)}-${sym.lineEnd.toString().padEnd(6)}`;
2341
2418
  const kindStr = sym.kind.padEnd(14);
2342
2419
  const bodyLen = sym.lineEnd - sym.lineStart + 1;
2343
- const docFirst = hasRealDocstring(sym.docstring) ? ` # ${clipDocSummary(sym.docstring.split("\n")[0] ?? "")}` : "";
2420
+ const docFirst = hasRealDocstring(sym.docstring) ? ` # ${displaySafeText(clipDocSummary(sym.docstring))}` : "";
2344
2421
  const statsStr = formatStatsSuffix(refCounts, sym);
2345
2422
  const notebookSuffix = isVirtualIndexedPath(sym.filePath) ? NOTEBOOK_CELL_LINES_SUFFIX : "";
2346
- lines.push(` ${rangeStr} ${kindStr} ${sym.name} (${bodyLen}\u2113)${docFirst}${statsStr}${notebookSuffix}`);
2423
+ lines.push(` ${rangeStr} ${kindStr} ${displaySafeText(sym.name)} (${bodyLen}\u2113)${docFirst}${statsStr}${notebookSuffix}`);
2347
2424
  }
2348
2425
  const text = guardText(staleWarning(resolved, "outline") + lines.join("\n"), "symbol");
2349
2426
  recordReadStat("outline", fullSourceBytes, text, opts.file);
@@ -2375,9 +2452,9 @@ function summarizeDistances(rows, weakDistance) {
2375
2452
  };
2376
2453
  }
2377
2454
  function formatDistanceReport(summary, thresholds, scope = "this project") {
2378
- const lines = [`Recorded semantic queries (${scope}): ${summary.total} queries`, `Current semantic.weak_distance: ${thresholds.weakDistance} semantic.max_distance: ${thresholds.maxDistance}`];
2455
+ const lines = [`Recorded semantic queries (${scope}): ${countNoun(summary.total, "query", "queries")}`, `Current semantic.weak_distance: ${thresholds.weakDistance} semantic.max_distance: ${thresholds.maxDistance}`];
2379
2456
  if (summary.total < MIN_QUERIES_FOR_ADVICE) {
2380
- lines.push(`Only ${summary.total} recorded, which is fewer than ${MIN_QUERIES_FOR_ADVICE}: too few to judge a threshold from. Run more semantic queries and check again.`);
2457
+ lines.push(`${summary.total === 0 ? "None" : `Only ${summary.total}`} recorded, which is fewer than ${MIN_QUERIES_FOR_ADVICE}: too few to judge a threshold from. Run more semantic queries and check again.`);
2381
2458
  return lines.join("\n");
2382
2459
  }
2383
2460
  if (summary.percentiles !== null) {
@@ -2399,7 +2476,7 @@ function recordSemanticQuery(row) {
2399
2476
  }
2400
2477
  function runSemanticDistances(opts) {
2401
2478
  const { weak_distance: weakDistance, max_distance: maxDistance } = loadConfig().semantic;
2402
- const db = getGlobalDb();
2479
+ const db = readGlobalDb();
2403
2480
  const rows = opts.all === true ? db.prepare("SELECT closest_distance FROM semantic_queries").all() : db.prepare("SELECT closest_distance FROM semantic_queries WHERE project_hash = ?").all(projectHash(resolveProjectRoot({ project: process.cwd() })));
2404
2481
  const scope = opts.all === true ? "all projects" : "this project";
2405
2482
  return { text: formatDistanceReport(summarizeDistances(rows, weakDistance), { weakDistance, maxDistance }, scope), code: 0 };
@@ -2407,7 +2484,7 @@ function runSemanticDistances(opts) {
2407
2484
 
2408
2485
  // src/read_semantic.ts
2409
2486
  init_define_import_meta_env();
2410
- import * as fs2 from "node:fs";
2487
+ import * as fs3 from "node:fs";
2411
2488
  import * as path2 from "node:path";
2412
2489
 
2413
2490
  // src/semantic_merge.ts
@@ -2469,6 +2546,36 @@ function mergeNearbyHits(hits, proximity = 20) {
2469
2546
  return merged;
2470
2547
  }
2471
2548
 
2549
+ // src/semantic_relevance.ts
2550
+ init_define_import_meta_env();
2551
+ function applyRelevanceFloor(hits, floor) {
2552
+ const kept = [];
2553
+ let nearestRejected = null;
2554
+ for (const h of hits) {
2555
+ if (h.distance <= floor) {
2556
+ kept.push(h);
2557
+ } else if (nearestRejected === null || h.distance < nearestRejected) {
2558
+ nearestRejected = h.distance;
2559
+ }
2560
+ }
2561
+ return { kept, nearestRejected };
2562
+ }
2563
+ function assessDenseRelevance(hits) {
2564
+ const { max_distance: floor, weak_distance: weakDistance } = loadConfig().semantic;
2565
+ const { kept, nearestRejected } = applyRelevanceFloor(hits, floor);
2566
+ const closestDistance = kept.reduce((best, h) => best === null || h.distance < best ? h.distance : best, null);
2567
+ const weakClosestDistance = closestDistance !== null && closestDistance > weakDistance ? closestDistance : null;
2568
+ return { kept, floor, nearestRejected, closestDistance, weakDistance, weakClosestDistance };
2569
+ }
2570
+ function floorEmptiedPhrase(r) {
2571
+ if (r.kept.length > 0 || r.nearestRejected === null) return null;
2572
+ return `nothing within ${r.floor} (closest was ${r.nearestRejected.toFixed(3)})`;
2573
+ }
2574
+ function weakMatchPhrase(r) {
2575
+ if (r.weakClosestDistance === null) return null;
2576
+ return `closest was ${r.weakClosestDistance.toFixed(3)}, weak above ${r.weakDistance}`;
2577
+ }
2578
+
2472
2579
  // src/read_semantic.ts
2473
2580
  function resolveEnclosingSymbol(filePath, chunkStartLine, chunkEndLine, linesOf) {
2474
2581
  const symbols = querySymbols({ filePath, limit: -1 }, globalDbPath());
@@ -2508,18 +2615,6 @@ function onlyBlankOrComment(lines, syntax) {
2508
2615
  return true;
2509
2616
  }
2510
2617
  var RRF_K = 60;
2511
- function applyRelevanceFloor(hits, floor) {
2512
- const kept = [];
2513
- let nearestRejected = null;
2514
- for (const h of hits) {
2515
- if (h.distance <= floor) {
2516
- kept.push(h);
2517
- } else if (nearestRejected === null || h.distance < nearestRejected) {
2518
- nearestRejected = h.distance;
2519
- }
2520
- }
2521
- return { kept, nearestRejected };
2522
- }
2523
2618
  function semanticDegradedFields(preflight, searchSemanticError) {
2524
2619
  if (preflight.status !== "ready") {
2525
2620
  return {
@@ -2535,20 +2630,20 @@ function semanticDegradedFields(preflight, searchSemanticError) {
2535
2630
  }
2536
2631
  async function runSemantic(query, opts) {
2537
2632
  if (opts.limit !== void 0 && opts.limit <= 0) {
2538
- const message = `--limit must be a positive number, got: ${opts.limit}`;
2633
+ const message = (shown) => `--limit must be a positive number, got: ${shown}`;
2539
2634
  if (opts.json === true) {
2540
- return { text: displaySafeJson({ error: message }), code: 1 };
2635
+ return { text: displaySafeJson({ error: message(String(opts.limit)) }), code: 1 };
2541
2636
  }
2542
- return { text: message, code: 1 };
2637
+ return { text: message(echoedValue(String(opts.limit))), code: 1 };
2543
2638
  }
2544
2639
  const n = opts.limit !== void 0 && Number.isFinite(opts.limit) ? opts.limit : 20;
2545
2640
  if (opts.projectRoot !== void 0) {
2546
- if (!path2.isAbsolute(opts.projectRoot) || !fs2.existsSync(opts.projectRoot) || !fs2.statSync(opts.projectRoot).isDirectory()) {
2547
- const message = `token-goat: projectRoot must be an absolute, existing directory, got '${opts.projectRoot}'`;
2641
+ if (!path2.isAbsolute(opts.projectRoot) || !fs3.existsSync(opts.projectRoot) || !fs3.statSync(opts.projectRoot).isDirectory()) {
2642
+ const message = (shown) => `projectRoot must be an absolute, existing directory, got ${shown}`;
2548
2643
  if (opts.json === true) {
2549
- return { text: displaySafeJson({ error: message }), code: 1 };
2644
+ return { text: displaySafeJson({ error: message(opts.projectRoot) }), code: 1 };
2550
2645
  }
2551
- return { text: message, code: 1 };
2646
+ return { text: message(echoedValue(opts.projectRoot)), code: 1 };
2552
2647
  }
2553
2648
  }
2554
2649
  const projectDenial = resolveProjectConfinement(opts.projectRoot).denial;
@@ -2615,7 +2710,7 @@ async function runSemantic(query, opts) {
2615
2710
  if (embeddingsEnabled && !deferred) {
2616
2711
  try {
2617
2712
  rawHits = await searchSemantic(
2618
- getDb(globalDbPath()),
2713
+ getReadDb(globalDbPath()),
2619
2714
  query,
2620
2715
  overFetchForMerge,
2621
2716
  void 0,
@@ -2631,21 +2726,18 @@ async function runSemantic(query, opts) {
2631
2726
  }
2632
2727
  }
2633
2728
  }
2634
- let floorNearestRejected = null;
2635
- if (rawHits.length > 0) {
2636
- const floor = loadConfig().semantic.max_distance;
2637
- const { kept, nearestRejected } = applyRelevanceFloor(rawHits, floor);
2638
- floorNearestRejected = nearestRejected;
2639
- if (kept.length === 0 && nearestRejected !== null) {
2640
- console.warn(
2641
- `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.`
2642
- );
2643
- }
2644
- rawHits = kept;
2729
+ const relevance = assessDenseRelevance(rawHits);
2730
+ const floorNearestRejected = relevance.nearestRejected;
2731
+ const floorEmptied = floorEmptiedPhrase(relevance);
2732
+ if (floorEmptied !== null) {
2733
+ console.warn(
2734
+ `Matching on meaning found ${floorEmptied}; these results come from keyword search alone. Raise semantic.max_distance to see weaker matches.`
2735
+ );
2645
2736
  }
2646
- const closestDense = rawHits.reduce((best, h) => best === null || h.distance < best ? h.distance : best, null);
2647
- const weakDistance = loadConfig().semantic.weak_distance;
2648
- const weakClosestDistance = closestDense !== null && closestDense > weakDistance ? closestDense : null;
2737
+ rawHits = relevance.kept;
2738
+ const closestDense = relevance.closestDistance;
2739
+ const { weakDistance, weakClosestDistance } = relevance;
2740
+ const weakPhrase = weakMatchPhrase(relevance);
2649
2741
  if (closestDense !== null || preflight.status === "ready" && !searchSemanticError) {
2650
2742
  recordSemanticQuery({ projectRoot: rootDir, closestDistance: closestDense, floorRejectedMin: floorNearestRejected, weak: weakClosestDistance !== null });
2651
2743
  }
@@ -2655,7 +2747,7 @@ async function runSemantic(query, opts) {
2655
2747
  const { indexedFiles, embeddedFiles } = enabled ? getEmbeddingCoverage(globalDbPath(), rootDir) : { indexedFiles: 0, embeddedFiles: 0 };
2656
2748
  if (indexedFiles > 0 && embeddedFiles < indexedFiles) {
2657
2749
  console.warn(
2658
- `Matching on meaning found nothing, and only ${embeddedFiles} of ${indexedFiles} indexed file(s) in this project have embeddings \u2014 these results come from keyword search alone. Run 'token-goat doctor' for why.`
2750
+ `Matching on meaning found nothing, and only ${embeddedFiles} of ${countNoun(indexedFiles, "indexed file")} in this project have embeddings \u2014 these results come from keyword search alone. Run \`token-goat doctor\` for why.`
2659
2751
  );
2660
2752
  }
2661
2753
  } catch {
@@ -2770,9 +2862,9 @@ ${previewLines(h.previewText, 3)}`;
2770
2862
  if (hits.length < eligibleCount) {
2771
2863
  emitErr(`Showing ${hits.length} of ${candidatesClipped ? "at least " : ""}${countNoun(eligibleCount, "match", "matches")} (raise --limit to see the rest).`);
2772
2864
  }
2773
- if (weakClosestDistance !== null) {
2865
+ if (weakPhrase !== null) {
2774
2866
  console.warn(
2775
- `Matching on meaning found nothing close for '${query}' (closest was ${weakClosestDistance.toFixed(3)}, weak above ${weakDistance}); these results may be unrelated. For a known name try token-goat symbol --grep <pattern> or rg, or rephrase the query.`
2867
+ `Matching on meaning found nothing close for ${echoedValue(query)} (${weakPhrase}); these results may be unrelated. For a known name try token-goat symbol --grep <pattern> or rg, or rephrase the query.`
2776
2868
  );
2777
2869
  }
2778
2870
  recordReadStat("semantic_search", largestFileSize(hits.map((h) => h.filePath)), text2, query);
@@ -2787,12 +2879,12 @@ ${previewLines(h.previewText, 3)}`;
2787
2879
  return { text: `token-goat: ${notice.trim()}`, code: 0 };
2788
2880
  }
2789
2881
  if (opts.excludeTests === true && suppressedTotal > 0) {
2790
- const notice = `no non-test matches for '${query}' (${excludeTestsHiddenNote(suppressedTotal)})`;
2882
+ const hidden = excludeTestsHiddenNote(suppressedTotal);
2791
2883
  if (opts.json === true) {
2792
- const payload = { source: "fts", items: [], truncated: false, totalCount: 0, excludeTestsFilteredToEmpty: true, hint: notice };
2884
+ const payload = { source: "fts", items: [], truncated: false, totalCount: 0, excludeTestsFilteredToEmpty: true, hint: `no non-test matches for "${query}" (${hidden})` };
2793
2885
  return { text: displaySafeJson(payload), code: 0 };
2794
2886
  }
2795
- return { text: `token-goat: ${notice}`, code: 0 };
2887
+ return { text: `token-goat: no non-test matches for ${echoedValue(query)} (${hidden})`, code: 0 };
2796
2888
  }
2797
2889
  if (!anyFilter) {
2798
2890
  const evidenceHits = await searchEvidenceSemantically(rootDir, query, n);
@@ -2848,15 +2940,15 @@ ${previewLines(entry.text, 3)}`).join("\n\n"),
2848
2940
  totalCount: 0,
2849
2941
  ...semanticDegradedFields(preflight, searchSemanticError),
2850
2942
  ...!indexEmpty && isIdentifier2 ? {
2851
- symbolSuggestion: `token-goat symbol "${trimmedQuery2}"`,
2943
+ symbolSuggestion: `token-goat symbol ${quotedArg(trimmedQuery2)}`,
2852
2944
  ...symFound ? { indexedSymbolFound: true } : {}
2853
2945
  } : {}
2854
2946
  };
2855
2947
  const text2 = displaySafeJson(payload);
2856
2948
  return { text: text2, code: 1 };
2857
2949
  }
2858
- let text = indexEmpty ? `token-goat: no matches for '${query}'
2859
- ${emptyIndexMessage(rootDir)}` : `token-goat: no matches for '${query}'`;
2950
+ let text = indexEmpty ? `no matches for ${echoedValue(query)}
2951
+ ${emptyIndexMessage(rootDir)}` : `no matches for ${echoedValue(query)}`;
2860
2952
  const trimmedQuery = query.trim();
2861
2953
  const isIdentifier = /^[A-Za-z0-9_.:-]+$/.test(trimmedQuery);
2862
2954
  if (!indexEmpty && isIdentifier) {
@@ -2869,11 +2961,11 @@ ${emptyIndexMessage(rootDir)}` : `token-goat: no matches for '${query}'`;
2869
2961
  } catch {
2870
2962
  }
2871
2963
  if (symFound) {
2872
- text += `
2873
- (note: '${trimmedQuery}' is an indexed symbol name; use: token-goat symbol "${trimmedQuery}")`;
2964
+ text += forClient(`
2965
+ (note: ${echoedValue(trimmedQuery)} is an indexed symbol name; use: ${fencedCommand("token-goat symbol " + quotedArg(trimmedQuery))})`);
2874
2966
  } else {
2875
- text += `
2876
- Try: token-goat symbol "${trimmedQuery}"`;
2967
+ text += forClient(`
2968
+ Try: token-goat symbol ${quotedArg(trimmedQuery)}`);
2877
2969
  }
2878
2970
  }
2879
2971
  if (preflight.status !== "ready") {
@@ -2898,7 +2990,7 @@ async function runSemanticMulti(queries, opts) {
2898
2990
  entries.push({ query, ...JSON.parse(sub.text) });
2899
2991
  continue;
2900
2992
  }
2901
- blocks.push(`'${query}':
2993
+ blocks.push(`${echoedValue(query)}:
2902
2994
  ${sub.text}`);
2903
2995
  }
2904
2996
  return { text: opts.json === true ? displaySafeJson(entries) : blocks.join("\n\n"), code: anyOk ? 0 : 1 };
@@ -2925,7 +3017,7 @@ function renderRefLines(ref, contextLines, indent = " ") {
2925
3017
  const base = `${indent}${displaySafeText(displayPath)}:${ref.line}: ${displaySafeText(ref.context)}${goneSuffix(ref.filePath)}`;
2926
3018
  const window = buildContextWindow(ref.filePath, ref.line, contextLines);
2927
3019
  if (window === null) return [base];
2928
- return [base, ...renderContextWindow(displayPath, ref.line, window, "", `${indent} `)];
3020
+ return [base, ...renderContextWindow(displaySafeText(displayPath), ref.line, window, "", `${indent} `)];
2929
3021
  }
2930
3022
  function withContextLines(items, contextLines) {
2931
3023
  if (!(contextLines > 0)) return items;
@@ -3002,27 +3094,27 @@ function refsSearchBaselineBytes(rows) {
3002
3094
  `, "utf8");
3003
3095
  return deliveredOutputBytes(total);
3004
3096
  }
3005
- function renderRefsTargets(targets, opts, {
3006
- annotateHiddenByGrep
3007
- }) {
3097
+ function renderRefsTargets(targets, opts) {
3008
3098
  for (const { file, symbol } of targets) {
3009
3099
  if (file === void 0 || !symbol.includes(".")) continue;
3010
3100
  const qualified = resolveQualifiedSpec(`${file}::${symbol}`, opts.projectRoot ?? process.cwd());
3011
3101
  if (qualified?.kind !== "ambiguous") continue;
3012
- emitErr(formatAmbiguity(qualified.symbol, qualified.file, qualified.candidates, opts.projectRoot, "refs"));
3102
+ emitErr(formatCommandError(new CliError(formatAmbiguity(qualified.symbol, qualified.file, qualified.candidates, opts.projectRoot, "refs").split("\n"))));
3013
3103
  return 1;
3014
3104
  }
3015
3105
  const jsonOut = {};
3016
3106
  let anyFound = false;
3107
+ let anyFilteredByGrep = false;
3017
3108
  const lines = [];
3018
3109
  const refRows = [];
3019
3110
  for (const { file, symbol, key } of targets) {
3020
3111
  const { queryOpts, results, preScanCount, scanLimit, suppressed, preGrepCount, clientFiltered, filteredTotal } = collectRefs(symbol, file, opts);
3021
3112
  if (results.length > 0) anyFound = true;
3113
+ else if (opts.grep !== void 0 && preGrepCount > 0) anyFilteredByGrep = true;
3022
3114
  refRows.push(...results);
3023
3115
  if (opts.json === true) {
3024
3116
  const hiddenByGrep = opts.grep !== void 0 ? preGrepCount - (filteredTotal ?? results.length) : 0;
3025
- const withHidden = (payload) => ({ ...payload, ...annotateHiddenByGrep && hiddenByGrep > 0 ? { hiddenByGrep } : {} });
3117
+ const withHidden = (payload) => ({ ...payload, ...hiddenByGrep > 0 ? { hiddenByGrep } : {} });
3026
3118
  if (opts.top !== void 0) {
3027
3119
  jsonOut[key] = withHidden(topFilesJsonPayload(results, opts.top));
3028
3120
  } else {
@@ -3067,32 +3159,36 @@ function renderRefsTargets(targets, opts, {
3067
3159
  const text2 = displaySafeJson(jsonOut);
3068
3160
  emit(text2);
3069
3161
  if (anyFound) recordReadStat("symbol_read", fullSourceBytes, text2, opts.spec);
3070
- return anyFound ? 0 : 1;
3162
+ return anyFound || anyFilteredByGrep ? 0 : 1;
3163
+ }
3164
+ if (!anyFound && !anyFilteredByGrep) {
3165
+ emitErr(formatCommandError(new CliError(lines)));
3166
+ return 1;
3071
3167
  }
3072
3168
  const text = lines.join("\n");
3073
3169
  emitGuarded(text, "symbol");
3074
3170
  if (anyFound) recordReadStat("symbol_read", fullSourceBytes, text, opts.spec);
3075
- return anyFound ? 0 : 1;
3171
+ return 0;
3076
3172
  }
3077
3173
  function runRefs(opts) {
3078
3174
  if (opts.limit !== void 0 && opts.limit <= 0) {
3079
- emitErr(`--limit must be a positive number, got: ${opts.limit}`);
3175
+ emitErr(formatCommandError(`--limit must be a positive number, got: ${echoedValue(String(opts.limit))}`));
3080
3176
  return 1;
3081
3177
  }
3082
3178
  if (opts.top !== void 0 && opts.top <= 0) {
3083
- emitErr(`--top must be a positive number, got: ${opts.top}`);
3179
+ emitErr(formatCommandError(`--top must be a positive number, got: ${echoedValue(String(opts.top))}`));
3084
3180
  return 1;
3085
3181
  }
3086
3182
  const { root: confinedRoot, denial: projectDenial } = resolveProjectConfinement(opts.projectRoot);
3087
3183
  if (projectDenial !== null) {
3088
- emitErr(projectDenial);
3184
+ emitErr(formatCommandError(projectDenial));
3089
3185
  return 1;
3090
3186
  }
3091
3187
  if (confinedRoot !== null) {
3092
3188
  for (const file2 of refsSpecFiles(opts.spec)) {
3093
3189
  const denial = confinementRefusal("This file", resolveSpecPath(file2, opts.projectRoot ?? process.cwd()), confinedRoot);
3094
3190
  if (denial !== null) {
3095
- emitErr(denial);
3191
+ emitErr(formatCommandError(denial));
3096
3192
  return 1;
3097
3193
  }
3098
3194
  }
@@ -3103,8 +3199,7 @@ function runRefs(opts) {
3103
3199
  if (symbols.length <= 1) return runRefsSingle(opts);
3104
3200
  return renderRefsTargets(
3105
3201
  symbols.map((symbol) => ({ file, symbol, key: symbol })),
3106
- opts,
3107
- { annotateHiddenByGrep: true }
3202
+ opts
3108
3203
  );
3109
3204
  }
3110
3205
  function runRefsCrossFile(pairs, opts) {
@@ -3112,16 +3207,14 @@ function runRefsCrossFile(pairs, opts) {
3112
3207
  const keyFor = (p) => distinctFiles.size === 1 ? p.symbol : `${p.file}::${p.symbol}`;
3113
3208
  return renderRefsTargets(
3114
3209
  pairs.map((p) => ({ file: p.file, symbol: p.symbol, key: keyFor(p) })),
3115
- opts,
3116
- // Not annotated today; renderRefsTargets's own option doc explains why that is a preserved divergence rather than a decision.
3117
- { annotateHiddenByGrep: false }
3210
+ opts
3118
3211
  );
3119
3212
  }
3120
3213
  function runRefsSingle(opts) {
3121
3214
  const { file, symbol } = parseReadSpec(opts.spec);
3122
3215
  const qualified = resolveQualifiedSpec(opts.spec, opts.projectRoot ?? process.cwd());
3123
3216
  if (qualified?.kind === "ambiguous") {
3124
- emitErr(formatAmbiguity(qualified.symbol, qualified.file, qualified.candidates, opts.projectRoot, "refs"));
3217
+ emitErr(formatCommandError(new CliError(formatAmbiguity(qualified.symbol, qualified.file, qualified.candidates, opts.projectRoot, "refs").split("\n"))));
3125
3218
  return 1;
3126
3219
  }
3127
3220
  const qualifiedDef = qualified?.kind === "ok" ? qualified.entry : void 0;
@@ -3137,29 +3230,29 @@ function runRefsSingle(opts) {
3137
3230
  return 0;
3138
3231
  }
3139
3232
  if (opts.excludeTests === true && suppressed > 0) {
3140
- emitErr(`No non-test references found for '${symName}' (${excludeTestsHiddenNote(suppressed)})`);
3233
+ emitErr(formatCommandError(`No non-test references found for ${echoedValue(symName)} (${excludeTestsHiddenNote(suppressed)})`));
3141
3234
  return 1;
3142
3235
  }
3143
3236
  const rootDir = opts.projectRoot ?? resolveProjectRoot({ project: process.cwd() });
3144
3237
  const defRows = querySymbols({ name: symName, rootDir, limit: REF_BLIND_DEF_PROBE_LIMIT });
3145
3238
  if (defRows.length === 0) {
3146
- emitErr(`Symbol not found: ${symName}${unknownSymbolSuggestion(symName, rootDir)}`);
3239
+ emitErr(formatCommandError(`Symbol not found: ${echoedValue(symName)}${unknownSymbolSuggestion(symName, rootDir)}`));
3147
3240
  if (opts.json !== true && isIndexEmptyForProject(globalDbPath(), rootDir)) emitErr(emptyIndexMessage(rootDir));
3148
3241
  return 1;
3149
3242
  }
3150
3243
  const defPaths = defFileHint !== void 0 ? [defFileHint] : defRows.map((r) => r.filePath);
3151
3244
  const firstDefPath = defPaths[0];
3152
3245
  if (firstDefPath !== void 0 && defPaths.every((fp) => !isRefIndexedFile(fp))) {
3153
- emitErr(refBlindLanguageNotice(symName, detectLanguageOfFile(firstDefPath), refsDisplayPath(firstDefPath)));
3246
+ emitErr(formatCommandError(refBlindLanguageNotice(symName, detectLanguageOfFile(firstDefPath), refsDisplayPath(firstDefPath))));
3154
3247
  return 1;
3155
3248
  }
3156
3249
  const kindRows = defFileHint !== void 0 ? querySymbols({ name: symName, filePath: defFileHint, rootDir, limit: REF_BLIND_DEF_PROBE_LIMIT }) : defRows;
3157
3250
  const kindVerdict = refBlindKindVerdict(kindRows);
3158
3251
  if (kindVerdict.allBlind) {
3159
- emitErr(refBlindKindNotice(symName, kindVerdict.blindKinds));
3252
+ emitErr(formatCommandError(refBlindKindNotice(symName, kindVerdict.blindKinds)));
3160
3253
  return 1;
3161
3254
  }
3162
- emitErr(`No references found for '${symName}'`);
3255
+ emitErr(formatCommandError(`No references found for ${echoedValue(symName)}`));
3163
3256
  if (kindVerdict.blindCount > 0) emitErr(refBlindKindPartialNote(symName, kindVerdict.blindKinds, kindVerdict.blindCount, kindRows.length));
3164
3257
  if (opts.json !== true) {
3165
3258
  if (isIndexEmptyForProject(globalDbPath(), rootDir)) emitErr(emptyIndexMessage(rootDir));
@@ -3208,7 +3301,7 @@ function renderTopFilesSummary(refs, topN, suppressed) {
3208
3301
  const omittedFiles = grouped.length - shown.length;
3209
3302
  if (omittedFiles > 0) {
3210
3303
  const shownRefs = shown.reduce((sum, g) => sum + g.count, 0);
3211
- lines.push(` ...(${omittedFiles} more files, ${refs.length - shownRefs} more references elided; use a higher --top to see more)`);
3304
+ lines.push(forClient(` ...(${countNoun(omittedFiles, "more file")}, ${countNoun(refs.length - shownRefs, "more reference")} elided; use a higher --top to see more)`));
3212
3305
  }
3213
3306
  return lines;
3214
3307
  }
@@ -3234,7 +3327,7 @@ function renderCallerGroups(refs, contextLines = 0) {
3234
3327
  for (const ref of fileRefs) {
3235
3328
  lines.push(` :${ref.line} ${ref.context !== "" ? displaySafeText(ref.context) : "(module scope)"}`);
3236
3329
  const window = buildContextWindow(file, ref.line, contextLines);
3237
- if (window !== null) lines.push(...renderContextWindow(displayPath, ref.line, window, "", " "));
3330
+ if (window !== null) lines.push(...renderContextWindow(displaySafeText(displayPath), ref.line, window, "", " "));
3238
3331
  }
3239
3332
  }
3240
3333
  return lines;
@@ -3242,7 +3335,7 @@ function renderCallerGroups(refs, contextLines = 0) {
3242
3335
 
3243
3336
  // src/read_git.ts
3244
3337
  init_define_import_meta_env();
3245
- import * as fs3 from "node:fs";
3338
+ import * as fs4 from "node:fs";
3246
3339
  import * as path3 from "node:path";
3247
3340
 
3248
3341
  // src/conflict_query.ts
@@ -3445,9 +3538,9 @@ function runConflicts(opts) {
3445
3538
  const abs = path3.resolve(opts.path);
3446
3539
  let stat;
3447
3540
  try {
3448
- stat = fs3.statSync(abs);
3541
+ stat = fs4.statSync(abs);
3449
3542
  } catch {
3450
- emitErr(`Could not read: ${opts.path}`);
3543
+ emitErr(formatCommandError(couldNotReadError(opts.path)));
3451
3544
  return 1;
3452
3545
  }
3453
3546
  files = stat.isDirectory() ? walkProject(abs).files : [abs];
@@ -3566,6 +3659,21 @@ function parseHunklessFiles(diffText) {
3566
3659
  return hunkless;
3567
3660
  }
3568
3661
  var EMPTY_TREE_HASH = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";
3662
+ var CHANGED_HINT_BATCH = 512;
3663
+ function batchRowResolved(row) {
3664
+ return row !== void 0 && /^[0-9a-f]{40,64} /.test(row);
3665
+ }
3666
+ function resolveHintRefs(cwd, ref, candidates) {
3667
+ const batch = runGit(["cat-file", "--batch-check"], { cwd, input: `${[ref, ...candidates].join("\n")}
3668
+ ` });
3669
+ const rows = batch.stdout.split(/\r?\n/);
3670
+ if (batch.exitCode === 0 && rows.length >= candidates.length + 1) {
3671
+ return { refResolves: batchRowResolved(rows[0]), suggestedRef: candidates.find((_, i) => batchRowResolved(rows[i + 1])) ?? null };
3672
+ }
3673
+ const resolves = (name) => runGit(["rev-parse", "--verify", "--quiet", name], { cwd }).exitCode === 0;
3674
+ if (resolves(ref)) return { refResolves: true, suggestedRef: null };
3675
+ return { refResolves: false, suggestedRef: candidates.find((c) => resolves(c)) ?? null };
3676
+ }
3569
3677
  function buildChangedRefHint(cwd, ref) {
3570
3678
  const countResult = runGit(["rev-list", "--count", "HEAD"], { cwd });
3571
3679
  if (countResult.exitCode !== 0) {
@@ -3575,61 +3683,67 @@ function buildChangedRefHint(cwd, ref) {
3575
3683
  if (!Number.isFinite(commitCount) || commitCount < 1) {
3576
3684
  return null;
3577
3685
  }
3578
- const refResolves = runGit(["rev-parse", "--verify", "--quiet", ref], { cwd });
3579
- if (refResolves.exitCode === 0) {
3686
+ if (/[\r\n]/.test(ref)) {
3580
3687
  return null;
3581
3688
  }
3582
- let suggestedRef = null;
3583
- for (let n = commitCount - 1; n >= 1; n--) {
3584
- const candidate = `HEAD~${n}`;
3585
- const candidateResolves = runGit(["rev-parse", "--verify", "--quiet", candidate], { cwd });
3586
- if (candidateResolves.exitCode === 0) {
3587
- suggestedRef = candidate;
3588
- break;
3589
- }
3689
+ const candidates = [];
3690
+ for (let n = commitCount - 1; n >= 1 && candidates.length < CHANGED_HINT_BATCH; n--) {
3691
+ candidates.push(`HEAD~${n}`);
3590
3692
  }
3693
+ const answer = resolveHintRefs(cwd, ref, candidates);
3694
+ if (answer.refResolves) {
3695
+ return null;
3696
+ }
3697
+ let suggestedRef = answer.suggestedRef;
3591
3698
  if (suggestedRef === null) {
3592
3699
  suggestedRef = EMPTY_TREE_HASH;
3593
3700
  }
3594
3701
  const commitWord = commitCount === 1 ? "1 commit" : `${commitCount} commits`;
3595
- return `Hint: this repo has only ${commitWord}; '${ref}' does not exist. Try: token-goat changed --since ${suggestedRef}`;
3702
+ return `Hint: this repo has only ${commitWord}; ${echoedValue(ref)} does not exist. Try: token-goat changed --since ${suggestedRef}`;
3596
3703
  }
3597
3704
  function refIsSafe(ref) {
3598
3705
  return !ref.startsWith("-");
3599
3706
  }
3600
3707
  function emitUnsafeRef(ref) {
3601
- emitErr(`Refusing a git ref that starts with '-': ${ref}`);
3708
+ emitErr(formatCommandError(`Refusing a git ref that starts with '-': ${ref}`));
3602
3709
  }
3603
3710
  function literalPathspec(file) {
3604
3711
  return `:(literal)${file}`;
3605
3712
  }
3606
- function withRenameSources(cwd, ref, files) {
3607
- const wanted = new Set(files);
3713
+ function parseNameStatus(stdout) {
3714
+ const unquote = (f) => f.startsWith('"') && f.endsWith('"') && f.length > 1 ? unquoteGitPath(f.slice(1, -1)) : f;
3715
+ const files = [];
3716
+ const renamedFrom = /* @__PURE__ */ new Map();
3717
+ for (const row of stdout.split(/\r?\n/)) {
3718
+ if (row === "") continue;
3719
+ const cols = row.split(" ");
3720
+ const last = cols[cols.length - 1];
3721
+ if (cols.length < 2 || last === void 0 || last === "") continue;
3722
+ files.push(unquote(last));
3723
+ const from = cols[1];
3724
+ if (cols[0]?.startsWith("R") === true && cols.length === 3 && from !== void 0) renamedFrom.set(unquote(last), unquote(from));
3725
+ }
3726
+ return { files, renamedFrom };
3727
+ }
3728
+ function withRenameSources(files, renamedFrom) {
3608
3729
  const paths = [...files];
3609
- try {
3610
- const result = runGit(["diff", ref, "--name-status", "-M"], { cwd });
3611
- if (result.exitCode !== 0) return paths;
3612
- const unquote = (f) => f.startsWith('"') && f.endsWith('"') && f.length > 1 ? unquoteGitPath(f.slice(1, -1)) : f;
3613
- for (const row of result.stdout.split(/\r?\n/)) {
3614
- const [status, from, to] = row.split(" ");
3615
- if (status?.startsWith("R") !== true || from === void 0 || to === void 0) continue;
3616
- if (wanted.has(unquote(to))) paths.push(unquote(from));
3617
- }
3618
- } catch {
3730
+ for (const file of files) {
3731
+ const from = renamedFrom.get(file);
3732
+ if (from !== void 0) paths.push(from);
3619
3733
  }
3620
3734
  return paths;
3621
3735
  }
3622
- function unifiedDiffOf(cwd, ref, files, extraArgs = []) {
3736
+ function unifiedDiffOf(cwd, ref, files, renamedFrom, extraArgs = []) {
3623
3737
  const run = (paths2) => runGit(["diff", ref, "-M", "--unified=0", ...extraArgs, "--", ...paths2.map(literalPathspec)], { cwd });
3624
3738
  const first = run(files);
3625
3739
  if (first.exitCode !== 0 || !first.stdout.includes("--- /dev/null")) return first;
3626
- const paths = withRenameSources(cwd, ref, files);
3740
+ const paths = withRenameSources(files, renamedFrom);
3627
3741
  return paths.length > files.length ? run(paths) : first;
3628
3742
  }
3629
- function changedDiffBaselineBytes(cwd, ref, files) {
3743
+ function changedDiffBaselineBytes(cwd, ref, files, renamedFrom) {
3630
3744
  if (files.length === 0) return 0;
3631
3745
  try {
3632
- const result = unifiedDiffOf(cwd, ref, files);
3746
+ const result = unifiedDiffOf(cwd, ref, files, renamedFrom);
3633
3747
  if (result.exitCode === 0) return deliveredOutputBytes(Buffer.byteLength(result.stdout, "utf8"));
3634
3748
  } catch {
3635
3749
  }
@@ -3643,25 +3757,27 @@ function runChanged(opts = {}) {
3643
3757
  }
3644
3758
  const projectDenial = opts.symbolMode === true ? resolveProjectConfinement(opts.projectRoot).denial : null;
3645
3759
  if (projectDenial !== null) {
3646
- emitErr(projectDenial);
3760
+ emitErr(formatCommandError(projectDenial));
3647
3761
  return 1;
3648
3762
  }
3649
3763
  const cwd = opts.projectRoot ?? process.cwd();
3650
- const projectRoot = resolveProjectRoot({ project: cwd });
3651
3764
  let changedFiles;
3765
+ let renamedFrom;
3652
3766
  try {
3653
- const result = runGit(["diff", ref, "--name-only"], { cwd });
3767
+ const result = runGit(["diff", ref, "--name-status"], { cwd });
3654
3768
  if (result.exitCode !== 0) {
3655
- emitErr(`git diff failed: ${result.stderr}`);
3769
+ emitErr(formatGitFailure("diff", result.stderr));
3656
3770
  const hint = buildChangedRefHint(cwd, ref);
3657
3771
  if (hint !== null) {
3658
- emitErr(hint);
3772
+ emitErr(formatCommandError(hint));
3659
3773
  }
3660
3774
  return 1;
3661
3775
  }
3662
- changedFiles = result.stdout.trim().split(/\r?\n/).filter(Boolean).map((f) => f.startsWith('"') && f.endsWith('"') && f.length > 1 ? unquoteGitPath(f.slice(1, -1)) : f);
3776
+ const listing = parseNameStatus(result.stdout);
3777
+ changedFiles = listing.files;
3778
+ renamedFrom = listing.renamedFrom;
3663
3779
  } catch {
3664
- emitErr(`Could not run git diff against '${ref}'`);
3780
+ emitErr(formatCommandError(`Could not run git diff against ${echoedValue(ref)}`));
3665
3781
  return 1;
3666
3782
  }
3667
3783
  const emptyEnvelope = () => {
@@ -3693,19 +3809,20 @@ function runChanged(opts = {}) {
3693
3809
  const grepRemoved = preGrepFileCount - postGrepFileCount;
3694
3810
  if (matchesGrep !== void 0 && grepRemoved > 0) {
3695
3811
  emit(
3696
- `No non-test files matched --grep ${opts.grep ?? ""} (${excludeTestsHiddenNote(hiddenTestFiles)}; ${countNoun(grepRemoved, "other changed file")} did not match the filter)`
3812
+ `No non-test files matched --grep ${displaySafeText(opts.grep ?? "")} (${excludeTestsHiddenNote(hiddenTestFiles)}; ${countNoun(grepRemoved, "other changed file")} did not match the filter)`
3697
3813
  );
3698
3814
  return 0;
3699
3815
  }
3700
3816
  emit(`No non-test files changed (${excludeTestsHiddenNote(hiddenTestFiles)})`);
3701
3817
  return 0;
3702
3818
  }
3819
+ const projectRoot = opts.projectRootResolved === true ? cwd : resolveProjectRoot({ project: cwd });
3703
3820
  if (opts.symbolMode === true) {
3704
3821
  let hunksByFile = /* @__PURE__ */ new Map();
3705
3822
  let hunklessFiles = /* @__PURE__ */ new Set();
3706
3823
  let symbolDiffBaselineBytes = 0;
3707
3824
  try {
3708
- const diffResult = unifiedDiffOf(projectRoot, ref, changedFiles, ["--src-prefix=a/", "--dst-prefix=b/"]);
3825
+ const diffResult = unifiedDiffOf(projectRoot, ref, changedFiles, renamedFrom, ["--src-prefix=a/", "--dst-prefix=b/"]);
3709
3826
  if (diffResult.exitCode === 0) {
3710
3827
  hunksByFile = parseDiffHunks(diffResult.stdout);
3711
3828
  hunklessFiles = parseHunklessFiles(diffResult.stdout);
@@ -3741,7 +3858,7 @@ function runChanged(opts = {}) {
3741
3858
  recordReadStat("changed_lookup", symbolFullBytes, symbolText, ref);
3742
3859
  return 0;
3743
3860
  }
3744
- const fullBytes = changedDiffBaselineBytes(projectRoot, ref, changedFiles);
3861
+ const fullBytes = changedDiffBaselineBytes(projectRoot, ref, changedFiles, renamedFrom);
3745
3862
  if (opts.json === true) {
3746
3863
  const capped = guardJsonRows(changedFiles);
3747
3864
  const text = displaySafeJson({ items: capped.items, truncated: capped.truncated, totalCount: capped.totalCount });
@@ -3800,22 +3917,22 @@ function runDiff(opts) {
3800
3917
  try {
3801
3918
  diffResult = runGit(diffArgs, { cwd });
3802
3919
  } catch {
3803
- emitErr(`Could not run git diff for '${match.filePath}'`);
3920
+ emitErr(formatCommandError(`Could not run git diff for ${echoedValue(match.filePath)}`));
3804
3921
  return 1;
3805
3922
  }
3806
3923
  if (diffResult.exitCode !== 0) {
3807
- emitErr(`git diff failed: ${diffResult.stderr}`);
3924
+ emitErr(formatGitFailure("diff", diffResult.stderr));
3808
3925
  return 1;
3809
3926
  }
3810
3927
  if (diffResult.stdout.trim() === "") {
3811
- emit(`No changes to '${displaySafeText(match.name)}' in '${displaySafeText(toDisplayPath(getDisplayRoot(opts.projectRoot), match.filePath))}'.`);
3928
+ emit(`No changes to ${echoedValue(match.name)} in ${echoedValue(toDisplayPath(getDisplayRoot(opts.projectRoot), match.filePath))}.`);
3812
3929
  return 0;
3813
3930
  }
3814
3931
  const { hunks } = splitDiffHunks(diffResult.stdout);
3815
3932
  const diffFileScoped = isVirtualIndexedPath(match.filePath);
3816
3933
  const overlapping = diffFileScoped ? hunks : hunks.filter((h) => h.start <= match.lineEnd && h.end >= match.lineStart);
3817
3934
  if (overlapping.length === 0) {
3818
- emit(`No changes to '${displaySafeText(match.name)}' (lines ${match.lineStart}-${match.lineEnd}) in '${displaySafeText(toDisplayPath(getDisplayRoot(opts.projectRoot), match.filePath))}'.`);
3935
+ emit(`No changes to ${echoedValue(match.name)} (lines ${match.lineStart}-${match.lineEnd}) in ${echoedValue(toDisplayPath(getDisplayRoot(opts.projectRoot), match.filePath))}.`);
3819
3936
  return 0;
3820
3937
  }
3821
3938
  if (opts.json === true) {
@@ -3898,15 +4015,15 @@ function runLog(opts) {
3898
4015
  try {
3899
4016
  logResult = runGit(logArgs, { cwd });
3900
4017
  } catch {
3901
- emitErr(`Could not run git log for '${match.filePath}'`);
4018
+ emitErr(formatCommandError(`Could not run git log for ${echoedValue(match.filePath)}`));
3902
4019
  return 1;
3903
4020
  }
3904
4021
  if (logResult.exitCode !== 0) {
3905
- emitErr(`git log failed: ${displaySafeText(logResult.stderr)}`);
4022
+ emitErr(formatGitFailure("log", logResult.stderr));
3906
4023
  return 1;
3907
4024
  }
3908
4025
  if (logResult.stdout.trim() === "") {
3909
- emit(`No history for '${displaySafeText(match.name)}' (lines ${match.lineStart}-${match.lineEnd}) in '${displaySafeText(toDisplayPath(getDisplayRoot(opts.projectRoot), match.filePath))}'.`);
4026
+ emit(`No history for ${echoedValue(match.name)} (lines ${match.lineStart}-${match.lineEnd}) in ${echoedValue(toDisplayPath(getDisplayRoot(opts.projectRoot), match.filePath))}.`);
3910
4027
  return 0;
3911
4028
  }
3912
4029
  if (opts.json === true) {
@@ -3934,14 +4051,14 @@ function runLog(opts) {
3934
4051
 
3935
4052
  // src/handle_stat.ts
3936
4053
  init_define_import_meta_env();
3937
- import * as fs4 from "node:fs";
3938
- var OPEN_FOR_STAT = process.platform === "win32" ? fs4.constants.O_RDONLY : fs4.constants.O_RDONLY | fs4.constants.O_NONBLOCK;
4054
+ import * as fs5 from "node:fs";
4055
+ var OPEN_FOR_STAT = process.platform === "win32" ? fs5.constants.O_RDONLY : fs5.constants.O_RDONLY | fs5.constants.O_NONBLOCK;
3939
4056
  function statThroughHandle(p) {
3940
- const fd = fs4.openSync(p, OPEN_FOR_STAT);
4057
+ const fd = fs5.openSync(p, OPEN_FOR_STAT);
3941
4058
  try {
3942
- return fs4.fstatSync(fd, { bigint: true });
4059
+ return fs5.fstatSync(fd, { bigint: true });
3943
4060
  } finally {
3944
- fs4.closeSync(fd);
4061
+ fs5.closeSync(fd);
3945
4062
  }
3946
4063
  }
3947
4064
 
@@ -4040,8 +4157,7 @@ function createHandoff(name, text, projectRoot) {
4040
4157
  name,
4041
4158
  projectRoot: root,
4042
4159
  contentId: contentIdValue,
4043
- // Keep the handoff independently resolvable if the generic content entry
4044
- // is later evicted from the shared bounded cache.
4160
+ // Keep the handoff independently resolvable if the generic content entry is later evicted from the shared bounded cache.
4045
4161
  text: safeText,
4046
4162
  createdAt: Date.now()
4047
4163
  };
@@ -4052,7 +4168,7 @@ function createHandoff(name, text, projectRoot) {
4052
4168
  });
4053
4169
  if (!ok) throw new Error("unable to persist handoff within the local cache bounds");
4054
4170
  recordStat("handoff_create");
4055
- return { id, name, contentId: contentIdValue, projectRoot: root, recovery: `token-goat handoff-resolve ${name}` };
4171
+ return { id, name, contentId: contentIdValue, projectRoot: root, recovery: `token-goat handoff-resolve -- ${quotedArg(name)}` };
4056
4172
  }
4057
4173
  function resolveHandoff(name, opts = {}) {
4058
4174
  const root = normalizeProjectRoot(opts.projectRoot);
@@ -4077,6 +4193,9 @@ export {
4077
4193
  checkSemanticReadiness,
4078
4194
  offlineEmbedNotice,
4079
4195
  mergeNearbyHits,
4196
+ assessDenseRelevance,
4197
+ floorEmptiedPhrase,
4198
+ weakMatchPhrase,
4080
4199
  runSymbol,
4081
4200
  runBrief,
4082
4201
  AMBIGUOUS_HEADING_LIMIT,