token-goat 2.9.26 → 2.9.29

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 (78) hide show
  1. package/README.md +30 -88
  2. package/SECURITY.md +14 -0
  3. package/dist/{token-goat-chunk-OZRSREKR.mjs → token-goat-chunk-2AWQ2R5X.mjs} +2 -2
  4. package/dist/{token-goat-chunk-BH4ZVRB2.mjs → token-goat-chunk-2NNUA2LR.mjs} +4 -4
  5. package/dist/token-goat-chunk-2WOUYWLM.mjs +955 -0
  6. package/dist/{token-goat-chunk-IKZLSRII.mjs → token-goat-chunk-435UQTKD.mjs} +5 -3
  7. package/dist/{token-goat-chunk-62IHOU6L.mjs → token-goat-chunk-44BM7DDQ.mjs} +5 -3
  8. package/dist/token-goat-chunk-52NSDWYY.mjs +96 -0
  9. package/dist/{token-goat-chunk-CXBOFPF4.mjs → token-goat-chunk-67BNIKKO.mjs} +32 -18
  10. package/dist/{token-goat-chunk-XBESNWEX.mjs → token-goat-chunk-6AK46ZT7.mjs} +2 -3
  11. package/dist/{token-goat-chunk-7SXPJOSZ.mjs → token-goat-chunk-7CPMDFGB.mjs} +166 -40
  12. package/dist/token-goat-chunk-ASLWOQ3I.mjs +14 -0
  13. package/dist/{token-goat-chunk-MWID3YOY.mjs → token-goat-chunk-BGYOZ6DO.mjs} +6 -4
  14. package/dist/{token-goat-chunk-PAV6NNY7.mjs → token-goat-chunk-C5YPNZKQ.mjs} +22 -8
  15. package/dist/{token-goat-chunk-D2X7XN5M.mjs → token-goat-chunk-CIQ2FTY3.mjs} +23 -242
  16. package/dist/token-goat-chunk-D4ETHJD6.mjs +246 -0
  17. package/dist/{token-goat-chunk-7Y6GWTII.mjs → token-goat-chunk-DNRPXHYH.mjs} +25 -17
  18. package/dist/{token-goat-chunk-L43RKNHA.mjs → token-goat-chunk-DNSPXQXQ.mjs} +2 -2
  19. package/dist/token-goat-chunk-DPNLUJWB.mjs +220 -0
  20. package/dist/token-goat-chunk-E4ZOJIZK.mjs +1382 -0
  21. package/dist/token-goat-chunk-E5TK5DNO.mjs +718 -0
  22. package/dist/{token-goat-chunk-VVROQBQJ.mjs → token-goat-chunk-EUSDXRXU.mjs} +62 -12
  23. package/dist/{token-goat-chunk-POOI26O6.mjs → token-goat-chunk-FTP4U4QA.mjs} +12 -8
  24. package/dist/token-goat-chunk-G23DWHV4.mjs +142 -0
  25. package/dist/{token-goat-chunk-MDV5VWF4.mjs → token-goat-chunk-G7IWXCFF.mjs} +223 -15
  26. package/dist/{token-goat-chunk-C2PG4K5D.mjs → token-goat-chunk-GLXRTTLE.mjs} +7 -5
  27. package/dist/{token-goat-chunk-M6CVNHTW.mjs → token-goat-chunk-H5J3C56Q.mjs} +95 -573
  28. package/dist/{token-goat-chunk-BAWKGODL.mjs → token-goat-chunk-HNFZZHFW.mjs} +2 -2
  29. package/dist/{token-goat-chunk-TG5ZPD6B.mjs → token-goat-chunk-HUYUHODZ.mjs} +1036 -759
  30. package/dist/token-goat-chunk-IVE6U7KV.mjs +53 -0
  31. package/dist/{token-goat-chunk-ZZT6PVB3.mjs → token-goat-chunk-IVWI2OCK.mjs} +72 -45
  32. package/dist/{token-goat-chunk-GMOUBOX4.mjs → token-goat-chunk-JTKCQMQA.mjs} +37 -5
  33. package/dist/{token-goat-chunk-H2CPLEMP.mjs → token-goat-chunk-KOPIR3KZ.mjs} +46 -23
  34. package/dist/token-goat-chunk-L7H3U27L.mjs +35 -0
  35. package/dist/{token-goat-chunk-FLEYOCAS.mjs → token-goat-chunk-LZNBQTDK.mjs} +6 -4
  36. package/dist/token-goat-chunk-MELOKFDJ.mjs +199 -0
  37. package/dist/{token-goat-chunk-RH27ZSPF.mjs → token-goat-chunk-NMBWLRHW.mjs} +164 -50
  38. package/dist/{token-goat-chunk-43JFN26X.mjs → token-goat-chunk-O6I2XU4P.mjs} +27 -967
  39. package/dist/{token-goat-chunk-G6EYO5CD.mjs → token-goat-chunk-ONXH6NZ5.mjs} +2 -87
  40. package/dist/token-goat-chunk-ORNFMIER.mjs +295 -0
  41. package/dist/{token-goat-chunk-LHUP4DXZ.mjs → token-goat-chunk-PGTH2U4C.mjs} +1 -1
  42. package/dist/{token-goat-chunk-5BQ7W7D7.mjs → token-goat-chunk-PKRWMHVP.mjs} +76 -59
  43. package/dist/{token-goat-chunk-DA43OE7L.mjs → token-goat-chunk-PQ53BSCF.mjs} +1 -1
  44. package/dist/{token-goat-chunk-STYRLQIW.mjs → token-goat-chunk-PYSUADX4.mjs} +2 -2
  45. package/dist/{token-goat-chunk-JALB3KWJ.mjs → token-goat-chunk-QO3LXVVR.mjs} +4247 -5005
  46. package/dist/{token-goat-chunk-L45IWWMC.mjs → token-goat-chunk-RLP6J7WR.mjs} +6 -6
  47. package/dist/token-goat-chunk-RQGGMPCR.mjs +205 -0
  48. package/dist/{token-goat-chunk-MBDJR6HU.mjs → token-goat-chunk-RTMVLHWX.mjs} +3708 -4003
  49. package/dist/{token-goat-chunk-E3K3BTEQ.mjs → token-goat-chunk-S4VSXURL.mjs} +8 -6
  50. package/dist/{token-goat-chunk-LKSXAMJB.mjs → token-goat-chunk-SE6E4BKJ.mjs} +1 -1
  51. package/dist/token-goat-chunk-TCQANXYC.mjs +351 -0
  52. package/dist/token-goat-chunk-TDUT2CL6.mjs +564 -0
  53. package/dist/{token-goat-chunk-LRIZ7K3F.mjs → token-goat-chunk-TGOXNAHW.mjs} +54 -111
  54. package/dist/{token-goat-chunk-WNBSCSAI.mjs → token-goat-chunk-UA5BKWWQ.mjs} +1 -1
  55. package/dist/{token-goat-chunk-RIB6XY2V.mjs → token-goat-chunk-UXSXQQIY.mjs} +1 -1
  56. package/dist/{token-goat-chunk-7EPYB34H.mjs → token-goat-chunk-VMFWNHGR.mjs} +84 -73
  57. package/dist/token-goat-chunk-VQ6F6T7X.mjs +36 -0
  58. package/dist/{token-goat-chunk-5M3NRJD2.mjs → token-goat-chunk-VZQEWRVH.mjs} +6 -4
  59. package/dist/{token-goat-chunk-OSUFN2FV.mjs → token-goat-chunk-XB5KKOCG.mjs} +5 -25
  60. package/dist/{token-goat-chunk-6E2IDLHF.mjs → token-goat-chunk-XYWPOSCN.mjs} +57 -615
  61. package/dist/{token-goat-chunk-CQHY4SL7.mjs → token-goat-chunk-YAGLESS3.mjs} +8 -5
  62. package/dist/token-goat-chunk-YKSRAWUU.mjs +33 -0
  63. package/dist/{token-goat-chunk-F2ARFHLJ.mjs → token-goat-chunk-YOOVFPTP.mjs} +2 -2
  64. package/dist/{token-goat-chunk-EEIDFMEM.mjs → token-goat-chunk-YZAAZU2S.mjs} +12 -3
  65. package/dist/token-goat-chunk-Z6KBMOBI.mjs +53 -0
  66. package/dist/{token-goat-chunk-4GEDH2WU.mjs → token-goat-chunk-ZER6EAXZ.mjs} +81 -70
  67. package/dist/token-goat-hook-client.cjs +475 -0
  68. package/dist/token-goat-hook-client.mjs +26 -0
  69. package/dist/token-goat-hook.mjs +31 -21
  70. package/dist/token-goat.core.mjs +9 -39
  71. package/docs/C4_RUNTIME_ARCHITECTURE.md +2 -2
  72. package/docs/cli.md +35 -23
  73. package/docs/install.md +18 -14
  74. package/package.json +1 -1
  75. package/dist/token-goat-chunk-ADMR3QVF.mjs +0 -41
  76. package/dist/token-goat-chunk-E6B2UFDF.mjs +0 -30
  77. package/dist/token-goat-chunk-GKZ2US5B.mjs +0 -187
  78. package/dist/token-goat-chunk-MZTO4FXH.mjs +0 -26
