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,48 @@
1
+ import { createRequire as __cjsRequire } from 'node:module';
2
+ const require = __cjsRequire(import.meta.url);
3
+ import {
4
+ DEFAULT_HEARTBEAT_INTERVAL_MS,
5
+ DEFAULT_TIMEOUT_SECONDS,
6
+ MAX_CAPTURE_BYTES,
7
+ resolveFilter,
8
+ run,
9
+ runRaw,
10
+ spawnTarget,
11
+ unknownFilterNotice
12
+ } from "./token-goat-chunk-VWDXLT4F.mjs";
13
+ import "./token-goat-chunk-DOWRSMWO.mjs";
14
+ import "./token-goat-chunk-INNPTRUX.mjs";
15
+ import "./token-goat-chunk-N5LSOVSU.mjs";
16
+ import "./token-goat-chunk-KQBLRPBN.mjs";
17
+ import "./token-goat-chunk-4ZBFWLXF.mjs";
18
+ import "./token-goat-chunk-IK2DRMFX.mjs";
19
+ import "./token-goat-chunk-U4WHMG6Y.mjs";
20
+ import "./token-goat-chunk-GVB2MUST.mjs";
21
+ import "./token-goat-chunk-XB5KKOCG.mjs";
22
+ import "./token-goat-chunk-OUKDTVNU.mjs";
23
+ import "./token-goat-chunk-4GILLLWY.mjs";
24
+ import "./token-goat-chunk-XX6O25RN.mjs";
25
+ import "./token-goat-chunk-HAVAOB3S.mjs";
26
+ import "./token-goat-chunk-X2SUP3EI.mjs";
27
+ import "./token-goat-chunk-T5P5ACNQ.mjs";
28
+ import "./token-goat-chunk-7EZTZOMC.mjs";
29
+ import "./token-goat-chunk-QYHO5CPH.mjs";
30
+ import "./token-goat-chunk-4GBVPH3D.mjs";
31
+ import "./token-goat-chunk-YZAAZU2S.mjs";
32
+ import "./token-goat-chunk-IVE6U7KV.mjs";
33
+ import "./token-goat-chunk-HU4TORC5.mjs";
34
+ import "./token-goat-chunk-GGGG7RWB.mjs";
35
+ import "./token-goat-chunk-AM5V6GSX.mjs";
36
+ import "./token-goat-chunk-FNFBKLRD.mjs";
37
+ import "./token-goat-chunk-CO3UYX6G.mjs";
38
+ import "./token-goat-chunk-A37V4PBF.mjs";
39
+ export {
40
+ DEFAULT_HEARTBEAT_INTERVAL_MS,
41
+ DEFAULT_TIMEOUT_SECONDS,
42
+ MAX_CAPTURE_BYTES,
43
+ resolveFilter,
44
+ run,
45
+ runRaw,
46
+ spawnTarget,
47
+ unknownFilterNotice
48
+ };
@@ -10,13 +10,89 @@ import {
10
10
  stripMultilineStringSpan,
11
11
  stripNestedBlockCommentSpan,
12
12
  stripStringLiterals
13
- } from "./token-goat-chunk-7CPMDFGB.mjs";
13
+ } from "./token-goat-chunk-OUKDTVNU.mjs";
14
14
  import {
15
15
  init_define_import_meta_env
16
16
  } from "./token-goat-chunk-A37V4PBF.mjs";
17
17
 
18
+ // src/languages/body_segments.ts
19
+ init_define_import_meta_env();
20
+ function bodySegments(code, from) {
21
+ const out = [];
22
+ let braces = 0;
23
+ let nest = 0;
24
+ let inString = false;
25
+ let start = from;
26
+ const cut = (end) => {
27
+ if (/[^\s;]/.test(code.slice(start, end))) out.push({ start, end, open: false });
28
+ start = end;
29
+ };
30
+ for (let i = from; i < code.length; i++) {
31
+ const ch = code[i];
32
+ if (ch === '"') inString = !inString;
33
+ else if (inString) continue;
34
+ else if (ch === "(" || ch === "[") nest++;
35
+ else if (ch === ")" || ch === "]") nest = Math.max(0, nest - 1);
36
+ else if (ch === "{") braces++;
37
+ else if (ch === "}") {
38
+ if (braces === 0) {
39
+ cut(i);
40
+ return out;
41
+ }
42
+ braces--;
43
+ if (braces === 0 && nest === 0) cut(i + 1);
44
+ } else if (ch === ";" && braces === 0 && nest === 0) cut(i + 1);
45
+ }
46
+ if (/[^\s;]/.test(code.slice(start))) out.push({ start, end: code.length, open: braces > 0 });
47
+ return out;
48
+ }
49
+ function bodyBraceAt(code, from, to) {
50
+ let parens = 0;
51
+ for (let i = from; i < to; i++) {
52
+ const ch = code[i];
53
+ if (ch === "(") parens++;
54
+ else if (ch === ")") parens = Math.max(0, parens - 1);
55
+ else if (ch === "{" && parens === 0) return i;
56
+ }
57
+ return -1;
58
+ }
59
+ function endOpenMember(symbols, settled, open, lineNum, lines) {
60
+ const { sym } = open;
61
+ const ended = { ...sym, lineEnd: lineNum, body: [sym.body, ...lines.slice(sym.lineStart, lineNum)].join("\n") };
62
+ symbols[symbols.indexOf(sym)] = ended;
63
+ settled.delete(sym);
64
+ settled.add(ended);
65
+ }
66
+ function spanUnsettled(symbols, settled, span) {
67
+ const spanned = span(symbols.filter((s) => !settled.has(s)));
68
+ let next = 0;
69
+ return symbols.map((s) => settled.has(s) ? s : spanned[next++]);
70
+ }
71
+ function bodyResumeAt(code, depthInside) {
72
+ if (depthInside <= 0) return 0;
73
+ let depth = depthInside;
74
+ for (let i = 0; i < code.length; i++) {
75
+ const ch = code[i];
76
+ if (ch === "{") depth++;
77
+ else if (ch === "}" && --depth === 0) return i + 1;
78
+ }
79
+ return -1;
80
+ }
81
+ function openMembersOf(blocks, bodyDepth) {
82
+ return blocks.map((b) => ({ sym: b.sym, depth: bodyDepth + b.level + 1 }));
83
+ }
84
+ function endOpenMembers(symbols, settled, open, braceDepth, lineNum, lines) {
85
+ const still = [];
86
+ for (const m of open) {
87
+ if (braceDepth < m.depth) endOpenMember(symbols, settled, m, lineNum, lines);
88
+ else still.push(m);
89
+ }
90
+ return still;
91
+ }
92
+
18
93
  // src/languages/swift.ts
