token-goat 2.9.29 → 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 (197) hide show
  1. package/README.md +53 -42
  2. package/SECURITY.md +37 -11
  3. package/THIRD_PARTY_NOTICES.md +41 -4
  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/ort-wasm-simd-threaded.mjs +59 -0
  9. package/dist/{token-goat-chunk-SE6E4BKJ.mjs → token-goat-chunk-25TRAWET.mjs} +23 -6
  10. package/dist/token-goat-chunk-2KXO6V2B.mjs +203 -0
  11. package/dist/{token-goat-chunk-UXSXQQIY.mjs → token-goat-chunk-2M7E4PF7.mjs} +43 -14
  12. package/dist/token-goat-chunk-2UPZGKKY.mjs +188 -0
  13. package/dist/token-goat-chunk-2WLPWKHV.mjs +135 -0
  14. package/dist/token-goat-chunk-2XBMMDBD.mjs +126 -0
  15. package/dist/token-goat-chunk-32ZOY4N5.mjs +23 -0
  16. package/dist/token-goat-chunk-3EZRNKTK.mjs +188 -0
  17. package/dist/token-goat-chunk-4ADZHI7J.mjs +63 -0
  18. package/dist/token-goat-chunk-4GBVPH3D.mjs +242 -0
  19. package/dist/{token-goat-chunk-2WOUYWLM.mjs → token-goat-chunk-4GILLLWY.mjs} +34 -7
  20. package/dist/token-goat-chunk-4NAPX7BA.mjs +90 -0
  21. package/dist/{token-goat-chunk-NMBWLRHW.mjs → token-goat-chunk-4SC7UJYV.mjs} +9981 -11563
  22. package/dist/token-goat-chunk-4SMRO4TO.mjs +366 -0
  23. package/dist/{token-goat-chunk-O6I2XU4P.mjs → token-goat-chunk-4ZBFWLXF.mjs} +310 -441
  24. package/dist/token-goat-chunk-57BIAXJL.mjs +286 -0
  25. package/dist/token-goat-chunk-5AC66HNP.mjs +115 -0
  26. package/dist/token-goat-chunk-5IMLKSOP.mjs +145 -0
  27. package/dist/token-goat-chunk-5RG5SBL6.mjs +221 -0
  28. package/dist/{token-goat-chunk-RRNZMM3A.mjs → token-goat-chunk-5Y6ZYL6U.mjs} +21 -2
  29. package/dist/token-goat-chunk-646E6U44.mjs +398 -0
  30. package/dist/token-goat-chunk-65N4RHP4.mjs +33 -0
  31. package/dist/{token-goat-chunk-6AK46ZT7.mjs → token-goat-chunk-6DG6HWP3.mjs} +13 -3
  32. package/dist/token-goat-chunk-6ENQSNRZ.mjs +573 -0
  33. package/dist/token-goat-chunk-6ZY4GNF2.mjs +91 -0
  34. package/dist/{token-goat-chunk-E5TK5DNO.mjs → token-goat-chunk-76FGDLRO.mjs} +574 -340
  35. package/dist/{token-goat-chunk-TGOXNAHW.mjs → token-goat-chunk-7EZTZOMC.mjs} +780 -767
  36. package/dist/token-goat-chunk-7MAOA6X4.mjs +3647 -0
  37. package/dist/token-goat-chunk-7R2ZVVAX.mjs +218 -0
  38. package/dist/{token-goat-chunk-TCQANXYC.mjs → token-goat-chunk-AM5V6GSX.mjs} +18 -2
  39. package/dist/token-goat-chunk-AUNGYYQX.mjs +184 -0
  40. package/dist/token-goat-chunk-AUQYRMMH.mjs +2985 -0
  41. package/dist/token-goat-chunk-B3PEKBYG.mjs +128 -0
  42. package/dist/{token-goat-chunk-KOPIR3KZ.mjs → token-goat-chunk-BA4HI6BW.mjs} +1910 -165
  43. package/dist/{token-goat-chunk-52NSDWYY.mjs → token-goat-chunk-BFCWY73P.mjs} +58 -20
  44. package/dist/token-goat-chunk-BPGCUMR7.mjs +30 -0
  45. package/dist/token-goat-chunk-BWGFUZZE.mjs +25 -0
  46. package/dist/token-goat-chunk-C75NA7PL.mjs +322 -0
  47. package/dist/token-goat-chunk-CBIQ7WTD.mjs +87 -0
  48. package/dist/token-goat-chunk-CETM74KC.mjs +307 -0
  49. package/dist/token-goat-chunk-CIMQ2BB3.mjs +233 -0
  50. package/dist/{token-goat-chunk-DNSPXQXQ.mjs → token-goat-chunk-CJLS3CDL.mjs} +70 -18
  51. package/dist/{token-goat-chunk-MELOKFDJ.mjs → token-goat-chunk-CO3UYX6G.mjs} +7 -1
  52. package/dist/token-goat-chunk-COPNXRJM.mjs +154 -0
  53. package/dist/token-goat-chunk-CSJ5L3NL.mjs +479 -0
  54. package/dist/token-goat-chunk-CVCEVUGK.mjs +315 -0
  55. package/dist/token-goat-chunk-CXHOFN7R.mjs +371 -0
  56. package/dist/token-goat-chunk-D735C4QM.mjs +603 -0
  57. package/dist/{token-goat-chunk-E4ZOJIZK.mjs → token-goat-chunk-DGS2LVNA.mjs} +70 -160
  58. package/dist/{token-goat-chunk-L7H3U27L.mjs → token-goat-chunk-DOWRSMWO.mjs} +1 -1
  59. package/dist/token-goat-chunk-E45INMY3.mjs +71 -0
  60. package/dist/token-goat-chunk-EC5F37F4.mjs +244 -0
  61. package/dist/{token-goat-chunk-XTQAOTSO.mjs → token-goat-chunk-EDBDRVH5.mjs} +4 -1
  62. package/dist/token-goat-chunk-EELTBKDM.mjs +613 -0
  63. package/dist/token-goat-chunk-EVMZJ27Z.mjs +147 -0
  64. package/dist/token-goat-chunk-EXKGNHEG.mjs +2096 -0
  65. package/dist/{token-goat-chunk-YOOVFPTP.mjs → token-goat-chunk-F4HYL64R.mjs} +12 -2
  66. package/dist/token-goat-chunk-F6PAUIEK.mjs +624 -0
  67. package/dist/token-goat-chunk-FDSREWLX.mjs +692 -0
  68. package/dist/{token-goat-chunk-NMTKNYGF.mjs → token-goat-chunk-FNFBKLRD.mjs} +74 -9
  69. package/dist/token-goat-chunk-G5PJ7AGM.mjs +36 -0
  70. package/dist/token-goat-chunk-GGGG7RWB.mjs +236 -0
  71. package/dist/{token-goat-chunk-TDUT2CL6.mjs → token-goat-chunk-GL3ETKSC.mjs} +276 -19
  72. package/dist/{token-goat-chunk-7CPMDFGB.mjs → token-goat-chunk-GVB2MUST.mjs} +265 -1567
  73. package/dist/token-goat-chunk-GWFLAUMQ.mjs +307 -0
  74. package/dist/token-goat-chunk-HAVAOB3S.mjs +87 -0
  75. package/dist/token-goat-chunk-HLPW63A7.mjs +48 -0
  76. package/dist/token-goat-chunk-HU4TORC5.mjs +1377 -0
  77. package/dist/token-goat-chunk-I7VKZZAW.mjs +35 -0
  78. package/dist/token-goat-chunk-IA6XSPE3.mjs +218 -0
  79. package/dist/token-goat-chunk-IAGXMHIK.mjs +863 -0
  80. package/dist/{token-goat-chunk-435UQTKD.mjs → token-goat-chunk-IK2DRMFX.mjs} +129 -74
  81. package/dist/{token-goat-chunk-ZER6EAXZ.mjs → token-goat-chunk-INNPTRUX.mjs} +2954 -2783
  82. package/dist/token-goat-chunk-JJ5BX4F4.mjs +129 -0
  83. package/dist/token-goat-chunk-JVFSHVFJ.mjs +129 -0
  84. package/dist/token-goat-chunk-KGEFFSHD.mjs +50 -0
  85. package/dist/token-goat-chunk-KKUFXAPD.mjs +25 -0
  86. package/dist/token-goat-chunk-KQBLRPBN.mjs +433 -0
  87. package/dist/token-goat-chunk-LCNQ2CNN.mjs +497 -0
  88. package/dist/token-goat-chunk-M3LFJDPU.mjs +58 -0
  89. package/dist/token-goat-chunk-M52KPT3C.mjs +87 -0
  90. package/dist/token-goat-chunk-MBEG42H7.mjs +150 -0
  91. package/dist/{token-goat-chunk-EVC4TOLE.mjs → token-goat-chunk-METECDOH.mjs} +3 -12
  92. package/dist/{token-goat-chunk-2AWQ2R5X.mjs → token-goat-chunk-MHX7XCC3.mjs} +3 -2
  93. package/dist/token-goat-chunk-MNWKPRAL.mjs +13 -0
  94. package/dist/token-goat-chunk-N5LSOVSU.mjs +137 -0
  95. package/dist/{token-goat-chunk-DPNLUJWB.mjs → token-goat-chunk-N5MMR2IW.mjs} +30 -8
  96. package/dist/token-goat-chunk-N7B3JQ2C.mjs +160 -0
  97. package/dist/{token-goat-chunk-VMFWNHGR.mjs → token-goat-chunk-NISNMD7T.mjs} +2545 -2953
  98. package/dist/token-goat-chunk-NMD42SFQ.mjs +434 -0
  99. package/dist/token-goat-chunk-NOSS5VWY.mjs +174 -0
  100. package/dist/token-goat-chunk-NSNSPPBG.mjs +69 -0
  101. package/dist/token-goat-chunk-OBOFIHKN.mjs +38 -0
  102. package/dist/token-goat-chunk-OBRFJ5O5.mjs +76 -0
  103. package/dist/token-goat-chunk-ODBT2USM.mjs +800 -0
  104. package/dist/token-goat-chunk-OS5EM5PP.mjs +107 -0
  105. package/dist/token-goat-chunk-OUKDTVNU.mjs +1178 -0
  106. package/dist/token-goat-chunk-OXFMP75N.mjs +566 -0
  107. package/dist/{token-goat-chunk-ASLWOQ3I.mjs → token-goat-chunk-OYIYKDDT.mjs} +2 -1
  108. package/dist/{token-goat-chunk-67BNIKKO.mjs → token-goat-chunk-P6HQSWQ3.mjs} +55 -47
  109. package/dist/token-goat-chunk-P6VGNTQT.mjs +71 -0
  110. package/dist/token-goat-chunk-PFWIMH2E.mjs +261 -0
  111. package/dist/token-goat-chunk-PJZXIS3G.mjs +39 -0
  112. package/dist/token-goat-chunk-PUO5INXP.mjs +606 -0
  113. package/dist/token-goat-chunk-PX5PQWTY.mjs +462 -0
  114. package/dist/token-goat-chunk-Q5QDBC6O.mjs +111 -0
  115. package/dist/token-goat-chunk-QFNQXSDT.mjs +40 -0
  116. package/dist/token-goat-chunk-QH7YVYOY.mjs +3957 -0
  117. package/dist/token-goat-chunk-QLMUHEPB.mjs +43 -0
  118. package/dist/{token-goat-chunk-PYSUADX4.mjs → token-goat-chunk-QQOJIHL3.mjs} +50 -14
  119. package/dist/token-goat-chunk-QQTWJY2O.mjs +85 -0
  120. package/dist/token-goat-chunk-QYHO5CPH.mjs +93 -0
  121. package/dist/token-goat-chunk-RELAVWAD.mjs +27 -0
  122. package/dist/token-goat-chunk-RSLPOBKQ.mjs +339 -0
  123. package/dist/token-goat-chunk-SAMFDIS2.mjs +712 -0
  124. package/dist/token-goat-chunk-SDELXLDM.mjs +48 -0
  125. package/dist/{token-goat-chunk-PGTH2U4C.mjs → token-goat-chunk-SOAFZNNZ.mjs} +164 -40
  126. package/dist/{token-goat-chunk-G23DWHV4.mjs → token-goat-chunk-SRTHT7KV.mjs} +33 -15
  127. package/dist/token-goat-chunk-T5P5ACNQ.mjs +212 -0
  128. package/dist/token-goat-chunk-T5YGG4V3.mjs +45 -0
  129. package/dist/token-goat-chunk-TAUZ4OFS.mjs +110 -0
  130. package/dist/token-goat-chunk-TM6MC754.mjs +40 -0
  131. package/dist/token-goat-chunk-TWUKBOMP.mjs +72 -0
  132. package/dist/token-goat-chunk-U2KSB4SG.mjs +56 -0
  133. package/dist/token-goat-chunk-U4WHMG6Y.mjs +898 -0
  134. package/dist/token-goat-chunk-UA5V6P3P.mjs +122 -0
  135. package/dist/token-goat-chunk-UGJHGR5A.mjs +52 -0
  136. package/dist/{token-goat-chunk-RQGGMPCR.mjs → token-goat-chunk-UOUDVA5U.mjs} +76 -16
  137. package/dist/{token-goat-chunk-HNFZZHFW.mjs → token-goat-chunk-URRJ33GR.mjs} +22 -4
  138. package/dist/token-goat-chunk-UZOROKIS.mjs +165 -0
  139. package/dist/token-goat-chunk-VIHGGGEI.mjs +4234 -0
  140. package/dist/token-goat-chunk-VTJLAA7P.mjs +21 -0
  141. package/dist/token-goat-chunk-VWDXLT4F.mjs +678 -0
  142. package/dist/token-goat-chunk-VWZA2H4P.mjs +368 -0
  143. package/dist/{token-goat-chunk-QO3LXVVR.mjs → token-goat-chunk-VXEXMJDL.mjs} +2964 -3153
  144. package/dist/token-goat-chunk-WBA5SKT4.mjs +547 -0
  145. package/dist/{token-goat-chunk-ONXH6NZ5.mjs → token-goat-chunk-WDH44VAU.mjs} +19 -22
  146. package/dist/token-goat-chunk-X2SUP3EI.mjs +107 -0
  147. package/dist/token-goat-chunk-X3BELZSJ.mjs +125 -0
  148. package/dist/{token-goat-chunk-RLP6J7WR.mjs → token-goat-chunk-XLRBNZCC.mjs} +40 -21
  149. package/dist/{token-goat-chunk-S4VSXURL.mjs → token-goat-chunk-XRKUX6CM.mjs} +4 -0
  150. package/dist/token-goat-chunk-XX6O25RN.mjs +82 -0
  151. package/dist/token-goat-chunk-XZSUHBVS.mjs +65 -0
  152. package/dist/token-goat-chunk-Y2ZTQOCL.mjs +35 -0
  153. package/dist/{token-goat-chunk-UA5BKWWQ.mjs → token-goat-chunk-YB4VMGK2.mjs} +15 -4
  154. package/dist/token-goat-chunk-YBIIY3HR.mjs +51 -0
  155. package/dist/{token-goat-chunk-PKRWMHVP.mjs → token-goat-chunk-YHVDKQBR.mjs} +389 -221
  156. package/dist/token-goat-chunk-YJB5XLWI.mjs +26 -0
  157. package/dist/{token-goat-chunk-PQ53BSCF.mjs → token-goat-chunk-YKB6AQG3.mjs} +53 -31
  158. package/dist/token-goat-chunk-YMTG2YA5.mjs +35 -0
  159. package/dist/token-goat-chunk-YPBZYQRV.mjs +40 -0
  160. package/dist/{token-goat-chunk-HUYUHODZ.mjs → token-goat-chunk-YY6AVUFL.mjs} +13246 -12247
  161. package/dist/token-goat-chunk-Z7N5OMMP.mjs +98 -0
  162. package/dist/{token-goat-chunk-BGHSSJUA.mjs → token-goat-chunk-ZFOBKUWH.mjs} +1 -1
  163. package/dist/token-goat-chunk-ZMBL6UVV.mjs +110 -0
  164. package/dist/token-goat-chunk-ZNMNUPAZ.mjs +938 -0
  165. package/dist/token-goat-hook-client.cjs +87 -23
  166. package/dist/token-goat-hook-client.mjs +3 -3
  167. package/dist/token-goat-hook.mjs +76 -31
  168. package/dist/token-goat.core.mjs +6 -6
  169. package/docs/C4_RUNTIME_ARCHITECTURE.md +2 -2
  170. package/docs/cli.md +113 -60
  171. package/docs/install.md +63 -20
  172. package/docs/security.md +10 -8
  173. package/package.json +18 -7
  174. package/scripts/verify-native-dist.mjs +386 -0
  175. package/dist/token-goat-chunk-2NNUA2LR.mjs +0 -143
  176. package/dist/token-goat-chunk-44BM7DDQ.mjs +0 -294
  177. package/dist/token-goat-chunk-BGYOZ6DO.mjs +0 -24
  178. package/dist/token-goat-chunk-C5YPNZKQ.mjs +0 -318
  179. package/dist/token-goat-chunk-CIQ2FTY3.mjs +0 -1990
  180. package/dist/token-goat-chunk-D4ETHJD6.mjs +0 -246
  181. package/dist/token-goat-chunk-DNRPXHYH.mjs +0 -1062
  182. package/dist/token-goat-chunk-EUSDXRXU.mjs +0 -1429
  183. package/dist/token-goat-chunk-FTP4U4QA.mjs +0 -64
  184. package/dist/token-goat-chunk-G7IWXCFF.mjs +0 -456
  185. package/dist/token-goat-chunk-GLXRTTLE.mjs +0 -36
  186. package/dist/token-goat-chunk-H5J3C56Q.mjs +0 -1511
  187. package/dist/token-goat-chunk-IVWI2OCK.mjs +0 -368
  188. package/dist/token-goat-chunk-JTKCQMQA.mjs +0 -418
  189. package/dist/token-goat-chunk-LZNBQTDK.mjs +0 -26
  190. package/dist/token-goat-chunk-ORNFMIER.mjs +0 -295
  191. package/dist/token-goat-chunk-RTMVLHWX.mjs +0 -7113
  192. package/dist/token-goat-chunk-VQ6F6T7X.mjs +0 -36
  193. package/dist/token-goat-chunk-VZQEWRVH.mjs +0 -312
  194. package/dist/token-goat-chunk-XYWPOSCN.mjs +0 -807
  195. package/dist/token-goat-chunk-YAGLESS3.mjs +0 -23
  196. package/dist/token-goat-chunk-YKSRAWUU.mjs +0 -33
  197. package/dist/token-goat-chunk-Z6KBMOBI.mjs +0 -53
