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,547 @@
1
+ import { createRequire as __cjsRequire } from 'node:module';
2
+ const require = __cjsRequire(import.meta.url);
3
+ import {
4
+ GENERIC_SERVED_OUTPUT_KEY,
5
+ MAX_BASH_START_CWDS,
6
+ MAX_GENERIC_SERVED_OUTPUTS,
7
+ MAX_OUTSTANDING_AGENT_SPAWNS,
8
+ MAX_RANGES_PER_FILE,
9
+ MAX_SEEN_IMAGE_HASHES,
10
+ MAX_SERVED_OUTPUTS_PER_FILE,
11
+ MAX_VERIFICATION_RUNS,
12
+ bashStartCwdsAtLoad,
13
+ coerceReadRangeEvasion,
14
+ consumedBashStartCwdKeys,
15
+ consumedCurlDownloadKeys,
16
+ consumedFileLineRangeKeys,
17
+ consumedFileServedOutputKeys,
18
+ consumedOutstandingAgentSpawnKeys,
19
+ consumedPendingLargeFileHintKeys,
20
+ curlDownloadsAtLoad,
21
+ exportSessionState,
22
+ filesFullReadCountAtLoad,
23
+ filesReadCountAtLoad,
24
+ importSessionState,
25
+ markCompacted,
26
+ mergeEpochBase,
27
+ mergeReadRangeEvasion,
28
+ migrateCurlDownloadKey,
29
+ migrateWebFetchKey,
30
+ outstandingAgentSpawnKey,
31
+ outstandingAgentSpawnsAtLoad,
32
+ pendingLargeFileHintsAtLoad
33
+ } from "./token-goat-chunk-GL3ETKSC.mjs";
34
+ import {
35
+ redactSerializedJson
36
+ } from "./token-goat-chunk-T5P5ACNQ.mjs";
37
+ import {
38
+ atomicWriteText,
39
+ ensureDirSync,
40
+ sanitizeIdForFilename,
41
+ withFileLock,
42
+ withRetryOnLock
43
+ } from "./token-goat-chunk-HU4TORC5.mjs";
44
+ import {
45
+ foldPath
46
+ } from "./token-goat-chunk-AM5V6GSX.mjs";
47
+ import {
48
+ normalizePath
49
+ } from "./token-goat-chunk-FNFBKLRD.mjs";
50
+ import {
51
+ tokenGoatHome
52
+ } from "./token-goat-chunk-CO3UYX6G.mjs";
53
+ import {
54
+ init_define_import_meta_env
55
+ } from "./token-goat-chunk-A37V4PBF.mjs";
56
+
57
+ // src/sessions_dir.ts
58
+ init_define_import_meta_env();
59
+ import * as path from "node:path";
60
+ var SESSIONS_SUBDIR = "sessions";
61
+ function sessionsDir() {
62
+ return path.join(tokenGoatHome(), SESSIONS_SUBDIR);
63
+ }
64
+
65
+ // src/session_store.ts
66
+ init_define_import_meta_env();
67
+ import { createHash } from "node:crypto";
68
+ import * as fs from "node:fs";
69
+ import * as path2 from "node:path";
70
+ var MAX_FILES = 500;
71
+ var AGENT_SALT_MARKER = sanitizeIdForFilename(":agent:");
72
+ var AGENT_SALT_SEPARATOR = ":agent:";
73
+ var AGENT_DIGEST_CHARS = 12;
74
+ var SALTED_SESSION_MAX = 64 - AGENT_SALT_MARKER.length - AGENT_DIGEST_CHARS;
75
+ function saltedStemPrefix(sessionId) {
76
+ return `${sanitizeIdForFilename(sessionId, SALTED_SESSION_MAX)}${AGENT_SALT_MARKER}`;
77
+ }
78
+ function sessionFileStem(sessionId) {
79
+ const sep = sessionId.indexOf(AGENT_SALT_SEPARATOR);
80
+ if (sep < 0) return sanitizeIdForFilename(sessionId, 64);
81
+ const agentId = sessionId.slice(sep + AGENT_SALT_SEPARATOR.length);
82
+ const digest = createHash("sha256").update(agentId).digest("hex").slice(0, AGENT_DIGEST_CHARS);
83
+ return `${saltedStemPrefix(sessionId.slice(0, sep))}${digest}`;
84
+ }
85
+ function sessionPath(sessionId) {
86
+ return sessionSidecarPath(sessionId, ".json");
87
+ }
88
+ function sessionSidecarPath(sessionId, suffix) {
89
+ if (!sessionId) return null;
90
+ const safe = sessionFileStem(sessionId);
91
+ if (!safe) return null;
92
+ if (suffix.includes("/") || suffix.includes("\\") || suffix.includes("..")) return null;
93
+ if (suffix !== ".json" && suffix.endsWith(".json")) return null;
94
+ const dir = sessionsDir();
95
+ const candidate = path2.join(dir, `${safe}${suffix}`);
96
+ try {
97
+ const rel = path2.relative(dir, candidate);
98
+ if (rel.startsWith("..")) return null;
99
+ } catch {
100
+ return null;
101
+ }
102
+ return candidate;
103
+ }
104
+ function asStringPairs(raw) {
105
+ if (!Array.isArray(raw)) return [];
106
+ const out = [];
107
+ for (const item of raw) {
108
+ if (Array.isArray(item) && typeof item[0] === "string" && typeof item[1] === "string") {
109
+ out.push([item[0], item[1]]);
110
+ }
111
+ }
112
+ return out;
113
+ }
114
+ function asFileEntry(raw) {
115
+ if (raw === null || typeof raw !== "object") return null;
116
+ const o = raw;
117
+ if (typeof o["path"] !== "string" || typeof o["readCount"] !== "number" || typeof o["lastReadAt"] !== "number" || typeof o["wasEdited"] !== "boolean" || typeof o["sizeBytes"] !== "number") {
118
+ return null;
119
+ }
120
+ let entry = {
121
+ path: o["path"],
122
+ readCount: o["readCount"],
123
+ lastReadAt: o["lastReadAt"],
124
+ wasEdited: o["wasEdited"],
125
+ sizeBytes: o["sizeBytes"]
126
+ };
127
+ if (o["wasTruncated"] === true) entry = { ...entry, wasTruncated: true };
128
+ if (typeof o["lastFullReadAt"] === "number") entry = { ...entry, lastFullReadAt: o["lastFullReadAt"] };
129
+ if (typeof o["fullReadCount"] === "number") entry = { ...entry, fullReadCount: o["fullReadCount"] };
130
+ if (typeof o["lastEditedAt"] === "number") entry = { ...entry, lastEditedAt: o["lastEditedAt"] };
131
+ if (Array.isArray(o["symbols_read"])) {
132
+ const symbols = o["symbols_read"].filter((s) => typeof s === "string");
133
+ if (symbols.length > 0) entry = { ...entry, symbols_read: symbols };
134
+ }
135
+ const rangeIdentity = o["rangeFileIdentity"];
136
+ if (rangeIdentity !== null && typeof rangeIdentity === "object" && typeof rangeIdentity["size"] === "number" && typeof rangeIdentity["mtimeMs"] === "number") {
137
+ entry = { ...entry, rangeFileIdentity: { size: rangeIdentity["size"], mtimeMs: rangeIdentity["mtimeMs"] } };
138
+ }
139
+ const epochBase = o["epochBase"];
140
+ if (epochBase !== null && typeof epochBase === "object") {
141
+ const b = epochBase;
142
+ if (typeof b["at"] === "number" && typeof b["readCount"] === "number" && typeof b["fullReadCount"] === "number") {
143
+ entry = { ...entry, epochBase: { at: b["at"], readCount: b["readCount"], fullReadCount: b["fullReadCount"] } };
144
+ }
145
+ }
146
+ return entry;
147
+ }
148
+ function asPyFileEntry(dictKey, raw) {
149
+ if (raw === null || typeof raw !== "object") return null;
150
+ const v = raw;
151
+ const p = typeof v["rel_or_abs"] === "string" ? v["rel_or_abs"] : dictKey;
152
+ if (!p) return null;
153
+ const readCount = typeof v["read_count"] === "number" ? Math.max(1, Math.round(v["read_count"])) : 1;
154
+ const lastReadTs = typeof v["last_read_ts"] === "number" ? v["last_read_ts"] : 0;
155
+ const sizeBytes = typeof v["read_size"] === "number" ? Math.round(v["read_size"]) : 0;
156
+ const wasEdited = typeof v["last_edit_ts"] === "number" && v["last_edit_ts"] > 0;
157
+ return { path: p, readCount, lastReadAt: lastReadTs * 1e3, wasEdited, sizeBytes };
158
+ }
159
+ function asRangeIdentities(raw) {
160
+ if (!Array.isArray(raw)) return [];
161
+ const out = [];
162
+ for (const pair of raw) {
163
+ if (!Array.isArray(pair) || pair.length !== 2 || typeof pair[0] !== "string") continue;
164
+ const id = pair[1];
165
+ if (id !== null && typeof id === "object" && typeof id["size"] === "number" && typeof id["mtimeMs"] === "number") out.push([pair[0], { size: id["size"], mtimeMs: id["mtimeMs"] }]);
166
+ }
167
+ return out;
168
+ }
169
+ function asLineRanges(raw) {
170
+ if (!Array.isArray(raw)) return [];
171
+ const out = [];
172
+ for (const pair of raw) {
173
+ if (!Array.isArray(pair) || pair.length !== 2) continue;
174
+ const filePath = pair[0];
175
+ const ranges = pair[1];
176
+ if (typeof filePath !== "string" || !Array.isArray(ranges)) continue;
177
+ const valid = [];
178
+ for (const r of ranges) {
179
+ if (Array.isArray(r) && r.length === 2 && typeof r[0] === "number" && typeof r[1] === "number") valid.push([r[0], r[1]]);
180
+ }
181
+ out.push([filePath, valid]);
182
+ }
183
+ return out;
184
+ }
185
+ function asServedOutputs(raw) {
186
+ if (!Array.isArray(raw)) return [];
187
+ const out = [];
188
+ for (const pair of raw) {
189
+ if (!Array.isArray(pair) || pair.length !== 2) continue;
190
+ const filePath = pair[0];
191
+ const ids = pair[1];
192
+ if (typeof filePath !== "string" || !Array.isArray(ids)) continue;
193
+ out.push([filePath, ids.filter((id) => typeof id === "string")]);
194
+ }
195
+ return out;
196
+ }
197
+ function migrateKeys(pairs, migrate) {
198
+ return pairs.map(([key, value]) => [migrate(key), value]);
199
+ }
200
+ function coerce(raw) {
201
+ const o = raw !== null && typeof raw === "object" ? raw : {};
202
+ const files = [];
203
+ if (Array.isArray(o["files"])) {
204
+ for (const f of o["files"]) {
205
+ const e = asFileEntry(f);
206
+ if (e !== null) files.push(e);
207
+ }
208
+ } else if (o["files"] !== null && typeof o["files"] === "object") {
209
+ for (const [key, val] of Object.entries(o["files"])) {
210
+ const e = asPyFileEntry(key, val);
211
+ if (e !== null) files.push(e);
212
+ }
213
+ }
214
+ const hintsShown = Array.isArray(o["hintsShown"]) ? o["hintsShown"].filter((h) => typeof h === "string") : Array.isArray(o["hints_seen"]) ? o["hints_seen"].filter((h) => typeof h === "string") : [];
215
+ const scheduledPromptCounts = Array.isArray(o["scheduledPromptCounts"]) ? o["scheduledPromptCounts"].filter(
216
+ (p) => Array.isArray(p) && p.length === 2 && typeof p[0] === "string" && typeof p[1] === "number" && Number.isSafeInteger(p[1]) && p[1] >= 0
217
+ ) : [];
218
+ const cliReads = Array.isArray(o["cliReads"]) ? o["cliReads"].filter((h) => typeof h === "string") : [];
219
+ const bashReruns = Array.isArray(o["bashReruns"]) ? o["bashReruns"].filter((h) => typeof h === "string") : [];
220
+ const seenImageHashes = Array.isArray(o["seenImageHashes"]) ? o["seenImageHashes"].filter((h) => typeof h === "string") : [];
221
+ const verificationRuns = Array.isArray(o["verificationRuns"]) ? o["verificationRuns"].filter(
222
+ (r) => r !== null && typeof r === "object" && typeof r.command === "string" && typeof r.at === "number" && (r.exitCode === null || typeof r.exitCode === "number")
223
+ ) : [];
224
+ const pendingLargeFileHints = Array.isArray(o["pendingLargeFileHints"]) ? o["pendingLargeFileHints"].filter(
225
+ (p) => Array.isArray(p) && p.length === 2 && typeof p[0] === "string" && typeof p[1] === "number"
226
+ ) : [];
227
+ const grepQueries = Array.isArray(o["grepQueries"]) ? o["grepQueries"].filter(
228
+ (p) => Array.isArray(p) && p.length === 2 && typeof p[0] === "string" && typeof p[1] === "number"
229
+ ) : [];
230
+ const globQueries = Array.isArray(o["globQueries"]) ? o["globQueries"].filter(
231
+ (p) => Array.isArray(p) && p.length === 2 && typeof p[0] === "string" && typeof p[1] === "number"
232
+ ) : [];
233
+ const outstandingAgentSpawns = Array.isArray(o["outstandingAgentSpawns"]) ? o["outstandingAgentSpawns"].filter(
234
+ (p) => Array.isArray(p) && p.length === 2 && typeof p[0] === "string" && typeof p[1] === "number"
235
+ ) : [];
236
+ const rangeIdentities = asRangeIdentities(o["fileLineRangeIdentities"]);
237
+ return {
238
+ files,
239
+ hintsShown,
240
+ ...scheduledPromptCounts.length > 0 ? { scheduledPromptCounts } : {},
241
+ webFetches: migrateKeys(asStringPairs(o["webFetches"]), migrateWebFetchKey),
242
+ bashOutputs: asStringPairs(o["bashOutputs"]),
243
+ curlDownloads: migrateKeys(asStringPairs(o["curlDownloads"]), migrateCurlDownloadKey),
244
+ fileLineRanges: asLineRanges(o["fileLineRanges"]),
245
+ readRangeEvasion: coerceReadRangeEvasion(o["readRangeEvasion"]),
246
+ ...rangeIdentities.length > 0 ? { fileLineRangeIdentities: rangeIdentities } : {},
247
+ fileServedOutputs: asServedOutputs(o["fileServedOutputs"]),
248
+ cliReads,
249
+ bashReruns,
250
+ pendingLargeFileHints,
251
+ bashStartCwds: asStringPairs(o["bashStartCwds"]),
252
+ grepQueries,
253
+ globQueries,
254
+ outstandingAgentSpawns,
255
+ ...typeof o["lastTabContextDigest"] === "string" ? { lastTabContextDigest: o["lastTabContextDigest"] } : {},
256
+ ...seenImageHashes.length > 0 ? { seenImageHashes } : {},
257
+ ...verificationRuns.length > 0 ? { verificationRuns } : {},
258
+ ...typeof o["compactedAt"] === "number" ? { compactedAt: o["compactedAt"] } : {},
259
+ ...typeof o["created_ts"] === "number" ? { created_ts: o["created_ts"] } : {}
260
+ };
261
+ }
262
+ function mergeFileEntry(a, b) {
263
+ const newest = a.lastReadAt >= b.lastReadAt ? a : b;
264
+ const baseline = filesReadCountAtLoad().get(b.path) ?? 0;
265
+ const newReadsThisProcess = Math.max(0, b.readCount - baseline);
266
+ let merged = {
267
+ path: a.path,
268
+ readCount: a.readCount + newReadsThisProcess,
269
+ lastReadAt: Math.max(a.lastReadAt, b.lastReadAt),
270
+ wasEdited: a.wasEdited || b.wasEdited,
271
+ sizeBytes: newest.sizeBytes
272
+ };
273
+ if (newest.rangeFileIdentity) merged = { ...merged, rangeFileIdentity: newest.rangeFileIdentity };
274
+ if (a.wasTruncated || b.wasTruncated) merged = { ...merged, wasTruncated: true };
275
+ const lastFullReadAt = Math.max(a.lastFullReadAt ?? 0, b.lastFullReadAt ?? 0);
276
+ if (lastFullReadAt > 0) merged = { ...merged, lastFullReadAt };
277
+ const fullReadBaseline = filesFullReadCountAtLoad().get(b.path) ?? 0;
278
+ const newFullReadsThisProcess = Math.max(0, (b.fullReadCount ?? 0) - fullReadBaseline);
279
+ const fullReadCount = (a.fullReadCount ?? 0) + newFullReadsThisProcess;
280
+ if (fullReadCount > 0) merged = { ...merged, fullReadCount };
281
+ const lastEditedAt = Math.max(a.lastEditedAt ?? 0, b.lastEditedAt ?? 0);
282
+ if (lastEditedAt > 0) merged = { ...merged, lastEditedAt };
283
+ const epochBase = mergeEpochBase(a.epochBase, b.epochBase);
284
+ if (epochBase !== void 0) merged = { ...merged, epochBase };
285
+ const symbols = Array.from(/* @__PURE__ */ new Set([...a.symbols_read ?? [], ...b.symbols_read ?? []]));
286
+ if (symbols.length > 0) merged = { ...merged, symbols_read: symbols };
287
+ return merged;
288
+ }
289
+ function mergePairs(disk, mem) {
290
+ return Array.from(new Map([...disk, ...mem]).entries());
291
+ }
292
+ function mergeMaxNumberPairs(disk, mem) {
293
+ const merged = new Map(disk);
294
+ for (const [key, value] of mem) {
295
+ merged.set(key, Math.max(merged.get(key) ?? 0, value));
296
+ }
297
+ return Array.from(merged.entries());
298
+ }
299
+ function mergeLineRanges(disk, mem) {
300
+ const byPath = /* @__PURE__ */ new Map();
301
+ for (const [filePath, ranges] of disk) byPath.set(filePath, [...ranges]);
302
+ for (const [filePath, ranges] of mem) {
303
+ const prev = byPath.get(filePath) ?? [];
304
+ const seen = new Set(prev.map(([s, e]) => s + ":" + e));
305
+ for (const [s, e] of ranges) {
306
+ const key = s + ":" + e;
307
+ if (seen.has(key) || prev.length >= MAX_RANGES_PER_FILE) continue;
308
+ prev.push([s, e]);
309
+ seen.add(key);
310
+ }
311
+ byPath.set(filePath, prev);
312
+ }
313
+ return Array.from(byPath.entries());
314
+ }
315
+ var GENERIC_SERVED_OUTPUT_FOLDED_KEY = foldPath(normalizePath(GENERIC_SERVED_OUTPUT_KEY));
316
+ function mergeServedOutputs(disk, mem) {
317
+ const byPath = /* @__PURE__ */ new Map();
318
+ for (const [filePath, ids] of disk) byPath.set(filePath, [...ids]);
319
+ for (const [filePath, ids] of mem) {
320
+ const prev = byPath.get(filePath) ?? [];
321
+ const merged = [...prev.filter((id) => !ids.includes(id)), ...ids];
322
+ const cap = filePath === GENERIC_SERVED_OUTPUT_FOLDED_KEY ? MAX_GENERIC_SERVED_OUTPUTS : MAX_SERVED_OUTPUTS_PER_FILE;
323
+ if (merged.length > cap) merged.splice(0, merged.length - cap);
324
+ byPath.set(filePath, merged);
325
+ }
326
+ return Array.from(byPath.entries());
327
+ }
328
+ function mergePendingLargeFileHints(disk, mem) {
329
+ const merged = new Map(disk);
330
+ for (const key of consumedPendingLargeFileHintKeys()) merged.delete(key);
331
+ const atLoad = pendingLargeFileHintsAtLoad();
332
+ for (const [key, size] of mem) {
333
+ if (atLoad.get(key) === size) continue;
334
+ merged.set(key, size);
335
+ }
336
+ return Array.from(merged.entries());
337
+ }
338
+ function mergeCurlDownloads(disk, mem) {
339
+ const merged = new Map(disk);
340
+ for (const key of consumedCurlDownloadKeys()) merged.delete(key);
341
+ const atLoad = curlDownloadsAtLoad();
342
+ for (const [url, savedPath] of mem) {
343
+ if (atLoad.get(url) === savedPath) continue;
344
+ merged.set(url, savedPath);
345
+ }
346
+ return Array.from(merged.entries());
347
+ }
348
+ function mergeBashStartCwds(disk, mem) {
349
+ const merged = new Map(disk);
350
+ for (const key of consumedBashStartCwdKeys()) merged.delete(key);
351
+ const atLoad = bashStartCwdsAtLoad();
352
+ for (const [toolUseId, cwd] of mem) {
353
+ if (atLoad.get(toolUseId) === cwd) continue;
354
+ merged.set(toolUseId, cwd);
355
+ }
356
+ const entries = Array.from(merged.entries());
357
+ return entries.length > MAX_BASH_START_CWDS ? entries.slice(entries.length - MAX_BASH_START_CWDS) : entries;
358
+ }
359
+ function mergeOutstandingAgentSpawns(disk, mem) {
360
+ const merged = new Map(disk.map(([prompt, ts]) => [outstandingAgentSpawnKey(prompt, ts), [prompt, ts]]));
361
+ for (const key of consumedOutstandingAgentSpawnKeys()) merged.delete(key);
362
+ const atLoad = new Set(outstandingAgentSpawnsAtLoad().map((e) => outstandingAgentSpawnKey(e.prompt, e.ts)));
363
+ for (const [prompt, ts] of mem) {
364
+ const key = outstandingAgentSpawnKey(prompt, ts);
365
+ if (atLoad.has(key)) continue;
366
+ merged.set(key, [prompt, ts]);
367
+ }
368
+ const result = Array.from(merged.values()).sort((a, b) => a[1] - b[1]);
369
+ if (result.length > MAX_OUTSTANDING_AGENT_SPAWNS) {
370
+ result.splice(0, result.length - MAX_OUTSTANDING_AGENT_SPAWNS);
371
+ }
372
+ return result;
373
+ }
374
+ function mergeSessionState(disk, mem) {
375
+ const byPath = /* @__PURE__ */ new Map();
376
+ for (const e of disk.files) byPath.set(foldPath(e.path), e);
377
+ for (const e of mem.files) {
378
+ const key = foldPath(e.path);
379
+ const prev = byPath.get(key);
380
+ byPath.set(key, prev ? mergeFileEntry(prev, e) : e);
381
+ }
382
+ const compactedAt = Math.max(disk.compactedAt ?? 0, mem.compactedAt ?? 0);
383
+ const rawDiskRanges = (disk.compactedAt ?? 0) === compactedAt ? disk.fileLineRanges ?? [] : [];
384
+ const memRanges = (mem.compactedAt ?? 0) === compactedAt ? mem.fileLineRanges ?? [] : [];
385
+ const rawDiskServed = (disk.compactedAt ?? 0) === compactedAt ? disk.fileServedOutputs ?? [] : [];
386
+ const memServed = (mem.compactedAt ?? 0) === compactedAt ? mem.fileServedOutputs ?? [] : [];
387
+ const rawDiskCliReads = (disk.compactedAt ?? 0) === compactedAt ? disk.cliReads ?? [] : [];
388
+ const memCliReads = (mem.compactedAt ?? 0) === compactedAt ? mem.cliReads ?? [] : [];
389
+ const latestRuns = /* @__PURE__ */ new Map();
390
+ for (const run of [...disk.verificationRuns ?? [], ...mem.verificationRuns ?? []]) {
391
+ const seen = latestRuns.get(run.command);
392
+ if (seen === void 0 || run.at >= seen.at) latestRuns.set(run.command, run);
393
+ }
394
+ const verificationRuns = Array.from(latestRuns.values()).sort((a, b) => a.at - b.at).slice(-MAX_VERIFICATION_RUNS);
395
+ const clearedRangeFiles = new Set(consumedFileLineRangeKeys());
396
+ const clearedServedFiles = new Set(consumedFileServedOutputKeys());
397
+ const diskRanges = rawDiskRanges.filter(([path3]) => !clearedRangeFiles.has(path3));
398
+ const diskServed = rawDiskServed.filter(([path3]) => !clearedServedFiles.has(path3));
399
+ const fileLineRanges = mergeLineRanges(diskRanges, memRanges);
400
+ const diskRangeEvasion = (disk.compactedAt ?? 0) === compactedAt ? disk.readRangeEvasion ?? [] : [];
401
+ const memRangeEvasion = (mem.compactedAt ?? 0) === compactedAt ? mem.readRangeEvasion ?? [] : [];
402
+ const rangedFiles = new Set(fileLineRanges.map(([path3]) => path3));
403
+ const rawDiskIdentities = (disk.compactedAt ?? 0) === compactedAt ? disk.fileLineRangeIdentities ?? [] : [];
404
+ const memIdentities = (mem.compactedAt ?? 0) === compactedAt ? mem.fileLineRangeIdentities ?? [] : [];
405
+ const fileLineRangeIdentities = mergePairs(rawDiskIdentities.filter(([path3]) => !clearedRangeFiles.has(path3)), memIdentities).filter(([path3]) => rangedFiles.has(path3));
406
+ return {
407
+ files: Array.from(byPath.values()),
408
+ hintsShown: Array.from(/* @__PURE__ */ new Set([...disk.hintsShown, ...mem.hintsShown])),
409
+ scheduledPromptCounts: mergeMaxNumberPairs(disk.scheduledPromptCounts ?? [], mem.scheduledPromptCounts ?? []),
410
+ webFetches: mergePairs(disk.webFetches, mem.webFetches),
411
+ bashOutputs: mergePairs(disk.bashOutputs, mem.bashOutputs),
412
+ curlDownloads: mergeCurlDownloads(disk.curlDownloads, mem.curlDownloads),
413
+ fileLineRanges,
414
+ readRangeEvasion: mergeReadRangeEvasion(diskRangeEvasion, memRangeEvasion),
415
+ ...fileLineRangeIdentities.length > 0 ? { fileLineRangeIdentities } : {},
416
+ fileServedOutputs: mergeServedOutputs(diskServed, memServed),
417
+ ...compactedAt > 0 ? { compactedAt } : {},
418
+ // Same epoch filter as the line ranges above: a CLI read recorded before the winning compaction is not in the model's context any more, so merging it back would resurrect the "you already ran this" note the compaction just cleared.
419
+ cliReads: Array.from(/* @__PURE__ */ new Set([...rawDiskCliReads, ...memCliReads])),
420
+ bashReruns: Array.from(/* @__PURE__ */ new Set([...disk.bashReruns ?? [], ...mem.bashReruns ?? []])),
421
+ pendingLargeFileHints: mergePendingLargeFileHints(disk.pendingLargeFileHints ?? [], mem.pendingLargeFileHints ?? []),
422
+ bashStartCwds: mergeBashStartCwds(disk.bashStartCwds ?? [], mem.bashStartCwds ?? []),
423
+ grepQueries: mergePairs(disk.grepQueries ?? [], mem.grepQueries ?? []),
424
+ globQueries: mergePairs(disk.globQueries ?? [], mem.globQueries ?? []),
425
+ outstandingAgentSpawns: mergeOutstandingAgentSpawns(disk.outstandingAgentSpawns ?? [], mem.outstandingAgentSpawns ?? []),
426
+ // An accumulating collection, so union rather than pick a winner: two hook processes can each see a screenshot the other never did. Disk first, then mem, so the order stays oldest-to-newest and the cap evicts the oldest -- the same policy recordSeenImage applies in memory, applied again here because a union of two capped lists can exceed the cap.
427
+ seenImageHashes: mergeSeenImageHashes(disk.seenImageHashes ?? [], mem.seenImageHashes ?? []),
428
+ ...verificationRuns.length > 0 ? { verificationRuns } : {},
429
+ // Last-seen scalar, not an accumulating collection: prefer mem's value (this process's freshest observation) over disk's, since a newer write always supersedes an older one.
430
+ ...mem.lastTabContextDigest !== void 0 ? { lastTabContextDigest: mem.lastTabContextDigest } : disk.lastTabContextDigest !== void 0 ? { lastTabContextDigest: disk.lastTabContextDigest } : {},
431
+ // Prefer the value already on disk: it marks the original creation time, and must never be bumped forward to the merge's "now". `mem` never carries one (it is not tracked in memory), so this is really "keep whatever disk has".
432
+ ...disk.created_ts !== void 0 ? { created_ts: disk.created_ts } : mem.created_ts !== void 0 ? { created_ts: mem.created_ts } : {}
433
+ };
434
+ }
435
+ function mergeSeenImageHashes(disk, mem) {
436
+ const merged = Array.from(/* @__PURE__ */ new Set([...disk, ...mem]));
437
+ return merged.length > MAX_SEEN_IMAGE_HASHES ? merged.slice(merged.length - MAX_SEEN_IMAGE_HASHES) : merged;
438
+ }
439
+ function capFiles(s, max) {
440
+ if (s.files.length <= max) return s;
441
+ const kept = [...s.files].sort((a, b) => a.wasEdited === b.wasEdited ? b.lastReadAt - a.lastReadAt : a.wasEdited ? -1 : 1).slice(0, max);
442
+ return { ...s, files: kept };
443
+ }
444
+ function readDiskState(p) {
445
+ try {
446
+ return readDiskStateForMerge(p);
447
+ } catch {
448
+ return null;
449
+ }
450
+ }
451
+ function readDiskStateForMerge(p) {
452
+ let text = "";
453
+ try {
454
+ withRetryOnLock(() => {
455
+ text = fs.readFileSync(p, "utf8");
456
+ });
457
+ } catch (err) {
458
+ if (err.code === "ENOENT") return null;
459
+ throw err;
460
+ }
461
+ try {
462
+ return coerce(JSON.parse(text));
463
+ } catch {
464
+ return null;
465
+ }
466
+ }
467
+ function readSessionStateFile(sessionId) {
468
+ const p = sessionPath(sessionId);
469
+ if (!p) return null;
470
+ return readDiskState(p);
471
+ }
472
+ function listSiblingSessionStates(sessionId) {
473
+ if (!sessionId) return [];
474
+ const prefix = saltedStemPrefix(sessionId);
475
+ if (prefix === AGENT_SALT_MARKER) return [];
476
+ const dir = sessionsDir();
477
+ const out = [];
478
+ try {
479
+ if (!fs.existsSync(dir)) return out;
480
+ for (const file of fs.readdirSync(dir)) {
481
+ if (!file.endsWith(".json") || !file.startsWith(prefix)) continue;
482
+ const state = readDiskState(path2.join(dir, file));
483
+ if (state !== null) out.push(state);
484
+ }
485
+ } catch {
486
+ return out;
487
+ }
488
+ return out;
489
+ }
490
+ var EMPTY_SESSION = { files: [], hintsShown: [], webFetches: [], bashOutputs: [], curlDownloads: [] };
491
+ function loadSessionState(sessionId) {
492
+ const p = sessionPath(sessionId);
493
+ importSessionState((p ? readDiskState(p) : null) ?? EMPTY_SESSION);
494
+ applySessionCompaction(sessionId);
495
+ }
496
+ var COMPACTED_AT_SUFFIX = ".compacted-at";
497
+ function applySessionCompaction(stateKey) {
498
+ const at = stateKey.indexOf(":agent:");
499
+ const p = sessionSidecarPath(at < 0 ? stateKey : stateKey.slice(0, at), COMPACTED_AT_SUFFIX);
500
+ if (!p) return;
501
+ try {
502
+ const epoch = Number(fs.readFileSync(p, "utf8").trim());
503
+ if (Number.isFinite(epoch) && epoch > 0) markCompacted(epoch);
504
+ } catch {
505
+ }
506
+ }
507
+ var SESSION_SAVE_LOCK_WAIT_MS = 500;
508
+ function saveSessionState(sessionId) {
509
+ const p = sessionPath(sessionId);
510
+ if (!p) return;
511
+ try {
512
+ const dir = path2.dirname(p);
513
+ if (!fs.existsSync(dir)) ensureDirSync(dir);
514
+ const mem = exportSessionState();
515
+ const writeMerged = () => {
516
+ const disk = readDiskStateForMerge(p);
517
+ const merged = capFiles(disk ? mergeSessionState(disk, mem) : mem, MAX_FILES);
518
+ if (merged.created_ts === void 0) merged.created_ts = Date.now() / 1e3;
519
+ let json;
520
+ try {
521
+ json = redactSerializedJson(JSON.stringify(merged)).text;
522
+ } catch {
523
+ return true;
524
+ }
525
+ atomicWriteText(p, json);
526
+ return true;
527
+ };
528
+ let heldByAnother = false;
529
+ if (withFileLock(`${p}.lock`, writeMerged, { waitMs: SESSION_SAVE_LOCK_WAIT_MS, onContended: () => {
530
+ heldByAnother = true;
531
+ } }) === void 0 && !heldByAnother) writeMerged();
532
+ } catch {
533
+ }
534
+ }
535
+
536
+ export {
537
+ SESSIONS_SUBDIR,
538
+ sessionsDir,
539
+ AGENT_SALT_MARKER,
540
+ sessionFileStem,
541
+ sessionSidecarPath,
542
+ readSessionStateFile,
543
+ listSiblingSessionStates,
544
+ loadSessionState,
545
+ COMPACTED_AT_SUFFIX,
546
+ saveSessionState
547
+ };
@@ -1,25 +1,21 @@
1
1
  import { createRequire as __cjsRequire } from 'node:module';