@@ -1,36 +1,36 @@
1
1
  import { createRequire as __cjsRequire } from 'node:module';
2
2
  const require = __cjsRequire(import.meta.url);
3
3
  import {
4
- getDb
5
- } from "./token-goat-chunk-7SXPJOSZ.mjs";
4
+ getDb,
5
+ isReadOnlyDb
6
+ } from "./token-goat-chunk-7CPMDFGB.mjs";
6
7
  import {
7
8
  getHarnessName,
8
9
  loadConfig
9
- } from "./token-goat-chunk-LRIZ7K3F.mjs";
10
- import {
11
- registerReset
12
- } from "./token-goat-chunk-EEIDFMEM.mjs";
10
+ } from "./token-goat-chunk-TGOXNAHW.mjs";
13
11
  import {
14
12
  Database
15
- } from "./token-goat-chunk-OSUFN2FV.mjs";
13
+ } from "./token-goat-chunk-XB5KKOCG.mjs";
14
+ import {
15
+ registerReset
16
+ } from "./token-goat-chunk-YZAAZU2S.mjs";
16
17
  import {
17
- VERSION,
18
- atomicWriteText,
19
18
  countNoun,
20
- dataDir,
21
- dataDirForHome,
22
19
  ensureDirSync,
23
- extractErrorMessage,
24
- sanitizeIdForFilename,
25
- tokenGoatHome
26
- } from "./token-goat-chunk-6E2IDLHF.mjs";
20
+ extractErrorMessage
21
+ } from "./token-goat-chunk-XYWPOSCN.mjs";
27
22
  import {
28
23
  displaySafeText
29
24
  } from "./token-goat-chunk-NMTKNYGF.mjs";