@@ -0,0 +1,800 @@
1
+ import { createRequire as __cjsRequire } from 'node:module';
2
+ const require = __cjsRequire(import.meta.url);
3
+ import {
4
+ CHANGES_WHAT_RUNS_NAMES,
5
+ extractCatFile,
6
+ extractHeadFile,
7
+ extractLineRangeRead,
8
+ extractLineRangeReadsCompound,
9
+ extractTailFile,
10
+ isTscCommand,
11
+ splitShellSegments,
12
+ stripLeadingAssignments
13
+ } from "./token-goat-chunk-DGS2LVNA.mjs";
14
+ import {
15
+ detectFromCommand,
16
+ filterByName
17
+ } from "./token-goat-chunk-INNPTRUX.mjs";
18
+ import {
19
+ enqueueDirtyPathSafe,
20
+ requestReconcileSafe
21
+ } from "./token-goat-chunk-CIMQ2BB3.mjs";
22
+ import {
23
+ RECALL_DEFAULT_LIMIT,
24
+ isBuildCommand,
25
+ isTestRunnerCommand,
26
+ listRecentRecall,
27
+ parsePorcelainZ,
28
+ searchRecall
29
+ } from "./token-goat-chunk-4ZBFWLXF.mjs";
30
+ import {
31
+ fenceIfScanMatched,
32
+ fenceUntrusted
33
+ } from "./token-goat-chunk-4NAPX7BA.mjs";
34
+ import {
35
+ hasBareBackgroundOrNewline,
36
+ hasUnquotedOperator,
37
+ maskQuotedSpans,
38
+ shlexSplit
39
+ } from "./token-goat-chunk-4GILLLWY.mjs";
40
+ import {
41
+ appendWorkerErrorLog
42
+ } from "./token-goat-chunk-F6PAUIEK.mjs";
43
+ import {
44
+ shortFingerprint
45
+ } from "./token-goat-chunk-4GBVPH3D.mjs";
46
+ import {
47
+ pad,
48
+ runGit
49
+ } from "./token-goat-chunk-HU4TORC5.mjs";
50
+ import {
51
+ UNTRUSTED_TOOL_TAG,
52
+ UNTRUSTED_WEB_TAG,
53
+ displaySafeJson,
54
+ displaySafeText,
55
+ normalizePath,
56
+ resolveIndexPath
57
+ } from "./token-goat-chunk-FNFBKLRD.mjs";
58
+ import {
59
+ dataDir
60
+ } from "./token-goat-chunk-CO3UYX6G.mjs";
61
+ import {
62
+ init_define_import_meta_env
63
+ } from "./token-goat-chunk-A37V4PBF.mjs";
64
+
65
+ // src/hooks_bash_commands.ts
66
+ init_define_import_meta_env();
67
+ import { statSync } from "node:fs";
68
+ import { homedir } from "node:os";
69
+ import * as path from "node:path";
70
+
71
+ // src/cli_recall.ts
72
+ init_define_import_meta_env();
73
+ var RECALL_COMMAND = {
74
+ bash: "bash-output",
75
+ web: "web-output",
76
+ mcp: "mcp-output"
77
+ };
78
+ function fenceTagForCacheType(cacheType) {
79
+ return cacheType === "web" ? UNTRUSTED_WEB_TAG : UNTRUSTED_TOOL_TAG;
80
+ }
81
+ function fenceRecallListing(text, hits) {
82
+ const tags = new Set(hits.map((hit) => fenceTagForCacheType(hit.cacheType)));
83
+ const tag = tags.size === 1 ? [...tags][0] ?? UNTRUSTED_TOOL_TAG : UNTRUSTED_TOOL_TAG;
84
+ return fenceUntrusted(text, tag);
85
+ }
86
+ function fenceSnippetIfMatched(hit) {
87
+ return fenceIfScanMatched(hit.snippet, fenceTagForCacheType(hit.cacheType));
88
+ }
89
+ function printHits(query, hits) {
90
+ const w = (text) => {
91
+ process.stdout.write(text);
92
+ };
93
+ if (hits.length === 0) {
94
+ w(query === void 0 ? "No cache entries yet.\n" : `No cache entries match: ${query}
95
+ `);
96
+ return;
97
+ }
98
+ const body = hits.map((hit) => {
99
+ const label = hit.label.length > 80 ? hit.label.slice(0, 77) + "..." : hit.label;
100
+ const pointer = hit.blobPresent ? ` (token-goat ${RECALL_COMMAND[hit.cacheType]} ${hit.id})` : " (blob expired -- content below is all that remains)";
101
+ return `[${pad(hit.cacheType, 4)}] ${hit.id}
102
+ ${pointer}
103
+ ${label}
104
+ ${hit.snippet}
105
+ `;
106
+ }).join("\n");
107
+ w(`${fenceRecallListing(body, hits)}
108
+ `);
109
+ }
110
+ function runRecallCommand(query, opts = {}) {
111
+ const browse = query === void 0 || query.trim() === "";
112
+ const scope = {
113
+ ...opts.type !== void 0 ? { type: opts.type } : {},
114
+ ...opts.limit !== void 0 ? { limit: opts.limit } : {}
115
+ };
116
+ const effectiveLimit = opts.limit ?? RECALL_DEFAULT_LIMIT;
117
+ const fetched = browse ? listRecentRecall({ ...scope, limit: effectiveLimit + 1 }) : searchRecall(query, { ...scope, limit: effectiveLimit + 1 });
118
+ const hits = fetched.slice(0, effectiveLimit);
119
+ if (fetched.length > hits.length) {
120
+ process.stderr.write(`Showing ${hits.length} entries; more are available (raise --limit to see them).
121
+ `);
122
+ }
123
+ if (opts.json === true) {
124
+ const fenced = hits.map((hit) => ({ ...hit, snippet: fenceSnippetIfMatched(hit) }));
125
+ process.stdout.write(`${displaySafeJson(fenced, 0)}
126
+ `);
127
+ return;
128
+ }
129
+ printHits(browse ? void 0 : query, hits);
130
+ }
131
+
132
+ // src/hooks_bash_commands.ts
133
+ var CD_PREFIX_RE = /^(?:cd\s+(?:"[^"]*"|'[^']*'|\S+)[ \t]*(?:&&|;|\r?\n)\s*)+/;
134
+ var EXPORT_VALUE = String.raw`(?:[\w./:@%+,=-]*|"[^"$\`\\\r\n]*"|'[^'\r\n]*')`;
135
+ var EXPORT_NAME = String.raw`(?!(?:${CHANGES_WHAT_RUNS_NAMES})=)[A-Za-z_]\w*`;
136
+ var EXPORT_PREFIX_RE = new RegExp(String.raw`^(?:export[ \t]+${EXPORT_NAME}=${EXPORT_VALUE}(?:[ \t]+${EXPORT_NAME}=${EXPORT_VALUE})*[ \t]*(?:&&|;|\r?\n)\s*)+`);
137
+ function stripExportPrefix(cmd) {
138
+ const stripped = cmd.replace(EXPORT_PREFIX_RE, "");
139
+ return stripped.trim() || cmd;
140
+ }
141
+ function stripCdPrefix(cmd) {
142
+ const stripped = cmd.replace(CD_PREFIX_RE, "");
143
+ return stripped.trim() || cmd;
144
+ }
145
+ function stripSubshellGroup(cmd) {
146
+ const t = cmd.trim();
147
+ if (!t.startsWith("(") || t.startsWith("((") || !t.endsWith(")")) return cmd;
148
+ const masked = maskQuotedSpans(t);
149
+ let depth = 0;
150
+ for (let i = 0; i < masked.length; i++) {
151
+ if (masked[i] === "(") depth++;
152
+ else if (masked[i] === ")" && --depth === 0) return i === masked.length - 1 ? t.slice(1, -1).trim() || cmd : cmd;
153
+ }
154
+ return cmd;
155
+ }
156
+ function stripGroupAndExports(rawCmd) {
157
+ return stripExportPrefix(stripSubshellGroup(rawCmd));
158
+ }
159
+ function stripCommandPrefix(rawCmd) {
160
+ return stripLeadingAssignments(stripExportPrefix(stripCdPrefix(stripGroupAndExports(rawCmd))));
161
+ }
162
+ function stripTrailingStderrRedirect(cmd) {
163
+ const stripped = cmd.replace(/\s*2>&1\s*$/, "");
164
+ return stripped.trim() || cmd;
165
+ }
166
+ function hasTestRunScopeOrBudget(cmd) {
167
+ const hasTimeout = /(?:^|\s)(?:timeout(?:\.exe)?\s+\S+|--(?:test)?timeout(?:=|\s)\S+)/i.test(cmd);
168
+ const hasSelector = /(?:\s::\S+|\s(?:-k|-t|-run|--(?:testNamePattern|last-failed|test|project))(?:=|\s)|\b(?:tests?|spec)\S*\.(?:[cm]?[jt]sx?|py|go|rs)\b|(?:^|\s)\.\/\S+)/i.test(cmd);
169
+ return hasTimeout || hasSelector;
170
+ }
171
+ function isDirectTestRunnerCommand(cmd) {
172
+ return /^(?:pytest|(?:npx\s+)?(?:jest|vitest)|go\s+test|cargo\s+test)\b/i.test(cmd);
173
+ }
174
+ function extractCdPrefixDirs(rawCmd) {
175
+ const prefixMatch = stripGroupAndExports(rawCmd).match(CD_PREFIX_RE);
176
+ if (prefixMatch === null) return [];
177
+ const dirs = [];
178
+ const segmentPattern = /cd\s+(?:"([^"]*)"|'([^']*)'|(\S+))[ \t]*(?:&&|;|\r?\n)/g;
179
+ let match;
180
+ while ((match = segmentPattern.exec(prefixMatch[0])) !== null) {
181
+ const dir = match[1] ?? match[2] ?? (match[3] === void 0 ? void 0 : expandHomePrefix(match[3]));
182
+ if (dir !== void 0) dirs.push(dir);
183
+ }
184
+ return dirs;
185
+ }
186
+ function expandHomePrefix(word) {
187
+ return word === "~" || word.startsWith("~/") ? path.join(homedir(), word.slice(1)) : word;
188
+ }
189
+ function resolveCdHintPath(rawCmd, filePath, cwd) {
190
+ if (extractCdPrefixDirs(rawCmd).length === 0) return filePath;
191
+ return resolveIndexPath(filePath, cdPrefixCwd(rawCmd, cwd));
192
+ }
193
+ function cdPrefixCwd(rawCmd, cwd) {
194
+ let dir = cwd;
195
+ for (const target of extractCdPrefixDirs(rawCmd)) dir = resolveIndexPath(target, dir);
196
+ return dir;
197
+ }
198
+ function commandRunDir(rawCmd, cwd) {
199
+ return cwd === null && extractCdPrefixDirs(rawCmd).length === 0 ? null : cdPrefixCwd(rawCmd, cwd ?? process.cwd());
200
+ }
201
+ function bashRecallKey(cmd, runDir) {
202
+ const base = stripOutputPipeline(cmd);
203
+ return shortFingerprint(runDir === null ? base : `${normalizePath(runDir)}\0${base}`);
204
+ }
205
+ function resolveBashCall(reported, startCwd) {
206
+ const rawCmd = unwrapCompressCommand(reported) ?? reported;
207
+ return { rawCmd, cmd: stripCommandPrefix(rawCmd), runDir: commandRunDir(rawCmd, startCwd) };
208
+ }
209
+ function stripOutputPipeline(cmd) {
210
+ let base = cmd.slice(0, firstTopLevelPipe(cmd));
211
+ let prev;
212
+ do {
213
+ prev = base;
214
+ const masked = base.replace(/"((?:[^"\\]|\\.)*)"/g, (_m, inner) => '"' + " ".repeat(inner.length) + '"').replace(/'([^']*)'/g, (_m, inner) => "'" + " ".repeat(inner.length) + "'");
215
+ const newMasked = masked.replace(/\s*(?:[0-9]*>&[0-9]+|[0-9&]*>>?\s*(?:"[^"]*"|'[^']*'|[^\s|]+))\s*$/, "");
216
+ if (newMasked.length < masked.length) {
217
+ base = base.slice(0, newMasked.length);
218
+ }
219
+ } while (base !== prev);
220
+ return base.trim();
221
+ }
222
+ function firstTopLevelPipe(cmd) {
223
+ let inSingle = false;
224
+ let inDouble = false;
225
+ let cut = cmd.length;
226
+ let backslashes = 0;
227
+ for (let i = 0; i < cmd.length; i++) {
228
+ const ch = cmd[i];
229
+ if (ch === "\\") {
230
+ backslashes++;
231
+ continue;
232
+ }
233
+ const escaped = backslashes % 2 === 1;
234
+ backslashes = 0;
235
+ if (ch === "'" && !inDouble) {
236
+ if (!escaped) inSingle = !inSingle;
237
+ } else if (ch === '"' && !inSingle) {
238
+ if (!escaped) inDouble = !inDouble;
239
+ } else if (ch === "|" && !inSingle && !inDouble) {
240
+ if (cmd[i + 1] === "|") {
241
+ i++;
242
+ continue;
243
+ }
244
+ cut = i;
245
+ break;
246
+ }
247
+ }
248
+ return cut;
249
+ }
250
+ function pipelineDivergenceNote(cmd, entryCommand) {
251
+ if (entryCommand === cmd) return "";
252
+ const preview = entryCommand.length > 60 ? entryCommand.slice(0, 57).trimEnd() + "..." : entryCommand;
253
+ return " (cached from a differently-piped run, `" + displaySafeText(preview) + "` \u2014 verify it covers what you need before trusting it)";
254
+ }
255
+ function outputSlice(cmd) {
256
+ const pipe = firstTopLevelPipe(cmd);
257
+ if (pipe >= cmd.length) return { kind: "none" };
258
+ const tail = cmd.slice(pipe + 1).replace(/\s*[0-9]*>&[0-9]+\s*$/, "").trim();
259
+ const head = /^head\s+(?:-n\s*|-)(\d+)$/.exec(tail);
260
+ if (head?.[1] !== void 0) return { kind: "head", n: Number(head[1]) };
261
+ const last = /^tail\s+(?:-n\s*|-)(\d+)$/.exec(tail);
262
+ if (last?.[1] !== void 0) return { kind: "tail", n: Number(last[1]) };
263
+ const sed = /^sed\s+-n\s+'?(\d+),(\d+)p'?$/.exec(tail);
264
+ if (sed?.[1] !== void 0 && sed[2] !== void 0) return { kind: "sed", from: Number(sed[1]), to: Number(sed[2]) };
265
+ return { kind: "unknown" };
266
+ }
267
+ function cachedRunCoversCommand(cachedCommand, cmd) {
268
+ const cached = outputSlice(cachedCommand);
269
+ const wanted = outputSlice(cmd);
270
+ if (cached.kind === "unknown" || wanted.kind === "unknown") return false;
271
+ if (cached.kind === "none") return true;
272
+ if (wanted.kind === "none") return false;
273
+ if (cached.kind === "tail") return wanted.kind === "tail" && wanted.n === cached.n;
274
+ const cachedFrom = cached.kind === "head" ? 1 : cached.from;
275
+ const cachedTo = cached.kind === "head" ? cached.n : cached.to;
276
+ if (wanted.kind === "tail") return false;
277
+ const wantedFrom = wanted.kind === "head" ? 1 : wanted.from;
278
+ const wantedTo = wanted.kind === "head" ? wanted.n : wanted.to;
279
+ return cachedFrom <= wantedFrom && wantedTo <= cachedTo;
280
+ }
281
+ function extractCommand(event) {
282
+ const cmd = event.toolInput["command"];
283
+ return typeof cmd === "string" && cmd.trim() !== "" ? cmd.trim() : void 0;
284
+ }
285
+ var HEAD_MOVING_GIT_RE = /^\s*git\s+(?:checkout|switch|pull|merge|rebase|reset|cherry-pick|stash\s+branch)\b/i;
286
+ var PATH_SCOPED_CHECKOUT_RE = /^\s*git\s+checkout\s+(?:\S.*?\s)?--(?:\s|$)/i;
287
+ function isHeadMovingGitCommand(cmd) {
288
+ if (!HEAD_MOVING_GIT_RE.test(cmd)) return false;
289
+ if (PATH_SCOPED_CHECKOUT_RE.test(cmd)) return false;
290
+ return true;
291
+ }
292
+ var ORIG_HEAD_ELIGIBLE_GIT_RE = /^\s*git\s+(?:pull|merge|rebase)\b/i;
293
+ var ORIG_HEAD_REFLOG_MSG_RE = /^(merge\s|rebase\s\(|pull\s)/i;
294
+ var GIT_RESTORE_RE = /^\s*git\s+restore\b/i;
295
+ var GIT_RESTORE_STAGED_ONLY_RE = /(?:^|\s)(?:--staged|-S)(?:\s|$)/;
296
+ var GIT_STASH_REWRITE_SUBCOMMANDS = /* @__PURE__ */ new Set(["pop", "apply", "branch", "push", "save"]);
297
+ var GIT_OPTIONS_WITH_VALUE = /* @__PURE__ */ new Set(["-C", "-c", "--git-dir", "--work-tree", "--namespace", "--super-prefix", "--config-env"]);
298
+ function gitStashRewriteDir(segment, runDir) {
299
+ const tokens = safeShlexSplit(segment);
300
+ if (tokens === null) return null;
301
+ let i = 0;
302
+ while (i < tokens.length && /^[A-Za-z_][A-Za-z0-9_]*=/.test(tokens[i])) i++;
303
+ const head = tokens[i];
304
+ if (head === void 0 || path.basename(head.replace(/\\/g, "/")).replace(/\.exe$/i, "").toLowerCase() !== "git") return null;
305
+ let dir = runDir;
306
+ for (i++; i < tokens.length && tokens[i].startsWith("-"); i++) {
307
+ const t = tokens[i];
308
+ if (!GIT_OPTIONS_WITH_VALUE.has(t)) continue;
309
+ const value = tokens[++i];
310
+ if (t === "-C" && value !== void 0 && value !== "") dir = path.resolve(dir, value);
311
+ }
312
+ if (tokens[i] !== "stash") return null;
313
+ const rest = tokens.slice(i + 1);
314
+ if (rest.some((t) => t === "-h" || t === "--help")) return null;
315
+ const sub = rest[0];
316
+ return sub === void 0 || sub.startsWith("-") || GIT_STASH_REWRITE_SUBCOMMANDS.has(sub) ? dir : null;
317
+ }
318
+ var PATCH_APPLY_SEGMENT_RE = /^\s*(?:\S*[/\\])?(?:git\s+apply|patch)\b/i;
319
+ var PATCH_APPLY_INSPECT_ONLY_RE = /(?:^|\s)--(?:check|stat|numstat|summary|dry-run)(?:\s|=|$)/i;
320
+ function isFormatterWriteSegment(segment) {
321
+ return /(?:^|\s|[/\\])(?:prettier|eslint)\b/i.test(segment) && /(?:^|\s)--(?:write|fix)(?:\s|$)/i.test(segment);
322
+ }
323
+ function safeShlexSplit(segment) {
324
+ try {
325
+ return shlexSplit(segment);
326
+ } catch {
327
+ return null;
328
+ }
329
+ }
330
+ function segmentCommandIs(segment, name) {
331
+ return new RegExp("^\\s*(?:\\S*[/\\\\])?" + name + "(?:\\.exe)?\\b", "i").test(segment);
332
+ }
333
+ function extractSedInPlaceFiles(segment) {
334
+ if (!segmentCommandIs(segment, "sed")) return [];
335
+ const tokens = safeShlexSplit(segment);
336
+ if (tokens === null) return [];
337
+ const rest = tokens.slice(1);
338
+ const inPlaceIdx = rest.findIndex((t) => t === "--in-place" || t.startsWith("--in-place=") || /^-[a-zA-Z]*i/.test(t));
339
+ if (inPlaceIdx === -1) return [];
340
+ const files = [];
341
+ let scriptTaken = rest.some((t) => t === "-e" || t === "-f" || t.startsWith("--expression") || t.startsWith("--file"));
342
+ for (let i = 0; i < rest.length; i++) {
343
+ const t = rest[i];
344
+ if (i === inPlaceIdx) {
345
+ if (t === "-i" && rest[i + 1] === "") i++;
346
+ continue;
347
+ }
348
+ if (t === "-e" || t === "-f" || t === "--expression" || t === "--file") {
349
+ i++;
350
+ continue;
351
+ }
352
+ if (t.length > 1 && t.startsWith("-")) continue;
353
+ if (!scriptTaken) {
354
+ scriptTaken = true;
355
+ continue;
356
+ }
357
+ files.push(t);
358
+ }
359
+ return files;
360
+ }
361
+ function extractTeeFiles(segment) {
362
+ if (!segmentCommandIs(segment, "tee")) return [];
363
+ const tokens = safeShlexSplit(segment);
364
+ if (tokens === null) return [];
365
+ return tokens.slice(1).filter((t) => t.length > 0 && !t.startsWith("-"));
366
+ }
367
+ function extractRedirectTargets(segment) {
368
+ const targets = [];
369
+ const re = /(?:^|\s)[0-9]?>>?\s*("[^"]*"|'[^']*'|[^\s|&<>]+)/g;
370
+ let m;
371
+ while ((m = re.exec(segment)) !== null) {
372
+ const raw = m[1];
373
+ targets.push(raw.length >= 2 && (raw[0] === '"' || raw[0] === "'") ? raw.slice(1, -1) : raw);
374
+ }
375
+ return targets;
376
+ }
377
+ function extractGitRestorePathspecs(cmd) {
378
+ const m = /^\s*git\s+restore\b(.*)$/i.exec(cmd);
379
+ if (m === null) return [];
380
+ const tokens = safeShlexSplit(m[1] ?? "");
381
+ if (tokens === null) return [];
382
+ const dashDash = tokens.indexOf("--");
383
+ if (dashDash !== -1) return tokens.slice(dashDash + 1);
384
+ const specs = [];
385
+ let skipNext = false;
386
+ for (const t of tokens) {
387
+ if (skipNext) {
388
+ skipNext = false;
389
+ continue;
390
+ }
391
+ if (t === "-s" || t === "--source") {
392
+ skipNext = true;
393
+ continue;
394
+ }
395
+ if (t.startsWith("-")) continue;
396
+ specs.push(t);
397
+ }
398
+ return specs;
399
+ }
400
+ function gitRepoRootOrNull(gitDir) {
401
+ const toplevel = runGit(["rev-parse", "--show-toplevel"], { cwd: gitDir, timeoutMs: 5e3 });
402
+ return toplevel.exitCode === 0 && toplevel.stdout.trim() !== "" ? toplevel.stdout.trim() : null;
403
+ }
404
+ function reconcileIfGitTimedOut(result, gitDir, what, gitCommand) {
405
+ if (result.timedOut !== true) return;
406
+ const recorded = requestReconcileSafe(gitDir);
407
+ appendWorkerErrorLog(dataDir(), `${(/* @__PURE__ */ new Date()).toISOString()} post-bash ${what} in ${gitDir}: ${gitCommand} did not answer in time (${result.stderr.trim().slice(0, 200)}); ${recorded ? "asked the worker to reconcile the project" : "could not record a reconcile request, so the index may stay stale until the next index run"}
408
+ `);
409
+ }
410
+ function expandGitPathspecs(specs, gitDir) {
411
+ if (specs.length === 0) return [];
412
+ const listed = runGit(["ls-files", "-z", "--full-name", "--", ...specs], { cwd: gitDir, timeoutMs: 5e3 });
413
+ reconcileIfGitTimedOut(listed, gitDir, "git restore", "git ls-files");
414
+ if (listed.exitCode !== 0) return [];
415
+ const repoRoot = gitRepoRootOrNull(gitDir);
416
+ if (repoRoot === null) {
417
+ requestReconcileSafe(gitDir);
418
+ return [];
419
+ }
420
+ return listed.stdout.split("\0").filter((rel) => rel.length > 0).map((rel) => resolveIndexPath(rel, repoRoot));
421
+ }
422
+ var STATUS_SWEEP_CAP = 2e3;
423
+ function workingTreeStatusPaths(gitDir) {
424
+ const status = runGit(["status", "--porcelain", "-z", "--untracked-files=all"], { cwd: gitDir, timeoutMs: 5e3 });
425
+ reconcileIfGitTimedOut(status, gitDir, "status sweep", "git status");
426
+ const stamp = `${(/* @__PURE__ */ new Date()).toISOString()} post-bash status sweep in ${gitDir}`;
427
+ if (status.exitCode === -1 && status.timedOut !== true && /ENOBUFS/.test(status.stderr)) {
428
+ const recorded2 = requestReconcileSafe(gitDir);
429
+ appendWorkerErrorLog(dataDir(), `${stamp}: git status listed more than the output buffer holds; ${recorded2 ? "asked the worker to reconcile the project" : "could not record a reconcile request, so the index may stay stale until the next index run"}
430
+ `);
431
+ }
432
+ if (status.exitCode !== 0) return [];
433
+ const recorded = requestReconcileSafe(gitDir);
434
+ const repoRoot = gitRepoRootOrNull(gitDir);
435
+ if (repoRoot === null) return [];
436
+ const entries = parsePorcelainZ(status.stdout);
437
+ const rels = [...entries.filter((e) => e.untracked === true), ...entries.filter((e) => e.untracked !== true)].flatMap((e) => e.origPath === void 0 ? [e.path] : [e.path, e.origPath]);
438
+ if (!recorded && rels.length <= STATUS_SWEEP_CAP) {
439
+ appendWorkerErrorLog(dataDir(), `${stamp}: could not record a reconcile request, so a file this sweep could not see may stay stale until the next index run
440
+ `);
441
+ }
442
+ if (rels.length > STATUS_SWEEP_CAP) {
443
+ const untrackedDropped = Math.max(0, entries.filter((e) => e.untracked === true).length - STATUS_SWEEP_CAP);
444
+ appendWorkerErrorLog(dataDir(), `${stamp}: git listed ${rels.length} paths, so only the first ${STATUS_SWEEP_CAP} were queued, untracked ones first; ${untrackedDropped > 0 ? `${untrackedDropped} untracked ${untrackedDropped === 1 ? "file was" : "files were"} left out, which no reconcile finds, and ` : ""}${recorded ? "asked the worker to reconcile the project for the rest of the tracked files" : "could not record a reconcile request, so the index may stay stale until the next index run"}
445
+ `);
446
+ }
447
+ return rels.slice(0, STATUS_SWEEP_CAP).map((rel) => resolveIndexPath(rel, repoRoot));
448
+ }
449
+ function enqueueRewrittenPath(absPath) {
450
+ if (/(?:^|[/\\])(?:NUL|nul)$/.test(absPath) || absPath.replace(/\\/g, "/").endsWith("/dev/null")) return;
451
+ try {
452
+ if (!statSync(absPath).isFile()) return;
453
+ } catch {
454
+ return;
455
+ }
456
+ enqueueDirtyPathSafe(absPath, { alreadyResolved: true });
457
+ }
458
+ function enqueueNonHeadMovingRewrites(cmd, runDir) {
459
+ const atRunDir = (f) => resolveIndexPath(f, runDir);
460
+ const paths = [];
461
+ const sweepDirs = /* @__PURE__ */ new Set();
462
+ if (GIT_RESTORE_RE.test(cmd) && !GIT_RESTORE_STAGED_ONLY_RE.test(cmd)) {
463
+ const specs = extractGitRestorePathspecs(cmd);
464
+ paths.push(...expandGitPathspecs(specs, runDir));
465
+ for (const spec of specs) if (spec !== "." && !spec.startsWith(":") && !/[*?[]/.test(spec)) paths.push(atRunDir(spec));
466
+ }
467
+ for (const segment of splitShellSegments(cmd)) {
468
+ if (PATCH_APPLY_SEGMENT_RE.test(segment) && !PATCH_APPLY_INSPECT_ONLY_RE.test(segment)) sweepDirs.add(runDir);
469
+ if (isFormatterWriteSegment(segment)) sweepDirs.add(runDir);
470
+ const stashDir = gitStashRewriteDir(segment, runDir);
471
+ if (stashDir !== null) sweepDirs.add(stashDir);
472
+ for (const f of extractSedInPlaceFiles(segment)) paths.push(atRunDir(f));
473
+ for (const f of extractTeeFiles(segment)) paths.push(atRunDir(f));
474
+ for (const f of extractRedirectTargets(segment)) paths.push(atRunDir(f));
475
+ }
476
+ for (const p of new Set(paths)) enqueueRewrittenPath(p);
477
+ for (const dir of sweepDirs) for (const p of workingTreeStatusPaths(dir)) enqueueSweptPath(p);
478
+ }
479
+ function enqueueSweptPath(absPath) {
480
+ try {
481
+ if (!statSync(absPath).isFile()) return;
482
+ } catch (err) {
483
+ const code = err.code;
484
+ if (code !== "ENOENT" && code !== "ENOTDIR") return;
485
+ }
486
+ enqueueDirtyPathSafe(absPath, { alreadyResolved: true });
487
+ }
488
+ var PIPELINE_PASSTHROUGH_HEADS = /* @__PURE__ */ new Set(["head", "tail", "cat", "tee", "less", "more"]);
489
+ var CI_FILTER_NAMES = /^(?:generic-ci|jest|vitest|pytest|go_test|cargo_test|cargo|go|make|cmake|gradle|maven|dotnet|turbo|nx|lerna|webpack|eslint|ruff|clippy|flake8|mypy|prettier|tsc)$/;
490
+ function isCiBuildTestSegment(cleaned, cwd) {
491
+ if (isTestRunnerCommand(cleaned) || isBuildCommand(cleaned) || isTscCommand(cleaned)) return true;
492
+ if (/^\s*(npm|pnpm|yarn|bun)\s+(run\s+)?(test|build|lint|typecheck|check|ci|guards)\b/i.test(cleaned)) return true;
493
+ if (/^\s*(cargo|go|dotnet|make|gradle|mvn|pytest|vitest|jest|eslint|ruff)\b/i.test(cleaned)) return true;
494
+ const detected = detectFromCommand(cleaned, cwd ?? void 0);
495
+ if (detected !== null && CI_FILTER_NAMES.test(detected.filter.name)) return true;
496
+ return false;
497
+ }
498
+ function pipelineShapeFilter(cmd, cwd) {
499
+ if (hasUnquotedOperator(cmd, ["&&", "||", ";"])) {
500
+ const forSplit2 = cmd.replace(/\s2>(?:&1|\/dev\/null)/g, "");
501
+ if (hasBareBackgroundOrNewline(forSplit2)) return null;
502
+ const segments2 = splitShellSegments(forSplit2);
503
+ if (segments2.length >= 2) {
504
+ let recognizedCiCount = 0;
505
+ for (const segment of segments2) {
506
+ const cleaned = stripOutputPipeline(segment.trim());
507
+ if (cleaned.length === 0) continue;
508
+ if (isCiBuildTestSegment(cleaned, cwd)) {
509
+ recognizedCiCount++;
510
+ }
511
+ }
512
+ if (recognizedCiCount > 0) {
513
+ const ci = filterByName("generic-ci");
514
+ return ci === null ? null : { filter: ci, argv: [] };
515
+ }
516
+ }
517
+ return null;
518
+ }
519
+ const forSplit = cmd.replace(/\s2>(?:&1|\/dev\/null)/g, "");
520
+ if (hasBareBackgroundOrNewline(forSplit)) return null;
521
+ const segments = splitShellSegments(forSplit);
522
+ if (segments.length < 2) return null;
523
+ for (const segment of segments.slice(1)) {
524
+ const head = safeShlexSplit(segment)?.[0];
525
+ if (head === void 0) return null;
526
+ if (!PIPELINE_PASSTHROUGH_HEADS.has(head.replace(/^.*[/\\]/, ""))) return null;
527
+ }
528
+ const detected = detectFromCommand(stripOutputPipeline(cmd), cwd ?? void 0);
529
+ return detected === null ? null : { filter: detected.filter, argv: detected.argv };
530
+ }
531
+ function recallStageTokens(cmd) {
532
+ const forSplit = cmd.replace(/\s2>(?:&1|\/dev\/null)/g, "");
533
+ if (hasBareBackgroundOrNewline(forSplit)) return null;
534
+ const first = splitShellSegments(forSplit)[0];
535
+ if (first === void 0) return null;
536
+ const args = tokenGoatInvocation(stripOutputPipeline(first));
537
+ if (args === null) return null;
538
+ return Object.values(RECALL_COMMAND).includes(args[0] ?? "") ? ["token-goat", ...args] : null;
539
+ }
540
+ function tokenGoatInvocation(segment) {
541
+ const tokens = safeShlexSplit(segment);
542
+ if (tokens === null || tokens.length === 0) return null;
543
+ const base = (t) => t.replace(/^.*[/\\]/, "").replace(/\.exe$/i, "").toLowerCase();
544
+ const head = base(tokens[0] ?? "");
545
+ if (head === "token-goat" || head === "tg") return tokens.slice(1);
546
+ if (head === "node") {
547
+ const script = tokens[1];
548
+ return script !== void 0 && /(?:^|[/\\:])token-goat(?:\.core)?\.mjs$/i.test(script) ? tokens.slice(2) : null;
549
+ }
550
+ if (head === "npx") {
551
+ let i = 1;
552
+ while (tokens[i] === "-y" || tokens[i] === "--yes") i++;
553
+ return /^token-goat(?:@\S+)?$/.test(tokens[i] ?? "") ? tokens.slice(i + 1) : null;
554
+ }
555
+ return null;
556
+ }
557
+ function isTokenGoatOwnCommand(cmd) {
558
+ const forSplit = cmd.replace(/\s2>(?:&1|\/dev\/null)/g, "");
559
+ if (hasBareBackgroundOrNewline(forSplit)) return false;
560
+ const first = splitShellSegments(forSplit)[0];
561
+ return first !== void 0 && tokenGoatInvocation(stripOutputPipeline(first)) !== null;
562
+ }
563
+ function isRecallCommand(cmd) {
564
+ return recallStageTokens(cmd) !== null;
565
+ }
566
+ function isFullRecallCommand(cmd) {
567
+ return recallStageTokens(cmd)?.includes("--full") === true;
568
+ }
569
+ function pureFileReadPath(cmd) {
570
+ const single = extractCatFile(cmd)?.filePath ?? extractHeadFile(cmd)?.filePath ?? extractTailFile(cmd)?.filePath ?? extractLineRangeRead(cmd)?.filePath;
571
+ if (single !== void 0) return single;
572
+ return singleFileCompoundReadPath(cmd);
573
+ }
574
+ function singleFileCompoundReadPath(cmd) {
575
+ const reads = extractLineRangeReadsCompound(cmd);
576
+ if (reads === null || reads.length !== 1) return null;
577
+ return reads[0]?.filePath ?? null;
578
+ }
579
+ function deliveredLineNumbers(cmd, lineCount) {
580
+ const ranged = extractLineRangeRead(cmd);
581
+ if (ranged !== null) {
582
+ const nums = [];
583
+ for (const [lo, hi] of ranged.ranges) for (let n = lo; n <= hi; n++) nums.push(n);
584
+ if (nums.length === 0) return null;
585
+ while (nums.length < lineCount) nums.push((nums[nums.length - 1] ?? 0) + 1);
586
+ return nums;
587
+ }
588
+ if (extractCatFile(cmd) !== null || extractHeadFile(cmd) !== null) return Array.from({ length: lineCount }, (_, i) => i + 1);
589
+ if (singleFileCompoundReadPath(cmd) !== null) return Array.from({ length: lineCount }, () => null);
590
+ return null;
591
+ }
592
+ var WHOLE_FILE_DUMP_RE = /^(?:(?:cat|type|Get-Content|gc)|(?:head|tail)[ \t]+-n[ \t]+\d+)[ \t]+(?:"([A-Za-z0-9._\-/\\:+@ ]+)"|'([A-Za-z0-9._\-/\\:+@ ]+)'|([A-Za-z0-9._\-/\\:+@]+))(?:[ \t]+2>(?:&1|\/dev\/null))?[ \t]*$/i;
593
+ function isWholeFileDump(cmd, extractedPath) {
594
+ const m = WHOLE_FILE_DUMP_RE.exec(cmd);
595
+ if (m === null) return false;
596
+ const shaped = m[1] ?? m[2] ?? m[3];
597
+ return shaped !== void 0 && shaped === extractedPath;
598
+ }
599
+ function unwrapCompressCommand(executed) {
600
+ const t = executed.trim();
601
+ if (!/^(?:token-goat|tg)\s+compress\b/.test(t)) return null;
602
+ let argv;
603
+ try {
604
+ argv = shlexSplit(t);
605
+ } catch {
606
+ return null;
607
+ }
608
+ for (let i = 0; i + 1 < argv.length; i++) {
609
+ const tok = argv[i];
610
+ if (tok === "-c" || tok === "--cmd") return argv[i + 1] ?? null;
611
+ if (tok === "--cmd-b64") {
612
+ try {
613
+ return Buffer.from(argv[i + 1] ?? "", "base64").toString("utf8");
614
+ } catch {
615
+ return null;
616
+ }
617
+ }
618
+ }
619
+ return null;
620
+ }
621
+ function detectUnbalancedShellSyntax(cmd) {
622
+ let inSingle = false;
623
+ let inDouble = false;
624
+ let i = 0;
625
+ while (i < cmd.length) {
626
+ const ch = cmd[i];
627
+ if (inSingle) {
628
+ if (ch === "'") {
629
+ inSingle = false;
630
+ }
631
+ i++;
632
+ continue;
633
+ }
634
+ if (inDouble) {
635
+ if (ch === "\\" && i + 1 < cmd.length) {
636
+ i += 2;
637
+ continue;
638
+ }
639
+ if (ch === '"') {
640
+ inDouble = false;
641
+ }
642
+ i++;
643
+ continue;
644
+ }
645
+ if (ch === "\\" && i + 1 < cmd.length) {
646
+ i += 2;
647
+ continue;
648
+ }
649
+ if (ch === "$" && cmd[i + 1] === "(" && cmd[i + 2] === "(") {
650
+ let depth = 2;
651
+ let j = i + 3;
652
+ while (j < cmd.length && depth > 0) {
653
+ if (cmd[j] === "(") depth++;
654
+ else if (cmd[j] === ")") depth--;
655
+ j++;
656
+ }
657
+ i = j;
658
+ continue;
659
+ }
660
+ if (ch === "$" && cmd[i + 1] === "'") {
661
+ let j = i + 2;
662
+ let closed = false;
663
+ while (j < cmd.length) {
664
+ if (cmd[j] === "\\") {
665
+ j += 2;
666
+ continue;
667
+ }
668
+ if (cmd[j] === "'") {
669
+ j++;
670
+ closed = true;
671
+ break;
672
+ }
673
+ j++;
674
+ }
675
+ if (!closed) {
676
+ inSingle = true;
677
+ break;
678
+ }
679
+ i = j;
680
+ continue;
681
+ }
682
+ if (ch === "#" && (i === 0 || /\s/.test(cmd[i - 1] ?? ""))) {
683
+ const nl = cmd.indexOf("\n", i);
684
+ i = nl === -1 ? cmd.length : nl + 1;
685
+ continue;
686
+ }
687
+ if (ch === "'") {
688
+ inSingle = true;
689
+ i++;
690
+ continue;
691
+ }
692
+ if (ch === '"') {
693
+ inDouble = true;
694
+ i++;
695
+ continue;
696
+ }
697
+ if (ch === "<" && i + 1 < cmd.length && cmd[i + 1] === "<") {
698
+ if (i + 2 < cmd.length && cmd[i + 2] === "<") {
699
+ i += 3;
700
+ continue;
701
+ }
702
+ let j = i + 2;
703
+ let hasIndentModifier = false;
704
+ if (j < cmd.length && (cmd[j] === "-" || cmd[j] === "~")) {
705
+ hasIndentModifier = true;
706
+ j++;
707
+ }
708
+ while (j < cmd.length && cmd[j] === " ") {
709
+ j++;
710
+ }
711
+ if (j < cmd.length) {
712
+ let delimStart = j;
713
+ if (cmd[j] === '"' || cmd[j] === "'") {
714
+ delimStart = j + 1;
715
+ const quoteChar = cmd[j];
716
+ let delimEnd = delimStart;
717
+ while (delimEnd < cmd.length && cmd[delimEnd] !== quoteChar) {
718
+ delimEnd++;
719
+ }
720
+ if (delimEnd >= cmd.length) {
721
+ return "an unclosed quote in a heredoc opener";
722
+ }
723
+ j = delimEnd + 1;
724
+ } else {
725
+ let delimEnd = delimStart;
726
+ while (delimEnd < cmd.length && /\w/.test(cmd.charAt(delimEnd))) {
727
+ delimEnd++;
728
+ }
729
+ j = delimEnd;
730
+ }
731
+ const delimiter = cmd.slice(delimStart, j).replace(/["']/g, "");
732
+ if (delimiter) {
733
+ let scanPos = j;
734
+ let terminatorEnd = -1;
735
+ while (scanPos <= cmd.length) {
736
+ const nl = cmd.indexOf("\n", scanPos);
737
+ const lineEnd = nl === -1 ? cmd.length : nl;
738
+ let line = cmd.slice(scanPos, lineEnd);
739
+ if (line.endsWith("\r")) {
740
+ line = line.slice(0, -1);
741
+ }
742
+ const isMatch = hasIndentModifier ? line.trim() === delimiter : line === delimiter;
743
+ if (isMatch) {
744
+ terminatorEnd = nl === -1 ? cmd.length : nl + 1;
745
+ break;
746
+ }
747
+ if (nl === -1) break;
748
+ scanPos = nl + 1;
749
+ }
750
+ if (terminatorEnd === -1) {
751
+ return `an unterminated heredoc (${delimiter} never appears on its own line)`;
752
+ }
753
+ i = terminatorEnd;
754
+ continue;
755
+ }
756
+ }
757
+ }
758
+ i++;
759
+ }
760
+ if (inSingle) {
761
+ return "an unclosed single quote";
762
+ }
763
+ if (inDouble) {
764
+ return "an unclosed double quote";
765
+ }
766
+ return null;
767
+ }
768
+
769
+ export {
770
+ runRecallCommand,
771
+ stripCdPrefix,
772
+ stripGroupAndExports,
773
+ stripCommandPrefix,
774
+ stripTrailingStderrRedirect,
775
+ hasTestRunScopeOrBudget,
776
+ isDirectTestRunnerCommand,
777
+ resolveCdHintPath,
778
+ cdPrefixCwd,
779
+ commandRunDir,
780
+ bashRecallKey,
781
+ resolveBashCall,
782
+ pipelineDivergenceNote,
783
+ cachedRunCoversCommand,
784
+ extractCommand,
785
+ isHeadMovingGitCommand,
786
+ ORIG_HEAD_ELIGIBLE_GIT_RE,
787
+ ORIG_HEAD_REFLOG_MSG_RE,
788
+ gitRepoRootOrNull,
789
+ enqueueNonHeadMovingRewrites,
790
+ PIPELINE_PASSTHROUGH_HEADS,
791
+ pipelineShapeFilter,
792
+ isTokenGoatOwnCommand,
793
+ isRecallCommand,
794
+ isFullRecallCommand,
795
+ pureFileReadPath,
796
+ deliveredLineNumbers,
797
+ isWholeFileDump,
798
+ unwrapCompressCommand,
799
+ detectUnbalancedShellSyntax
800
+ };