2
2
  const require = __cjsRequire(import.meta.url);
3
+ import {
4
+ matchRestOfLine
5
+ } from "./token-goat-chunk-EVMZJ27Z.mjs";
3
6
  import {
4
7
  estimateTokensFromLength
5
- } from "./token-goat-chunk-52NSDWYY.mjs";
8
+ } from "./token-goat-chunk-BFCWY73P.mjs";
9
+ import {
10
+ quotedArg
11
+ } from "./token-goat-chunk-GGGG7RWB.mjs";
6
12
  import {
7
13
  displaySafeText
8
- } from "./token-goat-chunk-NMTKNYGF.mjs";
14
+ } from "./token-goat-chunk-FNFBKLRD.mjs";
9
15
  import {
10
16
  init_define_import_meta_env
11
17
  } from "./token-goat-chunk-A37V4PBF.mjs";
12
18
 
13
- // src/claude_config_dir.ts
14
- init_define_import_meta_env();
15
- import * as os from "node:os";
16
- import * as path from "node:path";
17
- function claudeConfigDir(homeDir = os.homedir()) {
18
- const override = process.env["CLAUDE_CONFIG_DIR"];
19
- if (override !== void 0 && override !== "") return override;
20
- return path.join(homeDir, ".claude");
21
- }
22
-
23
19
  // src/resident_context.ts
