token-goat 2.9.30 → 2.9.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (172) hide show
  1. package/README.md +24 -7
  2. package/SECURITY.md +10 -2
  3. package/THIRD_PARTY_NOTICES.md +1 -1
  4. package/dist/native/linux-arm64/tg-hook +0 -0
  5. package/dist/native/linux-x64/tg-hook +0 -0
  6. package/dist/native/win32-arm64/tg-hook.exe +0 -0
  7. package/dist/native/win32-x64/tg-hook.exe +0 -0
  8. package/dist/{token-goat-chunk-QSBRTGM2.mjs → token-goat-chunk-25TRAWET.mjs} +17 -7
  9. package/dist/token-goat-chunk-2KXO6V2B.mjs +203 -0
  10. package/dist/{token-goat-chunk-IVKIZWAB.mjs → token-goat-chunk-2M7E4PF7.mjs} +41 -12
  11. package/dist/{token-goat-chunk-SMVRN2HU.mjs → token-goat-chunk-2UPZGKKY.mjs} +2 -2
  12. package/dist/token-goat-chunk-2WLPWKHV.mjs +135 -0
  13. package/dist/token-goat-chunk-2XBMMDBD.mjs +126 -0
  14. package/dist/token-goat-chunk-32ZOY4N5.mjs +23 -0
  15. package/dist/token-goat-chunk-3EZRNKTK.mjs +188 -0
  16. package/dist/token-goat-chunk-4ADZHI7J.mjs +63 -0
  17. package/dist/token-goat-chunk-4GBVPH3D.mjs +242 -0
  18. package/dist/{token-goat-chunk-KWPNJBDH.mjs → token-goat-chunk-4GILLLWY.mjs} +7 -4
  19. package/dist/{token-goat-chunk-67TQJ76B.mjs → token-goat-chunk-4NAPX7BA.mjs} +36 -3
  20. package/dist/{token-goat-chunk-PU7V3FD6.mjs → token-goat-chunk-4SC7UJYV.mjs} +3354 -2553
  21. package/dist/token-goat-chunk-4SMRO4TO.mjs +366 -0
  22. package/dist/{token-goat-chunk-AFLYLHDH.mjs → token-goat-chunk-4ZBFWLXF.mjs} +283 -427
  23. package/dist/{token-goat-chunk-JDWCRD6M.mjs → token-goat-chunk-57BIAXJL.mjs} +73 -40
  24. package/dist/token-goat-chunk-5AC66HNP.mjs +115 -0
  25. package/dist/token-goat-chunk-5IMLKSOP.mjs +145 -0
  26. package/dist/token-goat-chunk-646E6U44.mjs +398 -0
  27. package/dist/token-goat-chunk-65N4RHP4.mjs +33 -0
  28. package/dist/{token-goat-chunk-JN4XMLSD.mjs → token-goat-chunk-6DG6HWP3.mjs} +8 -2
  29. package/dist/token-goat-chunk-6ENQSNRZ.mjs +573 -0
  30. package/dist/token-goat-chunk-6ZY4GNF2.mjs +91 -0
  31. package/dist/{token-goat-chunk-VPBBTSJR.mjs → token-goat-chunk-76FGDLRO.mjs} +262 -255
  32. package/dist/{token-goat-chunk-7IN2MKDS.mjs → token-goat-chunk-7EZTZOMC.mjs} +121 -289
  33. package/dist/{token-goat-chunk-OJBNYTJP.mjs → token-goat-chunk-7MAOA6X4.mjs} +640 -80
  34. package/dist/token-goat-chunk-7R2ZVVAX.mjs +218 -0
  35. package/dist/{token-goat-chunk-PD5VKH46.mjs → token-goat-chunk-AUNGYYQX.mjs} +2 -2
  36. package/dist/{token-goat-chunk-HG45AF2B.mjs → token-goat-chunk-AUQYRMMH.mjs} +794 -37
  37. package/dist/token-goat-chunk-B3PEKBYG.mjs +128 -0
  38. package/dist/{token-goat-chunk-A3CK6N5Z.mjs → token-goat-chunk-BA4HI6BW.mjs} +1309 -110
  39. package/dist/{token-goat-chunk-JB6QN6VF.mjs → token-goat-chunk-BFCWY73P.mjs} +59 -23
  40. package/dist/{token-goat-chunk-B45VMIIH.mjs → token-goat-chunk-BWGFUZZE.mjs} +7 -5
  41. package/dist/{token-goat-chunk-P4QMM4WK.mjs → token-goat-chunk-C75NA7PL.mjs} +50 -23
  42. package/dist/token-goat-chunk-CBIQ7WTD.mjs +87 -0
  43. package/dist/token-goat-chunk-CETM74KC.mjs +307 -0
  44. package/dist/{token-goat-chunk-H2PHHGM5.mjs → token-goat-chunk-CIMQ2BB3.mjs} +57 -12
  45. package/dist/{token-goat-chunk-N2NMER56.mjs → token-goat-chunk-CJLS3CDL.mjs} +46 -4
  46. package/dist/{token-goat-chunk-VES7EL7O.mjs → token-goat-chunk-CO3UYX6G.mjs} +1 -1
  47. package/dist/token-goat-chunk-COPNXRJM.mjs +154 -0
  48. package/dist/token-goat-chunk-CSJ5L3NL.mjs +479 -0
  49. package/dist/{token-goat-chunk-4LCCNRTG.mjs → token-goat-chunk-CVCEVUGK.mjs} +8 -6
  50. package/dist/{token-goat-chunk-B2RZZCSS.mjs → token-goat-chunk-CXHOFN7R.mjs} +37 -20
  51. package/dist/token-goat-chunk-D735C4QM.mjs +603 -0
  52. package/dist/{token-goat-chunk-APGZXSPS.mjs → token-goat-chunk-DGS2LVNA.mjs} +47 -30
  53. package/dist/{token-goat-chunk-54K3EUV3.mjs → token-goat-chunk-DOWRSMWO.mjs} +1 -1
  54. package/dist/token-goat-chunk-E45INMY3.mjs +71 -0
  55. package/dist/token-goat-chunk-EC5F37F4.mjs +244 -0
  56. package/dist/{token-goat-chunk-XTQAOTSO.mjs → token-goat-chunk-EDBDRVH5.mjs} +4 -1
  57. package/dist/{token-goat-chunk-5BCIJXMO.mjs → token-goat-chunk-EELTBKDM.mjs} +14 -10
  58. package/dist/{token-goat-chunk-W3QCJS6G.mjs → token-goat-chunk-F4HYL64R.mjs} +8 -6
  59. package/dist/token-goat-chunk-F6PAUIEK.mjs +624 -0
  60. package/dist/token-goat-chunk-FDSREWLX.mjs +692 -0
  61. package/dist/token-goat-chunk-GGGG7RWB.mjs +236 -0
  62. package/dist/{token-goat-chunk-C63JQV5K.mjs → token-goat-chunk-GL3ETKSC.mjs} +233 -15
  63. package/dist/token-goat-chunk-GVB2MUST.mjs +1298 -0
  64. package/dist/token-goat-chunk-GWFLAUMQ.mjs +307 -0
  65. package/dist/{token-goat-chunk-ZEJVMUQH.mjs → token-goat-chunk-HLPW63A7.mjs} +2 -2
  66. package/dist/{token-goat-chunk-GOLEOXZP.mjs → token-goat-chunk-HU4TORC5.mjs} +44 -26
  67. package/dist/{token-goat-chunk-Z57YODA2.mjs → token-goat-chunk-I7VKZZAW.mjs} +2 -2
  68. package/dist/{token-goat-chunk-NYKZLXMK.mjs → token-goat-chunk-IA6XSPE3.mjs} +6 -6
  69. package/dist/{token-goat-chunk-E3OQX2XT.mjs → token-goat-chunk-IAGXMHIK.mjs} +81 -42
  70. package/dist/{token-goat-chunk-HYBFA5X3.mjs → token-goat-chunk-IK2DRMFX.mjs} +24 -68
  71. package/dist/{token-goat-chunk-COBQGL5S.mjs → token-goat-chunk-INNPTRUX.mjs} +249 -299
  72. package/dist/{token-goat-chunk-7NADEDKJ.mjs → token-goat-chunk-JJ5BX4F4.mjs} +6 -1
  73. package/dist/{token-goat-chunk-PEPTHRFF.mjs → token-goat-chunk-JVFSHVFJ.mjs} +6 -6
  74. package/dist/token-goat-chunk-KGEFFSHD.mjs +50 -0
  75. package/dist/token-goat-chunk-KQBLRPBN.mjs +433 -0
  76. package/dist/{token-goat-chunk-Q5VTGRH7.mjs → token-goat-chunk-LCNQ2CNN.mjs} +55 -319
  77. package/dist/token-goat-chunk-M3LFJDPU.mjs +58 -0
  78. package/dist/token-goat-chunk-M52KPT3C.mjs +87 -0
  79. package/dist/token-goat-chunk-MBEG42H7.mjs +150 -0
  80. package/dist/{token-goat-chunk-EVC4TOLE.mjs → token-goat-chunk-METECDOH.mjs} +3 -12
  81. package/dist/{token-goat-chunk-T4FK7VOV.mjs → token-goat-chunk-MHX7XCC3.mjs} +2 -1
  82. package/dist/token-goat-chunk-N5LSOVSU.mjs +137 -0
  83. package/dist/{token-goat-chunk-LOBGHXPB.mjs → token-goat-chunk-N5MMR2IW.mjs} +1 -1
  84. package/dist/token-goat-chunk-N7B3JQ2C.mjs +160 -0
  85. package/dist/{token-goat-chunk-RHXKCZX3.mjs → token-goat-chunk-NISNMD7T.mjs} +2182 -2959
  86. package/dist/token-goat-chunk-NMD42SFQ.mjs +434 -0
  87. package/dist/token-goat-chunk-NOSS5VWY.mjs +174 -0
  88. package/dist/{token-goat-chunk-KQNZDCBD.mjs → token-goat-chunk-NSNSPPBG.mjs} +25 -3
  89. package/dist/token-goat-chunk-OBOFIHKN.mjs +38 -0
  90. package/dist/token-goat-chunk-OBRFJ5O5.mjs +76 -0
  91. package/dist/{token-goat-chunk-JTQQGXZH.mjs → token-goat-chunk-ODBT2USM.mjs} +124 -57
  92. package/dist/token-goat-chunk-OS5EM5PP.mjs +107 -0
  93. package/dist/token-goat-chunk-OUKDTVNU.mjs +1178 -0
  94. package/dist/token-goat-chunk-OXFMP75N.mjs +566 -0
  95. package/dist/{token-goat-chunk-DZX2YDPT.mjs → token-goat-chunk-OYIYKDDT.mjs} +2 -2
  96. package/dist/{token-goat-chunk-QCLDAQTS.mjs → token-goat-chunk-P6HQSWQ3.mjs} +50 -53
  97. package/dist/token-goat-chunk-P6VGNTQT.mjs +71 -0
  98. package/dist/{token-goat-chunk-7BXSNBY5.mjs → token-goat-chunk-PFWIMH2E.mjs} +23 -15
  99. package/dist/token-goat-chunk-PJZXIS3G.mjs +39 -0
  100. package/dist/token-goat-chunk-PUO5INXP.mjs +606 -0
  101. package/dist/{token-goat-chunk-GFBSN7BD.mjs → token-goat-chunk-PX5PQWTY.mjs} +22 -250
  102. package/dist/token-goat-chunk-Q5QDBC6O.mjs +111 -0
  103. package/dist/token-goat-chunk-QFNQXSDT.mjs +40 -0
  104. package/dist/{token-goat-chunk-FBNQNSJK.mjs → token-goat-chunk-QH7YVYOY.mjs} +2198 -2782
  105. package/dist/{token-goat-chunk-64FBPDTK.mjs → token-goat-chunk-QLMUHEPB.mjs} +12 -9
  106. package/dist/{token-goat-chunk-RZRTDST7.mjs → token-goat-chunk-QQOJIHL3.mjs} +37 -11
  107. package/dist/{token-goat-chunk-XKI4SEMX.mjs → token-goat-chunk-QQTWJY2O.mjs} +19 -0
  108. package/dist/{token-goat-chunk-U4N3BN2W.mjs → token-goat-chunk-QYHO5CPH.mjs} +3 -2
  109. package/dist/token-goat-chunk-RELAVWAD.mjs +27 -0
  110. package/dist/{token-goat-chunk-ETBHVDB6.mjs → token-goat-chunk-RSLPOBKQ.mjs} +22 -11
  111. package/dist/token-goat-chunk-SAMFDIS2.mjs +712 -0
  112. package/dist/token-goat-chunk-SDELXLDM.mjs +48 -0
  113. package/dist/{token-goat-chunk-4JJS54TR.mjs → token-goat-chunk-SOAFZNNZ.mjs} +161 -38
  114. package/dist/{token-goat-chunk-664RTTUV.mjs → token-goat-chunk-SRTHT7KV.mjs} +21 -16
  115. package/dist/{token-goat-chunk-4FVIAHSI.mjs → token-goat-chunk-T5P5ACNQ.mjs} +7 -6
  116. package/dist/token-goat-chunk-T5YGG4V3.mjs +45 -0
  117. package/dist/token-goat-chunk-TAUZ4OFS.mjs +110 -0
  118. package/dist/{token-goat-chunk-COTXZHTS.mjs → token-goat-chunk-TM6MC754.mjs} +4 -3
  119. package/dist/token-goat-chunk-TWUKBOMP.mjs +72 -0
  120. package/dist/{token-goat-chunk-3CHUNJ2O.mjs → token-goat-chunk-U2KSB4SG.mjs} +8 -5
  121. package/dist/{token-goat-chunk-3Z5S4KGM.mjs → token-goat-chunk-U4WHMG6Y.mjs} +29 -49
  122. package/dist/{token-goat-chunk-PY533T7F.mjs → token-goat-chunk-UGJHGR5A.mjs} +21 -15
  123. package/dist/{token-goat-chunk-CYCEYAEO.mjs → token-goat-chunk-UOUDVA5U.mjs} +1 -1
  124. package/dist/{token-goat-chunk-JDHE26RP.mjs → token-goat-chunk-URRJ33GR.mjs} +16 -5
  125. package/dist/{token-goat-chunk-56EIMS3E.mjs → token-goat-chunk-UZOROKIS.mjs} +23 -17
  126. package/dist/{token-goat-chunk-CZ3LUXYZ.mjs → token-goat-chunk-VIHGGGEI.mjs} +427 -308
  127. package/dist/token-goat-chunk-VTJLAA7P.mjs +21 -0
  128. package/dist/token-goat-chunk-VWDXLT4F.mjs +678 -0
  129. package/dist/{token-goat-chunk-YARZFCZS.mjs → token-goat-chunk-VWZA2H4P.mjs} +62 -53
  130. package/dist/{token-goat-chunk-SQSSNQPE.mjs → token-goat-chunk-VXEXMJDL.mjs} +3979 -4745
  131. package/dist/token-goat-chunk-WBA5SKT4.mjs +547 -0
  132. package/dist/{token-goat-chunk-SJHWVNDQ.mjs → token-goat-chunk-WDH44VAU.mjs} +7 -4
  133. package/dist/token-goat-chunk-X2SUP3EI.mjs +107 -0
  134. package/dist/token-goat-chunk-X3BELZSJ.mjs +125 -0
  135. package/dist/{token-goat-chunk-FZ3NEW5O.mjs → token-goat-chunk-XLRBNZCC.mjs} +13 -8
  136. package/dist/{token-goat-chunk-Z44YO3QZ.mjs → token-goat-chunk-XRKUX6CM.mjs} +1 -1
  137. package/dist/token-goat-chunk-XX6O25RN.mjs +82 -0
  138. package/dist/token-goat-chunk-XZSUHBVS.mjs +65 -0
  139. package/dist/{token-goat-chunk-WY3L4DVT.mjs → token-goat-chunk-Y2ZTQOCL.mjs} +13 -8
  140. package/dist/{token-goat-chunk-UQ5UK2T7.mjs → token-goat-chunk-YB4VMGK2.mjs} +1 -1
  141. package/dist/token-goat-chunk-YBIIY3HR.mjs +51 -0
  142. package/dist/{token-goat-chunk-ZQSJMO2R.mjs → token-goat-chunk-YHVDKQBR.mjs} +105 -105
  143. package/dist/{token-goat-chunk-H2K3QP6H.mjs → token-goat-chunk-YJB5XLWI.mjs} +8 -6
  144. package/dist/{token-goat-chunk-ZCDTCVIS.mjs → token-goat-chunk-YKB6AQG3.mjs} +5 -2
  145. package/dist/token-goat-chunk-YMTG2YA5.mjs +35 -0
  146. package/dist/token-goat-chunk-YPBZYQRV.mjs +40 -0
  147. package/dist/{token-goat-chunk-HOJLCGDP.mjs → token-goat-chunk-YY6AVUFL.mjs} +2033 -2251
  148. package/dist/token-goat-chunk-Z7N5OMMP.mjs +98 -0
  149. package/dist/token-goat-chunk-ZNMNUPAZ.mjs +938 -0
  150. package/dist/token-goat-hook-client.cjs +1 -1
  151. package/dist/token-goat-hook-client.mjs +3 -3
  152. package/dist/token-goat-hook.mjs +67 -38
  153. package/dist/token-goat.core.mjs +4 -4
  154. package/docs/C4_RUNTIME_ARCHITECTURE.md +1 -1
  155. package/docs/cli.md +40 -21
  156. package/docs/install.md +19 -9
  157. package/docs/security.md +5 -3
  158. package/package.json +2 -1
  159. package/dist/token-goat-chunk-5KDMCMF2.mjs +0 -362
  160. package/dist/token-goat-chunk-6QMAS7AB.mjs +0 -42
  161. package/dist/token-goat-chunk-7F2UBPD3.mjs +0 -397
  162. package/dist/token-goat-chunk-ARDNEC2U.mjs +0 -248
  163. package/dist/token-goat-chunk-ATCPY7EQ.mjs +0 -134
  164. package/dist/token-goat-chunk-EFHMMIGP.mjs +0 -68
  165. package/dist/token-goat-chunk-IVALLT3S.mjs +0 -48
  166. package/dist/token-goat-chunk-JDU3EXSU.mjs +0 -65
  167. package/dist/token-goat-chunk-MKPF4CL5.mjs +0 -37
  168. package/dist/token-goat-chunk-RC35RBUL.mjs +0 -312
  169. package/dist/token-goat-chunk-USILZ3T3.mjs +0 -53
  170. package/dist/token-goat-chunk-VL3YIFHZ.mjs +0 -2975
  171. package/dist/token-goat-chunk-XU4P6Z24.mjs +0 -133
  172. package/dist/token-goat-chunk-Y776AENC.mjs +0 -1597