19
94
  init_define_import_meta_env();
95
+ var SWIFT_STRIP = { swiftInterpolation: true };
20
96
  var IDENT_START = "A-Za-z_\\u00C0-\\uFFFF";
21
97
  var IDENT_CONT = "A-Za-z0-9_\\u00C0-\\uFFFF";
22
98
  var IDENT = `(?:\`[^\`]+\`|[${IDENT_START}][${IDENT_CONT}]*)`;
@@ -45,6 +121,9 @@ var SUBSCRIPT_RE = new RegExp(
45
121
  var PROPERTY_RE = new RegExp(
46
122
  "^\\s*(?:" + MODIFIER_ALT + `\\s+)*(?:var|let)\\s+(${IDENT}[^\\n]*)`
47
123
  );
124
+ var ENUM_CASE_RE = new RegExp(
125
+ "^\\s*(?:" + MODIFIER_ALT + `\\s+)*(?:@[A-Za-z_][A-Za-z0-9_.]*\\s+)*case\\s+(${IDENT}[^\\n]*)`
126
+ );
48
127
  function splitDeclaratorNames(tail) {
49
128
  const names = [];
50
129
  let depth = 0;
@@ -72,7 +151,7 @@ var TYPE_HEADER_RE = new RegExp(
72
151
  `^(?:(?:public|private|fileprivate|internal|open|package|final|indirect|distributed|nonisolated)\\s+)*(class|struct|enum|protocol|extension|actor)\\s+(?!(?:func|var|let|subscript)\\b)(${IDENT}(?:\\.${IDENT})*)`
73
152
  );
74
153
  function stripRegexLiterals(line) {
75
- return line.replace(/([=(,[:]|^|\breturn\b)(\s*)\/(?![\s/*])(?:\\.|[^\\/\n])*\//g, "$1$2");
154
+ return line.replace(/([=(,[:]|^|\breturn\b)(\s*)(\/(?![\s/*])(?:\\.|[^\\/\n])*\/)/g, (_m, lead, gap, literal) => lead + gap + " ".repeat(literal.length));
76
155
  }
77
156
  var ALIAS_RE = new RegExp(
78
157
  "^(?:" + MODIFIER_ALT + "\\s+)*(typealias|associatedtype|macro)\\s+(" + IDENT + ")"
@@ -80,6 +159,50 @@ var ALIAS_RE = new RegExp(
80
159
  function typeKindFor(keyword2) {
81
160
  return keyword2 === "struct" ? "struct" : keyword2 === "enum" ? "enum" : keyword2 === "protocol" ? "protocol" : keyword2 === "extension" ? "extension" : keyword2 === "actor" ? "actor" : "class";
82
161
  }
162
+ function memberSymbols(text, parent, sig, site) {
163
+ const { filePath, lineNum, lines } = site;
164
+ const style = lines !== void 0 ? "c" : void 0;
165
+ const noAttr = stripLeadingAttributes(text);
166
+ const initM = INIT_RE.exec(noAttr);
167
+ if (initM) return [makeLineSymbol(filePath, initM[1] ?? "init", "method", lineNum, sig, parent, lines, style)];
168
+ if (DEINIT_RE.exec(noAttr)) return [makeLineSymbol(filePath, "deinit", "method", lineNum, sig, parent, lines, style)];
169
+ const subscriptM = SUBSCRIPT_RE.exec(noAttr);
170
+ if (subscriptM) return [makeLineSymbol(filePath, subscriptM[1] ?? "subscript", "method", lineNum, sig, parent, lines, style)];
171
+ const fm = FUNC_RE.exec(noAttr);
172
+ if (fm) return [makeLineSymbol(filePath, unquoteIdent(fm[1] ?? ""), parent === void 0 ? "function" : "method", lineNum, sig, parent, lines, style)];
173
+ const propM = PROPERTY_RE.exec(noAttr);
174
+ if (propM) return splitDeclaratorNames(propM[1] ?? "").map((name) => makeLineSymbol(filePath, name, "var", lineNum, sig, parent, lines, style));
175
+ const caseM = parent === void 0 ? null : ENUM_CASE_RE.exec(noAttr);
176
+ if (caseM) return splitDeclaratorNames(caseM[1] ?? "").map((name) => makeLineSymbol(filePath, name, "enum_member", lineNum, sig, parent, lines, style));
177
+ return [];
178
+ }
179
+ function inlineSwiftMembers(line, code, segs, parent, filePath, lineNum, level = 0) {
180
+ const members = [];
181
+ const opens = [];
182
+ for (const seg of segs) {
183
+ const text = line.slice(seg.start, seg.end).trim();
184
+ const noAttr = stripLeadingAttributes(text);
185
+ const tm = TYPE_HEADER_RE.exec(noAttr);
186
+ if (tm) {
187
+ const brace = bodyBraceAt(code, seg.start, seg.end);
188
+ if (seg.open && brace === -1) continue;
189
+ const name = unquoteIdent(tm[2] ?? "");
190
+ const typeSym = makeLineSymbol(filePath, name, typeKindFor(tm[1] ?? "class"), lineNum, text, parent);
191
+ members.push(typeSym);
192
+ if (brace !== -1) {
193
+ const inner = inlineSwiftMembers(line, code, bodySegments(code, brace + 1), name, filePath, lineNum, level + 1);
194
+ members.push(...inner.members);
195
+ if (seg.open) opens.push({ sym: typeSym, level, isType: true }, ...inner.opens);
196
+ }
197
+ continue;
198
+ }
199
+ const am = ALIAS_RE.exec(noAttr);
200
+ const found = am ? [makeLineSymbol(filePath, unquoteIdent(am[2] ?? ""), am[1] === "macro" ? "macro" : "type", lineNum, text, parent)] : memberSymbols(text, parent, text, { filePath, lineNum });
201
+ members.push(...found);
202
+ if (seg.open && found.length > 0) opens.push({ sym: found[found.length - 1], level, isType: false });
203
+ }
204
+ return { members, opens };
205
+ }
83
206
  function extractSwift(content, filePath) {
84
207
  const symbols = [];
85
208
  const imports = [];
@@ -88,37 +211,10 @@ function extractSwift(content, filePath) {
88
211
  let braceDepth = 0;
89
212
  let commentDepth = 0;
90
213
  let mlState = null;
214
+ const settled = /* @__PURE__ */ new Set();
215
+ let openMembers = [];
91
216
  function pushMembers(text, parent, lineNum, sig) {
92
- const noAttr = stripLeadingAttributes(text);
93
- const kind = parent === void 0 ? "function" : "method";
94
- const initM = INIT_RE.exec(noAttr);
95
- if (initM) {
96
- symbols.push(makeLineSymbol(filePath, initM[1] ?? "init", "method", lineNum, sig, parent, lines, "c"));
97
- return true;
98
- }
99
- if (DEINIT_RE.exec(noAttr)) {
100
- symbols.push(makeLineSymbol(filePath, "deinit", "method", lineNum, sig, parent, lines, "c"));
101
- return true;
102
- }
103
- const subscriptM = SUBSCRIPT_RE.exec(noAttr);
104
- if (subscriptM) {
105
- symbols.push(makeLineSymbol(filePath, subscriptM[1] ?? "subscript", "method", lineNum, sig, parent, lines, "c"));
106
- return true;
107
- }
108
- const fm = FUNC_RE.exec(noAttr);
109
- if (fm) {
110
- symbols.push(makeLineSymbol(filePath, unquoteIdent(fm[1] ?? ""), kind, lineNum, sig, parent, lines, "c"));
111
- return true;
112
- }
113
- const propM = PROPERTY_RE.exec(noAttr);
114
- if (propM) {
115
- const names = splitDeclaratorNames(propM[1] ?? "");
116
- for (const name of names) {
117
- symbols.push(makeLineSymbol(filePath, name, "var", lineNum, sig, parent, lines, "c"));
118
- }
119
- return names.length > 0;
120
- }
121
- return false;
217
+ symbols.push(...memberSymbols(text, parent, sig, { filePath, lineNum, lines }));
122
218
  }
123
219
  for (let i = 0; i < lines.length; i++) {
124
220
  const rawLine = lines[i] ?? "";
@@ -134,7 +230,7 @@ function extractSwift(content, filePath) {
134
230
  const line = stripLineComment(blockStripped).trimEnd();
135
231
  const stripped = line.trim();
136
232
  if (!stripped) {
137
- const braceLine2 = stripRegexLiterals(stripStringLiterals(line));
233
+ const braceLine2 = stripRegexLiterals(stripStringLiterals(line, SWIFT_STRIP));
138
234
  braceDepth += (braceLine2.match(/\{/g) ?? []).length - (braceLine2.match(/\}/g) ?? []).length;
139
235
  continue;
140
236
  }
@@ -152,11 +248,6 @@ function extractSwift(content, filePath) {
152
248
  const parent = typeStack.length > 0 ? typeStack[typeStack.length - 1].name : void 0;
153
249
  symbols.push(makeLineSymbol(filePath, tname, typeKindFor(tm[1] ?? "class"), lineNum, stripped.slice(0, 200), parent, lines, "c"));
154
250
  typeStack.push({ name: tname, startDepth: braceDepth, bodyEntered: false });
155
- const open = strippedNoAttr.indexOf("{");
156
- if (open !== -1) {
157
- const tail = strippedNoAttr.slice(open + 1).replace(/\}\s*$/, "").trim();
158
- if (tail) pushMembers(tail, tname, lineNum, tail.slice(0, 200));
159
- }
160
251
  }
161
252
  const am = tm === null && typeDetectionGateOk && (braceDepth === 0 || typeStack.length > 0) ? ALIAS_RE.exec(strippedNoAttr) : null;
162
253
  if (am) {
@@ -172,7 +263,29 @@ function extractSwift(content, filePath) {
172
263
  } else if (frame === null && braceDepth === 0) {
173
264
  pushMembers(line, void 0, lineNum, stripped.slice(0, 200));
174
265
  }
175
- const braceLine = stripRegexLiterals(stripStringLiterals(line));
266
+ const braceLine = stripRegexLiterals(stripStringLiterals(line, SWIFT_STRIP));
267
+ const lineOpens = [];
268
+ const queueMembers = (segs, parent, bodyDepth) => {
269
+ const { members, opens } = inlineSwiftMembers(line, braceLine, segs, parent, filePath, lineNum);
270
+ symbols.push(...members);
271
+ for (const m of members) settled.add(m);
272
+ lineOpens.push(...openMembersOf(opens, bodyDepth));
273
+ for (const o of opens) {
274
+ if (!o.isType) continue;
275
+ const enclosing = typeStack[typeStack.length - 1];
276
+ if (enclosing !== void 0) enclosing.bodyEntered = true;
277
+ typeStack.push({ name: o.sym.name, startDepth: bodyDepth + o.level, bodyEntered: true });
278
+ }
279
+ };
280
+ const lineSegs = bodySegments(braceLine, 0);
281
+ if (tm !== null && frame !== null && lineSegs[0] !== void 0) {
282
+ const brace = bodyBraceAt(braceLine, lineSegs[0].start, lineSegs[0].end);
283
+ if (brace !== -1) queueMembers(bodySegments(braceLine, brace + 1), frame.name, braceDepth + 1);
284
+ }
285
+ if (outerFrame !== null && outerDepthInType >= 1) {
286
+ const resume = bodyResumeAt(braceLine, outerDepthInType - 1);
287
+ if (resume >= 0) queueMembers(outerDepthInType === 1 ? lineSegs.slice(1) : bodySegments(braceLine, resume), outerFrame.name, outerFrame.startDepth + 1);
288
+ } else if (outerFrame === null && braceDepth === 0) queueMembers(lineSegs.slice(1), void 0, braceDepth);
176
289
  for (const ch of braceLine) {
177
290
  if (ch === "{") {
178
291
  braceDepth++;
@@ -184,6 +297,8 @@ function extractSwift(content, filePath) {
184
297
  braceDepth--;
185
298
  }
186
299
  }
300
+ openMembers = endOpenMembers(symbols, settled, openMembers, braceDepth, lineNum, lines);
301
+ openMembers.push(...lineOpens);
187
302
  while (typeStack.length > 0) {
188
303
  const top = typeStack[typeStack.length - 1];
189
304
  if (top.bodyEntered && braceDepth <= top.startDepth) {
@@ -193,7 +308,7 @@ function extractSwift(content, filePath) {
193
308
  }
194
309
  }
195
310
  }
196
- return { symbols, imports };
311
+ return { symbols, imports, settled };
197
312
  }
198
313
 
199
314
  // src/languages/cobol.ts
@@ -1619,6 +1734,7 @@ function scanBraceLanguage(content, filePath, lang) {
1619
1734
  codeOffset: code.length - code.trimStart().length,
1620
1735
  header: () => headerFrom(masked, i)
1621
1736
  };
1737
+ if (pending !== null && pending.parens === 0 && pending.line < i && lang.memberStart?.test(trimmed) === true) pending = null;
1622
1738
  const inHeader = pending !== null && pending.parens > 0;
1623
1739
  const d = items.length < MAX_SYMBOLS4 && !inHeader ? lang.match(trimmed, ctx) : null;
1624
1740
  if (d !== null && d.name.length <= MAX_NAME_LENGTH2 && (d.name !== "" || d.nameAfterClose === true)) {
@@ -1793,6 +1909,7 @@ function matchGroovy(code, ctx) {
1793
1909
  var GROOVY = {
1794
1910
  lex: { lineComments: ["//"], blockComment: ["/*", "*/"], quotes: `"'`, tripleQuotes: true, shebang: true, slashyStrings: true },
1795
1911
  match: matchGroovy,
1912
+ memberStart: /^static\s*\{/,
1796
1913
  importOf: (code) => /^import\s+(?:static\s+)?([\w.]+(?:\.\*)?)/.exec(code)?.[1] ?? null,
1797
1914
  docComments: true
1798
1915
  };
@@ -3709,6 +3826,13 @@ function extractErlang(content, filePath) {
3709
3826
  }
3710
3827
 
3711
3828
  export {
3829
+ bodySegments,
3830
+ bodyBraceAt,
3831
+ endOpenMember,
3832
+ spanUnsettled,
3833
+ bodyResumeAt,
3834
+ openMembersOf,
3835
+ endOpenMembers,
3712
3836
  stripLeadingAttributes,
3713
3837
  IMPORT_RE,
3714
3838
  extractSwift,
@@ -4,26 +4,35 @@ import {
4
4
  CONTENT_DELIVERED_REASON,
5
5
  classifyToolError,
6
6
  errorPrefix
7
- } from "./token-goat-chunk-E4ZOJIZK.mjs";
8
- import "./token-goat-chunk-E5TK5DNO.mjs";
9
- import "./token-goat-chunk-ZER6EAXZ.mjs";
10
- import "./token-goat-chunk-EUSDXRXU.mjs";
11
- import "./token-goat-chunk-TDUT2CL6.mjs";
12
- import "./token-goat-chunk-52NSDWYY.mjs";
13
- import "./token-goat-chunk-2WOUYWLM.mjs";
14
- import "./token-goat-chunk-CIQ2FTY3.mjs";
15
- import "./token-goat-chunk-7CPMDFGB.mjs";
16
- import "./token-goat-chunk-TGOXNAHW.mjs";
7
+ } from "./token-goat-chunk-JVFSHVFJ.mjs";
8
+ import "./token-goat-chunk-DGS2LVNA.mjs";
9
+ import "./token-goat-chunk-INNPTRUX.mjs";
10
+ import "./token-goat-chunk-MNWKPRAL.mjs";
11
+ import "./token-goat-chunk-P6VGNTQT.mjs";
12
+ import "./token-goat-chunk-76FGDLRO.mjs";
13
+ import "./token-goat-chunk-GL3ETKSC.mjs";
14
+ import "./token-goat-chunk-U4WHMG6Y.mjs";
15
+ import "./token-goat-chunk-GVB2MUST.mjs";
17
16
  import "./token-goat-chunk-XB5KKOCG.mjs";
17
+ import "./token-goat-chunk-OUKDTVNU.mjs";
18
+ import "./token-goat-chunk-4GILLLWY.mjs";
19
+ import "./token-goat-chunk-BFCWY73P.mjs";
20
+ import "./token-goat-chunk-KGEFFSHD.mjs";
21
+ import "./token-goat-chunk-XX6O25RN.mjs";
22
+ import "./token-goat-chunk-HAVAOB3S.mjs";
23
+ import "./token-goat-chunk-T5P5ACNQ.mjs";
24
+ import "./token-goat-chunk-7EZTZOMC.mjs";
25
+ import "./token-goat-chunk-QYHO5CPH.mjs";
26
+ import "./token-goat-chunk-4GBVPH3D.mjs";
18
27
  import "./token-goat-chunk-YZAAZU2S.mjs";
19
28
  import "./token-goat-chunk-IVE6U7KV.mjs";
20
- import "./token-goat-chunk-XYWPOSCN.mjs";
21
- import "./token-goat-chunk-TCQANXYC.mjs";
29
+ import "./token-goat-chunk-HU4TORC5.mjs";
30
+ import "./token-goat-chunk-GGGG7RWB.mjs";
31
+ import "./token-goat-chunk-AM5V6GSX.mjs";
22
32
  import {
23
33
  displaySafeText
24
- } from "./token-goat-chunk-NMTKNYGF.mjs";
25
- import "./token-goat-chunk-MELOKFDJ.mjs";
26
- import "./token-goat-chunk-JTKCQMQA.mjs";
34
+ } from "./token-goat-chunk-FNFBKLRD.mjs";
35
+ import "./token-goat-chunk-CO3UYX6G.mjs";
27
36
  import {
28
37
  init_define_import_meta_env
29
38
  } from "./token-goat-chunk-A37V4PBF.mjs";
@@ -78,6 +87,15 @@ function newToolErrorAccumulator() {
78
87
  finish() {
79
88
  const topUnknown = [...unknownPrefixes.values()].sort((a, b) => b.count - a.count || byCodeUnit(a.tool, b.tool) || byCodeUnit(a.prefix, b.prefix)).slice(0, UNKNOWN_PREFIX_LIMIT);
80
89
  return { byTool: sortTallies(tools), byModel: sortTallies(models), unknownPrefixes: topUnknown };
90
+ },
91
+ checkpoint() {
92
+ const saved = structuredClone([[...tools], [...models], [...unknownPrefixes]]);
93
+ return () => {
94
+ for (const [live, copy] of [[tools, saved[0]], [models, saved[1]], [unknownPrefixes, saved[2]]]) {
95
+ live.clear();
96
+ for (const [k, v] of copy) live.set(k, v);
97
+ }
98
+ };
81
99
  }
82
100
  };
83
101
  }
@@ -0,0 +1,212 @@
1
+ import { createRequire as __cjsRequire } from 'node:module';
2
+ const require = __cjsRequire(import.meta.url);
3
+ import {
4
+ loadConfig
5
+ } from "./token-goat-chunk-7EZTZOMC.mjs";
6
+ import {
7
+ growsExponentially,
8
+ hasNestedQuantifier
9
+ } from "./token-goat-chunk-HU4TORC5.mjs";
10
+ import {
11
+ init_define_import_meta_env
12
+ } from "./token-goat-chunk-A37V4PBF.mjs";
13
+
14
+ // src/secret_redact.ts
15
+ init_define_import_meta_env();
16
+ var SECRET_PATTERNS = [
17
+ // Anthropic keys share OpenAI's "sk-" prefix but are more specific ("sk-ant-"), so they're matched first — the generic OpenAI pattern's negative lookahead below is defense in depth, not the sole guard.
18
+ ["anthropic_api_key", /sk-ant-[A-Za-z0-9_-]{20,}/g],
19
+ // Modern (post-2024, now the default) OpenAI project keys: "sk-proj-" followed by a long base64url-ish body that legitimately contains '-' and '_' -- the generic pattern below deliberately excludes those characters (hyphenated prose would false-fire), so this needs its own entry with the more specific prefix matched first, like sk-ant- above.
20
+ ["openai_project_key", /sk-proj-[A-Za-z0-9_-]{20,}/g],
21
+ ["openai_api_key", /sk-(?!ant-|proj-)[A-Za-z0-9]{20,}/g],
22
+ ["aws_access_key", /AKIA[0-9A-Z]{16}/g],
23
+ // Fine-grained PATs ("github_pat_...") are matched before the classic gh[oprsu]_ pattern so the full token is always consumed as one match -- a fine-grained token's own body can contain '_' and could otherwise partially match the classic pattern.
24
+ ["github_token", /github_pat_[A-Za-z0-9_]{22,}/g],
25
+ ["github_token", /gh[oprsu]_[A-Za-z0-9]{36,}/g],
26
+ // xapp- is Slack's app-level token (Socket Mode), a bearer credential in its own right that the xox[baprs]- prefix does not cover. It gets its own entry rather than joining the alternation above because it needs the full segmented shape (xapp-<ver>-<app id>-<digits>- <hex>) to be safe: a bare /xapp-[A-Za-z0-9-]+/ redacted ordinary identifiers like "xapp-config" and the css class "xapp-container", mangling normal source. The xox* prefixes are distinctive enough on their own; "xapp-" is not.
27
+ ["slack_token", /xox[baprs]-[A-Za-z0-9-]+/g],
28
+ ["slack_token", /xapp-\d-[A-Za-z0-9]{6,}-\d{8,}-[A-Za-z0-9]{16,}/g],
29
+ // Matches the full block (BEGIN marker through its matching END marker), not just the header -- the actual secret material is the base64 body between them, so redacting only the header line would leave the key bytes themselves fully readable in the cached blob. The body is lazy and additionally refuses to cross a following BEGIN marker. Both halves matter. The laziness bounds a successful match at the very next END marker; the negative lookahead bounds a *failing* one, because a BEGIN with no END of its own would otherwise scan to end-of-input, and a blob full of such markers made the pass quadratic -- 6 ms, 20 ms and 78 ms for 2000, 4000 and 8000 of them, four times the work for twice the input, the same shape as the lookbehind incident described above. Private key blocks do not nest, so refusing to cross a BEGIN costs nothing in correctness. The algorithm and ` BLOCK` groups are backreferenced in the END marker rather than repeated, so a BEGIN only ever pairs with its own END spelling. Written as two independent optional groups, `BEGIN PGP PRIVATE KEY` would happily close on a distant `END RSA PRIVATE KEY BLOCK` and redact everything in between. A non-participating group backreferences as the empty string in JS, which is exactly what the unprefixed `BEGIN PRIVATE KEY` form needs. The algorithm list covers every armored private-key header openssl, ssh-keygen and gpg actually emit, not just the ones a first draft happened to think of. ENCRYPTED is the PKCS#8 passphrase-protected form (`openssl genpkey -aes256`, `ssh-keygen -m PKCS8`) and is the most common shape of all; DSA is legacy but still written verbatim; PGP carries the ` BLOCK` suffix, which is why that suffix is optional here. All three used to fall through to disk in full. An encrypted key is still key material: the passphrase can be attacked offline once the bytes are cached, so it is redacted like any other. PuTTY `.ppk` files are deliberately not matched. They have no END marker -- the private section is a `Private-Lines: N` count followed by exactly N base64 lines -- so bounding a match would take a stateful parse rather than a regex, on a path that runs over every command output. A regex guess at where the body ends is exactly the over-eager match this module's header warns against.
30
+ ["private_key_block", /-----BEGIN (RSA |DSA |EC |OPENSSH |ENCRYPTED |PGP )?PRIVATE KEY( BLOCK)?-----(?:(?!-----BEGIN )[\s\S])*?-----END \1PRIVATE KEY\2-----/g],
31
+ // Redacts only the token itself, not the "Authorization: Bearer " prefix -- the lookbehind anchors on the header name and scheme so the surrounding request-log line stays readable, matching how AWS_ACCESS_KEY_ID=... above keeps its own prefix intact. The optional quotes on either side of the colon are what let this see a header carried in JSON rather than in raw wire format. Without them the lookbehind demanded the colon sit directly against the header name and the scheme directly against the space, so a body like {"Authorization": "Bearer <token>"} -- the shape any logged fetch or MCP result arrives in -- matched nothing and the token was cached verbatim. `token` is the second scheme spelling in wide use -- it is what curl and gh examples pass for GitHub and many other APIs -- and an opaque value behind it carries exactly the same authority as one behind `Bearer`. The trailing gap is `{1,8}` rather than a single space for the same reason every other gap in this lookbehind already is: a hand-aligned or reformatted header ("Authorization: Bearer <token>") is ordinary, and demanding exactly one space there made this the one position in the pattern that a second space defeated.
32
+ ["auth_bearer_token", /(?<=Authorization["']?[ \t]{0,8}:[ \t]{0,8}["']?[ \t]{0,8}(?:Bearer|token)[ \t]{1,8})[A-Za-z0-9\-._~+/]{10,}=*/gi],
33
+ ["auth_basic_token", /(?<=Authorization["']?[ \t]{0,8}:[ \t]{0,8}["']?[ \t]{0,8}Basic[ \t]{1,8})[A-Za-z0-9+/]{6,}=*/gi],
34
+ // JWTs have no distinctive prefix of their own, but the base64url encoding of the smallest realistic header ('{"alg":' or similar) always starts with "eyJ", so that's the practical anchor here -- each of the three dot-separated segments requires a minimum length to avoid matching a short, coincidentally dotted token. The trailing `={0,2}` on each segment is what makes a padded token match. Base64url as the JWT spec defines it drops the `=` padding, but producers that reach for a plain base64 encoder emit it anyway, and a `=` in the header or payload segment used to defeat the match outright: not a partial redaction, but none at all, so the entire token was printed. `=` cannot appear anywhere except the end of a segment, since it is not one of the characters the segment body allows, so accepting it here cannot widen the match onto anything else.
35
+ ["jwt", /eyJ[A-Za-z0-9_-]{10,}={0,2}\.[A-Za-z0-9_-]{10,}={0,2}\.[A-Za-z0-9_-]{10,}={0,2}/g],
36
+ ["npm_token", /npm_[A-Za-z0-9]{36}/g],
37
+ // rk_live_ (restricted keys) share the sk_live_/sk_test_ secret-key shape and risk level, so one pattern covers all three rather than adding a near-duplicate entry.
38
+ ["stripe_key", /(?:sk_live_|sk_test_|rk_live_)[A-Za-z0-9]{20,}/g],
39
+ ["google_api_key", /AIza[A-Za-z0-9_-]{35}/g],
40
+ // Presigned-url signatures: AWS SigV4 (X-Amz-Signature), Google Cloud Storage (X-Goog-Signature), and Azure blob SAS (sig). These are bearer credentials in query-string clothing -- anyone holding the whole url can read or write the object until it expires, and none of the prefix-anchored patterns above match them because the signature is a bare hex or base64 blob with no distinctive prefix of its own. The '[?&]' anchor and the 16-char floor are what make the short, generic 'sig' name safe to key on: a prose or code mention of "sig" never sits directly after a query separator followed by that much opaque token.
41
+ ["presigned_signature", /(?<=[?&](?:X-Amz-Signature|X-Goog-Signature|sig)=)[A-Za-z0-9%+/=_-]{16,}/gi],
42
+ // A password inside a connection url. `postgres://user:hunter2@db.internal` carries the credential in the authority section, where there is no `key=value` separator for the generic pattern below to anchor on, so a DATABASE_URL echoed by a failing migration or a psql error went through untouched. The anchors are what keep this narrow: a scheme's `://`, a userinfo segment, the colon, and a following `@`. `http://host:8080/path` has no `@` and is left alone; so is any url without credentials. The password class admits `:` and `@` (RFC 3986 lets userinfo carry the first, and a sloppy producer leaves the second unencoded), so the greedy run backtracks to the LAST `@` before the host; it still stops at whitespace, `/`, quotes and angle brackets, which keeps a quoted JSON neighbour or a following email out of the match. The username may be empty, because redis-py, Celery and most broker clients write a password-only url as `redis://:password@host:6379/0`, and it may hold an unencoded `@`, because a username that is itself an email address arrives that way; it still excludes `:` so the first colon after the scheme is the one that starts the password.
43
+ ["url_credentials", /(?<=:\/\/[^\s:/]{0,64}:)[^\s/"'`<>]{1,256}(?=@)/g],
44
+ // Azure storage account connection strings (`DefaultEndpointsProtocol=https;AccountName=...; AccountKey=<base64>==;EndpointSuffix=core.windows.net`) carry a full read/write key to the account in the AccountKey field, and none of the generic patterns above catch it: generic_secret_assignment's keyword list (password|passwd|secret|api[_-]?key| access[_-]?token|refresh[_-]?token|id[_-]?token) has nothing that matches "AccountKey", and an unanchored base64-shape pattern was deliberately rejected -- this module's header already warns that a bare high-entropy-blob heuristic false-fires on ordinary code, JSON and log output, and an 88-char base64 value is exactly the shape a hash, a compiled asset digest or a generated id can also take. Anchoring on the literal `AccountKey=` field name instead keeps the match specific to this one connection-string field. The value class is base64 proper (letters, digits, `+`, `/`, trailing `=` padding) and none of those characters include `;`, so the match terminates on its own at the `;` that starts the next `Name=` field -- unlike generic_secret_assignment's separator characters (`& ; # , :`), which double as ordinary credential characters and need a lookahead to tell the two roles apart, `;` is never valid base64 and needs no such lookahead here. The lookbehind keeps `AccountKey=` itself in the output, matching auth_bearer_token and presigned_signature above, so `;EndpointSuffix=core.windows.net` after it stays fully readable too. `SharedAccessKey` is the same credential one Azure service over: Service Bus, Event Hubs and Relay spell it that way (`Endpoint=sb://ns.servicebus.windows.net/;SharedAccessKeyName=Root; SharedAccessKey=<base64>`) and it carries the same authority over that namespace that AccountKey does over a storage account. `SharedAccessKeyName` is a plain identifier rather than a secret, and never matches: the separator in the lookbehind sits directly against the key name, so the `Name` in between stops it dead. The separator is spelled the way auth_bearer_token above spells its own, for the same reasons that comment records having learned the hard way. Optional quotes on either side of it, so the JSON and YAML forms a logged MCP result or api response actually arrives in are matched rather than stopped dead at the opening quote. A bounded gap rather than exactly one space, so a hand-aligned or reformatted `AccountKey = ...` in an appsettings file is not the single variant that defeats the whole pattern. Case-insensitive for the same reason presigned_signature is. The leading word boundary is what keeps the widened name from reaching into the middle of a longer identifier such as `myaccountkey=`.
45
+ ["azure_storage_key", /(?<=\b(?:AccountKey|SharedAccessKey)["']?[ \t]{0,8}[:=][ \t]{0,8}["']?)[A-Za-z0-9+/]{40,}=*/gi],
46
+ // Generic key=value assignments in .env-file and connection-string/query-string shape. The lookbehind again redacts only the value, and the value's character class deliberately excludes whitespace, '&', ';', '#', quote characters, and '[' ']' ':' -- that exclusion is what stops this from swallowing the rest of the line (a trailing comment or the next key=value pair) or the remainder of a query string past the matched parameter, which is exactly the kind of over-eager match this module's own design note above warns broad heuristics produce. The '[' ']' ':' exclusion also matters because this pattern runs last: an earlier pattern's own "OPENAI_API_KEY=[REDACTED:openai_project_key]" replacement text contains "API_KEY=" too, and without excluding those characters this pattern would re-match and double-redact its own placeholder. The length has a lower bound only (no upper bound): capping it at 64 used to leave the tail of any longer secret unredacted in plain text, which is worse than no redaction because it looks handled. A single negated-class quantifier like this cannot backtrack catastrophically -- there is no nested or overlapping quantifier for the engine to explore multiple ways of matching, so removing the upper bound does not introduce a ReDoS risk. Quotes are permitted around the separator, but never inside the value class. A quoted value is the ordinary way secrets are written -- .env files, JSON, YAML, TOML all quote by default -- and the lookbehind used to stop dead at the opening quote, so `API_KEY="..."` passed through in full while the bare `API_KEY=...` was caught. The closing quote of the key name blocked it from the other side too, which is what kept every JSON body unredacted. Keeping quotes out of the value class is still what stops the match running past the closing quote. The keyword may be a prefix of a longer key name rather than the whole of it, so the trailing identifier class below is load-bearing: without it the lookbehind required the keyword to sit immediately before the separator, and AWS_SECRET_ACCESS_KEY=, SECRET_KEY=, and DB_PASSWORD_HASH= all passed through in full. That class matches identifier characters only, so prose that merely mentions a keyword still never reaches a separator and stays unredacted. api[_-]?key covers the apikey and api-key spellings too. `& ; # , :` play two incompatible roles. They separate one field from the next (a query string, a cookie header, an inline env list), and they are also perfectly ordinary credential characters. Rejecting them outright got the first role right and the second badly wrong: the match stopped at the first one and left everything after it in plain text, so `password=corr&horse&battery` redacted four characters and printed the rest, and `DB_PASSWORD=Aa1:xyz` matched nothing at all because the run before the `:` was under the four-character floor. A tail left sitting in the open is the outcome this module's header calls worse than no redaction, because it reads as handled. So the separator role is decided by what follows rather than assumed: one of these characters ends the value only when the next thing along is another `name=` / `name:` pair, which is what an actual field separator is always followed by. `,OTHER=public` and `; other=1` still end it; the `&` in the middle of a passphrase does not. Whitespace, quotes and brackets are unchanged -- they end a value unconditionally, which is also what keeps this pattern from re-matching the `[REDACTED:...]` placeholder it just wrote.
47
+ ["generic_secret_assignment", /(?<=(?:password|passwd|secret|api[_-]?key|access[_-]?token|refresh[_-]?token|id[_-]?token)[a-z0-9_-]{0,64}["']?[ \t]{0,8}[:=][ \t]{0,8}["']?)(?:\\[^\n]|[^\s\\&;#,:'"[\]{}]|[&;#,:](?![ \t]*[A-Za-z_][A-Za-z0-9_.-]*[ \t]*[:=])){4,}/gi]
48
+ ];
49
+ function countRedactionPlaceholders(text) {
50
+ return text.match(/\[REDACTED:[a-z0-9_]+\]/g)?.length ?? 0;
51
+ }
52
+ var MAX_CUSTOM_PATTERNS = 64;
53
+ var MAX_CUSTOM_PATTERN_LENGTH = 512;
54
+ var ZERO_WIDTH_PROBES = ["", "a b"];
55
+ function matchesZeroWidth(compiled) {
56
+ return ZERO_WIDTH_PROBES.some((probe) => Array.from(probe.matchAll(compiled)).some((m) => m[0].length === 0));
57
+ }
58
+ var customCache = null;
59
+ function compileCustomPatterns(sources) {
60
+ const key = JSON.stringify(sources);
61
+ if (customCache !== null && customCache.key === key) {
62
+ return { patterns: customCache.patterns, problems: customCache.problems };
63
+ }
64
+ const patterns = [];
65
+ const problems = [];
66
+ const written = sources.map((raw) => raw.trim()).filter((source) => source.length > 0);
67
+ for (const source of written.slice(0, MAX_CUSTOM_PATTERNS)) {
68
+ if (source.length > MAX_CUSTOM_PATTERN_LENGTH) {
69
+ problems.push({ pattern: source.slice(0, 60), reason: `longer than ${MAX_CUSTOM_PATTERN_LENGTH} characters` });
70
+ continue;
71
+ }
72
+ if (hasNestedQuantifier(source)) {
73
+ problems.push({
74
+ pattern: source,
75
+ reason: "repeats a group that already repeats, which can take exponential time to match"
76
+ });
77
+ continue;
78
+ }
79
+ let compiled;
80
+ try {
81
+ compiled = new RegExp(source, "g");
82
+ } catch (e) {
83
+ problems.push({ pattern: source, reason: e instanceof Error ? e.message : "is not a valid regular expression" });
84
+ continue;
85
+ }
86
+ if (matchesZeroWidth(compiled)) {
87
+ problems.push({
88
+ pattern: source,
89
+ reason: "matches the empty string, so it would replace every position in the text"
90
+ });
91
+ continue;
92
+ }
93
+ if (growsExponentially(compiled)) {
94
+ problems.push({
95
+ pattern: source,
96
+ reason: "its running time doubles as the text grows, which can stall the process on a short input"
97
+ });
98
+ continue;
99
+ }
100
+ patterns.push(compiled);
101
+ }
102
+ if (written.length > MAX_CUSTOM_PATTERNS) {
103
+ problems.push({
104
+ pattern: `(${written.length} entries)`,
105
+ reason: `only the first ${MAX_CUSTOM_PATTERNS} custom patterns are used`
106
+ });
107
+ }
108
+ customCache = { key, patterns, problems };
109
+ return { patterns, problems };
110
+ }
111
+ var STRICT_CANDIDATE = /[A-Za-z0-9+/_-]{24,}={0,2}/g;
112
+ function entropyBitsPerChar(s) {
113
+ const counts = /* @__PURE__ */ new Map();
114
+ for (const ch of s) counts.set(ch, (counts.get(ch) ?? 0) + 1);
115
+ let bits = 0;
116
+ for (const n of counts.values()) {
117
+ const p = n / s.length;
118
+ bits -= p * Math.log2(p);
119
+ }
120
+ return bits;
121
+ }
122
+ function characterClasses(s) {
123
+ let n = 0;
124
+ if (/[a-z]/.test(s)) n++;
125
+ if (/[A-Z]/.test(s)) n++;
126
+ if (/[0-9]/.test(s)) n++;
127
+ if (/[+/=_-]/.test(s)) n++;
128
+ return n;
129
+ }
130
+ function looksLikeCredential(s) {
131
+ return characterClasses(s) >= 3 && entropyBitsPerChar(s) >= 3.5;
132
+ }
133
+ var RECALL_TUNED_KIND = "generic_secret_assignment";
134
+ function matchesAnywhere(pattern, text) {
135
+ pattern.lastIndex = 0;
136
+ const hit = pattern.test(text);
137
+ pattern.lastIndex = 0;
138
+ return hit;
139
+ }
140
+ function matchesNonEmpty(compiled, text) {
141
+ compiled.lastIndex = 0;
142
+ for (const match of text.matchAll(compiled)) {
143
+ if (match[0].length > 0) return true;
144
+ }
145
+ return false;
146
+ }
147
+ function hasPreciseSecret(text, config = loadConfig()) {
148
+ for (const [kind, pattern] of SECRET_PATTERNS) {
149
+ if (kind === RECALL_TUNED_KIND) continue;
150
+ if (matchesAnywhere(pattern, text)) return true;
151
+ }
152
+ for (const custom of compileCustomPatterns(config.redaction.custom_patterns).patterns) {
153
+ if (matchesNonEmpty(custom, text)) return true;
154
+ }
155
+ if (config.redaction.strict) {
156
+ for (const candidate of text.match(STRICT_CANDIDATE) ?? []) {
157
+ if (looksLikeCredential(candidate)) return true;
158
+ }
159
+ }
160
+ return false;
161
+ }
162
+ function redactSecrets(text, config = loadConfig(), opts = {}) {
163
+ let count = 0;
164
+ let out = text;
165
+ const placeholder = (tag, match) => opts.keepLineCount === true ? match.split(/(\r?\n)/).map((part, i) => i % 2 === 1 ? part : tag).join("") : tag;
166
+ for (const [kind, pattern] of SECRET_PATTERNS) {
167
+ out = out.replace(pattern, (match) => {
168
+ count++;
169
+ return placeholder(`[REDACTED:${kind}]`, match);
170
+ });
171
+ }
172
+ for (const pattern of compileCustomPatterns(config.redaction.custom_patterns).patterns) {
173
+ out = out.replace(pattern, (match) => {
174
+ if (match.length === 0) return match;
175
+ count++;
176
+ return placeholder("[REDACTED:custom]", match);
177
+ });
178
+ }
179
+ if (config.redaction.strict) {
180
+ out = out.replace(STRICT_CANDIDATE, (candidate) => {
181
+ if (!looksLikeCredential(candidate)) return candidate;
182
+ count++;
183
+ return "[REDACTED:high_entropy]";
184
+ });
185
+ }
186
+ return { text: out, count };
187
+ }
188
+ var CONTROL_ESCAPES = new Map(
189
+ Array.from({ length: 32 }, (_, code) => {
190
+ const ch = String.fromCharCode(code);
191
+ return [ch, JSON.stringify(ch).slice(1, -1)];
192
+ })
193
+ );
194
+ var CONTROL_CHARACTER_OF_ESCAPE = new Map([...CONTROL_ESCAPES].map(([ch, escape]) => [escape, ch]));
195
+ var JSON_ESCAPE = /\\(?:u[0-9a-fA-F]{4}|[^u])/g;
196
+ var SURROGATE_ESCAPE = /^\\u[dD][89a-fA-F][0-9a-fA-F]{2}$/;
197
+ var DECODED_CHARACTER = /[\u0000-\u001f]|[\ud800-\udbff](?![\udc00-\udfff])|(?<![\ud800-\udbff])[\udc00-\udfff]/g;
198
+ function decodeEscape(escape) {
199
+ return CONTROL_CHARACTER_OF_ESCAPE.get(escape) ?? (SURROGATE_ESCAPE.test(escape) ? String.fromCharCode(Number.parseInt(escape.slice(2), 16)) : escape);
200
+ }
201
+ function redactSerializedJson(json) {
202
+ const result = redactSecrets(json.replace(JSON_ESCAPE, decodeEscape));
203
+ return { text: result.text.replace(DECODED_CHARACTER, (ch) => CONTROL_ESCAPES.get(ch) ?? JSON.stringify(ch).slice(1, -1)), count: result.count };
204
+ }
205
+
206
+ export {
207
+ countRedactionPlaceholders,
208
+ compileCustomPatterns,
209
+ hasPreciseSecret,
210
+ redactSecrets,
211
+ redactSerializedJson
212
+ };