25
+ import {
26
+ VERSION,
27
+ dataDir,
28
+ dataDirForHome
29
+ } from "./token-goat-chunk-MELOKFDJ.mjs";
30
30
  import {
31
31
  growsExponentially,
32
32
  hasNestedQuantifier
33
- } from "./token-goat-chunk-GMOUBOX4.mjs";
33
+ } from "./token-goat-chunk-JTKCQMQA.mjs";
34
34
  import {
35
35
  init_define_import_meta_env
36
36
  } from "./token-goat-chunk-A37V4PBF.mjs";
@@ -1007,6 +1007,8 @@ var KIND_TO_SOURCE = {
1007
1007
  reconcile_note_failed: SOURCE_OTHER,
1008
1008
  // Measurement of what a compaction produced (hooks_compact.ts postCompactHandler): summary size and how many manifest paths survived into it. SOURCE_OTHER and always recorded at (0, 0) -- the summary was written whether or not token-goat was watching, so there is no counterfactual in which those bytes were saved. Filing it anywhere with a savings total would credit token-goat for the whole summary, which is the accounting mistake this registry exists to prevent.
1009
1009
  compact_summary: SOURCE_OTHER,
1010
+ // One row per failed tool call the post_tool_use_failure hook sees (hooks_tool_failure.ts), with its tool_error_class.ts verdict in `detail` so failure rates by reason accumulate going forward. A measurement at (0, 0): a failure saves nothing.
1011
+ tool_failure: SOURCE_OTHER,
1010
1012
  // Envelope compaction of an oversized subagent report (hooks_agent_spawn.ts). SOURCE_CONTENT, not SOURCE_HINT: the handler's sibling session_hint entry is advisory (it only appends a recall pointer and genuinely saves nothing), whereas this kind records a real rewrite with real bytes removed, so filing it under the advisory bucket would understate the compaction and repeat the zero-savings desync this registry keeps getting bitten by.
1011
1013
  agent_report_compact: SOURCE_CONTENT,
1012
1014
  // Decline counterpart to agent_report_compact: the fence-collapse net-benefit gate ran and found at least one over-long fence, but declined to rewrite because net savings did not clear the notice cost. Always recorded at (0, 0) -- see the recordStat call site -- so it never contributes to any savings total; it exists purely to make gate hit-rate and near-misses visible instead of the decline being invisible.
@@ -1203,7 +1205,7 @@ CREATE TABLE IF NOT EXISTS unmapped_tools (
1203
1205
  );
1204
1206
  `;
1205
1207
  var _globalSchemaApplied = /* @__PURE__ */ new Set();
1206
- registerReset(() => _globalSchemaApplied.clear());
1208
+ registerReset(() => _globalSchemaApplied.clear(), { perRequest: true });
1207
1209
  function migrateGlobalSchema(db) {
1208
1210
  try {
1209
1211
  db.exec("ALTER TABLE stats ADD COLUMN harness TEXT");
@@ -1308,7 +1310,7 @@ function getGlobalDb(homeDir) {
1308
1310
  const basePath = homeDir ? dataDirForHome(homeDir) : dataDir();
1309
1311
  const dbPath = path.join(basePath, "global.db");
1310
1312
  const db = getDb(dbPath);
1311
- if (!_globalSchemaApplied.has(dbPath)) {
1313
+ if (!_globalSchemaApplied.has(dbPath) && !isReadOnlyDb(dbPath)) {
1312
1314
  db.exec(GLOBAL_SCHEMA_SQL);
1313
1315
  migrateGlobalSchema(db);
1314
1316
  _globalSchemaApplied.add(dbPath);
@@ -1422,7 +1424,9 @@ function recordStat(kind, bytesSaved = 0, tokensSaved = 0, _testDb, detail, trac
1422
1424
  let db;
1423
1425
  try {
1424
1426
  if (!_testDb) getGlobalDb();
1427
+ if (!_testDb && isReadOnlyDb(path.join(dataDir(), "global.db"))) return;
1425
1428
  db = _testDb ?? new Database(path.join(dataDir(), "global.db"), { timeout: STATS_WRITE_BUSY_TIMEOUT_MS });
1429
+ if (!_testDb && String(db.pragma("journal_mode", { simple: true })).toLowerCase() === "wal") db.pragma("synchronous = NORMAL");
1426
1430
  const ts = Math.floor(Date.now() / 1e3);
1427
1431
  const tp = traceparent ?? process.env["TRACEPARENT"] ?? process.env["traceparent"] ?? null;
1428
1432
  const cols = ["ts", "kind", "bytes_saved", "tokens_saved", "detail"];
@@ -1955,220 +1959,6 @@ function redactSecrets(text, config = loadConfig()) {
1955
1959
  return { text: out, count };
1956
1960
  }
1957
1961
 
1958
- // src/disk_cache.ts
1959
- init_define_import_meta_env();
1960
- import * as fs2 from "node:fs";
1961
- import * as path2 from "node:path";
1962
- var DEFAULT_MAX_COUNT = 200;
1963
- var DEFAULT_MAX_AGE_MS = 24 * 3600 * 1e3;
1964
- function sanitizeId(id) {
1965
- return sanitizeIdForFilename(id, 64);
1966
- }
1967
- function blobDir(subdir) {
1968
- return path2.join(tokenGoatHome(), subdir);
1969
- }
1970
- function blobPath(subdir, id) {
1971
- const safe = sanitizeId(id);
1972
- if (!safe) return null;
1973
- const dir = blobDir(subdir);
1974
- const candidate = path2.join(dir, `${safe}.json`);
1975
- try {
1976
- const rel = path2.relative(dir, candidate);
1977
- if (rel.startsWith("..")) return null;
1978
- } catch {
1979
- return null;
1980
- }
1981
- return candidate;
1982
- }
1983
- function isBlobStale(subdir, id) {
1984
- const p = blobPath(subdir, id);
1985
- if (p === null) return false;
1986
- try {
1987
- const stat = fs2.statSync(p);
1988
- return Date.now() - stat.mtimeMs > DEFAULT_MAX_AGE_MS;
1989
- } catch {
1990
- return false;
1991
- }
1992
- }
1993
- function subdirCacheDefaults(subdir) {
1994
- try {
1995
- if (subdir === "bash_outputs") {
1996
- const bc = loadConfig().bash_compress;
1997
- return { maxCount: bc.cache_max_file_count, maxBytes: bc.cache_max_bytes, maxBytesPerItem: bc.cache_max_bytes_per_output };
1998
- }
1999
- if (subdir === "web_outputs") {
2000
- const wf = loadConfig().webfetch;
2001
- return { maxCount: wf.max_file_count, maxBytes: wf.max_bytes, maxBytesPerItem: Number.POSITIVE_INFINITY };
2002
- }
2003
- } catch {
2004
- }
2005
- return { maxCount: DEFAULT_MAX_COUNT, maxBytes: Number.POSITIVE_INFINITY, maxBytesPerItem: Number.POSITIVE_INFINITY };
2006
- }
2007
- function storeBlob(subdir, id, value, opts = {}) {
2008
- const p = blobPath(subdir, id);
2009
- if (!p) return false;
2010
- const defaults = subdirCacheDefaults(subdir);
2011
- const maxBytesPerItem = opts.maxBytesPerItem ?? defaults.maxBytesPerItem;
2012
- let rawJson;
2013
- try {
2014
- rawJson = JSON.stringify(value);
2015
- } catch {
2016
- return false;
2017
- }
2018
- let json;
2019
- try {
2020
- const result = redactSecrets(rawJson);
2021
- json = result.text;
2022
- if (result.count > 0) recordStat("secret_redacted", 0, result.count, void 0, subdir);
2023
- } catch {
2024
- return false;
2025
- }
2026
- if (Number.isFinite(maxBytesPerItem) && Buffer.byteLength(json, "utf-8") > maxBytesPerItem) return false;
2027
- try {
2028
- const dir = path2.dirname(p);
2029
- if (!fs2.existsSync(dir)) ensureDirSync(dir);
2030
- atomicWriteText(p, json);
2031
- } catch {
2032
- return false;
2033
- }
2034
- pruneBlobs(
2035
- subdir,
2036
- opts.maxCount ?? defaults.maxCount,
2037
- opts.maxAgeMs ?? DEFAULT_MAX_AGE_MS,
2038
- opts.maxBytes ?? defaults.maxBytes,
2039
- p
2040
- );
2041
- return true;
2042
- }
2043
- function loadBlob(subdir, id) {
2044
- const p = blobPath(subdir, id);
2045
- if (!p) return null;
2046
- try {
2047
- if (!fs2.existsSync(p)) return null;
2048
- return JSON.parse(fs2.readFileSync(p, "utf8"));
2049
- } catch {
2050
- return null;
2051
- }
2052
- }
2053
- function listBlobs(subdir) {
2054
- const dir = blobDir(subdir);
2055
- const out = [];
2056
- try {
2057
- if (!fs2.existsSync(dir)) return out;
2058
- for (const file of fs2.readdirSync(dir)) {
2059
- if (!file.endsWith(".json")) continue;
2060
- const id = file.slice(0, -5);
2061
- let mtime = 0;
2062
- try {
2063
- mtime = fs2.statSync(path2.join(dir, file)).mtimeMs;
2064
- } catch {
2065
- }
2066
- const value = loadBlob(subdir, id);
2067
- if (value !== null) out.push({ id, mtime, value });
2068
- }
2069
- } catch {
2070
- return out;
2071
- }
2072
- return out;
2073
- }
2074
- function pruneBlobs(subdir, maxCount = DEFAULT_MAX_COUNT, maxAgeMs = DEFAULT_MAX_AGE_MS, maxBytes = Number.POSITIVE_INFINITY, protectedPath) {
2075
- return pruneBlobDir(blobDir(subdir), maxCount, maxAgeMs, maxBytes, protectedPath);
2076
- }
2077
- function pruneBlobDir(dir, maxCount = DEFAULT_MAX_COUNT, maxAgeMs = DEFAULT_MAX_AGE_MS, maxBytes = Number.POSITIVE_INFINITY, protectedPath) {
2078
- let removed = 0;
2079
- try {
2080
- if (!fs2.existsSync(dir)) return 0;
2081
- const cutoff = Date.now() - maxAgeMs;
2082
- let kept = [];
2083
- let protectedEntry;
2084
- for (const file of fs2.readdirSync(dir)) {
2085
- const full = path2.join(dir, file);
2086
- let stat;
2087
- try {
2088
- stat = fs2.statSync(full);
2089
- } catch {
2090
- continue;
2091
- }
2092
- if (!stat.isFile()) continue;
2093
- if (protectedPath !== void 0 && full === protectedPath) {
2094
- protectedEntry = [full, stat.mtimeMs, stat.size];
2095
- continue;
2096
- }
2097
- if (stat.mtimeMs < cutoff) {
2098
- try {
2099
- fs2.unlinkSync(full);
2100
- removed++;
2101
- } catch {
2102
- continue;
2103
- }
2104
- } else if (file.endsWith(".json")) {
2105
- kept.push([full, stat.mtimeMs, stat.size]);
2106
- }
2107
- }
2108
- const countBudget = protectedEntry ? Math.max(0, maxCount - 1) : maxCount;
2109
- if (kept.length > countBudget) {
2110
- kept.sort((a, b) => a[1] - b[1]);
2111
- const excess = kept.slice(0, kept.length - countBudget);
2112
- kept = kept.slice(kept.length - countBudget);
2113
- for (const [full] of excess) {
2114
- try {
2115
- fs2.unlinkSync(full);
2116
- removed++;
2117
- } catch {
2118
- continue;
2119
- }
2120
- }
2121
- }
2122
- if (Number.isFinite(maxBytes)) {
2123
- kept.sort((a, b) => a[1] - b[1]);
2124
- let total = kept.reduce((sum, [, , size]) => sum + size, 0) + (protectedEntry ? protectedEntry[2] : 0);
2125
- while (total > maxBytes && kept.length > 0) {
2126
- const oldest = kept.shift();
2127
- if (!oldest) break;
2128
- const [full, , size] = oldest;
2129
- try {
2130
- fs2.unlinkSync(full);
2131
- removed++;
2132
- total -= size;
2133
- } catch {
2134
- break;
2135
- }
2136
- }
2137
- }
2138
- } catch {
2139
- return removed;
2140
- }
2141
- return removed;
2142
- }
2143
- var SWEEPABLE_CACHE_SUBDIRS = [
2144
- { subdir: "bash_outputs", countCapped: true },
2145
- { subdir: "web_outputs", countCapped: true },
2146
- { subdir: "mcp_outputs", countCapped: true },
2147
- { subdir: "sessions", countCapped: false }
2148
- ];
2149
- function sweepCacheRoots(extraRoots = []) {
2150
- let removed = 0;
2151
- const roots = [tokenGoatHome(), ...extraRoots];
2152
- const seen = /* @__PURE__ */ new Set();
2153
- for (const root of roots) {
2154
- if (!root || seen.has(root)) continue;
2155
- seen.add(root);
2156
- for (const { subdir, countCapped } of SWEEPABLE_CACHE_SUBDIRS) {
2157
- try {
2158
- const defaults = subdirCacheDefaults(subdir);
2159
- removed += pruneBlobDir(
2160
- path2.join(root, subdir),
2161
- countCapped ? defaults.maxCount : Number.POSITIVE_INFINITY,
2162
- DEFAULT_MAX_AGE_MS,
2163
- countCapped ? defaults.maxBytes : Number.POSITIVE_INFINITY
2164
- );
2165
- } catch {
2166
- }
2167
- }
2168
- }
2169
- return removed;
2170
- }
2171
-
2172
1962
  export {
2173
1963
  BYTES_PER_TOKEN,
2174
1964
  guardDivisor,
@@ -2196,14 +1986,5 @@ export {
2196
1986
  countRedactionPlaceholders,
2197
1987
  compileCustomPatterns,
2198
1988
  hasPreciseSecret,
2199
- redactSecrets,
2200
- DEFAULT_MAX_COUNT,
2201
- DEFAULT_MAX_AGE_MS,
2202
- blobPath,
2203
- isBlobStale,
2204
- storeBlob,
2205
- loadBlob,
2206
- listBlobs,
2207
- pruneBlobs,
2208
- sweepCacheRoots
1989
+ redactSecrets
2209
1990
  };
@@ -0,0 +1,246 @@
1
+ import { createRequire as __cjsRequire } from 'node:module';
2
+ const require = __cjsRequire(import.meta.url);
3
+ import {
4
+ recordStat,
5
+ redactSecrets
6
+ } from "./token-goat-chunk-CIQ2FTY3.mjs";
7
+ import {
8
+ loadConfig
9
+ } from "./token-goat-chunk-TGOXNAHW.mjs";
10
+ import {
11
+ atomicWriteText,
12
+ ensureDirSync,
13
+ sanitizeIdForFilename
14
+ } from "./token-goat-chunk-XYWPOSCN.mjs";
15
+ import {
16
+ tokenGoatHome
17
+ } from "./token-goat-chunk-MELOKFDJ.mjs";
18
+ import {
19
+ init_define_import_meta_env
20
+ } from "./token-goat-chunk-A37V4PBF.mjs";
21
+
22
+ // src/disk_cache.ts
23
+ init_define_import_meta_env();
24
+ import * as fs from "node:fs";
25
+ import * as path from "node:path";
26
+ var DEFAULT_MAX_COUNT = 200;
27
+ var DEFAULT_MAX_AGE_MS = 24 * 3600 * 1e3;
28
+ function sanitizeId(id) {
29
+ return sanitizeIdForFilename(id, 64);
30
+ }
31
+ function blobDir(subdir) {
32
+ return path.join(tokenGoatHome(), subdir);
33
+ }
34
+ function blobPath(subdir, id) {
35
+ const safe = sanitizeId(id);
36
+ if (!safe) return null;
37
+ const dir = blobDir(subdir);
38
+ const candidate = path.join(dir, `${safe}.json`);
39
+ try {
40
+ const rel = path.relative(dir, candidate);
41
+ if (rel.startsWith("..")) return null;
42
+ } catch {
43
+ return null;
44
+ }
45
+ return candidate;
46
+ }
47
+ function isBlobStale(subdir, id) {
48
+ const p = blobPath(subdir, id);
49
+ if (p === null) return false;
50
+ try {
51
+ const stat = fs.statSync(p);
52
+ return Date.now() - stat.mtimeMs > DEFAULT_MAX_AGE_MS;
53
+ } catch {
54
+ return false;
55
+ }
56
+ }
57
+ function subdirCacheDefaults(subdir) {
58
+ try {
59
+ if (subdir === "bash_outputs") {
60
+ const bc = loadConfig().bash_compress;
61
+ return { maxCount: bc.cache_max_file_count, maxBytes: bc.cache_max_bytes, maxBytesPerItem: bc.cache_max_bytes_per_output };
62
+ }
63
+ if (subdir === "web_outputs") {
64
+ const wf = loadConfig().webfetch;
65
+ return { maxCount: wf.max_file_count, maxBytes: wf.max_bytes, maxBytesPerItem: Number.POSITIVE_INFINITY };
66
+ }
67
+ } catch {
68
+ }
69
+ return { maxCount: DEFAULT_MAX_COUNT, maxBytes: Number.POSITIVE_INFINITY, maxBytesPerItem: Number.POSITIVE_INFINITY };
70
+ }
71
+ function storeBlob(subdir, id, value, opts = {}) {
72
+ const p = blobPath(subdir, id);
73
+ if (!p) return false;
74
+ const defaults = subdirCacheDefaults(subdir);
75
+ const maxBytesPerItem = opts.maxBytesPerItem ?? defaults.maxBytesPerItem;
76
+ let rawJson;
77
+ try {
78
+ rawJson = JSON.stringify(value);
79
+ } catch {
80
+ return false;
81
+ }
82
+ let json;
83
+ try {
84
+ const result = redactSecrets(rawJson);
85
+ json = result.text;
86
+ if (result.count > 0) recordStat("secret_redacted", 0, result.count, void 0, subdir);
87
+ } catch {
88
+ return false;
89
+ }
90
+ if (Number.isFinite(maxBytesPerItem) && Buffer.byteLength(json, "utf-8") > maxBytesPerItem) return false;
91
+ try {
92
+ const dir = path.dirname(p);
93
+ if (!fs.existsSync(dir)) ensureDirSync(dir);
94
+ atomicWriteText(p, json);
95
+ } catch {
96
+ return false;
97
+ }
98
+ pruneBlobs(
99
+ subdir,
100
+ opts.maxCount ?? defaults.maxCount,
101
+ opts.maxAgeMs ?? DEFAULT_MAX_AGE_MS,
102
+ opts.maxBytes ?? defaults.maxBytes,
103
+ p
104
+ );
105
+ return true;
106
+ }
107
+ function loadBlob(subdir, id) {
108
+ const p = blobPath(subdir, id);
109
+ if (!p) return null;
110
+ try {
111
+ if (!fs.existsSync(p)) return null;
112
+ return JSON.parse(fs.readFileSync(p, "utf8"));
113
+ } catch {
114
+ return null;
115
+ }
116
+ }
117
+ function listBlobs(subdir) {
118
+ const dir = blobDir(subdir);
119
+ const out = [];
120
+ try {
121
+ if (!fs.existsSync(dir)) return out;
122
+ for (const file of fs.readdirSync(dir)) {
123
+ if (!file.endsWith(".json")) continue;
124
+ const id = file.slice(0, -5);
125
+ let mtime = 0;
126
+ try {
127
+ mtime = fs.statSync(path.join(dir, file)).mtimeMs;
128
+ } catch {
129
+ }
130
+ const value = loadBlob(subdir, id);
131
+ if (value !== null) out.push({ id, mtime, value });
132
+ }
133
+ } catch {
134
+ return out;
135
+ }
136
+ return out;
137
+ }
138
+ function pruneBlobs(subdir, maxCount = DEFAULT_MAX_COUNT, maxAgeMs = DEFAULT_MAX_AGE_MS, maxBytes = Number.POSITIVE_INFINITY, protectedPath) {
139
+ return pruneBlobDir(blobDir(subdir), maxCount, maxAgeMs, maxBytes, protectedPath);
140
+ }
141
+ function pruneBlobDir(dir, maxCount = DEFAULT_MAX_COUNT, maxAgeMs = DEFAULT_MAX_AGE_MS, maxBytes = Number.POSITIVE_INFINITY, protectedPath) {
142
+ let removed = 0;
143
+ try {
144
+ if (!fs.existsSync(dir)) return 0;
145
+ const cutoff = Date.now() - maxAgeMs;
146
+ let kept = [];
147
+ let protectedEntry;
148
+ for (const file of fs.readdirSync(dir)) {
149
+ const full = path.join(dir, file);
150
+ let stat;
151
+ try {
152
+ stat = fs.statSync(full);
153
+ } catch {
154
+ continue;
155
+ }
156
+ if (!stat.isFile()) continue;
157
+ if (protectedPath !== void 0 && full === protectedPath) {
158
+ protectedEntry = [full, stat.mtimeMs, stat.size];
159
+ continue;
160
+ }
161
+ if (stat.mtimeMs < cutoff) {
162
+ try {
163
+ fs.unlinkSync(full);
164
+ removed++;
165
+ } catch {
166
+ continue;
167
+ }
168
+ } else if (file.endsWith(".json")) {
169
+ kept.push([full, stat.mtimeMs, stat.size]);
170
+ }
171
+ }
172
+ const countBudget = protectedEntry ? Math.max(0, maxCount - 1) : maxCount;
173
+ if (kept.length > countBudget) {
174
+ kept.sort((a, b) => a[1] - b[1]);
175
+ const excess = kept.slice(0, kept.length - countBudget);
176
+ kept = kept.slice(kept.length - countBudget);
177
+ for (const [full] of excess) {
178
+ try {
179
+ fs.unlinkSync(full);
180
+ removed++;
181
+ } catch {
182
+ continue;
183
+ }
184
+ }
185
+ }
186
+ if (Number.isFinite(maxBytes)) {
187
+ kept.sort((a, b) => a[1] - b[1]);
188
+ let total = kept.reduce((sum, [, , size]) => sum + size, 0) + (protectedEntry ? protectedEntry[2] : 0);
189
+ while (total > maxBytes && kept.length > 0) {
190
+ const oldest = kept.shift();
191
+ if (!oldest) break;
192
+ const [full, , size] = oldest;
193
+ try {
194
+ fs.unlinkSync(full);
195
+ removed++;
196
+ total -= size;
197
+ } catch {
198
+ break;
199
+ }
200
+ }
201
+ }
202
+ } catch {
203
+ return removed;
204
+ }
205
+ return removed;
206
+ }
207
+ var SWEEPABLE_CACHE_SUBDIRS = [
208
+ { subdir: "bash_outputs", countCapped: true },
209
+ { subdir: "web_outputs", countCapped: true },
210
+ { subdir: "mcp_outputs", countCapped: true },
211
+ { subdir: "sessions", countCapped: false }
212
+ ];
213
+ function sweepCacheRoots(extraRoots = []) {
214
+ let removed = 0;
215
+ const roots = [tokenGoatHome(), ...extraRoots];
216
+ const seen = /* @__PURE__ */ new Set();
217
+ for (const root of roots) {
218
+ if (!root || seen.has(root)) continue;
219
+ seen.add(root);
220
+ for (const { subdir, countCapped } of SWEEPABLE_CACHE_SUBDIRS) {
221
+ try {
222
+ const defaults = subdirCacheDefaults(subdir);
223
+ removed += pruneBlobDir(
224
+ path.join(root, subdir),
225
+ countCapped ? defaults.maxCount : Number.POSITIVE_INFINITY,
226
+ DEFAULT_MAX_AGE_MS,
227
+ countCapped ? defaults.maxBytes : Number.POSITIVE_INFINITY
228
+ );
229
+ } catch {
230
+ }
231
+ }
232
+ }
233
+ return removed;
234
+ }
235
+
236
+ export {
237
+ DEFAULT_MAX_COUNT,
238
+ DEFAULT_MAX_AGE_MS,
239
+ blobPath,
240
+ isBlobStale,
241
+ storeBlob,
242
+ loadBlob,
243
+ listBlobs,
244
+ pruneBlobs,
245
+ sweepCacheRoots
246
+ };
@@ -3,48 +3,52 @@ const require = __cjsRequire(import.meta.url);
3
3
  import {
4
4
  enqueueDirtyPathsSafe,
5
5
  fenceUntrusted,
6
- getToolName,
7
6
  getTrackedFiles,
8
7
  scanAndRecord
9
- } from "./token-goat-chunk-MBDJR6HU.mjs";
8
+ } from "./token-goat-chunk-RTMVLHWX.mjs";
9
+ import {
10
+ getToolName
11
+ } from "./token-goat-chunk-E5TK5DNO.mjs";
10
12
  import {
11
13
  RECALL_DEFAULT_LIMIT,
12
14
  indexRecallEntry,
13
15
  listRecentRecall,
14
16
  searchRecall
15
- } from "./token-goat-chunk-43JFN26X.mjs";
17
+ } from "./token-goat-chunk-O6I2XU4P.mjs";
16
18
  import {
17
19
  isBlobStale,
18
20
  loadBlob,
19
- redactSecrets,
20
21
  storeBlob
21
- } from "./token-goat-chunk-D2X7XN5M.mjs";
22
+ } from "./token-goat-chunk-D4ETHJD6.mjs";
23
+ import {
24
+ redactSecrets
25
+ } from "./token-goat-chunk-CIQ2FTY3.mjs";
22
26
  import {
23
27
  parserFingerprintForLanguage
24
- } from "./token-goat-chunk-7EPYB34H.mjs";
28
+ } from "./token-goat-chunk-VMFWNHGR.mjs";
25
29
  import {
26
30
  getProjectFileEntries,
27
31
  projectScopeClause
28
- } from "./token-goat-chunk-IKZLSRII.mjs";
32
+ } from "./token-goat-chunk-435UQTKD.mjs";
29
33
  import {
30
34
  getDb
31
- } from "./token-goat-chunk-7SXPJOSZ.mjs";
35
+ } from "./token-goat-chunk-7CPMDFGB.mjs";
32
36
  import {
33
37
  fingerprintFile,
34
38
  getDisplayRoot,
35
39
  shortFingerprint
36
- } from "./token-goat-chunk-LRIZ7K3F.mjs";
40
+ } from "./token-goat-chunk-TGOXNAHW.mjs";
37
41
  import {
38
42
  registerReset
39
- } from "./token-goat-chunk-EEIDFMEM.mjs";
43
+ } from "./token-goat-chunk-YZAAZU2S.mjs";
40
44
  import {
41
- SYMBOL_BODY_CHAR_CAP,
42
45
  countNoun,
43
46
  extractErrorMessage,
44
- foldPath,
45
- globalDbPath,
46
47
  pad
47
- } from "./token-goat-chunk-6E2IDLHF.mjs";
48
+ } from "./token-goat-chunk-XYWPOSCN.mjs";
49
+ import {
50
+ foldPath
51
+ } from "./token-goat-chunk-TCQANXYC.mjs";
48
52
  import {
49
53
  UNTRUSTED_TOOL_TAG,
50
54
  UNTRUSTED_WEB_TAG,
@@ -54,9 +58,13 @@ import {
54
58
  resolveIndexPath,
55
59
  toDisplayPath
56
60
  } from "./token-goat-chunk-NMTKNYGF.mjs";
61
+ import {
62
+ SYMBOL_BODY_CHAR_CAP,
63
+ globalDbPath
64
+ } from "./token-goat-chunk-MELOKFDJ.mjs";
57
65
  import {
58
66
  compileGuardedRegex
59
- } from "./token-goat-chunk-GMOUBOX4.mjs";
67
+ } from "./token-goat-chunk-JTKCQMQA.mjs";
60
68
  import {
61
69
  init_define_import_meta_env
62
70
  } from "./token-goat-chunk-A37V4PBF.mjs";
@@ -116,7 +124,7 @@ registerReset(() => {
116
124
  _byId = /* @__PURE__ */ new Map();
117
125
  _rawById = /* @__PURE__ */ new Map();
118
126
  _urlIndex = /* @__PURE__ */ new Map();
119
- });
127
+ }, { perRequest: true });
120
128
 
121
129
  // src/stdin_json.ts
122
130
  init_define_import_meta_env();
@@ -534,7 +542,7 @@ async function describeTarget(target, table, opts) {
534
542
  const absPath = resolve(process.cwd(), target);
535
543
  if (existsSync(absPath)) {
536
544
  try {
537
- const { isSqliteFile, getSqliteSchema, formatSqliteSchema } = await import("./token-goat-chunk-OZRSREKR.mjs");
545
+ const { isSqliteFile, getSqliteSchema, formatSqliteSchema } = await import("./token-goat-chunk-2AWQ2R5X.mjs");
538
546
  if (isSqliteFile(absPath)) {
539
547
  const schema = getSqliteSchema(absPath);
540
548
  if (table) {
@@ -5,13 +5,13 @@ import {
5
5
  } from "./token-goat-chunk-3BTK54F3.mjs";
6
6
  import {
7
7
  filtersFilteredToEmptyNotice
8
- } from "./token-goat-chunk-6E2IDLHF.mjs";
8
+ } from "./token-goat-chunk-XYWPOSCN.mjs";
9
9
  import {
10
10
  displaySafeText
11
11
  } from "./token-goat-chunk-NMTKNYGF.mjs";
12
12
  import {
13
13
  compileGuardedRegexCached
14
- } from "./token-goat-chunk-GMOUBOX4.mjs";
14
+ } from "./token-goat-chunk-JTKCQMQA.mjs";
15
15
  import {
16
16
  init_define_import_meta_env
17
17
  } from "./token-goat-chunk-A37V4PBF.mjs";