@@ -2,49 +2,252 @@ import { createRequire as __cjsRequire } from 'node:module';
2
2
  const require = __cjsRequire(import.meta.url);
3
3
  import {
4
4
  sanitizeFtsQuery
5
- } from "./token-goat-chunk-HYBFA5X3.mjs";
5
+ } from "./token-goat-chunk-IK2DRMFX.mjs";
6
6
  import {
7
- DEFAULT_MAX_AGE_MS,
8
- blobPath,
9
- isBlobStale,
10
- loadBlob,
11
- storeBlob
12
- } from "./token-goat-chunk-ARDNEC2U.mjs";
13
- import {
14
- getDb
15
- } from "./token-goat-chunk-VL3YIFHZ.mjs";
7
+ recordStat
8
+ } from "./token-goat-chunk-U4WHMG6Y.mjs";
16
9
  import {
17
- redactSecrets
18
- } from "./token-goat-chunk-4FVIAHSI.mjs";
10
+ getDb,
11
+ getReadDb
12
+ } from "./token-goat-chunk-GVB2MUST.mjs";
19
13
  import {
20
- shortFingerprint
21
- } from "./token-goat-chunk-7IN2MKDS.mjs";
14
+ hasUnquotedOperator
15
+ } from "./token-goat-chunk-4GILLLWY.mjs";
22
16
  import {
23
- registerReset
24
- } from "./token-goat-chunk-YZAAZU2S.mjs";
17
+ stripAnsiEscapes
18
+ } from "./token-goat-chunk-HAVAOB3S.mjs";
25
19
  import {
26
- runGit
27
- } from "./token-goat-chunk-GOLEOXZP.mjs";
20
+ redactSerializedJson
21
+ } from "./token-goat-chunk-T5P5ACNQ.mjs";
28
22
  import {
29
- normalizePath
30
- } from "./token-goat-chunk-FNFBKLRD.mjs";
23
+ loadConfig
24
+ } from "./token-goat-chunk-7EZTZOMC.mjs";
31
25
  import {
32
- globalDbPath
33
- } from "./token-goat-chunk-VES7EL7O.mjs";
26
+ atomicWriteText,
27
+ ensureDirSync,
28
+ sanitizeIdForFilename
29
+ } from "./token-goat-chunk-HU4TORC5.mjs";
34
30
  import {
35
- hasUnquotedOperator
36
- } from "./token-goat-chunk-KWPNJBDH.mjs";
37
- import {
38
- stripAnsiEscapes
39
- } from "./token-goat-chunk-HAVAOB3S.mjs";
31
+ globalDbPath,
32
+ tokenGoatHome
33
+ } from "./token-goat-chunk-CO3UYX6G.mjs";
40
34
  import {
41
35
  init_define_import_meta_env
42
36
  } from "./token-goat-chunk-A37V4PBF.mjs";