24
20
  init_define_import_meta_env();
25
21
  import * as fs from "node:fs";
@@ -59,14 +55,16 @@ function messageText(message) {
59
55
  return out;
60
56
  }
61
57
  function skillNameFromBody(text) {
62
- const dir = /^Base directory for this skill:\s*(.+?)\s*$/m.exec(text);
63
- if (dir?.[1] !== void 0) {
64
- const segments = dir[1].split(/[\\/]/).filter((s) => s.length > 0);
58
+ const dirAt = /^Base directory for this skill:/m.exec(text);
59
+ const dir = dirAt === null ? null : matchRestOfLine(text, dirAt.index + dirAt[0].length, 0);
60
+ if (dir !== null) {
61
+ const segments = dir.split(/[\\/]/).filter((s) => s.length > 0);
65
62
  const last = segments[segments.length - 1];
66
63
  if (last !== void 0 && last.length > 0) return last;
67
64
  }
68
- const heading = /^#\s+(.+?)\s*$/m.exec(text);
69
- if (heading?.[1] !== void 0 && heading[1].length > 0) return heading[1];
65
+ const hashAt = /^#(?=\s)/m.exec(text);
66
+ const heading = hashAt === null ? null : matchRestOfLine(text, hashAt.index + 1, 1);
67
+ if (heading !== null && heading.length > 0) return heading;
70
68
  return null;
71
69
  }
72
70
  function readTaskList(attachment, bytes) {
@@ -111,9 +109,9 @@ function collectInvokedSkills(acc, record) {
111
109
  function skillName(skill) {
112
110
  const name = skill["name"];
113
111
  if (typeof name === "string" && name.trim() !== "") return name.trim();
114
- const path2 = skill["path"];
115
- if (typeof path2 !== "string") return null;
116
- const segments = path2.split(/[\\/]/).filter((part) => part !== "");
112
+ const path = skill["path"];
113
+ if (typeof path !== "string") return null;
114
+ const segments = path.split(/[\\/]/).filter((part) => part !== "");
117
115
  const last = segments[segments.length - 1];
118
116
  return last === void 0 || last === "" ? null : last;
119
117
  }
@@ -179,7 +177,7 @@ function repeatedSkillBodyHint(injections) {
179
177
  if (worst.count < SKILL_BODY_REPEAT_THRESHOLD || worst.bytes < LARGE_SKILL_BODY_BYTES) return null;
180
178
  const skill = displaySafeText(worst.skill);
181
179
  const tokens = formatTokenEstimate(estimateTokensFromLength(worst.bytes));
182
- return `The \`${skill}\` skill body has been injected ${worst.count} times this session (${formatBytes(worst.bytes)} total, ~${tokens} tok est). Slash expansion and the Skill tool both send the whole body every time, and no hook can intercept either. If it is already loaded, work from it instead of re-invoking; to reread one part, use \`token-goat skill-section ${skill} '<heading>'\`.`;
180
+ return `The \`${skill}\` skill body has been injected ${worst.count} times this session (${formatBytes(worst.bytes)} total, ~${tokens} tok est). Slash expansion and the Skill tool both send the whole body every time, and no hook can intercept either. If it is already loaded, work from it instead of re-invoking; to reread one part, use \`token-goat skill-section ${quotedArg(skill)} "<heading>"\`.`;
183
181
  }
184
182
  function readTranscriptTail(transcriptPath, maxBytes = RESIDENT_TAIL_MAX_BYTES) {
185
183
  let fd = null;
@@ -225,7 +223,6 @@ function accumulateResidentLines(lines) {
225
223
  }
226
224
 
227
225
  export {
228
- claudeConfigDir,
229
226
  createResidentContextStats,
230
227
  accumulateResidentLine,
231
228
  summarizeResidentContext,