43
37
 
44
- // src/bash_output_cache.ts
38
+ // src/disk_cache.ts
45
39
  init_define_import_meta_env();
46
- import { readdirSync, readFileSync, statSync } from "fs";
47
- import { resolve } from "path";
40
+ import * as fs from "node:fs";
41
+ import * as path from "node:path";
42
+ var DEFAULT_MAX_COUNT = 200;
43
+ var DEFAULT_MAX_AGE_MS = 24 * 3600 * 1e3;
44
+ function sanitizeId(id) {
45
+ return sanitizeIdForFilename(id, 64);
46
+ }
47
+ function blobDir(subdir) {
48
+ return path.join(tokenGoatHome(), subdir);
49
+ }
50
+ function blobPath(subdir, id) {
51
+ const safe = sanitizeId(id);
52
+ if (!safe) return null;
53
+ const dir = blobDir(subdir);
54
+ const candidate = path.join(dir, `${safe}.json`);
55
+ try {
56
+ const rel = path.relative(dir, candidate);
57
+ if (rel.startsWith("..")) return null;
58
+ } catch {
59
+ return null;
60
+ }
61
+ return candidate;
62
+ }
63
+ function isBlobStale(subdir, id) {
64
+ const p = blobPath(subdir, id);
65
+ if (p === null) return false;
66
+ try {
67
+ const stat = fs.statSync(p);
68
+ return Date.now() - stat.mtimeMs > DEFAULT_MAX_AGE_MS;
69
+ } catch {
70
+ return false;
71
+ }
72
+ }
73
+ function subdirCacheDefaults(subdir) {
74
+ try {
75
+ if (subdir === "bash_outputs") {
76
+ const bc = loadConfig().bash_compress;
77
+ return { maxCount: bc.cache_max_file_count, maxBytes: bc.cache_max_bytes, maxBytesPerItem: bc.cache_max_bytes_per_output };
78
+ }
79
+ if (subdir === "web_outputs") {
80
+ const wf = loadConfig().webfetch;
81
+ return { maxCount: wf.max_file_count, maxBytes: wf.max_bytes, maxBytesPerItem: Number.POSITIVE_INFINITY };
82
+ }
83
+ } catch {
84
+ }
85
+ return { maxCount: DEFAULT_MAX_COUNT, maxBytes: Number.POSITIVE_INFINITY, maxBytesPerItem: Number.POSITIVE_INFINITY };
86
+ }
87
+ function storeBlob(subdir, id, value, opts = {}) {
88
+ const p = blobPath(subdir, id);
89
+ if (!p) return false;
90
+ const defaults = subdirCacheDefaults(subdir);
91
+ const maxBytesPerItem = opts.maxBytesPerItem ?? defaults.maxBytesPerItem;
92
+ let rawJson;
93
+ try {
94
+ rawJson = JSON.stringify(value);
95
+ } catch {
96
+ return false;
97
+ }
98
+ let json;
99
+ try {
100
+ const result = redactSerializedJson(rawJson);
101
+ json = result.text;
102
+ if (result.count > 0) recordStat("secret_redacted", 0, result.count, void 0, subdir);
103
+ } catch {
104
+ return false;
105
+ }
106
+ if (Number.isFinite(maxBytesPerItem) && Buffer.byteLength(json, "utf-8") > maxBytesPerItem) return false;
107
+ try {
108
+ const dir = path.dirname(p);
109
+ if (!fs.existsSync(dir)) ensureDirSync(dir);
110
+ atomicWriteText(p, json);
111
+ } catch {
112
+ return false;
113
+ }
114
+ pruneBlobs(
115
+ subdir,
116
+ opts.maxCount ?? defaults.maxCount,
117
+ opts.maxAgeMs ?? DEFAULT_MAX_AGE_MS,
118
+ opts.maxBytes ?? defaults.maxBytes,
119
+ p
120
+ );
121
+ return true;
122
+ }
123
+ function loadBlob(subdir, id) {
124
+ const p = blobPath(subdir, id);
125
+ if (!p) return null;
126
+ try {
127
+ if (!fs.existsSync(p)) return null;
128
+ return JSON.parse(fs.readFileSync(p, "utf8"));
129
+ } catch {
130
+ return null;
131
+ }
132
+ }
133
+ function listBlobs(subdir) {
134
+ const dir = blobDir(subdir);
135
+ const out = [];
136
+ try {
137
+ if (!fs.existsSync(dir)) return out;
138
+ for (const file of fs.readdirSync(dir)) {
139
+ if (!file.endsWith(".json")) continue;
140
+ const id = file.slice(0, -5);
141
+ let mtime = 0;
142
+ try {
143
+ mtime = fs.statSync(path.join(dir, file)).mtimeMs;
144
+ } catch {
145
+ }
146
+ const value = loadBlob(subdir, id);
147
+ if (value !== null) out.push({ id, mtime, value });
148
+ }
149
+ } catch {
150
+ return out;
151
+ }
152
+ return out;
153
+ }
154
+ function pruneBlobs(subdir, maxCount = DEFAULT_MAX_COUNT, maxAgeMs = DEFAULT_MAX_AGE_MS, maxBytes = Number.POSITIVE_INFINITY, protectedPath) {
155
+ return pruneBlobDir(blobDir(subdir), maxCount, maxAgeMs, maxBytes, protectedPath);
156
+ }
157
+ function pruneBlobDir(dir, maxCount = DEFAULT_MAX_COUNT, maxAgeMs = DEFAULT_MAX_AGE_MS, maxBytes = Number.POSITIVE_INFINITY, protectedPath) {
158
+ let removed = 0;
159
+ try {
160
+ if (!fs.existsSync(dir)) return 0;
161
+ const cutoff = Date.now() - maxAgeMs;
162
+ let kept = [];
163
+ let protectedEntry;
164
+ for (const file of fs.readdirSync(dir)) {
165
+ const full = path.join(dir, file);
166
+ let stat;
167
+ try {
168
+ stat = fs.statSync(full);
169
+ } catch {
170
+ continue;
171
+ }
172
+ if (!stat.isFile()) continue;
173
+ if (protectedPath !== void 0 && full === protectedPath) {
174
+ protectedEntry = [full, stat.mtimeMs, stat.size];
175
+ continue;
176
+ }
177
+ if (stat.mtimeMs < cutoff) {
178
+ try {
179
+ fs.unlinkSync(full);
180
+ removed++;
181
+ } catch {
182
+ continue;
183
+ }
184
+ } else if (file.endsWith(".json")) {
185
+ kept.push([full, stat.mtimeMs, stat.size]);
186
+ }
187
+ }
188
+ const countBudget = protectedEntry ? Math.max(0, maxCount - 1) : maxCount;
189
+ if (kept.length > countBudget) {
190
+ kept.sort((a, b) => a[1] - b[1]);
191
+ const excess = kept.slice(0, kept.length - countBudget);
192
+ kept = kept.slice(kept.length - countBudget);
193
+ for (const [full] of excess) {
194
+ try {
195
+ fs.unlinkSync(full);
196
+ removed++;
197
+ } catch {
198
+ continue;
199
+ }
200
+ }
201
+ }
202
+ if (Number.isFinite(maxBytes)) {
203
+ kept.sort((a, b) => a[1] - b[1]);
204
+ let total = kept.reduce((sum, [, , size]) => sum + size, 0) + (protectedEntry ? protectedEntry[2] : 0);
205
+ while (total > maxBytes && kept.length > 0) {
206
+ const oldest = kept.shift();
207
+ if (!oldest) break;
208
+ const [full, , size] = oldest;
209
+ try {
210
+ fs.unlinkSync(full);
211
+ removed++;
212
+ total -= size;
213
+ } catch {
214
+ break;
215
+ }
216
+ }
217
+ }
218
+ } catch {
219
+ return removed;
220
+ }
221
+ return removed;
222
+ }
223
+ var SWEEPABLE_CACHE_SUBDIRS = [
224
+ { subdir: "bash_outputs", countCapped: true },
225
+ { subdir: "web_outputs", countCapped: true },
226
+ { subdir: "mcp_outputs", countCapped: true },
227
+ { subdir: "sessions", countCapped: false }
228
+ ];
229
+ function sweepCacheRoots(extraRoots = []) {
230
+ let removed = 0;
231
+ const roots = [tokenGoatHome(), ...extraRoots];
232
+ const seen = /* @__PURE__ */ new Set();
233
+ for (const root of roots) {
234
+ if (!root || seen.has(root)) continue;
235
+ seen.add(root);
236
+ for (const { subdir, countCapped } of SWEEPABLE_CACHE_SUBDIRS) {
237
+ try {
238
+ const defaults = subdirCacheDefaults(subdir);
239
+ removed += pruneBlobDir(
240
+ path.join(root, subdir),
241
+ countCapped ? defaults.maxCount : Number.POSITIVE_INFINITY,
242
+ DEFAULT_MAX_AGE_MS,
243
+ countCapped ? defaults.maxBytes : Number.POSITIVE_INFINITY
244
+ );
245
+ } catch {
246
+ }
247
+ }
248
+ }
249
+ return removed;
250
+ }
48
251
 
49
252
  // src/hints/lang_patterns.ts
50
253
  init_define_import_meta_env();
@@ -332,16 +535,46 @@ function getMonitoringRecallHint(cmd) {
332
535
  return null;
333
536
  }
334
537
 
538
+ // src/git_porcelain.ts
539
+ init_define_import_meta_env();
540
+ function parsePorcelainZ(stdout) {
541
+ const fields = stdout.split("\0");
542
+ const out = [];
543
+ for (let i = 0; i < fields.length; i++) {
544
+ const field = fields[i] ?? "";
545
+ if (field.length < 4) continue;
546
+ const entry = { path: field.slice(3) };
547
+ if (field.startsWith("??")) entry.untracked = true;
548
+ if (/[RC]/.test(field.slice(0, 2))) {
549
+ i++;
550
+ const orig = fields[i];
551
+ if (orig !== void 0 && orig !== "") entry.origPath = orig;
552
+ }
553
+ out.push(entry);
554
+ }
555
+ return out;
556
+ }
557
+
335
558
  // src/recall_index.ts
336
559
  init_define_import_meta_env();
337
- import * as fs from "node:fs";
560
+ import * as fs2 from "node:fs";
561
+
562
+ // src/snippet_window.ts
563
+ init_define_import_meta_env();
564
+ function snippetAround(text, idx, maxLen) {
565
+ const start = Math.max(0, idx - Math.floor(maxLen / 3));
566
+ const end = Math.min(text.length, start + maxLen);
567
+ return (start > 0 ? "..." : "") + text.slice(start, end) + (end < text.length ? "..." : "");
568
+ }
569
+
570
+ // src/recall_index.ts
338
571
  function subdirForCacheType(cacheType) {
339
572
  return cacheType === "web" ? "web_outputs" : "bash_outputs";
340
573
  }
341
574
  function blobStillExists(cacheType, id) {
342
575
  try {
343
576
  const p = blobPath(subdirForCacheType(cacheType), id);
344
- return p !== null && fs.existsSync(p);
577
+ return p !== null && fs2.existsSync(p);
345
578
  } catch {
346
579
  return false;
347
580
  }
@@ -379,7 +612,7 @@ var _ftsAvailable = null;
379
612
  function hasFtsTable() {
380
613
  if (_ftsAvailable !== null) return _ftsAvailable;
381
614
  try {
382
- const db = getDb(globalDbPath());
615
+ const db = getReadDb(globalDbPath());
383
616
  const row = db.prepare(`SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'cache_recall_fts'`).get();
384
617
  _ftsAvailable = row !== void 0;
385
618
  } catch {
@@ -399,14 +632,7 @@ function buildSnippet(content, query, maxLen = 160) {
399
632
  break;
400
633
  }
401
634
  }
402
- if (idx === -1) {
403
- return flat.length > maxLen ? flat.slice(0, maxLen) + "..." : flat;
404
- }
405
- const start = Math.max(0, idx - Math.floor(maxLen / 3));
406
- const end = Math.min(flat.length, start + maxLen);
407
- const prefix = start > 0 ? "..." : "";
408
- const suffix = end < flat.length ? "..." : "";
409
- return prefix + flat.slice(start, end) + suffix;
635
+ return snippetAround(flat, Math.max(0, idx), maxLen);
410
636
  }
411
637
  function toFtsMatchExpr(query) {
412
638
  if (query.trim().length === 0) return null;
@@ -425,7 +651,7 @@ function mapRowsToHits(rows, snippetQuery) {
425
651
  function ftsSearch(query, type, limit) {
426
652
  const matchExpr = toFtsMatchExpr(query);
427
653
  if (matchExpr === null) return [];
428
- const db = getDb(globalDbPath());
654
+ const db = getReadDb(globalDbPath());
429
655
  const rows = type !== void 0 ? db.prepare(
430
656
  `SELECT c.entry_id AS id, c.cache_type AS cacheType, c.label AS label, c.content AS content, c.stored_at AS storedAt
431
657
  FROM cache_recall_fts
@@ -446,7 +672,7 @@ function ftsSearch(query, type, limit) {
446
672
  function likeSearch(query, type, limit) {
447
673
  const trimmed = query.trim();
448
674
  if (!trimmed) return [];
449
- const db = getDb(globalDbPath());
675
+ const db = getReadDb(globalDbPath());
450
676
  const needle = `%${trimmed.replace(/\\/g, "\\\\").replace(/[%_]/g, (c) => `\\${c}`)}%`;
451
677
  const rows = type !== void 0 ? db.prepare(
452
678
  `SELECT entry_id AS id, cache_type AS cacheType, label, content, stored_at AS storedAt
@@ -467,7 +693,7 @@ function listRecentRecall(opts = {}) {
467
693
  const limit = opts.limit ?? RECALL_DEFAULT_LIMIT;
468
694
  const columns = `SELECT entry_id AS id, cache_type AS cacheType, label, content, stored_at AS storedAt FROM cache_recall`;
469
695
  try {
470
- const db = getDb(globalDbPath());
696
+ const db = getReadDb(globalDbPath());
471
697
  const rows = opts.type !== void 0 ? db.prepare(`${columns} WHERE cache_type = ? ORDER BY stored_at DESC LIMIT ?`).all(opts.type, limit) : db.prepare(`${columns} ORDER BY stored_at DESC LIMIT ?`).all(limit);
472
698
  return mapRowsToHits(rows, "");
473
699
  } catch {
@@ -491,399 +717,29 @@ function searchRecall(query, opts = {}) {
491
717
  }
492
718
  }
493
719
 
494
- // src/bash_output_cache.ts
495
- var BASH_OUTPUT_SUBDIR = "bash_outputs";
496
- var _byId = /* @__PURE__ */ new Map();
497
- var COMMAND_PATTERNS = {
498
- gitMutable: /^\s*git\s+(diff|status)\b/i,
499
- gitImmutable: /^\s*git\s+show\s+[0-9a-f]{40}\b/i,
500
- gitDiffScoped: /\s--\s+\S/,
501
- dirListing: /^\s*(?:ls|eza|exa|dir|Get-ChildItem|gci)\b/i,
502
- depList: /^\s*(?:npm\s+(?:--?[a-zA-Z0-9_-]+(?:\s+|=))*(?:ls|list)\b|pip\s+(?:--?[a-zA-Z0-9_-]+(?:\s+|=))*(?:list|freeze)\b|uv\s+pip\s+(?:--?[a-zA-Z0-9_-]+(?:\s+|=))*(?:list|freeze)\b|pnpm\s+(?:--?[a-zA-Z0-9_-]+(?:\s+|=))*(?:list|ls)\b|yarn\s+(?:--?[a-zA-Z0-9_-]+(?:\s+|=))*(?:list)\b|cargo\s+(?:--?[a-zA-Z0-9_-]+(?:\s+|=))*tree\b|bundle\s+(?:--?[a-zA-Z0-9_-]+(?:\s+|=))*(?:list|show)\b|composer\s+(?:--?[a-zA-Z0-9_-]+(?:\s+|=))*show\b)/i,
503
- npmInstall: /^\s*npm\s+(?:--?[a-zA-Z0-9_-]+(?:\s+|=))*(?:install|ci)\b/i,
504
- npmAudit: /^\s*npm\s+(?:--?[a-zA-Z0-9_-]+(?:\s+|=))*audit\b(?!.*(?:--fix|fix)\b)/i,
505
- npmOutdated: /^\s*npm\s+(?:--?[a-zA-Z0-9_-]+(?:\s+|=))*outdated\b/i,
506
- envProbe: /^\s*(?:node\s+(?:-v|--version)|npm\s+(?:-v|--version)|python3?\s+(?:(?:-V)\b|--?version)|git\s+--version|uv\s+--version|go\s+version|rustc\s+--version|cargo\s+--version|java\s+--version|ruby\s+--version|gem\s+--version|php\s+--version|which\b|where\b)/i,
507
- npx: /^(?!.*\b(?:install|add|remove|uninstall|i|rm|update|upgrade|set|get|publish|link|ci|audit|shrinkwrap|dedupe|prune|rebuild)\b)\s*npx\s+(?:--?yes\s+)?/i,
508
- gitPush: /^\s*git\s+push\b/i,
509
- lintCommand: /^\s*(?:(?:npx\s+)?eslint|(?:uv\s+run\s+)?ruff)\b/i,
510
- npmRunScript: /^\s*npm\s+run(?:-script)?\b/i,
511
- catCommand: /^\s*cat\b/i
512
- };
513
- var DEP_LOCKFILES = {
514
- npm: ["package-lock.json", "yarn.lock"],
515
- pip: ["requirements.txt"],
516
- uv: ["uv.lock", "requirements.txt"],
517
- pnpm: ["pnpm-lock.yaml"],
518
- yarn: ["yarn.lock"],
519
- cargo: ["Cargo.lock"],
520
- bundle: ["Gemfile.lock"],
521
- composer: ["composer.lock"]
522
- };
523
- function isCommandOfType(cmd, type) {
524
- const pattern = COMMAND_PATTERNS[type];
525
- return pattern?.test(cmd) ?? false;
526
- }
527
- var isGitMutableCommand = (cmd) => isCommandOfType(cmd, "gitMutable");
528
- var isDirListingCommand = (cmd) => isCommandOfType(cmd, "dirListing");
529
- var isDepListCommand = (cmd) => isCommandOfType(cmd, "depList");
530
- var isNpmInstallCommand = (cmd) => isCommandOfType(cmd, "npmInstall");
531
- var isNpmAuditCommand = (cmd) => isCommandOfType(cmd, "npmAudit");
532
- var isNpmOutdatedCommand = (cmd) => isCommandOfType(cmd, "npmOutdated");
533
- var isGitPushCommand = (cmd) => isCommandOfType(cmd, "gitPush");
534
- var isLintCommand = (cmd) => isCommandOfType(cmd, "lintCommand");
535
- var isNpmRunScriptCommand = (cmd) => isCommandOfType(cmd, "npmRunScript");
536
- var isCatCommand = (cmd) => isCommandOfType(cmd, "catCommand");
537
- function isScopedGitStatusOrDiffStatCommand(cmd) {
538
- if (!isCommandOfType(cmd, "gitMutable")) return false;
539
- if (!isCommandOfType(cmd, "gitDiffScoped")) return false;
540
- if (/^\s*git\s+diff\b/i.test(cmd) && !/--stat\b/.test(cmd)) return false;
541
- return true;
542
- }
543
- function gitStateFingerprintSync(cwd) {
544
- try {
545
- const headResult = runGit(["rev-parse", "HEAD"], { cwd });
546
- if (headResult.exitCode !== 0) return null;
547
- const headSha = headResult.stdout.trim();
548
- let statusHash = "";
549
- const statusResult = runGit(["status", "--porcelain"], { cwd });
550
- if (statusResult.exitCode === 0) {
551
- statusHash = shortFingerprint(statusResult.stdout);
552
- }
553
- const key = `${headSha}\0${statusHash}`;
554
- return shortFingerprint(key);
555
- } catch {
556
- return null;
557
- }
558
- }
559
- var DIR_FINGERPRINT_LISTING_CAP_ENTRIES = 1e4;
560
- function dirStateFingerprintSync(path) {
561
- try {
562
- const stat = statSync(path);
563
- if (!stat.isDirectory()) return null;
564
- const entries = readdirSync(path);
565
- if (entries.length <= DIR_FINGERPRINT_LISTING_CAP_ENTRIES) {
566
- return shortFingerprint(entries.slice().sort().join("\0"));
567
- }
568
- return shortFingerprint(stat.mtimeMs.toString());
569
- } catch {
570
- return null;
571
- }
572
- }
573
- var FILE_FINGERPRINT_CONTENT_CAP_BYTES = 2 * 1024 * 1024;
574
- function fileStateFingerprintSync(path) {
575
- try {
576
- const stat = statSync(path);
577
- if (!stat.isFile()) return null;
578
- if (stat.size <= FILE_FINGERPRINT_CONTENT_CAP_BYTES) {
579
- return shortFingerprint(readFileSync(path));
580
- }
581
- return shortFingerprint(`${stat.mtimeMs}\0${stat.size}`);
582
- } catch {
583
- return null;
584
- }
585
- }
586
- function depLockfileFingerprintSync(cmd, cwd) {
587
- if (!cwd) return null;
588
- const stripped = cmd.trim();
589
- const firstToken = stripped.split(/\s+/)[0]?.toLowerCase() || "";
590
- if (!firstToken) return null;
591
- const candidates = firstToken === "uv" ? DEP_LOCKFILES["uv"] : DEP_LOCKFILES[firstToken];
592
- if (!candidates) return null;
593
- for (const lockfile of candidates) {
594
- try {
595
- const content = readFileSync(resolve(cwd, lockfile));
596
- return shortFingerprint(content);
597
- } catch {
598
- continue;
599
- }
600
- }
601
- return null;
602
- }
603
- function normalizeCommandForCacheKey(cmd) {
604
- const trimmed = cmd.trim();
605
- const tokens = [];
606
- let current = "";
607
- let quoteChar = null;
608
- const flush = () => {
609
- if (current.length > 0) {
610
- tokens.push(current);
611
- current = "";
612
- }
613
- };
614
- for (let i = 0; i < trimmed.length; i++) {
615
- const ch = trimmed[i];
616
- if (quoteChar !== null) {
617
- current += ch;
618
- if (ch === quoteChar) quoteChar = null;
619
- continue;
620
- }
621
- if (ch === '"' || ch === "'") {
622
- quoteChar = ch;
623
- current += ch;
624
- continue;
625
- }
626
- if (/\s/.test(ch)) {
627
- flush();
628
- continue;
629
- }
630
- current += ch === "\\" ? "/" : ch;
631
- }
632
- flush();
633
- const normalized_tokens = tokens.map((token) => {
634
- if (token.startsWith("-") || ["&&", "||", "|", ">", ">>", ";", "&"].includes(token)) {
635
- return token;
636
- }
637
- if (token.startsWith("./") && !token.startsWith("../")) {
638
- token = token.slice(2);
639
- }
640
- if (token.endsWith("/") && token !== "/") {
641
- token = token.slice(0, -1);
642
- }
643
- return token || ".";
644
- });
645
- return normalized_tokens.join(" ");
646
- }
647
- function commandHashSync(command, cwd = null) {
648
- const normalized = normalizeCommandForCacheKey(command);
649
- let key = cwd ? `${normalizePath(cwd)}\0${normalized}` : normalized;
650
- if (cwd && isGitMutableCommand(command)) {
651
- const fp = gitStateFingerprintSync(cwd);
652
- if (fp) key = `${key}\0git:${fp}`;
653
- }
654
- if (cwd && isDirListingCommand(command)) {
655
- const target = extractFirstPathArg(command, cwd, cwd);
656
- if (target) {
657
- const fp = dirStateFingerprintSync(target);
658
- if (fp) key = `${key}\0dir:${fp}`;
659
- }
660
- }
661
- if (isDepListCommand(command)) {
662
- const fp = depLockfileFingerprintSync(command, cwd);
663
- if (fp) key = `${key}\0lockfile:${fp}`;
664
- }
665
- if (cwd && (isNpmInstallCommand(command) || isNpmAuditCommand(command) || isNpmOutdatedCommand(command))) {
666
- const fp = depLockfileFingerprintSync(command, cwd);
667
- if (fp) key = `${key}\0npm-install:${fp}`;
668
- }
669
- return shortFingerprint(key);
670
- }
671
- function commandHash(command, cwd = null) {
672
- return Promise.resolve(commandHashSync(command, cwd));
673
- }
674
- function bashOutputIdSync(command, output, cwd = null) {
675
- return shortFingerprint(`${commandHashSync(command, cwd)}\0${output}`);
676
- }
677
- function computeBashFingerprints(command, cwd) {
678
- const fingerprints = {};
679
- if (cwd && (isGitMutableCommand(command) || isGitPushCommand(command) || isTestRunnerCommand(command) || isLintCommand(command) || isBuildCommand(command) || isDevServerCommand(command) || isNpmRunScriptCommand(command))) {
680
- const fp = gitStateFingerprintSync(cwd);
681
- if (fp) fingerprints.git = fp;
682
- }
683
- if (cwd && isDirListingCommand(command)) {
684
- const target = extractFirstPathArg(command, cwd, cwd);
685
- if (target) {
686
- const fp = dirStateFingerprintSync(target);
687
- if (fp) fingerprints.dir = fp;
688
- }
689
- }
690
- if (isDepListCommand(command) || cwd && (isNpmInstallCommand(command) || isNpmAuditCommand(command) || isNpmOutdatedCommand(command))) {
691
- const fp = depLockfileFingerprintSync(command, cwd);
692
- if (fp) fingerprints.lockfile = fp;
693
- }
694
- if (cwd && isCatCommand(command)) {
695
- const target = extractFirstPathArg(command, cwd, null);
696
- if (target) {
697
- const fp = fileStateFingerprintSync(target);
698
- if (fp) fingerprints.file = fp;
699
- }
700
- }
701
- return Object.keys(fingerprints).length > 0 ? fingerprints : void 0;
702
- }
703
- function isBashEntryStale(entry, command, cwd) {
704
- const stored = entry.fingerprints;
705
- if (!stored) return false;
706
- const current = computeBashFingerprints(command, cwd);
707
- if (stored.git !== void 0 && stored.git !== current?.git) return true;
708
- if (stored.dir !== void 0 && stored.dir !== current?.dir) return true;
709
- if (stored.lockfile !== void 0 && stored.lockfile !== current?.lockfile) return true;
710
- if (stored.file !== void 0 && stored.file !== current?.file) return true;
711
- return false;
712
- }
713
- function tokenizeShellArgs(cmd) {
714
- const trimmed = cmd.trim();
715
- const tokens = [];
716
- let current = "";
717
- let quoteChar = null;
718
- let hasToken = false;
719
- for (let i = 0; i < trimmed.length; i++) {
720
- const ch = trimmed[i];
721
- if (quoteChar !== null) {
722
- if (ch === quoteChar) {
723
- quoteChar = null;
724
- } else {
725
- current += ch;
726
- }
727
- continue;
728
- }
729
- if (ch === '"' || ch === "'") {
730
- quoteChar = ch;
731
- hasToken = true;
732
- continue;
733
- }
734
- if (/\s/.test(ch)) {
735
- if (hasToken) {
736
- tokens.push(current);
737
- current = "";
738
- hasToken = false;
739
- }
740
- continue;
741
- }
742
- current += ch;
743
- hasToken = true;
744
- }
745
- if (hasToken) tokens.push(current);
746
- return tokens;
747
- }
748
- function extractFirstPathArg(cmd, cwd, fallback) {
749
- const tokens = tokenizeShellArgs(cmd);
750
- for (let i = 1; i < tokens.length; i++) {
751
- const token = tokens[i];
752
- if (!token.startsWith("-")) {
753
- if (!token.startsWith("/")) {
754
- return resolve(cwd, token);
755
- }
756
- return token;
757
- }
758
- }
759
- return fallback;
760
- }
761
- var ISSUE_LINE_PATTERN = /\b(?:error|fail(?:ed|ure)?|warning)\b/i;
762
- function summarizeOutputDelta(oldOutput, newOutput) {
763
- if (oldOutput === newOutput) return null;
764
- const oldLines = oldOutput.split("\n");
765
- const newLines = newOutput.split("\n");
766
- const oldIssueLines = oldLines.filter((l) => ISSUE_LINE_PATTERN.test(l));
767
- if (oldIssueLines.length > 0) {
768
- const newIssueLines = newLines.filter((l) => ISSUE_LINE_PATTERN.test(l));
769
- const priorTotal = oldIssueLines.length;
770
- const availableCounts = /* @__PURE__ */ new Map();
771
- for (const l of newIssueLines) availableCounts.set(l, (availableCounts.get(l) ?? 0) + 1);
772
- let resolved = 0;
773
- for (const l of oldIssueLines) {
774
- const avail = availableCounts.get(l) ?? 0;
775
- if (avail > 0) {
776
- availableCounts.set(l, avail - 1);
777
- } else {
778
- resolved++;
779
- }
780
- }
781
- const remaining = newIssueLines.length;
782
- return `[token-goat: delta] ${resolved} of ${priorTotal} prior issues resolved; remaining: ${remaining}`;
783
- }
784
- return `[token-goat: delta] output changed: ${oldLines.length} -> ${newLines.length} lines`;
785
- }
786
- function storeBashOutputSync(command, output, exitCode, cwd = null) {
787
- const id = bashOutputIdSync(command, output, cwd);
788
- const commandKey = commandHashSync(command, cwd);
789
- const fingerprints = computeBashFingerprints(command, cwd);
790
- const redactedOutput = redactSecrets(output).text;
791
- const redactedCommand = redactSecrets(command).text;
792
- const entry = {
793
- id,
794
- command: redactedCommand,
795
- output: redactedOutput,
796
- exitCode,
797
- storedAt: Date.now(),
798
- sizeBytes: Buffer.byteLength(redactedOutput, "utf-8"),
799
- ...fingerprints ? { fingerprints } : {}
800
- };
801
- _byId.set(id, entry);
802
- _byId.set(commandKey, entry);
803
- storeBlob(BASH_OUTPUT_SUBDIR, id, entry);
804
- if (commandKey !== id) storeBlob(BASH_OUTPUT_SUBDIR, commandKey, { latestId: id });
805
- indexRecallEntry("bash", id, redactedCommand, `${redactedCommand}
806
- ${redactedOutput}`, entry.storedAt);
807
- return id;
808
- }
809
- function coerceBashRedirect(raw) {
810
- if (raw === null || typeof raw !== "object") return null;
811
- const latest = raw["latestId"];
812
- return typeof latest === "string" && latest.length > 0 ? latest : null;
813
- }
814
- function storeBashOutput(command, output, exitCode, cwd = null) {
815
- return Promise.resolve(storeBashOutputSync(command, output, exitCode, cwd));
816
- }
817
- function coerceBashEntry(raw) {
818
- if (raw === null || typeof raw !== "object") return null;
819
- const o = raw;
820
- if (typeof o["id"] !== "string" || typeof o["command"] !== "string" || typeof o["output"] !== "string" || typeof o["exitCode"] !== "number" || typeof o["storedAt"] !== "number" || typeof o["sizeBytes"] !== "number") {
821
- return null;
822
- }
823
- const entry = {
824
- id: o["id"],
825
- command: o["command"],
826
- output: o["output"],
827
- exitCode: o["exitCode"],
828
- storedAt: o["storedAt"],
829
- sizeBytes: o["sizeBytes"]
830
- };
831
- const rawFingerprints = o["fingerprints"];
832
- if (rawFingerprints !== null && typeof rawFingerprints === "object") {
833
- const f = rawFingerprints;
834
- const fingerprints = {};
835
- if (typeof f["git"] === "string") fingerprints.git = f["git"];
836
- if (typeof f["dir"] === "string") fingerprints.dir = f["dir"];
837
- if (typeof f["lockfile"] === "string") fingerprints.lockfile = f["lockfile"];
838
- if (typeof f["file"] === "string") fingerprints.file = f["file"];
839
- if (Object.keys(fingerprints).length > 0) return { ...entry, fingerprints };
840
- }
841
- return entry;
842
- }
843
- function getBashOutput(id) {
844
- const hit = _byId.get(id);
845
- if (hit !== void 0) return hit;
846
- if (isBlobStale(BASH_OUTPUT_SUBDIR, id)) return null;
847
- const raw = loadBlob(BASH_OUTPUT_SUBDIR, id);
848
- const target = coerceBashRedirect(raw);
849
- if (target !== null) {
850
- if (isBlobStale(BASH_OUTPUT_SUBDIR, target)) return null;
851
- const latest = coerceBashEntry(loadBlob(BASH_OUTPUT_SUBDIR, target));
852
- if (latest === null) return null;
853
- _byId.set(target, latest);
854
- _byId.set(id, latest);
855
- return latest;
856
- }
857
- const entry = coerceBashEntry(raw);
858
- if (entry === null) return null;
859
- _byId.set(id, entry);
860
- return entry;
861
- }
862
- registerReset(() => {
863
- _byId = /* @__PURE__ */ new Map();
864
- }, { perRequest: true });
865
-
866
720
  export {
721
+ parsePorcelainZ,
722
+ DEFAULT_MAX_COUNT,
723
+ DEFAULT_MAX_AGE_MS,
724
+ blobPath,
725
+ isBlobStale,
726
+ storeBlob,
727
+ loadBlob,
728
+ listBlobs,
729
+ pruneBlobs,
730
+ sweepCacheRoots,
867
731
  isLockFile,
868
732
  isManifestFile,
869
733
  isInBuildDir,
870
734
  isGeneratedFile,
871
735
  isBuildCommand,
872
736
  isTestRunnerCommand,
737
+ isDevServerCommand,
873
738
  getMonitoringRecallHint,
739
+ snippetAround,
874
740
  RECALL_DEFAULT_LIMIT,
875
741
  isRecallCacheType,
876
742
  indexRecallEntry,
877
743
  listRecentRecall,
878
- searchRecall,
879
- BASH_OUTPUT_SUBDIR,
880
- isScopedGitStatusOrDiffStatCommand,
881
- normalizeCommandForCacheKey,
882
- commandHash,
883
- bashOutputIdSync,
884
- isBashEntryStale,
885
- summarizeOutputDelta,
886
- storeBashOutputSync,
887
- storeBashOutput,
888
- getBashOutput
744
+ searchRecall
889
745
  };