token-goat 2.9.13 → 2.9.14

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 (44) hide show
  1. package/README.md +13 -0
  2. package/dist/token-goat-chunk-2ESBO4IN.mjs +209 -0
  3. package/dist/token-goat-chunk-3BTK54F3.mjs +1733 -0
  4. package/dist/{token-goat-chunk-2WC4ZUXN.mjs → token-goat-chunk-3XQPEJMV.mjs} +1 -1
  5. package/dist/token-goat-chunk-4SDX3QP3.mjs +122 -0
  6. package/dist/token-goat-chunk-7OGKZ7AP.mjs +142 -0
  7. package/dist/token-goat-chunk-AH6QILZM.mjs +26 -0
  8. package/dist/token-goat-chunk-AMYCQJX4.mjs +1548 -0
  9. package/dist/{token-goat-chunk-6B44WLIF.mjs → token-goat-chunk-ASVVF4JV.mjs} +10 -7
  10. package/dist/{token-goat-chunk-3ESRORNM.mjs → token-goat-chunk-DAMXYVIW.mjs} +12026 -11796
  11. package/dist/{token-goat-chunk-YOA4N6WA.mjs → token-goat-chunk-DBNY4RLN.mjs} +2 -2
  12. package/dist/token-goat-chunk-EG3663UT.mjs +226 -0
  13. package/dist/token-goat-chunk-EZNVAIR3.mjs +21 -0
  14. package/dist/token-goat-chunk-GMOUBOX4.mjs +386 -0
  15. package/dist/{token-goat-chunk-B3CTCQTH.mjs → token-goat-chunk-HF6H7RNK.mjs} +1 -1
  16. package/dist/{token-goat-chunk-ZZI3IDQZ.mjs → token-goat-chunk-IT6O3PNN.mjs} +2874 -7088
  17. package/dist/token-goat-chunk-NEI4NC54.mjs +424 -0
  18. package/dist/token-goat-chunk-O5WAMISC.mjs +167 -0
  19. package/dist/{token-goat-chunk-RDITECDL.mjs → token-goat-chunk-PGGDW7DZ.mjs} +28 -13
  20. package/dist/token-goat-chunk-POBYR64E.mjs +1632 -0
  21. package/dist/{token-goat-chunk-4NXUKV7D.mjs → token-goat-chunk-PRJVGIC5.mjs} +6 -4
  22. package/dist/{token-goat-chunk-U7X6LQD2.mjs → token-goat-chunk-RUDOKYPJ.mjs} +10160 -10053
  23. package/dist/token-goat-chunk-SAQ5PG4L.mjs +2634 -0
  24. package/dist/{token-goat-chunk-UMXJN7DI.mjs → token-goat-chunk-T2IWWTHB.mjs} +288 -2654
  25. package/dist/{token-goat-chunk-JOXLE672.mjs → token-goat-chunk-VZYD4OZB.mjs} +1164 -92
  26. package/dist/token-goat-chunk-XEH6KBWW.mjs +23 -0
  27. package/dist/token-goat-chunk-XQF5J25J.mjs +33 -0
  28. package/dist/token-goat-chunk-XTQAOTSO.mjs +89 -0
  29. package/dist/{token-goat-chunk-QWSUZWFP.mjs → token-goat-chunk-XVZ4MNQC.mjs} +587 -587
  30. package/dist/token-goat-chunk-Y4AFKTHK.mjs +22 -0
  31. package/dist/token-goat-chunk-YHGTGG6K.mjs +396 -0
  32. package/dist/{token-goat-chunk-FZU7GMUS.mjs → token-goat-chunk-YTQHZJXW.mjs} +20 -11
  33. package/dist/token-goat-chunk-Z6UXPYJA.mjs +62 -0
  34. package/dist/token-goat-chunk-ZD4EM4LR.mjs +30 -0
  35. package/dist/token-goat-chunk-ZFM4PWXL.mjs +585 -0
  36. package/dist/{token-goat-chunk-FQCNJV4V.mjs → token-goat-chunk-ZYNNQ36L.mjs} +116 -330
  37. package/dist/token-goat-hook.mjs +12 -8
  38. package/dist/token-goat.core.mjs +22 -10
  39. package/docs/cli.md +1 -0
  40. package/package.json +4 -2
  41. package/dist/token-goat-chunk-JVNPCQB7.mjs +0 -31
  42. package/dist/token-goat-chunk-P2PU4CR5.mjs +0 -26
  43. package/dist/token-goat-chunk-QKXBGBQR.mjs +0 -3653
  44. package/dist/token-goat-chunk-UM47DRD3.mjs +0 -242
@@ -1,2568 +1,52 @@
1
1
  import { createRequire as __cjsRequire } from 'node:module';
2
2
  const require = __cjsRequire(import.meta.url);
3
3
  import {
4
- registerReset
5
- } from "./token-goat-chunk-EEIDFMEM.mjs";
6
- import {
7
- ENV_KEYS,
8
- SYMBOL_BODY_CHAR_CAP,
9
- VERSION,
10
- _detectOpenQuote,
11
- _lineClosesQuote,
12
- atomicWriteText,
13
- canonicalize,
14
- configPath,
15
- countNoun,
16
- dataDir,
17
- dataDirForHome,
18
- decodeSource,
19
- displaySafeText,
20
- ensureDirSync,
21
- extractErrorMessage,
22
- foldCase,
23
- foldPath,
24
- growsExponentially,
25
- hasNestedQuantifier,
26
- isAblSource,
27
- isLatexClassFile,
28
- isMatlabSource,
29
- isObjcHeader,
30
- isObjcSource,
31
- isPascalSource,
32
- isPerlSource,
33
- isPrologSource,
34
- normalizeDarwinSystemAlias,
35
- projectConfigPath,
36
- runGit,
37
- safeJoin,
38
- sleepSync
39
- } from "./token-goat-chunk-QKXBGBQR.mjs";
40
- import {
41
- init_define_import_meta_env
42
- } from "./token-goat-chunk-A37V4PBF.mjs";
43
-
44
- // src/bridges/registry.ts
45
- init_define_import_meta_env();
46
- var KNOWN_HARNESS_NAMES = /* @__PURE__ */ new Set([
47
- "claudecode",
48
- "codex",
49
- "opencode",
50
- "gemini",
51
- "hermes",
52
- "openclaw",
53
- "pi",
54
- "copilot_cli",
55
- "grok",
56
- "qwen",
57
- "kimi",
58
- "vscode",
59
- "visualstudio",
60
- "generic"
61
- ]);
62
- function detectHarness() {
63
- const env = process.env;
64
- const override = (env[ENV_KEYS.HARNESS_OVERRIDE] ?? "").toLowerCase().trim();
65
- if (override && KNOWN_HARNESS_NAMES.has(override)) {
66
- return override;
67
- }
68
- if (env["HERMES_SESSION_ID"] || env["HERMES_HOME"]) {
69
- return "hermes";
70
- }
71
- if (env["TERM_PROGRAM"] === "claude-code" || env["CLAUDE_CODE_VERSION"] !== void 0 || env["CLAUDE_CODE_SESSION_ID"]) {
72
- return "claudecode";
73
- }
74
- if (env["CODEX_SESSION_ID"] !== void 0 || env["CODEX_SESSION"]) {
75
- return "codex";
76
- }
77
- if (env["OPENCODE_SESSION_ID"] !== void 0 || env["OPENCODE_SESSION"]) {
78
- return "opencode";
79
- }
80
- if (env["GROK_SESSION_ID"] !== void 0) {
81
- return "grok";
82
- }
83
- if (env["OPENCLAW_SESSION_ID"] !== void 0) {
84
- return "openclaw";
85
- }
86
- if (env["ANTHROPIC_API_KEY"]) {
87
- return "claudecode";
88
- }
89
- if (env["OPENAI_API_KEY"] && !env["ANTHROPIC_API_KEY"]) {
90
- return "codex";
91
- }
92
- if ((env["GEMINI_API_KEY"] || env["GOOGLE_API_KEY"]) && !env["ANTHROPIC_API_KEY"]) {
93
- return "gemini";
94
- }
95
- return "generic";
96
- }
97
- var _cached = null;
98
- function getHarnessName() {
99
- if (_cached === null) {
100
- _cached = detectHarness();
101
- }
102
- return _cached;
103
- }
104
- function resetHarnessCache() {
105
- _cached = null;
106
- }
107
- registerReset(resetHarnessCache);
108
-
109
- // src/env.ts
110
- init_define_import_meta_env();
111
- var FALSY_ENV_VALUES = /* @__PURE__ */ new Set(["0", "false", "no", "off"]);
112
- var TRUTHY_ENV_VALUES = /* @__PURE__ */ new Set(["1", "true", "yes", "on"]);
113
- function envStr(key, defaultVal) {
114
- const raw = process.env[key];
115
- if (raw === void 0) return defaultVal;
116
- const trimmed = raw.trim();
117
- return trimmed === "" ? defaultVal : trimmed;
118
- }
119
- function envBool(key, defaultVal) {
120
- const raw = process.env[key];
121
- if (raw === void 0) return defaultVal;
122
- const norm = raw.trim().toLowerCase();
123
- if (norm === "") return defaultVal;
124
- if (TRUTHY_ENV_VALUES.has(norm)) return true;
125
- if (FALSY_ENV_VALUES.has(norm)) return false;
126
- return defaultVal;
127
- }
128
- function envInt(key, defaultVal, min, max) {
129
- const raw = process.env[key];
130
- if (raw === void 0) return defaultVal;
131
- const norm = raw.trim();
132
- if (norm === "") return defaultVal;
133
- if (!/^[+-]?\d+$/.test(norm)) return defaultVal;
134
- const val = parseInt(norm, 10);
135
- if (!Number.isFinite(val)) return defaultVal;
136
- let clamped = val;
137
- if (min !== void 0) clamped = Math.max(min, clamped);
138
- if (max !== void 0) clamped = Math.min(max, clamped);
139
- return clamped;
140
- }
141
- function envStrList(key, defaultVal, delimiter2) {
142
- const raw = process.env[key];
143
- if (raw === void 0) return defaultVal;
144
- const entries = raw.split(delimiter2).map((s) => s.trim()).filter((s) => s !== "");
145
- return entries.length > 0 ? entries : defaultVal;
146
- }
147
-
148
- // src/fingerprint.ts
149
- init_define_import_meta_env();
150
- import { createHash } from "node:crypto";
151
- import * as fs from "node:fs";
152
- function fingerprintContent(content) {
153
- const hash = createHash("sha256");
154
- hash.update(typeof content === "string" ? Buffer.from(content, "utf-8") : content);
155
- return hash.digest("hex");
156
- }
157
- function shortFingerprint(content) {
158
- return fingerprintContent(content).slice(0, 16);
159
- }
160
- function fingerprintFile(filePath) {
161
- let data;
162
- try {
163
- data = fs.readFileSync(filePath);
164
- } catch {
165
- return null;
166
- }
167
- return fingerprintContent(data);
168
- }
169
- function fileIsAbsent(filePath) {
170
- try {
171
- return fs.statSync(filePath, { throwIfNoEntry: false }) === void 0;
172
- } catch {
173
- return false;
174
- }
175
- }
176
-
177
- // src/project.ts
178
- init_define_import_meta_env();
179
- import * as fs2 from "node:fs";
180
- import * as os from "node:os";
181
- import * as path from "node:path";
182
- var PROJECT_MARKERS = [
183
- ".git",
184
- "package.json",
185
- "pyproject.toml",
186
- "Cargo.toml",
187
- "go.mod",
188
- "shopify.app.toml",
189
- "_config.yml",
190
- "deno.json",
191
- "deno.jsonc"
192
- ];
193
- var REPO_CONTAINER_THRESHOLD = 3;
194
- function projectHash(canonicalRoot) {
195
- return shortFingerprint(foldPath(canonicalRoot));
196
- }
197
- function makeProjectAt(root) {
198
- let canonical;
199
- try {
200
- canonical = canonicalize(root);
201
- } catch (exc) {
202
- throw new Error(
203
- `makeProjectAt: could not resolve path: ${extractErrorMessage(exc)}`,
204
- { cause: exc }
205
- );
206
- }
207
- try {
208
- const stat = fs2.statSync(canonical);
209
- if (!stat.isDirectory()) {
210
- throw new Error(`makeProjectAt: path is not a directory: ${canonical}`);
211
- }
212
- } catch (exc) {
213
- if (exc instanceof Error && exc.message.includes("ENOENT")) {
214
- throw new Error(`makeProjectAt: path does not exist: ${canonical}`, { cause: exc });
215
- }
216
- throw exc;
217
- }
218
- const hash = projectHash(canonical);
219
- return { root: canonical, hash, marker: "manual" };
220
- }
221
- function isRepoContainer(pathStr) {
222
- let nestedRepos = 0;
223
- try {
224
- const entries = fs2.readdirSync(pathStr, { withFileTypes: true });
225
- for (const entry of entries) {
226
- if (entry.isDirectory()) {
227
- const gitPath = path.join(pathStr, entry.name, ".git");
228
- if (fs2.existsSync(gitPath)) {
229
- let isGitDir = false;
230
- try {
231
- isGitDir = fs2.statSync(gitPath).isDirectory();
232
- } catch {
233
- }
234
- if (isGitDir) {
235
- nestedRepos++;
236
- if (nestedRepos >= REPO_CONTAINER_THRESHOLD) {
237
- return true;
238
- }
239
- }
240
- }
241
- }
242
- }
243
- } catch {
244
- return false;
245
- }
246
- return false;
247
- }
248
- function markerExists(current, marker) {
249
- const markerPath = path.join(current, marker);
250
- try {
251
- if (!fs2.existsSync(markerPath)) {
252
- return false;
253
- }
254
- const stat = fs2.lstatSync(markerPath);
255
- if (!stat.isSymbolicLink()) {
256
- return true;
257
- }
258
- const resolved = fs2.realpathSync(markerPath);
259
- const rel = path.relative(path.resolve(current), path.resolve(resolved));
260
- return !rel.startsWith("..") && !path.isAbsolute(rel);
261
- } catch {
262
- return false;
263
- }
264
- }
265
- function findProject(cwd) {
266
- let p;
267
- try {
268
- p = canonicalize(cwd);
269
- } catch {
270
- return null;
271
- }
272
- let sysTemp = null;
273
- try {
274
- sysTemp = canonicalize(os.tmpdir());
275
- } catch {
276
- }
277
- let current = p;
278
- while (true) {
279
- if (sysTemp && normalizeDarwinSystemAlias(foldPath(current)) === normalizeDarwinSystemAlias(foldPath(sysTemp))) {
280
- break;
281
- }
282
- for (const marker of PROJECT_MARKERS) {
283
- if (markerExists(current, marker)) {
284
- if (!isRepoContainer(current)) {
285
- return {
286
- root: current,
287
- hash: projectHash(current),
288
- marker
289
- };
290
- }
291
- break;
292
- }
293
- }
294
- const parent = path.dirname(current);
295
- if (parent === current) {
296
- break;
297
- }
298
- current = parent;
299
- }
300
- return null;
301
- }
302
- var _displayRootCache = null;
303
- function getDisplayRoot(explicitRoot) {
304
- if (explicitRoot !== void 0) return explicitRoot;
305
- const cwd = process.cwd();
306
- if (_displayRootCache !== null && _displayRootCache.cwd === cwd) return _displayRootCache.root;
307
- const project = findProject(cwd);
308
- const root = project !== null ? project.root : void 0;
309
- _displayRootCache = { cwd, root };
310
- return root;
311
- }
312
- registerReset(() => {
313
- _displayRootCache = null;
314
- });
315
- function isUnderSystemTemp(filePath) {
316
- let sysTemp;
317
- try {
318
- sysTemp = canonicalize(os.tmpdir());
319
- } catch {
320
- return false;
321
- }
322
- let target;
323
- try {
324
- target = canonicalize(filePath);
325
- } catch {
326
- return false;
327
- }
328
- const foldedTemp = normalizeDarwinSystemAlias(foldPath(sysTemp));
329
- const foldedTarget = normalizeDarwinSystemAlias(foldPath(target));
330
- return foldedTarget === foldedTemp || foldedTarget.startsWith(`${foldedTemp}/`);
331
- }
332
- function resolveProjectRoot(opts) {
333
- const base = opts?.project !== void 0 ? path.resolve(opts.project) : process.cwd();
334
- const toplevel = runGit(["rev-parse", "--show-toplevel"], { cwd: base });
335
- if (toplevel.exitCode === 0) {
336
- const trimmed = toplevel.stdout.trim();
337
- if (trimmed.length > 0) return canonicalize(trimmed);
338
- }
339
- const project = findProject(base);
340
- if (project !== null) return project.root;
341
- return canonicalize(base);
342
- }
343
-
344
- // src/ocr_languages.ts
345
- init_define_import_meta_env();
346
- var DEFAULT_OCR_LANG = "eng";
347
- var SUPPORTED_OCR_LANG_CODES = [
348
- "eng",
349
- "fra",
350
- "spa",
351
- "deu",
352
- "ita",
353
- "por",
354
- "nld",
355
- "pol",
356
- "rus",
357
- "tur",
358
- "swe",
359
- "ara",
360
- "chi_sim",
361
- "chi_tra",
362
- "jpn",
363
- "kor"
364
- ];
365
- var SUPPORTED_SET = new Set(SUPPORTED_OCR_LANG_CODES);
366
- function isSupportedOcrLang(lang) {
367
- return SUPPORTED_SET.has(lang);
368
- }
369
- function resolveOcrLangs(input) {
370
- const result = [DEFAULT_OCR_LANG];
371
- if (!input) return result;
372
- const tokens = input.split(/[+,;\s]+/).map((s) => s.trim().toLowerCase());
373
- for (const token of tokens) {
374
- if (token && isSupportedOcrLang(token) && !result.includes(token)) {
375
- result.push(token);
376
- }
377
- }
378
- return result;
379
- }
380
-
381
- // src/config.ts
382
- init_define_import_meta_env();
383
- import * as fs3 from "node:fs";
384
- import * as path2 from "node:path";
385
-
386
- // node_modules/smol-toml/dist/index.js
387
- init_define_import_meta_env();
388
-
389
- // node_modules/smol-toml/dist/parse.js
390
- init_define_import_meta_env();
391
-
392
- // node_modules/smol-toml/dist/struct.js
393
- init_define_import_meta_env();
394
-
395
- // node_modules/smol-toml/dist/primitive.js
396
- init_define_import_meta_env();
397
-
398
- // node_modules/smol-toml/dist/date.js
399
- init_define_import_meta_env();
400
- var DATE_TIME_RE = /^(\d{4}-\d{2}-\d{2})?[T ]?(?:(\d{2}):\d{2}(?::\d{2}(?:\.\d+)?)?)?(Z|[-+]\d{2}:\d{2})?$/i;
401
- var TomlDate = class _TomlDate extends Date {
402
- #hasDate = false;
403
- #hasTime = false;
404
- #offset = null;
405
- constructor(date) {
406
- let hasDate = true;
407
- let hasTime = true;
408
- let offset = "Z";
409
- if (typeof date === "string") {
410
- let match = date.match(DATE_TIME_RE);
411
- if (match) {
412
- if (!match[1]) {
413
- hasDate = false;
414
- date = `0000-01-01T${date}`;
415
- }
416
- hasTime = !!match[2];
417
- hasTime && date[10] === " " && (date = date.replace(" ", "T"));
418
- if (match[2] && +match[2] > 23) {
419
- date = "";
420
- } else {
421
- offset = match[3] || null;
422
- date = date.toUpperCase();
423
- if (!offset && hasTime)
424
- date += "Z";
425
- }
426
- } else {
427
- date = "";
428
- }
429
- }
430
- super(date);
431
- if (!isNaN(this.getTime())) {
432
- this.#hasDate = hasDate;
433
- this.#hasTime = hasTime;
434
- this.#offset = offset;
435
- }
436
- }
437
- isDateTime() {
438
- return this.#hasDate && this.#hasTime;
439
- }
440
- isLocal() {
441
- return !this.#hasDate || !this.#hasTime || !this.#offset;
442
- }
443
- isDate() {
444
- return this.#hasDate && !this.#hasTime;
445
- }
446
- isTime() {
447
- return this.#hasTime && !this.#hasDate;
448
- }
449
- isValid() {
450
- return this.#hasDate || this.#hasTime;
451
- }
452
- toISOString() {
453
- let iso = super.toISOString();
454
- if (this.isDate())
455
- return iso.slice(0, 10);
456
- if (this.isTime())
457
- return iso.slice(11, 23);
458
- if (this.#offset === null)
459
- return iso.slice(0, -1);
460
- if (this.#offset === "Z")
461
- return iso;
462
- let offset = +this.#offset.slice(1, 3) * 60 + +this.#offset.slice(4, 6);
463
- offset = this.#offset[0] === "-" ? offset : -offset;
464
- let offsetDate = new Date(this.getTime() - offset * 6e4);
465
- return offsetDate.toISOString().slice(0, -1) + this.#offset;
466
- }
467
- static wrapAsOffsetDateTime(jsDate, offset = "Z") {
468
- let date = new _TomlDate(jsDate);
469
- date.#offset = offset;
470
- return date;
471
- }
472
- static wrapAsLocalDateTime(jsDate) {
473
- let date = new _TomlDate(jsDate);
474
- date.#offset = null;
475
- return date;
476
- }
477
- static wrapAsLocalDate(jsDate) {
478
- let date = new _TomlDate(jsDate);
479
- date.#hasTime = false;
480
- date.#offset = null;
481
- return date;
482
- }
483
- static wrapAsLocalTime(jsDate) {
484
- let date = new _TomlDate(jsDate);
485
- date.#hasDate = false;
486
- date.#offset = null;
487
- return date;
488
- }
489
- };
490
-
491
- // node_modules/smol-toml/dist/error.js
492
- init_define_import_meta_env();
493
- function getLineColFromPtr(string, ptr) {
494
- let lines = string.slice(0, ptr).split(/\r\n|\n|\r/g);
495
- return [lines.length, lines.pop().length + 1];
496
- }
497
- function makeCodeBlock(string, line, column) {
498
- let lines = string.split(/\r\n|\n|\r/g);
499
- let codeblock = "";
500
- let numberLen = (Math.log10(line + 1) | 0) + 1;
501
- for (let i = line - 1; i <= line + 1; i++) {
502
- let l = lines[i - 1];
503
- if (!l)
504
- continue;
505
- codeblock += i.toString().padEnd(numberLen, " ");
506
- codeblock += ": ";
507
- codeblock += l;
508
- codeblock += "\n";
509
- if (i === line) {
510
- codeblock += " ".repeat(numberLen + column + 2);
511
- codeblock += "^\n";
512
- }
513
- }
514
- return codeblock;
515
- }
516
- var TomlError = class extends Error {
517
- line;
518
- column;
519
- codeblock;
520
- constructor(message, options) {
521
- const [line, column] = getLineColFromPtr(options.toml, options.ptr);
522
- const codeblock = makeCodeBlock(options.toml, line, column);
523
- super(`Invalid TOML document: ${message}
524
-
525
- ${codeblock}`, options);
526
- this.line = line;
527
- this.column = column;
528
- this.codeblock = codeblock;
529
- }
530
- };
531
-
532
- // node_modules/smol-toml/dist/util.js
533
- init_define_import_meta_env();
534
- function indexOfNewline(str, start = 0) {
535
- let idx = str.indexOf("\n", start);
536
- if (str.charCodeAt(idx - 1) === 13)
537
- idx--;
538
- return idx;
539
- }
540
- function skipComment(ctx) {
541
- for (; ctx.p < ctx.s.length; ctx.p++) {
542
- let c = ctx.s.charCodeAt(ctx.p);
543
- if (c === 10)
544
- break;
545
- if (c === 13 && ctx.s.charCodeAt(ctx.p + 1) === 10) {
546
- ctx.p++;
547
- break;
548
- }
549
- if (c < 32 && c !== 9 || c === 127) {
550
- throw new TomlError("control characters are not allowed in comments", {
551
- toml: ctx.s,
552
- ptr: ctx.p
553
- });
554
- }
555
- }
556
- }
557
- function skipVoid(ctx, banNewLines, banComments) {
558
- let c;
559
- while (1) {
560
- while ((c = ctx.s.charCodeAt(ctx.p)) === 32 || c === 9 || !banNewLines && (c === 10 || c === 13 && ctx.s.charCodeAt(ctx.p + 1) === 10))
561
- ctx.p++;
562
- if (banComments || c !== 35)
563
- break;
564
- skipComment(ctx);
565
- }
566
- }
567
- function skipUntil(ctx, sep, end) {
568
- let ptr = ctx.p;
569
- if (!end) {
570
- ptr = indexOfNewline(ctx.s, ptr);
571
- ctx.p = ptr < 0 ? ctx.s.length : ptr;
572
- return;
573
- }
574
- for (; ctx.p < ctx.s.length; ctx.p++) {
575
- let c = ctx.s.charCodeAt(ctx.p);
576
- if (c === 35) {
577
- skipComment(ctx);
578
- } else if (c === end || c === sep) {
579
- return;
580
- }
581
- }
582
- throw new TomlError("cannot find end of structure", {
583
- toml: ctx.s,
584
- ptr
585
- });
586
- }
587
-
588
- // node_modules/smol-toml/dist/primitive.js
589
- var INT_REGEX = /^((0x[0-9a-fA-F](_?[0-9a-fA-F])*)|(([+-]|0[ob])?\d(_?\d)*))$/;
590
- var FLOAT_REGEX = /^[+-]?\d(_?\d)*(\.\d(_?\d)*)?([eE][+-]?\d(_?\d)*)?$/;
591
- var LEADING_ZERO = /^[+-]?0[0-9_]/;
592
- function parseString(ctx) {
593
- let start = ctx.p;
594
- let c = ctx.s.charCodeAt(ctx.p++);
595
- let first = c;
596
- let isLiteral = c === 39;
597
- let isMultiline = c === ctx.s.charCodeAt(ctx.p) && c === ctx.s.charCodeAt(ctx.p + 1);
598
- if (isMultiline) {
599
- if ((c = ctx.s.charCodeAt(ctx.p += 2)) === 10)
600
- ctx.p++;
601
- else if (c === 13 && ctx.s.charCodeAt(ctx.p + 1) === 10)
602
- ctx.p += 2;
603
- }
604
- let parsed = "";
605
- let sliceStart = ctx.p;
606
- let state = 0;
607
- for (; ctx.p < ctx.s.length; ctx.p++) {
608
- c = ctx.s.charCodeAt(ctx.p);
609
- if (isMultiline && (c === 10 || c === 13 && ctx.s.charCodeAt(ctx.p + 1) === 10)) {
610
- state = state && 3;
611
- } else if (c < 32 && c !== 9 || c === 127) {
612
- throw new TomlError("control characters are not allowed in strings", {
613
- toml: ctx.s,
614
- ptr: ctx.p
615
- });
616
- } else if ((!state || state === 3) && c === first && (!isMultiline || ctx.s.charCodeAt(ctx.p + 1) === first && ctx.s.charCodeAt(ctx.p + 2) === first)) {
617
- if (isMultiline) {
618
- if (ctx.s.charCodeAt(ctx.p + 3) === first)
619
- ctx.p++;
620
- if (ctx.s.charCodeAt(ctx.p + 3) === first)
621
- ctx.p++;
622
- }
623
- if (!state)
624
- parsed += ctx.s.slice(sliceStart, ctx.p);
625
- ctx.p += isMultiline ? 3 : 1;
626
- return parsed;
627
- } else if (!state) {
628
- if (!isLiteral && c === 92) {
629
- parsed += ctx.s.slice(sliceStart, sliceStart = ctx.p);
630
- state = 1;
631
- }
632
- } else if (state === 1) {
633
- if (c === 120 || c === 117 || c === 85) {
634
- let value = 0;
635
- let len = c === 120 ? 2 : c === 117 ? 4 : 8;
636
- for (let j = 0; j < len; j++, ctx.p++) {
637
- let hex = ctx.s.charCodeAt(ctx.p + 1);
638
- let digit = (
639
- /* 0-9 */
640
- hex >= 48 && hex <= 57 ? hex - 48 : (
641
- /* A-F */
642
- hex >= 65 && hex <= 70 ? hex - 65 + 10 : (
643
- /* a-f */
644
- hex >= 97 && hex <= 102 ? hex - 97 + 10 : -1
645
- )
646
- )
647
- );
648
- if (digit < 0)
649
- throw new TomlError("invalid non-hex character in unicode escape", { toml: ctx.s, ptr: ctx.p + 1 });
650
- value = value << 4 | digit;
651
- }
652
- if (value < 0 || value > 1114111 || value >= 55296 && value <= 57343) {
653
- throw new TomlError("invalid unicode escape", { toml: ctx.s, ptr: ctx.p });
654
- }
655
- parsed += String.fromCodePoint(value);
656
- sliceStart = ctx.p + 1;
657
- state = 0;
658
- } else if (c === 32 || c === 9) {
659
- state = 2;
660
- } else {
661
- if (c === 98)
662
- parsed += "\b";
663
- else if (c === 116)
664
- parsed += " ";
665
- else if (c === 110)
666
- parsed += "\n";
667
- else if (c === 102)
668
- parsed += "\f";
669
- else if (c === 114)
670
- parsed += "\r";
671
- else if (c === 101)
672
- parsed += "\x1B";
673
- else if (c === 34)
674
- parsed += '"';
675
- else if (c === 92)
676
- parsed += "\\";
677
- else
678
- throw new TomlError("unrecognized escape sequence", { toml: ctx.s, ptr: ctx.p });
679
- sliceStart = ctx.p + 1;
680
- state = 0;
681
- }
682
- } else if (c !== 32 && c !== 9) {
683
- if (state === 2) {
684
- throw new TomlError("invalid escape: only line-ending whitespace may be escaped", {
685
- toml: ctx.s,
686
- ptr: sliceStart
687
- });
688
- }
689
- state = !isLiteral && c === 92 ? 1 : 0;
690
- sliceStart = ctx.p;
691
- }
692
- }
693
- throw new TomlError("unfinished string", { toml: ctx.s, ptr: start });
694
- }
695
- function sliceAndTrimEndOf(ctx, start, end) {
696
- let value = ctx.s.slice(start, end);
697
- let commentIdx = value.indexOf("#");
698
- if (commentIdx > 0) {
699
- skipComment({ s: value, p: commentIdx, d: 0 });
700
- value = value.slice(0, commentIdx);
701
- }
702
- return value.trimEnd();
703
- }
704
- function parseValue(ctx, integersAsBigInt, end) {
705
- let ptr = ctx.p;
706
- let err = { toml: ctx.s, ptr };
707
- skipUntil(ctx, 44, end);
708
- let value = sliceAndTrimEndOf(ctx, ptr, ctx.p);
709
- if (!value)
710
- throw new TomlError("incomplete declaration: value expected", err);
711
- if (value === "-inf")
712
- return -Infinity;
713
- if (value === "inf" || value === "+inf")
714
- return Infinity;
715
- if (value === "nan" || value === "+nan" || value === "-nan")
716
- return NaN;
717
- if (value === "-0")
718
- return integersAsBigInt ? 0n : 0;
719
- let isInt = INT_REGEX.test(value);
720
- if (isInt || FLOAT_REGEX.test(value)) {
721
- if (LEADING_ZERO.test(value)) {
722
- throw new TomlError("leading zeroes are not allowed", err);
723
- }
724
- value = value.replace(/_/g, "");
725
- let numeric = +value;
726
- if (isNaN(numeric)) {
727
- throw new TomlError("invalid number", err);
728
- }
729
- if (isInt) {
730
- if ((isInt = !Number.isSafeInteger(numeric)) && !integersAsBigInt) {
731
- throw new TomlError("integer value cannot be represented losslessly", err);
732
- }
733
- if (isInt || integersAsBigInt === true)
734
- numeric = BigInt(value);
735
- }
736
- return numeric;
737
- }
738
- const date = new TomlDate(value);
739
- if (!date.isValid())
740
- throw new TomlError("invalid value", err);
741
- return date;
742
- }
743
-
744
- // node_modules/smol-toml/dist/extract.js
745
- init_define_import_meta_env();
746
- function extractValue(ctx, end, integersAsBigInt) {
747
- let ptr = ctx.p;
748
- let c = ctx.s.charCodeAt(ptr);
749
- if (c === 91 || c === 123) {
750
- if (!ctx.d--) {
751
- throw new TomlError("document contains excessively nested structures. aborting.", {
752
- toml: ctx.s,
753
- ptr
754
- });
755
- }
756
- let value = c === 91 ? parseArray(ctx, integersAsBigInt) : parseInlineTable(ctx, integersAsBigInt);
757
- ctx.d++;
758
- return value;
759
- }
760
- if (c === 34 || c === 39) {
761
- return parseString(ctx);
762
- }
763
- if (c === 116) {
764
- if (ctx.s.charCodeAt(++ctx.p) !== 114 || ctx.s.charCodeAt(++ctx.p) !== 117 || ctx.s.charCodeAt(++ctx.p) !== 101)
765
- throw new TomlError("invalid value", { toml: ctx.s, ptr });
766
- ctx.p++;
767
- return true;
768
- }
769
- if (c === 102) {
770
- if (ctx.s.charCodeAt(++ctx.p) !== 97 || ctx.s.charCodeAt(++ctx.p) !== 108 || ctx.s.charCodeAt(++ctx.p) !== 115 || ctx.s.charCodeAt(++ctx.p) !== 101)
771
- throw new TomlError("invalid value", { toml: ctx.s, ptr });
772
- ctx.p++;
773
- return false;
774
- }
775
- return parseValue(ctx, integersAsBigInt, end);
776
- }
777
-
778
- // node_modules/smol-toml/dist/struct.js
779
- var KEY_PART_RE = /^[a-zA-Z0-9-_]+[ \t]*$/;
780
- function parseKey(ctx, end = "=") {
781
- let start = ctx.p;
782
- let dot = start - 1;
783
- let parsed = [];
784
- let endPtr = ctx.s.indexOf(end, start);
785
- if (endPtr < 0) {
786
- throw new TomlError("incomplete key-value: cannot find end of key", {
787
- toml: ctx.s,
788
- ptr: start
789
- });
790
- }
791
- do {
792
- let c = ctx.s.charCodeAt(ctx.p = ++dot);
793
- if (c !== 32 && c !== 9) {
794
- if (c === 34 || c === 39) {
795
- if (c === ctx.s.charCodeAt(ctx.p + 1) && c === ctx.s.charCodeAt(ctx.p + 2)) {
796
- throw new TomlError("multiline strings are not allowed in keys", {
797
- toml: ctx.s,
798
- ptr: ctx.p
799
- });
800
- }
801
- let part = parseString(ctx);
802
- dot = ctx.s.indexOf(".", ctx.p);
803
- let strEnd = ctx.s.slice(ctx.p, dot < 0 || dot > endPtr ? endPtr : dot);
804
- let newLine = indexOfNewline(strEnd);
805
- if (newLine > -1) {
806
- throw new TomlError("newlines are not allowed in keys", {
807
- toml: ctx.s,
808
- ptr: newLine
809
- });
810
- }
811
- if (strEnd.trimStart()) {
812
- throw new TomlError("found extra tokens after the string part", {
813
- toml: ctx.s,
814
- ptr: ctx.p
815
- });
816
- }
817
- if (endPtr < ctx.p) {
818
- endPtr = ctx.s.indexOf(end, ctx.p);
819
- if (endPtr < 0) {
820
- throw new TomlError("incomplete key-value: cannot find end of key", {
821
- toml: ctx.s,
822
- ptr: start
823
- });
824
- }
825
- }
826
- parsed.push(part);
827
- } else {
828
- dot = ctx.s.indexOf(".", ctx.p);
829
- let part = ctx.s.slice(ctx.p, dot < 0 || dot > endPtr ? endPtr : dot);
830
- if (!KEY_PART_RE.test(part)) {
831
- throw new TomlError("only letter, numbers, dashes and underscores are allowed in keys", {
832
- toml: ctx.s,
833
- ptr: ctx.p
834
- });
835
- }
836
- parsed.push(part.trimEnd());
837
- }
838
- }
839
- } while (dot + 1 && dot < endPtr);
840
- ctx.p = endPtr + 1;
841
- skipVoid(ctx, true, true);
842
- return parsed;
843
- }
844
- function parseInlineTable(ctx, integersAsBigInt) {
845
- let res = {};
846
- let seen = /* @__PURE__ */ new Set();
847
- let c;
848
- ctx.p++;
849
- while (ctx.p < ctx.s.length) {
850
- skipVoid(ctx);
851
- if ((c = ctx.s.charCodeAt(ctx.p)) === 125) {
852
- ctx.p++;
853
- return res;
854
- }
855
- let k;
856
- let t = res;
857
- let hasOwn = false;
858
- let p = ctx.p;
859
- let key = parseKey(ctx);
860
- for (let i = 0; i < key.length; i++) {
861
- if (i)
862
- t = hasOwn ? t[k] : t[k] = {};
863
- k = key[i];
864
- if ((hasOwn = Object.hasOwn(t, k)) && (typeof t[k] !== "object" || seen.has(t[k]))) {
865
- throw new TomlError("trying to redefine an already defined value", {
866
- toml: ctx.s,
867
- ptr: p
868
- });
869
- }
870
- if (!hasOwn && k === "__proto__") {
871
- Object.defineProperty(t, k, { enumerable: true, configurable: true, writable: true });
872
- }
873
- }
874
- if (hasOwn) {
875
- throw new TomlError("trying to redefine an already defined value", {
876
- toml: ctx.s,
877
- ptr: ctx.p
878
- });
879
- }
880
- let value = extractValue(ctx, 125, integersAsBigInt);
881
- seen.add(t[k] = value);
882
- skipVoid(ctx);
883
- if ((c = ctx.s.charCodeAt(ctx.p++)) === 125) {
884
- return res;
885
- }
886
- if (c !== 44) {
887
- throw new TomlError("expected comma or end of structure", { toml: ctx.s, ptr: ctx.p - 1 });
888
- }
889
- }
890
- throw new TomlError("unfinished table encountered", {
891
- toml: ctx.s,
892
- ptr: ctx.p
893
- });
894
- }
895
- function parseArray(ctx, integersAsBigInt) {
896
- let res = [];
897
- let c;
898
- ctx.p++;
899
- while (ctx.p < ctx.s.length) {
900
- skipVoid(ctx);
901
- if ((c = ctx.s.charCodeAt(ctx.p)) === 93) {
902
- ctx.p++;
903
- return res;
904
- }
905
- res.push(extractValue(ctx, 93, integersAsBigInt));
906
- skipVoid(ctx);
907
- if ((c = ctx.s.charCodeAt(ctx.p++)) === 93) {
908
- return res;
909
- }
910
- if (c !== 44) {
911
- throw new TomlError("expected comma or end of structure", { toml: ctx.s, ptr: ctx.p - 1 });
912
- }
913
- }
914
- throw new TomlError("unfinished array encountered", {
915
- toml: ctx.s,
916
- ptr: ctx.p
917
- });
918
- }
919
-
920
- // node_modules/smol-toml/dist/parse.js
921
- function peekTable(key, table, meta, type) {
922
- let t = table;
923
- let m = meta;
924
- let k;
925
- let hasOwn = false;
926
- let state;
927
- for (let i = 0; i < key.length; i++) {
928
- if (i) {
929
- t = hasOwn ? t[k] : t[k] = {};
930
- m = (state = m[k]).c;
931
- if (type === 0 && (state.t === 1 || state.t === 2)) {
932
- return null;
933
- }
934
- if (state.t === 2) {
935
- let l = t.length - 1;
936
- t = t[l];
937
- m = m[l].c;
938
- }
939
- }
940
- k = key[i];
941
- if ((hasOwn = Object.hasOwn(t, k)) && m[k]?.t === 0 && m[k]?.d) {
942
- return null;
943
- }
944
- if (!hasOwn) {
945
- if (k === "__proto__") {
946
- Object.defineProperty(t, k, { enumerable: true, configurable: true, writable: true });
947
- Object.defineProperty(m, k, { enumerable: true, configurable: true, writable: true });
948
- }
949
- m[k] = {
950
- t: i < key.length - 1 && type === 2 ? 3 : type,
951
- d: false,
952
- i: 0,
953
- c: {}
954
- };
955
- }
956
- }
957
- state = m[k];
958
- if (state.t !== type && !(type === 1 && state.t === 3)) {
959
- return null;
960
- }
961
- if (type === 2) {
962
- if (!state.d) {
963
- state.d = true;
964
- t[k] = [];
965
- }
966
- t[k].push(t = {});
967
- state.c[state.i++] = state = { t: 1, d: false, i: 0, c: {} };
968
- }
969
- if (state.d) {
970
- return null;
971
- }
972
- state.d = true;
973
- if (type === 1) {
974
- t = hasOwn ? t[k] : t[k] = {};
975
- } else if (type === 0 && hasOwn) {
976
- return null;
977
- }
978
- return [k, t, state.c];
979
- }
980
- function parse(toml, { maxDepth = 1e3, integersAsBigInt } = {}) {
981
- let ctx = { s: toml, p: 0, d: maxDepth };
982
- let res = {};
983
- let meta = {};
984
- let tmp;
985
- let tbl = res;
986
- let m = meta;
987
- skipVoid(ctx);
988
- while (ctx.p < toml.length) {
989
- if (toml.charCodeAt(ctx.p) === 91) {
990
- let isTableArray = toml.charCodeAt(++ctx.p) === 91;
991
- tmp = ctx.p += +isTableArray;
992
- let k = parseKey(ctx, "]");
993
- if (isTableArray) {
994
- if (toml.charCodeAt(ctx.p - 1) !== 93) {
995
- throw new TomlError("expected end of table declaration", {
996
- toml,
997
- ptr: ctx.p - 1
998
- });
999
- }
1000
- ctx.p++;
1001
- }
1002
- let p = peekTable(
1003
- k,
1004
- res,
1005
- meta,
1006
- isTableArray ? 2 : 1
1007
- /* Type.EXPLICIT */
1008
- );
1009
- if (!p) {
1010
- throw new TomlError("trying to redefine an already defined table or value", {
1011
- toml,
1012
- ptr: tmp
1013
- });
1014
- }
1015
- m = p[2];
1016
- tbl = p[1];
1017
- } else {
1018
- tmp = ctx.p;
1019
- let k = parseKey(ctx);
1020
- let p = peekTable(
1021
- k,
1022
- tbl,
1023
- m,
1024
- 0
1025
- /* Type.DOTTED */
1026
- );
1027
- if (!p) {
1028
- throw new TomlError("trying to redefine an already defined table or value", {
1029
- toml,
1030
- ptr: tmp
1031
- });
1032
- }
1033
- p[1][p[0]] = extractValue(ctx, void 0, integersAsBigInt);
1034
- }
1035
- skipVoid(ctx, true);
1036
- if (ctx.p < toml.length && (tmp = toml.charCodeAt(ctx.p)) !== 10 && tmp !== 13) {
1037
- throw new TomlError("each key-value declaration must be followed by an end-of-line", {
1038
- toml,
1039
- ptr: ctx.p
1040
- });
1041
- }
1042
- skipVoid(ctx);
1043
- }
1044
- return res;
1045
- }
1046
-
1047
- // node_modules/smol-toml/dist/stringify.js
1048
- init_define_import_meta_env();
1049
- var BARE_KEY = /^[a-z0-9-_]+$/i;
1050
- function extendedTypeOf(obj) {
1051
- let type = typeof obj;
1052
- if (type === "object") {
1053
- if (Array.isArray(obj))
1054
- return "array";
1055
- if (typeof obj?.getUTCDate === "function" && obj instanceof Date)
1056
- return "date";
1057
- if (globalThis.Temporal && // check for the 'since' property as an early bailout that avoids running all 5 instanceof checks
1058
- typeof obj?.since === "function" && (obj instanceof Temporal.Instant || obj instanceof Temporal.PlainDate || obj instanceof Temporal.PlainDateTime || obj instanceof Temporal.PlainTime || obj instanceof Temporal.ZonedDateTime)) {
1059
- return "temporal";
1060
- }
1061
- }
1062
- return type;
1063
- }
1064
- function isArrayOfTables(obj) {
1065
- for (let i = 0; i < obj.length; i++) {
1066
- if (extendedTypeOf(obj[i]) !== "object")
1067
- return false;
1068
- }
1069
- return obj.length != 0;
1070
- }
1071
- function formatString(s) {
1072
- return JSON.stringify(s).replace(/\x7f/g, "\\u007f");
1073
- }
1074
- function stringifyTemporal(temporal) {
1075
- return temporal.toString({
1076
- calendarName: "never",
1077
- timeZoneName: "never"
1078
- });
1079
- }
1080
- function stringifyValue(val, type, depth, numberAsFloat) {
1081
- if (depth === 0) {
1082
- throw new Error("Could not stringify the object: maximum object depth exceeded");
1083
- }
1084
- switch (type) {
1085
- // @ts-expect-error -- intentional fallthrough case
1086
- case "number":
1087
- if (isNaN(val))
1088
- return "nan";
1089
- if (val === Infinity)
1090
- return "inf";
1091
- if (val === -Infinity)
1092
- return "-inf";
1093
- if (Number.isInteger(val) && (numberAsFloat || !Number.isSafeInteger(val)))
1094
- return val.toFixed(1);
1095
- case "bigint":
1096
- case "boolean":
1097
- return val.toString();
1098
- case "string":
1099
- return formatString(val);
1100
- case "date":
1101
- if (isNaN(val.getTime()))
1102
- throw new TypeError("cannot serialize invalid date");
1103
- return val.toISOString();
1104
- case "object":
1105
- return stringifyInlineTable(val, depth, numberAsFloat);
1106
- case "array":
1107
- return stringifyArray(val, depth, numberAsFloat);
1108
- case "temporal":
1109
- return stringifyTemporal(val);
1110
- }
1111
- }
1112
- function stringifyInlineTable(obj, depth, numberAsFloat) {
1113
- let keys = Object.keys(obj);
1114
- if (keys.length === 0)
1115
- return "{}";
1116
- let res = "{ ";
1117
- for (let i = 0; i < keys.length; i++) {
1118
- let k = keys[i];
1119
- if (i)
1120
- res += ", ";
1121
- res += BARE_KEY.test(k) ? k : formatString(k);
1122
- res += " = ";
1123
- res += stringifyValue(obj[k], extendedTypeOf(obj[k]), depth - 1, numberAsFloat);
1124
- }
1125
- return res + " }";
1126
- }
1127
- function stringifyArray(array, depth, numberAsFloat) {
1128
- if (array.length === 0)
1129
- return "[]";
1130
- let res = "[ ";
1131
- for (let i = 0; i < array.length; i++) {
1132
- if (i)
1133
- res += ", ";
1134
- if (array[i] === null || array[i] === void 0) {
1135
- throw new TypeError("arrays cannot contain null or undefined values");
1136
- }
1137
- res += stringifyValue(array[i], extendedTypeOf(array[i]), depth - 1, numberAsFloat);
1138
- }
1139
- return res + " ]";
1140
- }
1141
- function stringifyArrayTable(array, key, depth, numberAsFloat) {
1142
- if (depth === 0) {
1143
- throw new Error("Could not stringify the object: maximum object depth exceeded");
1144
- }
1145
- let res = "";
1146
- for (let i = 0; i < array.length; i++) {
1147
- res += `${res && "\n"}[[${key}]]
1148
- `;
1149
- res += stringifyTable(0, array[i], key, depth, numberAsFloat);
1150
- }
1151
- return res;
1152
- }
1153
- function stringifyTable(tableKey, obj, prefix, depth, numberAsFloat) {
1154
- if (depth === 0) {
1155
- throw new Error("Could not stringify the object: maximum object depth exceeded");
1156
- }
1157
- let preamble = "";
1158
- let tables = "";
1159
- let keys = Object.keys(obj);
1160
- for (let i = 0; i < keys.length; i++) {
1161
- let k = keys[i];
1162
- if (obj[k] !== null && obj[k] !== void 0) {
1163
- let type = extendedTypeOf(obj[k]);
1164
- if (type === "symbol" || type === "function") {
1165
- throw new TypeError(`cannot serialize values of type '${type}'`);
1166
- }
1167
- let key = BARE_KEY.test(k) ? k : formatString(k);
1168
- if (type === "array" && isArrayOfTables(obj[k])) {
1169
- tables += (tables && "\n") + stringifyArrayTable(obj[k], prefix ? `${prefix}.${key}` : key, depth - 1, numberAsFloat);
1170
- } else if (type === "object") {
1171
- let tblKey = prefix ? `${prefix}.${key}` : key;
1172
- tables += (tables && "\n") + stringifyTable(tblKey, obj[k], tblKey, depth - 1, numberAsFloat);
1173
- } else {
1174
- preamble += key;
1175
- preamble += " = ";
1176
- preamble += stringifyValue(obj[k], type, depth, numberAsFloat);
1177
- preamble += "\n";
1178
- }
1179
- }
1180
- }
1181
- if (tableKey && (preamble || !tables))
1182
- preamble = preamble ? `[${tableKey}]
1183
- ${preamble}` : `[${tableKey}]`;
1184
- return preamble && tables ? `${preamble}
1185
- ${tables}` : preamble || tables;
1186
- }
1187
- function stringify(obj, { maxDepth = 1e3, numbersAsFloat = false } = {}) {
1188
- if (extendedTypeOf(obj) !== "object") {
1189
- throw new TypeError("stringify can only be called with an object");
1190
- }
1191
- let str = stringifyTable(0, obj, "", maxDepth, numbersAsFloat);
1192
- if (str[str.length - 1] !== "\n")
1193
- return str + "\n";
1194
- return str;
1195
- }
1196
-
1197
- // src/config.ts
1198
- var CONFIG_DEFAULTS = {
1199
- compact_assist: {
1200
- enabled: true,
1201
- triggers: ["manual", "auto"],
1202
- min_events: 3,
1203
- max_manifest_tokens: 400,
1204
- auto_trigger_multiplier: 2,
1205
- compact_skip_ttl_secs: 300,
1206
- noise_floor_tokens: 0,
1207
- edited_dir_group_threshold: 3,
1208
- max_section_lines: 0,
1209
- wide_session_threshold: 15,
1210
- orchestrator_commit_threshold: 5,
1211
- max_manifest_chars: 1600,
1212
- summary_budget_chars: 24e3,
1213
- harness: "auto"
1214
- },
1215
- bash_compress: {
1216
- enabled: true,
1217
- disabled_filters: [],
1218
- max_lines: 1e3,
1219
- max_bytes: 64 * 1024,
1220
- timeout_seconds: 600,
1221
- // Matches the hardcoded MIN_CACHE_BYTES floor hooks_bash.ts used before this
1222
- // knob was wired to a real consumer, so untouched-config installs see no
1223
- // behavior change now that hooks_bash.ts reads this value instead.
1224
- cache_min_bytes: 512,
1225
- cache_max_file_count: 4096,
1226
- cache_max_bytes: 16 * 1024 * 1024,
1227
- cache_max_bytes_per_output: 50 * 1024 * 1024,
1228
- // Measured against the filter test-fixture corpus (424 apply() calls, 298 with
1229
- // bytesSaved > 0): net-of-marker savings (bytesSaved - ~70-79B marker cost) is
1230
- // <= 0 for 130/298 (44%) of "compressed" results and <= 100 for 170/298 (57%),
1231
- // while the real-win half sits at p75=393B / p90=952B net. 100 kills the
1232
- // marker-doesn't-even-pay-for-itself tier without touching genuine wins.
1233
- min_net_savings_bytes: 100,
1234
- // Extends the per-file already-served elision (which only reaches cat/head/tail/sed/awk-shaped reads) to every other Bash command's output -- npm test, git, rg, build runs -- matched against a session-wide served-output list instead of a per-file one. On by default: it goes through the same isRewriteWorthwhile net-benefit gate as every other rewrite here, so it never ships a notice that costs more than the lines it withholds.
1235
- elide_served_shell_output: true
1236
- },
1237
- agent_report: {
1238
- // Well above the ~2,220 char/call average measured from real claude-skills session transcripts, so only genuine outlier reports are touched. Preserves the hardcoded AGENT_RESULT_CACHE_MIN_BYTES this replaced, so untouched-config installs see no behavior change.
1239
- min_bytes: 8e3,
1240
- fence_collapse_min_lines: 20,
1241
- fence_collapse_keep_lines: 6
1242
- },
1243
- bash_diff: {
1244
- max_hunks_per_file: 10
1245
- },
1246
- bash_severity_log: {
1247
- context_lines: 3,
1248
- score_threshold: 0.5
1249
- },
1250
- post_read_code_compress: {
1251
- min_lines: 200
1252
- },
1253
- session_brief: {
1254
- enabled: true
1255
- },
1256
- skill_preservation: {
1257
- enabled: true,
1258
- max_cache_bytes: 5 * 1024 * 1024,
1259
- orphan_sweep_enabled: true,
1260
- orphan_age_secs: 604800,
1261
- truncation_budget_tokens: 800,
1262
- compress_bodies: true,
1263
- compress_min_bytes: 16 * 1024,
1264
- inline_snippets: true,
1265
- pre_skill_enabled: true,
1266
- first_load_compact: false,
1267
- post_compact_full_loads: false
1268
- },
1269
- image_shrink: {
1270
- enabled: true,
1271
- jpeg_quality: 75,
1272
- max_image_pixels: 16e6,
1273
- screenshot_redirect: true,
1274
- ocr_enabled: true,
1275
- // Confidence is Tesseract's own 0-100 mean-word-confidence score. 65 is a deliberately
1276
- // conservative floor: a real screenshot of terminal/code/prose text routinely scores
1277
- // 85+, while a photo with an incidental sign or logo in frame scores much lower and
1278
- // noisier -- padding the threshold below the terminal/code norm still comfortably
1279
- // excludes photographic false positives without needing a second heuristic.
1280
- ocr_min_confidence: 65,
1281
- ocr_lang: DEFAULT_OCR_LANG,
1282
- // Which resolution tier the model being shown the image is on, which decides what its pixels
1283
- // cost. 'standard' (1568px long edge, 1568 visual tokens) is every model before Claude 4.7;
1284
- // 'high' (2576px, 4784 tokens) is 4.7 and later, and bills the same large image up to roughly
1285
- // three times higher. Only the saving *reported* by `token-goat stats` depends on this -- no
1286
- // image is encoded differently -- and 'standard' is the default because it is the floor: it
1287
- // caps the counterfactual at the smaller of the two bills and so can never credit a saving
1288
- // that was not there. Set it to 'high' on a Claude 4.7+ model to see the larger real figure.
1289
- vision_tier: "standard"
1290
- },
1291
- screenshot: {
1292
- chrome_path: "",
1293
- block_private_targets: true
1294
- },
1295
- repomap: {
1296
- compact_file_threshold: 50,
1297
- exclude_tests: true
1298
- },
1299
- overflow_guard: {
1300
- enabled: true,
1301
- max_tokens: 25e3
1302
- },
1303
- stats: {
1304
- record_zero_savings: false
1305
- },
1306
- hints: {
1307
- quiet_hours: "",
1308
- json_sidecar: false,
1309
- min_file_lines_for_hint: 0,
1310
- bash_dedup_min_bytes: 200,
1311
- web_dedup_min_bytes: 200,
1312
- grep_dedup_min_matches: 5,
1313
- glob_dedup_min_matches: 5,
1314
- // Existing on-disk file must have at least this many lines before a Write rewrite is even
1315
- // considered -- rewriting a small file whole is fine, so hooks_write.ts's detector skips
1316
- // comparison entirely below this floor rather than firing on trivial files.
1317
- write_rewrite_min_lines: 40,
1318
- // Minimum percentage of the existing file's lines that must survive unchanged (by LCS) in
1319
- // the incoming Write content for hooks_write.ts to advise Edit instead. High by design: this
1320
- // is only meant to catch the "mostly untouched, a few lines changed" case, not a genuine
1321
- // rewrite that happens to share some boilerplate.
1322
- write_rewrite_unchanged_pct: 75,
1323
- serve_diff_on_reread: true,
1324
- elide_served_lines: true,
1325
- subagent_markdown_first_read_deny: false,
1326
- backoff_thresholds: [1, 3, 10, 30],
1327
- git_hint_max_ms: 50,
1328
- min_session_hint_savings_bytes: 512,
1329
- pre_skill_advisory: true,
1330
- context_threshold_advisory: true,
1331
- diff_hint_min_tokens_saved: 1e3,
1332
- // Base for the pressure-scaled first-read deny gate in hooks_read.ts (large file, never read
1333
- // before). Matches that gate's long-tuned 500KB threshold at 'cool' context pressure; warm/hot/
1334
- // critical scale it down from there so the same read gets redirected to a surgical read sooner
1335
- // once the context window is nearly full.
1336
- large_read_redirect_bytes: 512e3,
1337
- reread_deny: true,
1338
- // Matches hooks_read.ts's previously-hardcoded REREAD_DENY_BYTES (50 * 1024) so wiring this
1339
- // key up as the real gate for that logic does not silently change default behavior for
1340
- // existing users -- see the reread_deny/reread_deny_min_bytes fix's commit message.
1341
- reread_deny_min_bytes: 51200,
1342
- stable_doc_compacts: true,
1343
- // On. It has now run. The gate that finds the spans answered only from the index, and the index carried the shipping parser stamp on 46 of 17,952 files, so the lever was very nearly dead in practice: a disk parse of the delivered file is now the fallback, worth +3.0 points of withheld bytes on shell reads with no index at all. The cost side is the one this comment used to call unobservable, and it is observable: joining folds to later reads of the folded symbol scores 62.3% recovery, but the same window measured backwards scores 55.8% and a shuffled pairing scores 24.3%, so the excess attributable to the fold is 6.6 points rather than 62. Unlike every re-read mechanism beside it this rewrites a FIRST look, where the reader has no prior copy to notice an omission against, which is why the notice names the symbol and the command that returns it verbatim.
1344
- fold_code_bodies: true,
1345
- // On, and separate from the body fold above because the two do not carry the same risk. A body fold needs symbol spans from the index, so it can cut at the wrong line when the index is stale, and it hides the implementation an agent came to read. A comment fold reads the block boundaries off the delivered text itself, so it cannot be stale and works on the first read of a file the indexer has never seen, which is exactly the surface nothing else here reaches. It keeps the opening two lines of a block of 12 or more, so the summary sentence a reader navigates by survives and only the elaboration is replaced, and it alters the text of no line it keeps, its notice naming the absolute range removed so the recall is exact. Measured across this project's own 259 source files it removes 8.07% of the delivered bytes over 420 folds in 170 files. The nearest published measurement is stronger and cruder: removing docstrings outright cost 3 points of resolution rate on SWE-bench Verified for 22% of the tokens (arXiv:2606.01326), and keeping the opening summary is the gentler trade on that curve.
1346
- fold_comment_blocks: true,
1347
- // On. It has now run: measured over 2,032 real document reads it removes 43.4% of the pool and 57.4% of the reads it touches, keeping every heading, table, block quote and fenced line, and replacing only the tail of a paragraph whose opening sentence is already a complete one. The recall it needs is a ranged Read of the single line named in the notice, which costs one call and is printed at the point of the cut rather than left for the reader to work out. The project-config lock below stays regardless of this default: a repository still cannot set this key, so the choice to fold is the reader's environment and never the code being read.
1348
- fold_prose_paragraphs: true,
1349
- // On. Fires on an untargeted (no offset/limit) Read of a markdown document at least 8,000 bytes with at least 6 headings, replacing the delivered body with a heading tree plus the document preamble when that replacement is meaningfully smaller. Built from the delivered text itself, never the index, so it works on a document the indexer has never seen. Measured over 5,104 real session transcripts (13,870 Read deliveries, 130,249,204 bytes): untargeted markdown reads with >=6 headings at this 8,000-byte floor withhold 41.03% of all Read bytes, within 1.8 points of the best floor tried (2,000 B) while firing far less often on small documents where the interruption is least worth it.
1350
- outline_large_documents: true,
1351
- // On. The source-code sibling of outline_large_documents directly above, and gated the same way: an untargeted (no offset/limit) Read of a tree-sitter language at least 12,000 bytes with at least 8 symbols is replaced by its structural skeleton, the preamble plus one declaration line per symbol, with each withheld run named and pointed at the command that returns it. Symbols come from tree-sitter over the delivered text, never the index and never the regex extractors, so a partial symbol list turns the fold off rather than shipping a skeleton missing declarations nothing signals. Measured over 5,104 real session transcripts (130,325,670 delivered Read bytes): 558 reads clear this floor, and the fold withholds 11,241,796 B, 8.63% of all Read bytes.
1352
- skeleton_large_sources: true,
1353
- truncated_read_min_lines: 200,
1354
- protect_recent_reads: 4,
1355
- warn_unbalanced_shell_quoting: true,
1356
- prompt_triggers: [],
1357
- log_large_file_hint_outcomes: false,
1358
- cross_session_read_dedup: false,
1359
- cross_session_read_dedup_ttl_secs: 2700,
1360
- mcp_dedup_ttl_secs: 45,
1361
- session_start_reminder: true
1362
- },
1363
- hooks: {
1364
- watchdog_ms: 700
1365
- },
1366
- webfetch: {
1367
- allow: [],
1368
- deny: [],
1369
- max_file_count: 4096,
1370
- max_bytes: 32 * 1024 * 1024,
1371
- compress_bodies: true,
1372
- compress_min_bytes: 16 * 1024
1373
- },
1374
- worker: {
1375
- blocked_roots: [],
1376
- max_pool_workers: 4,
1377
- // 4, not 2. Measured on a 26-core Windows host with a foreground CPU probe: at `priority`
1378
- // below_normal, 2, 4 and 6 threads are all indistinguishable from an idle machine, including
1379
- // when the indexer and the probe are pinned to the same 4 cores, and including 4 threads pinned
1380
- // to 2 cores, which is genuine oversubscription. The same probe reads -10% at 16 threads and
1381
- // -69% with a 292 ms stall at 4 threads on 2 cores once the priority is normal instead. So the
1382
- // priority below is what keeps the foreground responsive, not this number, and 4 buys a
1383
- // measured 1.77x on indexing for no foreground cost. It stays a cap rather than tracking the
1384
- // core count, because where the platform refuses the priority change (some hardened Linux
1385
- // setups, sandboxes) this is the only thing left holding indexing back.
1386
- embed_threads: 4,
1387
- priority: "below_normal"
1388
- },
1389
- indexing: {
1390
- large_file_symbol_only_kb: 500,
1391
- large_file_skip_kb: 2048,
1392
- skip_dirs: [],
1393
- skip_files: ["coverage.json", "coverage-final.json"],
1394
- embeddings_enabled: true,
1395
- cross_project_symbols: true
1396
- },
1397
- compression: {
1398
- profile: "auto"
1399
- },
1400
- context: {
1401
- model_window_tokens: 2e5
1402
- },
1403
- injection: {
1404
- enabled: true
1405
- },
1406
- gdrive: {
1407
- enabled: true
1408
- },
1409
- redaction: {
1410
- custom_patterns: [],
1411
- strict: false
1412
- },
1413
- network: {
1414
- offline: false
1415
- },
1416
- mcp: {
1417
- confine_reads_to_project_root: true,
1418
- allowed_roots: []
1419
- },
1420
- hint_stats: {
1421
- suppress_threshold_pct: 15,
1422
- min_sample_size: 5
1423
- },
1424
- semantic: {
1425
- archive_weight: 0.7,
1426
- docs_weight: 0.92
1427
- }
1428
- };
1429
- function getDefaultConfig(section2) {
1430
- return structuredClone(CONFIG_DEFAULTS[section2] ?? {});
1431
- }
1432
- function defaultConfig() {
1433
- return {
1434
- compact_assist: getDefaultConfig("compact_assist"),
1435
- bash_compress: getDefaultConfig("bash_compress"),
1436
- agent_report: getDefaultConfig("agent_report"),
1437
- bash_diff: getDefaultConfig("bash_diff"),
1438
- bash_severity_log: getDefaultConfig("bash_severity_log"),
1439
- post_read_code_compress: getDefaultConfig("post_read_code_compress"),
1440
- session_brief: getDefaultConfig("session_brief"),
1441
- skill_preservation: getDefaultConfig("skill_preservation"),
1442
- image_shrink: getDefaultConfig("image_shrink"),
1443
- screenshot: getDefaultConfig("screenshot"),
1444
- repomap: getDefaultConfig("repomap"),
1445
- overflow_guard: getDefaultConfig("overflow_guard"),
1446
- stats: getDefaultConfig("stats"),
1447
- hints: getDefaultConfig("hints"),
1448
- hooks: getDefaultConfig("hooks"),
1449
- webfetch: getDefaultConfig("webfetch"),
1450
- worker: getDefaultConfig("worker"),
1451
- indexing: getDefaultConfig("indexing"),
1452
- compression: getDefaultConfig("compression"),
1453
- context: getDefaultConfig("context"),
1454
- injection: getDefaultConfig("injection"),
1455
- gdrive: getDefaultConfig("gdrive"),
1456
- redaction: getDefaultConfig("redaction"),
1457
- network: getDefaultConfig("network"),
1458
- mcp: getDefaultConfig("mcp"),
1459
- hint_stats: getDefaultConfig("hint_stats"),
1460
- semantic: getDefaultConfig("semantic")
1461
- };
1462
- }
1463
- function validatedBool(raw, def) {
1464
- if (typeof raw === "boolean") return raw;
1465
- return def;
1466
- }
1467
- function validatedInt(raw, def, min, max) {
1468
- const n = typeof raw === "number" ? Math.trunc(raw) : def;
1469
- if (!Number.isFinite(n)) return def;
1470
- return Math.max(min, Math.min(max, n));
1471
- }
1472
- function validatedFloat(raw, def, min, max) {
1473
- const n = typeof raw === "number" ? raw : def;
1474
- if (!Number.isFinite(n)) return def;
1475
- return Math.max(min, Math.min(max, n));
1476
- }
1477
- function validatedVisionTier(raw, def) {
1478
- return raw === "standard" || raw === "high" ? raw : def;
1479
- }
1480
- function validatedOcrLang(raw, def) {
1481
- if (typeof raw !== "string") return def;
1482
- const tokens = raw.split(/[+,;\s]+/).map((s) => s.trim().toLowerCase()).filter(Boolean);
1483
- const valid = tokens.filter((t) => isSupportedOcrLang(t));
1484
- return valid.length > 0 ? valid.join("+") : def;
1485
- }
1486
- function validatedStr(raw, def) {
1487
- return typeof raw === "string" ? raw : def;
1488
- }
1489
- function validatedStrList(raw, def) {
1490
- if (!Array.isArray(raw)) return def;
1491
- return raw.filter((x) => typeof x === "string");
1492
- }
1493
- function validatedIntList(raw, def) {
1494
- if (!Array.isArray(raw)) return def;
1495
- return raw.filter((x) => typeof x === "number" && Number.isFinite(x)).map(Math.trunc);
1496
- }
1497
- function validatedIntWithLegacySentinel(raw, def, sentinel, min, max) {
1498
- return raw === sentinel ? def : validatedInt(raw, def, min, max);
1499
- }
1500
- function section(raw, key) {
1501
- const val = raw[key];
1502
- return val !== null && typeof val === "object" && !Array.isArray(val) ? val : {};
1503
- }
1504
- var NUMERIC_FIELD_BOUNDS = {
1505
- "compact_assist.min_events": { min: 0, max: 1e3 },
1506
- "compact_assist.max_manifest_tokens": { min: 50, max: 1e4 },
1507
- "compact_assist.auto_trigger_multiplier": { min: 1, max: 10 },
1508
- "compact_assist.compact_skip_ttl_secs": { min: 1, max: 3600 },
1509
- "compact_assist.noise_floor_tokens": { min: 0, max: 1e4 },
1510
- "compact_assist.edited_dir_group_threshold": { min: 0, max: 100 },
1511
- "compact_assist.max_section_lines": { min: 0, max: 1e4 },
1512
- "compact_assist.wide_session_threshold": { min: 1, max: 1e4 },
1513
- "compact_assist.orchestrator_commit_threshold": { min: 1, max: 1e4 },
1514
- "compact_assist.max_manifest_chars": { min: 0, max: 16e3 },
1515
- "compact_assist.summary_budget_chars": { min: 0, max: 2e5 },
1516
- "bash_compress.max_lines": { min: 50, max: 1e5 },
1517
- "bash_compress.max_bytes": { min: 1024, max: 16 * 1024 * 1024 },
1518
- "bash_compress.timeout_seconds": { min: 5, max: 7200 },
1519
- "bash_compress.cache_min_bytes": { min: 0, max: 100 * 1024 * 1024 },
1520
- "bash_compress.cache_max_file_count": { min: 1, max: 1e6 },
1521
- "bash_compress.cache_max_bytes": { min: 1024, max: 4 * 1024 * 1024 * 1024 },
1522
- "bash_compress.cache_max_bytes_per_output": { min: 1024, max: 4 * 1024 * 1024 * 1024, clampTo: "bash_compress.cache_max_bytes" },
1523
- "bash_compress.min_net_savings_bytes": { min: 0, max: 1024 * 1024 },
1524
- "agent_report.min_bytes": { min: 0, max: 100 * 1024 * 1024 },
1525
- "agent_report.fence_collapse_min_lines": { min: 1, max: 1e5 },
1526
- // Bounded below the min-lines floor's own minimum is NOT enforceable here (bounds are per-key), so the loader clamps keep_lines against min_lines after both are read -- see the clamp comment there.
1527
- "agent_report.fence_collapse_keep_lines": { min: 0, max: 1e5 },
1528
- "bash_diff.max_hunks_per_file": { min: 1, max: 1e4 },
1529
- "bash_severity_log.context_lines": { min: 0, max: 100 },
1530
- "bash_severity_log.score_threshold": { min: 0, max: 1 },
1531
- "post_read_code_compress.min_lines": { min: 0, max: 1e6 },
1532
- "skill_preservation.max_cache_bytes": { min: 64 * 1024, max: 512 * 1024 * 1024 },
1533
- "skill_preservation.orphan_age_secs": { min: 1, max: 2592e3 },
1534
- "skill_preservation.truncation_budget_tokens": { min: 0, max: 8e3 },
1535
- "skill_preservation.compress_min_bytes": { min: 1024, max: 10 * 1024 * 1024 },
1536
- "image_shrink.jpeg_quality": { min: 1, max: 100 },
1537
- "image_shrink.max_image_pixels": { min: 0, max: 1e9 },
1538
- "image_shrink.ocr_min_confidence": { min: 0, max: 100 },
1539
- "repomap.compact_file_threshold": { min: 0, max: 1e5 },
1540
- "overflow_guard.max_tokens": { min: 1e3, max: 1e6 },
1541
- "hints.min_file_lines_for_hint": { min: 0, max: 1e6 },
1542
- "hints.bash_dedup_min_bytes": { min: 0, max: 1e5 },
1543
- "hints.web_dedup_min_bytes": { min: 0, max: 1e5 },
1544
- "hints.grep_dedup_min_matches": { min: 0, max: 1e5 },
1545
- "hints.glob_dedup_min_matches": { min: 0, max: 1e5 },
1546
- "hints.write_rewrite_min_lines": { min: 0, max: 1e6 },
1547
- "hints.write_rewrite_unchanged_pct": { min: 0, max: 100 },
1548
- "hints.git_hint_max_ms": { min: 0, max: 1e4 },
1549
- "hints.min_session_hint_savings_bytes": { min: 0, max: 1e6 },
1550
- "hints.diff_hint_min_tokens_saved": { min: 0, max: 1e5 },
1551
- "hints.large_read_redirect_bytes": { min: 0, max: 1e8 },
1552
- "hints.reread_deny_min_bytes": { min: 0, max: 1e8 },
1553
- "hints.truncated_read_min_lines": { min: 0, max: 1e6 },
1554
- "hints.protect_recent_reads": { min: 0, max: 100 },
1555
- "hints.cross_session_read_dedup_ttl_secs": { min: 1, max: 86400 },
1556
- "hints.mcp_dedup_ttl_secs": { min: 1, max: 3600 },
1557
- "hooks.watchdog_ms": { min: 100, max: 3e4 },
1558
- "webfetch.max_file_count": { min: 0, max: 1e7 },
1559
- "webfetch.max_bytes": { min: 0, max: 100 * 1024 * 1024 * 1024 },
1560
- "webfetch.compress_min_bytes": { min: 1024, max: 10 * 1024 * 1024 },
1561
- "worker.max_pool_workers": { min: 1, max: 8 },
1562
- "worker.embed_threads": { min: 1, max: 16 },
1563
- "indexing.large_file_symbol_only_kb": { min: 1, max: 1048576, clampTo: "indexing.large_file_skip_kb" },
1564
- "indexing.large_file_skip_kb": { min: 1, max: 1048576 },
1565
- "context.model_window_tokens": { min: 1e4, max: 1e7 },
1566
- "hint_stats.suppress_threshold_pct": { min: 0, max: 100 },
1567
- "hint_stats.min_sample_size": { min: 1, max: 1e4 },
1568
- "semantic.archive_weight": { min: 0.05, max: 1 },
1569
- "semantic.docs_weight": { min: 0.05, max: 1 }
1570
- };
1571
- function boundsOf(key) {
1572
- const b = NUMERIC_FIELD_BOUNDS[key];
1573
- if (!b) throw new Error(`token-goat: no NUMERIC_FIELD_BOUNDS entry for '${key}'`);
1574
- return [b.min, b.max];
1575
- }
1576
- function walkGetNumeric(obj, parts) {
1577
- let cur = obj;
1578
- for (const part of parts) {
1579
- if (typeof cur !== "object" || cur === null) return void 0;
1580
- cur = cur[part];
1581
- if (cur === void 0) return void 0;
1582
- }
1583
- return typeof cur === "number" ? cur : void 0;
1584
- }
1585
- function validateNumericField(fieldKey, value, cfg) {
1586
- const bounds = NUMERIC_FIELD_BOUNDS[fieldKey];
1587
- if (!bounds) return void 0;
1588
- let clamped = Math.max(bounds.min, Math.min(bounds.max, value));
1589
- if (bounds.clampTo) {
1590
- const clampToValue = walkGetNumeric(cfg, bounds.clampTo.split("."));
1591
- if (typeof clampToValue === "number") {
1592
- clamped = Math.min(clamped, clampToValue);
1593
- }
1594
- }
1595
- return clamped;
1596
- }
1597
- var ENUM_FIELD_VALUES = {
1598
- "compression.profile": ["auto", "aggressive", "balanced", "minimal"],
1599
- "compact_assist.harness": ["auto", ...KNOWN_HARNESS_NAMES],
1600
- "image_shrink.ocr_lang": [...SUPPORTED_OCR_LANG_CODES],
1601
- // Deliberately has no entry above `normal`. This table is what `config set` checks; a
1602
- // hand-edited TOML bypasses it, which is why resolveWorkerPriority (process_priority.ts) maps an
1603
- // unrecognized value back to the default rather than trusting whatever the file said.
1604
- "worker.priority": ["below_normal", "low", "normal"]
1605
- };
1606
- function validateEnumField(fieldKey, value) {
1607
- if (fieldKey === "image_shrink.ocr_lang") {
1608
- const tokens = value.split(/[+,;\s]+/).map((s) => s.trim().toLowerCase()).filter(Boolean);
1609
- const allowed2 = [...SUPPORTED_OCR_LANG_CODES];
1610
- return tokens.length > 0 && tokens.every((t) => isSupportedOcrLang(t)) ? void 0 : allowed2;
1611
- }
1612
- const allowed = ENUM_FIELD_VALUES[fieldKey];
1613
- if (!allowed) return void 0;
1614
- return allowed.includes(value) ? void 0 : allowed;
1615
- }
1616
- var ENV_KEYS2 = [
1617
- "TOKEN_GOAT_COMPACT_ASSIST",
1618
- "TOKENWISE_COMPACT_ASSIST",
1619
- "TOKEN_GOAT_BASH_COMPRESS",
1620
- "TOKEN_GOAT_SESSION_BRIEF",
1621
- "TOKEN_GOAT_SKILL_PRESERVATION",
1622
- "TOKEN_GOAT_MAX_IMAGE_PIXELS",
1623
- "TOKEN_GOAT_OCR_LANG",
1624
- "TOKEN_GOAT_REPOMAP_COMPACT_THRESHOLD",
1625
- "TOKEN_GOAT_REPOMAP_EXCLUDE_TESTS",
1626
- "TOKEN_GOAT_OVERFLOW_GUARD",
1627
- "TOKEN_GOAT_OVERFLOW_MAX_TOKENS",
1628
- "TOKEN_GOAT_HINT_JSON_SIDECAR",
1629
- "TOKEN_GOAT_LARGE_READ_BYTES",
1630
- "TOKEN_GOAT_HINT_BUDGET",
1631
- "TOKEN_GOAT_HOOK_WATCHDOG_MS",
1632
- "TOKEN_GOAT_WEB_COMPRESS",
1633
- "TOKEN_GOAT_WORKER_WATCHDOG",
1634
- "TOKEN_GOAT_WORKER_MAX_POOL",
1635
- "TOKEN_GOAT_COMPRESS_PROFILE",
1636
- "TOKEN_GOAT_MODEL_WINDOW_TOKENS",
1637
- "TOKEN_GOAT_INJECTION_ENABLED",
1638
- "TOKEN_GOAT_MCP_CONFINE_READS",
1639
- "TOKEN_GOAT_SERVE_DIFF_ON_REREAD",
1640
- "TOKEN_GOAT_ELIDE_SERVED_LINES",
1641
- "TOKEN_GOAT_BASH_CACHE_MIN_BYTES",
1642
- "TOKEN_GOAT_BASH_CACHE_MAX_FILES",
1643
- "TOKEN_GOAT_BASH_CACHE_MAX_BYTES",
1644
- "TOKEN_GOAT_BASH_CACHE_MAX_BYTES_PER_OUTPUT",
1645
- "TOKEN_GOAT_SESSION_HINT_MIN_BYTES",
1646
- "TOKEN_GOAT_SKILL_COMPRESS",
1647
- "TOKEN_GOAT_PRE_SKILL",
1648
- "TOKEN_GOAT_ORPHAN_SWEEP",
1649
- "TOKEN_GOAT_WARN_UNBALANCED_SHELL_QUOTING",
1650
- "TOKEN_GOAT_LOG_LARGE_FILE_HINT_OUTCOMES",
1651
- "TOKEN_GOAT_CROSS_SESSION_READ_DEDUP",
1652
- "TOKEN_GOAT_CROSS_SESSION_READ_DEDUP_TTL_SECS",
1653
- "TOKEN_GOAT_MCP_DEDUP_TTL_SECS",
1654
- "TOKEN_GOAT_EMBEDDINGS_ENABLED",
1655
- "TOKEN_GOAT_BASH_DEDUP_MIN_BYTES",
1656
- "TOKEN_GOAT_WEB_DEDUP_MIN_BYTES",
1657
- "TOKEN_GOAT_GREP_DEDUP_MIN_MATCHES",
1658
- "TOKEN_GOAT_WEB_CACHE_MAX_FILES",
1659
- "TOKEN_GOAT_WEB_CACHE_MAX_BYTES",
1660
- "TOKEN_GOAT_WRITE_REWRITE_MIN_LINES",
1661
- "TOKEN_GOAT_WRITE_REWRITE_UNCHANGED_PCT"
1662
- ];
1663
- function allEnvKeys() {
1664
- return [.../* @__PURE__ */ new Set([...ENV_KEYS2, ...Object.values(CONFIG_KEY_ENV_OVERRIDES).flat()])];
1665
- }
1666
- function configEnvFingerprint() {
1667
- const snap = {};
1668
- for (const k of allEnvKeys()) {
1669
- snap[k] = process.env[k];
1670
- }
1671
- return JSON.stringify(snap);
1672
- }
1673
- var _cached2 = null;
1674
- function deepFreeze(value) {
1675
- if (value !== null && typeof value === "object" && !Object.isFrozen(value)) {
1676
- Object.freeze(value);
1677
- for (const v of Object.values(value)) {
1678
- deepFreeze(v);
1679
- }
1680
- }
1681
- return value;
1682
- }
1683
- var _lastConfigParseError = null;
1684
- function getLastConfigParseError() {
1685
- return _lastConfigParseError;
1686
- }
1687
- var _lastProjectConfigParseError = null;
1688
- function getLastProjectConfigParseError() {
1689
- return _lastProjectConfigParseError;
1690
- }
1691
- var PROJECT_LOCKED_SECTIONS = [
1692
- "injection",
1693
- "webfetch",
1694
- "gdrive",
1695
- "redaction",
1696
- "mcp",
1697
- "network",
1698
- "screenshot"
1699
- ];
1700
- var PROJECT_LOCKED_KEYS = [
1701
- // A repository must not be able to decide how much of its own source an agent gets to see. Turning this on folds function bodies out of every Read of this project's files, so a checked-in `.token-goat.toml` setting it true would shrink what a reviewing agent is shown of the very code it came to review -- and the fold is silent about intent, so it reads as normal output. The user's own global config and TOKEN_GOAT_FOLD_CODE_BODIES still set it freely; only the project-supplied layer is refused.
1702
- "hints.fold_code_bodies",
1703
- // Same reasoning as the body fold above, on the comments rather than the code: a checked-in project file must not be able to fold a repository's own explanatory comments out of what a reviewing agent is shown, which is precisely where an intent that disagrees with the code would be written down. The user's global config and TOKEN_GOAT_FOLD_COMMENT_BLOCKS still set it freely.
1704
- "hints.fold_comment_blocks",
1705
- // Same reasoning one document over: a repository must not be able to fold its own README or changelog out of what a reviewing agent is shown. The user's global config and TOKEN_GOAT_FOLD_PROSE_PARAGRAPHS still set it freely.
1706
- "hints.fold_prose_paragraphs",
1707
- // Same reasoning again: a repository must not be able to hide its own documentation's structure from a reviewing agent by disabling the heading-tree replacement, nor -- more to the point here -- by leaving it on to shrink what a reviewing agent sees of a doc the repo itself ships. The user's global config and TOKEN_GOAT_OUTLINE_LARGE_DOCUMENTS still set it freely.
1708
- "hints.outline_large_documents",
1709
- // Same reasoning one file type over: a repository must not be able to decide, from its own checked-in config, how much of its source a reviewing agent is shown -- neither by turning the skeleton off to bury a declaration in a wall of bodies, nor by leaving it on to withhold the bodies themselves. The user's global config and TOKEN_GOAT_SKELETON_LARGE_SOURCES still set it freely.
1710
- "hints.skeleton_large_sources",
1711
- // The widest blast radius of anything on this list. The fold keys above decide how much of a file an agent is shown; this decides how much of the whole session survives compaction. A checked-in `.token-goat.toml` setting it to a handful of characters would ask the summarizer to discard the session's accumulated state at every compaction boundary, and the loss is silent -- what comes back is a well-formed short summary, not an error. The user's own global config still sets it freely; only the project-supplied layer is refused.
1712
- "compact_assist.summary_budget_chars",
1713
- "image_shrink.max_image_pixels",
1714
- // The same principle as the four fold keys above, applied one layer earlier and with a wider blast radius: those decide how much of an indexed file is shown, these decide whether it is indexed at all. A checked-in `.token-goat.toml` adding its own attack surface to `skip_dirs` -- or dropping `large_file_skip_kb` to a handful of kilobytes -- removes those files from `symbol`, `read`, `refs`, `semantic` and `graph` for a reviewing agent, and every one of them then answers "not found" in the same words it uses for a name that genuinely does not exist. There is no notice to read, because from the index's point of view nothing was hidden. The user's own global config still sets all three freely; only the project-supplied layer is refused.
1715
- "indexing.skip_dirs",
1716
- "indexing.skip_files",
1717
- "indexing.large_file_skip_kb",
1718
- "indexing.large_file_symbol_only_kb",
1719
- "indexing.cross_project_symbols",
1720
- "worker.blocked_roots"
1721
- ];
1722
- var _lastProjectConfigLockedKeys = [];
1723
- function stripLockedProjectKeys(projectRaw) {
1724
- const cleaned = {};
1725
- const dropped = [];
1726
- for (const [section2, value] of Object.entries(projectRaw)) {
1727
- if (PROJECT_LOCKED_SECTIONS.includes(section2)) {
1728
- dropped.push(section2);
1729
- continue;
1730
- }
1731
- if (value !== null && typeof value === "object" && !Array.isArray(value)) {
1732
- const kept = {};
1733
- for (const [key, keyValue] of Object.entries(value)) {
1734
- if (PROJECT_LOCKED_KEYS.includes(`${section2}.${key}`)) dropped.push(`${section2}.${key}`);
1735
- else kept[key] = keyValue;
1736
- }
1737
- cleaned[section2] = kept;
1738
- continue;
1739
- }
1740
- cleaned[section2] = value;
1741
- }
1742
- return { cleaned, dropped };
1743
- }
1744
- function lastProjectConfigLockedKeys() {
1745
- return _lastProjectConfigLockedKeys;
1746
- }
1747
- function flattenRawKeys(raw) {
1748
- const keys = [];
1749
- for (const [sectionName, val] of Object.entries(raw)) {
1750
- if (val !== null && typeof val === "object" && !Array.isArray(val)) {
1751
- for (const sub of Object.keys(val)) {
1752
- keys.push(`${sectionName}.${sub}`);
1753
- }
1754
- } else {
1755
- keys.push(sectionName);
1756
- }
1757
- }
1758
- return keys;
1759
- }
1760
- function flattenRawValues(raw) {
1761
- const out = {};
1762
- for (const [sectionName, val] of Object.entries(raw)) {
1763
- if (val !== null && typeof val === "object" && !Array.isArray(val)) {
1764
- for (const [sub, v] of Object.entries(val)) {
1765
- out[`${sectionName}.${sub}`] = v;
1766
- }
1767
- } else {
1768
- out[sectionName] = val;
1769
- }
1770
- }
1771
- return out;
1772
- }
1773
- function getProjectConfigInfo(projectRoot) {
1774
- const root = projectRoot ?? resolveConfigProjectRoot();
1775
- const p = projectConfigPath(root);
1776
- if (!fs3.existsSync(p)) return null;
1777
- const { raw, parseError } = readConfigToml(p);
1778
- if (parseError !== null) return { path: p, keys: [], values: {}, parseError };
1779
- return { path: p, keys: flattenRawKeys(raw), values: flattenRawValues(raw), parseError };
1780
- }
1781
- function rawValueEquals(a, b) {
1782
- if (a === b) return true;
1783
- if (Array.isArray(a) || Array.isArray(b)) {
1784
- if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) return false;
1785
- return a.every((el, i) => rawValueEquals(el, b[i]));
1786
- }
1787
- if (typeof a === "object" && typeof b === "object" && a !== null && b !== null) {
1788
- const ka = Object.keys(a);
1789
- const kb = Object.keys(b);
1790
- if (ka.length !== kb.length) return false;
1791
- return ka.every((k) => Object.prototype.hasOwnProperty.call(b, k) && rawValueEquals(a[k], b[k]));
1792
- }
1793
- return false;
1794
- }
1795
- function rejectionReason(key, rawValue, effectiveValue, cfg) {
1796
- if (typeof rawValue === "number") {
1797
- const bounds = NUMERIC_FIELD_BOUNDS[key];
1798
- if (bounds !== void 0) {
1799
- if (rawValue < bounds.min || rawValue > bounds.max) return `outside the allowed range ${bounds.min}-${bounds.max}`;
1800
- if (!Number.isInteger(rawValue) && Number.isInteger(effectiveValue)) return "not a whole number";
1801
- const clamped = validateNumericField(key, rawValue, cfg);
1802
- if (clamped !== void 0 && clamped !== rawValue && bounds.clampTo !== void 0) return `above ${bounds.clampTo}, which caps it`;
1803
- }
1804
- return null;
1805
- }
1806
- if (typeof rawValue === "string") {
1807
- const allowed = validateEnumField(key, rawValue);
1808
- if (allowed !== void 0) return `not one of: ${allowed.join(", ")}`;
1809
- }
1810
- if (effectiveValue !== void 0 && typeof rawValue !== typeof effectiveValue) {
1811
- return `expected ${Array.isArray(effectiveValue) ? "a list" : `a ${typeof effectiveValue}`}, got ${Array.isArray(rawValue) ? "a list" : `a ${typeof rawValue}`}`;
1812
- }
1813
- return null;
1814
- }
1815
- function coerceEnvLike(rawStr, effectiveValue) {
1816
- const norm = rawStr.trim();
1817
- if (typeof effectiveValue === "number") {
1818
- if (norm === "" || !/^[+-]?\d+$/.test(norm)) return "unusable";
1819
- const val = parseInt(norm, 10);
1820
- return Number.isFinite(val) ? { parsed: val } : "unusable";
1821
- }
1822
- if (typeof effectiveValue === "boolean") {
1823
- const lower = norm.toLowerCase();
1824
- if (TRUTHY_ENV_VALUES.has(lower)) return { parsed: true };
1825
- if (FALSY_ENV_VALUES.has(lower)) return { parsed: false };
1826
- return "unusable";
1827
- }
1828
- if (typeof effectiveValue === "string") {
1829
- return norm === "" ? "unusable" : { parsed: norm };
1830
- }
1831
- return null;
1832
- }
1833
- function resolveConfigKeyLayer(key, effectiveValue, cfg, projectInfo) {
1834
- const envVar = (CONFIG_KEY_ENV_OVERRIDES[key] ?? []).find((name) => process.env[name] !== void 0);
1835
- if (envVar !== void 0) {
1836
- const rawStr = process.env[envVar] ?? "";
1837
- const judged = coerceEnvLike(rawStr, effectiveValue);
1838
- if (judged === null) return { layer: "env", envVar };
1839
- if (judged === "unusable") {
1840
- return { layer: "env-invalid", envVar, rawValue: rawStr, effectiveValue, reason: rawStr.trim() === "" ? "empty" : rejectionReason(key, rawStr, effectiveValue, cfg) };
1841
- }
1842
- if (rawValueEquals(judged.parsed, effectiveValue)) return { layer: "env", envVar };
1843
- return { layer: "env-invalid", envVar, rawValue: judged.parsed, effectiveValue, reason: rejectionReason(key, judged.parsed, effectiveValue, cfg) };
1844
- }
1845
- if (projectInfo === null) return { layer: "global" };
1846
- if (projectInfo.parseError !== null) return { layer: "project-unparsed", path: projectInfo.path, parseError: projectInfo.parseError };
1847
- if (!Object.prototype.hasOwnProperty.call(projectInfo.values, key)) return { layer: "global" };
1848
- const rawValue = projectInfo.values[key];
1849
- if (rawValueEquals(rawValue, effectiveValue)) return { layer: "project", path: projectInfo.path };
1850
- return { layer: "project-invalid", path: projectInfo.path, rawValue, effectiveValue, reason: rejectionReason(key, rawValue, effectiveValue, cfg) };
1851
- }
1852
- function readConfigSource(p) {
1853
- return decodeSource(fs3.readFileSync(p));
1854
- }
1855
- function readConfigToml(p) {
1856
- try {
1857
- return { raw: parse(readConfigSource(p)), parseError: null };
1858
- } catch (e) {
1859
- const code = e.code;
1860
- if (code === "ENOENT") return { raw: {}, parseError: null };
1861
- return { raw: {}, parseError: extractErrorMessage(e) };
1862
- }
1863
- }
1864
- function readConfigText(p) {
1865
- try {
1866
- return { text: readConfigSource(p), readError: null };
1867
- } catch (e) {
1868
- const code = e.code;
1869
- if (code === "ENOENT") return { text: null, readError: null };
1870
- return { text: null, readError: extractErrorMessage(e) };
1871
- }
1872
- }
1873
- function mergeRawConfig(base, override) {
1874
- const merged = { ...base };
1875
- for (const [key, overrideVal] of Object.entries(override)) {
1876
- if (overrideVal !== null && typeof overrideVal === "object" && !Array.isArray(overrideVal)) {
1877
- const baseVal = base[key];
1878
- const baseSection = baseVal !== null && typeof baseVal === "object" && !Array.isArray(baseVal) ? baseVal : {};
1879
- merged[key] = { ...baseSection, ...overrideVal };
1880
- } else {
1881
- const baseVal = base[key];
1882
- if (baseVal !== null && typeof baseVal === "object" && !Array.isArray(baseVal)) continue;
1883
- merged[key] = overrideVal;
1884
- }
1885
- }
1886
- return merged;
1887
- }
1888
- var _projectRootCache = null;
1889
- function resolveConfigProjectRoot() {
1890
- const cwd = process.cwd();
1891
- if (_projectRootCache !== null && _projectRootCache.cwd === cwd) return _projectRootCache.root;
1892
- const project = findProject(cwd);
1893
- const root = project !== null ? project.root : cwd;
1894
- _projectRootCache = { cwd, root };
1895
- return root;
1896
- }
1897
- registerReset(() => {
1898
- _projectRootCache = null;
1899
- });
1900
- function isAutoTriggerMultiplierExplicit() {
1901
- const setsMultiplier = (text) => {
1902
- const raw = parse(text);
1903
- const ca_raw = raw["compact_assist"];
1904
- if (ca_raw === null || typeof ca_raw !== "object" || Array.isArray(ca_raw)) {
1905
- return false;
1906
- }
1907
- return ca_raw["auto_trigger_multiplier"] !== void 0;
1908
- };
1909
- try {
1910
- if (setsMultiplier(readConfigSource(configPath()))) return true;
1911
- } catch {
1912
- }
1913
- try {
1914
- return setsMultiplier(readConfigSource(projectConfigPath(resolveConfigProjectRoot())));
1915
- } catch {
1916
- return false;
1917
- }
1918
- }
1919
- function loadConfig(projectRoot) {
1920
- const p = configPath();
1921
- const root = projectRoot ?? resolveConfigProjectRoot();
1922
- const projPath = projectConfigPath(root);
1923
- const { text, readError } = readConfigText(p);
1924
- const contentFp = text !== null ? shortFingerprint(text) : "";
1925
- const { text: projText, readError: projReadError } = readConfigText(projPath);
1926
- const projectContentFp = projText !== null ? shortFingerprint(projText) : "";
1927
- const envFp = configEnvFingerprint();
1928
- if (_cached2 !== null && _cached2.contentFp === contentFp && _cached2.envFp === envFp && _cached2.projectRoot === root && _cached2.projectContentFp === projectContentFp) {
1929
- return _cached2.config;
1930
- }
1931
- let raw = {};
1932
- if (text !== null) {
1933
- try {
1934
- raw = parse(text);
1935
- _lastConfigParseError = null;
1936
- } catch (e) {
1937
- _lastConfigParseError = extractErrorMessage(e);
1938
- }
1939
- } else {
1940
- _lastConfigParseError = readError;
1941
- }
1942
- let projectRaw = {};
1943
- if (projText !== null) {
1944
- try {
1945
- projectRaw = parse(projText);
1946
- _lastProjectConfigParseError = null;
1947
- } catch (e) {
1948
- _lastProjectConfigParseError = extractErrorMessage(e);
1949
- }
1950
- } else {
1951
- _lastProjectConfigParseError = projReadError;
1952
- }
1953
- const cfg = deepFreeze(_buildConfig(raw, projectRaw));
1954
- _cached2 = { config: cfg, contentFp, envFp, projectRoot: root, projectContentFp };
1955
- return cfg;
1956
- }
1957
- function invalidateConfigCache() {
1958
- _cached2 = null;
1959
- _lastProjectConfigLockedKeys = [];
1960
- }
1961
- function withoutConfigEnv(fn) {
1962
- const keys = allEnvKeys();
1963
- const saved = {};
1964
- for (const k of keys) {
1965
- saved[k] = process.env[k];
1966
- delete process.env[k];
1967
- }
1968
- try {
1969
- return fn();
1970
- } finally {
1971
- for (const k of keys) {
1972
- const v = saved[k];
1973
- if (v === void 0) delete process.env[k];
1974
- else process.env[k] = v;
1975
- }
1976
- }
1977
- }
1978
- function buildPersistedConfig(raw) {
1979
- return withoutConfigEnv(() => _buildConfig(raw));
1980
- }
1981
- function loadPersistedConfig() {
1982
- const p = configPath();
1983
- const { raw, parseError } = readConfigToml(p);
1984
- _lastConfigParseError = parseError;
1985
- return buildPersistedConfig(raw);
1986
- }
1987
- function _buildConfig(raw, projectRaw = {}) {
1988
- const { cleaned: safeProjectRaw, dropped: lockedKeys } = stripLockedProjectKeys(projectRaw);
1989
- _lastProjectConfigLockedKeys = lockedKeys;
1990
- if (Object.keys(safeProjectRaw).length > 0) {
1991
- raw = mergeRawConfig(raw, safeProjectRaw);
1992
- }
1993
- const ca_raw = section(raw, "compact_assist");
1994
- const ca = getDefaultConfig("compact_assist");
1995
- ca.enabled = validatedBool(ca_raw["enabled"], ca.enabled);
1996
- ca.triggers = validatedStrList(ca_raw["triggers"], ca.triggers);
1997
- ca.min_events = validatedInt(ca_raw["min_events"], ca.min_events, ...boundsOf("compact_assist.min_events"));
1998
- ca.max_manifest_tokens = validatedInt(ca_raw["max_manifest_tokens"], ca.max_manifest_tokens, ...boundsOf("compact_assist.max_manifest_tokens"));
1999
- ca.auto_trigger_multiplier = validatedFloat(ca_raw["auto_trigger_multiplier"], ca.auto_trigger_multiplier, ...boundsOf("compact_assist.auto_trigger_multiplier"));
2000
- ca.compact_skip_ttl_secs = validatedFloat(ca_raw["compact_skip_ttl_secs"], ca.compact_skip_ttl_secs, ...boundsOf("compact_assist.compact_skip_ttl_secs"));
2001
- ca.noise_floor_tokens = validatedInt(ca_raw["noise_floor_tokens"], ca.noise_floor_tokens, ...boundsOf("compact_assist.noise_floor_tokens"));
2002
- ca.edited_dir_group_threshold = validatedInt(ca_raw["edited_dir_group_threshold"], ca.edited_dir_group_threshold, ...boundsOf("compact_assist.edited_dir_group_threshold"));
2003
- ca.max_section_lines = validatedInt(ca_raw["max_section_lines"], ca.max_section_lines, ...boundsOf("compact_assist.max_section_lines"));
2004
- ca.wide_session_threshold = validatedInt(ca_raw["wide_session_threshold"], ca.wide_session_threshold, ...boundsOf("compact_assist.wide_session_threshold"));
2005
- ca.orchestrator_commit_threshold = validatedInt(ca_raw["orchestrator_commit_threshold"], ca.orchestrator_commit_threshold, ...boundsOf("compact_assist.orchestrator_commit_threshold"));
2006
- ca.max_manifest_chars = validatedInt(ca_raw["max_manifest_chars"], ca.max_manifest_chars, ...boundsOf("compact_assist.max_manifest_chars"));
2007
- ca.summary_budget_chars = validatedInt(ca_raw["summary_budget_chars"], ca.summary_budget_chars, ...boundsOf("compact_assist.summary_budget_chars"));
2008
- ca.harness = validatedStr(ca_raw["harness"], ca.harness);
2009
- ca.enabled = envBool("TOKEN_GOAT_COMPACT_ASSIST", envBool("TOKENWISE_COMPACT_ASSIST", ca.enabled));
2010
- const bc_raw = section(raw, "bash_compress");
2011
- const bc = getDefaultConfig("bash_compress");
2012
- bc.enabled = validatedBool(bc_raw["enabled"], bc.enabled);
2013
- bc.disabled_filters = validatedStrList(bc_raw["disabled_filters"], bc.disabled_filters);
2014
- bc.max_lines = validatedInt(bc_raw["max_lines"], bc.max_lines, ...boundsOf("bash_compress.max_lines"));
2015
- bc.max_bytes = validatedInt(bc_raw["max_bytes"], bc.max_bytes, ...boundsOf("bash_compress.max_bytes"));
2016
- bc.timeout_seconds = validatedInt(bc_raw["timeout_seconds"], bc.timeout_seconds, ...boundsOf("bash_compress.timeout_seconds"));
2017
- bc.cache_min_bytes = validatedIntWithLegacySentinel(bc_raw["cache_min_bytes"], bc.cache_min_bytes, 0, ...boundsOf("bash_compress.cache_min_bytes"));
2018
- bc.cache_max_file_count = validatedInt(bc_raw["cache_max_file_count"], bc.cache_max_file_count, ...boundsOf("bash_compress.cache_max_file_count"));
2019
- bc.cache_max_bytes = validatedInt(bc_raw["cache_max_bytes"], bc.cache_max_bytes, ...boundsOf("bash_compress.cache_max_bytes"));
2020
- bc.cache_max_bytes_per_output = validatedInt(bc_raw["cache_max_bytes_per_output"], bc.cache_max_bytes_per_output, ...boundsOf("bash_compress.cache_max_bytes_per_output"));
2021
- bc.min_net_savings_bytes = validatedInt(bc_raw["min_net_savings_bytes"], bc.min_net_savings_bytes, ...boundsOf("bash_compress.min_net_savings_bytes"));
2022
- bc.elide_served_shell_output = validatedBool(bc_raw["elide_served_shell_output"], bc.elide_served_shell_output);
2023
- bc.enabled = envBool("TOKEN_GOAT_BASH_COMPRESS", bc.enabled);
2024
- bc.cache_min_bytes = envInt("TOKEN_GOAT_BASH_CACHE_MIN_BYTES", bc.cache_min_bytes, ...boundsOf("bash_compress.cache_min_bytes"));
2025
- bc.cache_max_file_count = envInt("TOKEN_GOAT_BASH_CACHE_MAX_FILES", bc.cache_max_file_count, ...boundsOf("bash_compress.cache_max_file_count"));
2026
- bc.cache_max_bytes = envInt("TOKEN_GOAT_BASH_CACHE_MAX_BYTES", bc.cache_max_bytes, ...boundsOf("bash_compress.cache_max_bytes"));
2027
- bc.cache_max_bytes_per_output = envInt("TOKEN_GOAT_BASH_CACHE_MAX_BYTES_PER_OUTPUT", bc.cache_max_bytes_per_output, ...boundsOf("bash_compress.cache_max_bytes_per_output"));
2028
- bc.min_net_savings_bytes = envInt("TOKEN_GOAT_BASH_MIN_NET_SAVINGS_BYTES", bc.min_net_savings_bytes, ...boundsOf("bash_compress.min_net_savings_bytes"));
2029
- bc.cache_max_bytes_per_output = Math.min(bc.cache_max_bytes_per_output, bc.cache_max_bytes);
2030
- const ar_raw = section(raw, "agent_report");
2031
- const ar = getDefaultConfig("agent_report");
2032
- ar.min_bytes = validatedInt(ar_raw["min_bytes"], ar.min_bytes, ...boundsOf("agent_report.min_bytes"));
2033
- ar.fence_collapse_min_lines = validatedInt(ar_raw["fence_collapse_min_lines"], ar.fence_collapse_min_lines, ...boundsOf("agent_report.fence_collapse_min_lines"));
2034
- ar.fence_collapse_keep_lines = validatedInt(ar_raw["fence_collapse_keep_lines"], ar.fence_collapse_keep_lines, ...boundsOf("agent_report.fence_collapse_keep_lines"));
2035
- ar.min_bytes = envInt("TOKEN_GOAT_AGENT_REPORT_MIN_BYTES", ar.min_bytes, ...boundsOf("agent_report.min_bytes"));
2036
- ar.fence_collapse_min_lines = envInt("TOKEN_GOAT_AGENT_REPORT_FENCE_MIN_LINES", ar.fence_collapse_min_lines, ...boundsOf("agent_report.fence_collapse_min_lines"));
2037
- ar.fence_collapse_keep_lines = envInt("TOKEN_GOAT_AGENT_REPORT_FENCE_KEEP_LINES", ar.fence_collapse_keep_lines, ...boundsOf("agent_report.fence_collapse_keep_lines"));
2038
- ar.fence_collapse_keep_lines = Math.min(ar.fence_collapse_keep_lines, Math.floor((ar.fence_collapse_min_lines - 1) / 2));
2039
- const bd_raw = section(raw, "bash_diff");
2040
- const bd = getDefaultConfig("bash_diff");
2041
- bd.max_hunks_per_file = validatedInt(bd_raw["max_hunks_per_file"], bd.max_hunks_per_file, ...boundsOf("bash_diff.max_hunks_per_file"));
2042
- const sl_raw = section(raw, "bash_severity_log");
2043
- const sl = getDefaultConfig("bash_severity_log");
2044
- sl.context_lines = validatedInt(sl_raw["context_lines"], sl.context_lines, ...boundsOf("bash_severity_log.context_lines"));
2045
- sl.score_threshold = validatedFloat(sl_raw["score_threshold"], sl.score_threshold, ...boundsOf("bash_severity_log.score_threshold"));
2046
- const cc_raw = section(raw, "post_read_code_compress");
2047
- const cc = getDefaultConfig("post_read_code_compress");
2048
- cc.min_lines = validatedInt(cc_raw["min_lines"], cc.min_lines, ...boundsOf("post_read_code_compress.min_lines"));
2049
- const sb_raw = section(raw, "session_brief");
2050
- const sb = getDefaultConfig("session_brief");
2051
- sb.enabled = validatedBool(sb_raw["enabled"], sb.enabled);
2052
- sb.enabled = envBool("TOKEN_GOAT_SESSION_BRIEF", sb.enabled);
2053
- const sp_raw = section(raw, "skill_preservation");
2054
- const sp = getDefaultConfig("skill_preservation");
2055
- sp.enabled = validatedBool(sp_raw["enabled"], sp.enabled);
2056
- sp.max_cache_bytes = validatedInt(sp_raw["max_cache_bytes"], sp.max_cache_bytes, ...boundsOf("skill_preservation.max_cache_bytes"));
2057
- sp.orphan_sweep_enabled = validatedBool(sp_raw["orphan_sweep_enabled"], sp.orphan_sweep_enabled);
2058
- sp.orphan_age_secs = validatedInt(sp_raw["orphan_age_secs"], sp.orphan_age_secs, ...boundsOf("skill_preservation.orphan_age_secs"));
2059
- sp.truncation_budget_tokens = validatedInt(sp_raw["truncation_budget_tokens"], sp.truncation_budget_tokens, ...boundsOf("skill_preservation.truncation_budget_tokens"));
2060
- sp.compress_bodies = validatedBool(sp_raw["compress_bodies"], sp.compress_bodies);
2061
- sp.compress_min_bytes = validatedInt(sp_raw["compress_min_bytes"], sp.compress_min_bytes, ...boundsOf("skill_preservation.compress_min_bytes"));
2062
- sp.inline_snippets = validatedBool(sp_raw["inline_snippets"], sp.inline_snippets);
2063
- sp.pre_skill_enabled = validatedBool(sp_raw["pre_skill_enabled"], sp.pre_skill_enabled);
2064
- sp.first_load_compact = validatedBool(sp_raw["first_load_compact"], sp.first_load_compact);
2065
- sp.post_compact_full_loads = validatedBool(sp_raw["post_compact_full_loads"], sp.post_compact_full_loads);
2066
- sp.enabled = envBool("TOKEN_GOAT_SKILL_PRESERVATION", sp.enabled);
2067
- sp.compress_bodies = envBool("TOKEN_GOAT_SKILL_COMPRESS", sp.compress_bodies);
2068
- sp.pre_skill_enabled = envBool("TOKEN_GOAT_PRE_SKILL", sp.pre_skill_enabled);
2069
- sp.orphan_sweep_enabled = envBool("TOKEN_GOAT_ORPHAN_SWEEP", sp.orphan_sweep_enabled);
2070
- const is_raw = section(raw, "image_shrink");
2071
- const is_cfg = getDefaultConfig("image_shrink");
2072
- is_cfg.enabled = validatedBool(is_raw["enabled"], is_cfg.enabled);
2073
- is_cfg.jpeg_quality = validatedInt(is_raw["jpeg_quality"], is_cfg.jpeg_quality, ...boundsOf("image_shrink.jpeg_quality"));
2074
- is_cfg.max_image_pixels = validatedInt(is_raw["max_image_pixels"], is_cfg.max_image_pixels, ...boundsOf("image_shrink.max_image_pixels"));
2075
- is_cfg.screenshot_redirect = validatedBool(is_raw["screenshot_redirect"], is_cfg.screenshot_redirect);
2076
- is_cfg.ocr_enabled = validatedBool(is_raw["ocr_enabled"], is_cfg.ocr_enabled);
2077
- is_cfg.ocr_min_confidence = validatedInt(is_raw["ocr_min_confidence"], is_cfg.ocr_min_confidence, ...boundsOf("image_shrink.ocr_min_confidence"));
2078
- is_cfg.ocr_lang = validatedOcrLang(is_raw["ocr_lang"], is_cfg.ocr_lang);
2079
- is_cfg.vision_tier = validatedVisionTier(is_raw["vision_tier"], is_cfg.vision_tier);
2080
- is_cfg.max_image_pixels = envInt("TOKEN_GOAT_MAX_IMAGE_PIXELS", is_cfg.max_image_pixels, ...boundsOf("image_shrink.max_image_pixels"));
2081
- is_cfg.ocr_enabled = envBool("TOKEN_GOAT_OCR_ENABLED", is_cfg.ocr_enabled);
2082
- is_cfg.ocr_lang = validatedOcrLang(process.env["TOKEN_GOAT_OCR_LANG"], is_cfg.ocr_lang);
2083
- is_cfg.vision_tier = validatedVisionTier(process.env["TOKEN_GOAT_VISION_TIER"], is_cfg.vision_tier);
2084
- const sc_raw = section(raw, "screenshot");
2085
- const sc_cfg = getDefaultConfig("screenshot");
2086
- sc_cfg.chrome_path = validatedStr(sc_raw["chrome_path"], sc_cfg.chrome_path);
2087
- sc_cfg.block_private_targets = validatedBool(sc_raw["block_private_targets"], sc_cfg.block_private_targets);
2088
- sc_cfg.block_private_targets = envBool("TOKEN_GOAT_SCREENSHOT_BLOCK_PRIVATE_TARGETS", sc_cfg.block_private_targets);
2089
- const rm_raw = section(raw, "repomap");
2090
- const rm = getDefaultConfig("repomap");
2091
- rm.compact_file_threshold = validatedInt(rm_raw["compact_file_threshold"], rm.compact_file_threshold, ...boundsOf("repomap.compact_file_threshold"));
2092
- rm.exclude_tests = validatedBool(rm_raw["exclude_tests"], rm.exclude_tests);
2093
- rm.compact_file_threshold = envInt("TOKEN_GOAT_REPOMAP_COMPACT_THRESHOLD", rm.compact_file_threshold, ...boundsOf("repomap.compact_file_threshold"));
2094
- rm.exclude_tests = envBool("TOKEN_GOAT_REPOMAP_EXCLUDE_TESTS", rm.exclude_tests);
2095
- const og_raw = section(raw, "overflow_guard");
2096
- const og = getDefaultConfig("overflow_guard");
2097
- og.enabled = validatedBool(og_raw["enabled"], og.enabled);
2098
- og.max_tokens = validatedInt(og_raw["max_tokens"], og.max_tokens, ...boundsOf("overflow_guard.max_tokens"));
2099
- og.enabled = envBool("TOKEN_GOAT_OVERFLOW_GUARD", og.enabled);
2100
- og.max_tokens = envInt("TOKEN_GOAT_OVERFLOW_MAX_TOKENS", og.max_tokens, ...boundsOf("overflow_guard.max_tokens"));
2101
- const st_raw = section(raw, "stats");
2102
- const st = getDefaultConfig("stats");
2103
- st.record_zero_savings = validatedBool(st_raw["record_zero_savings"], st.record_zero_savings);
2104
- const hi_raw = section(raw, "hints");
2105
- const hi = getDefaultConfig("hints");
2106
- hi.quiet_hours = validatedStr(hi_raw["quiet_hours"], hi.quiet_hours);
2107
- hi.json_sidecar = validatedBool(hi_raw["json_sidecar"], hi.json_sidecar);
2108
- hi.min_file_lines_for_hint = validatedInt(hi_raw["min_file_lines_for_hint"], hi.min_file_lines_for_hint, ...boundsOf("hints.min_file_lines_for_hint"));
2109
- hi.bash_dedup_min_bytes = validatedInt(hi_raw["bash_dedup_min_bytes"], hi.bash_dedup_min_bytes, ...boundsOf("hints.bash_dedup_min_bytes"));
2110
- hi.bash_dedup_min_bytes = envInt("TOKEN_GOAT_BASH_DEDUP_MIN_BYTES", hi.bash_dedup_min_bytes, ...boundsOf("hints.bash_dedup_min_bytes"));
2111
- hi.web_dedup_min_bytes = validatedInt(hi_raw["web_dedup_min_bytes"], hi.web_dedup_min_bytes, ...boundsOf("hints.web_dedup_min_bytes"));
2112
- hi.web_dedup_min_bytes = envInt("TOKEN_GOAT_WEB_DEDUP_MIN_BYTES", hi.web_dedup_min_bytes, ...boundsOf("hints.web_dedup_min_bytes"));
2113
- hi.grep_dedup_min_matches = validatedInt(hi_raw["grep_dedup_min_matches"], hi.grep_dedup_min_matches, ...boundsOf("hints.grep_dedup_min_matches"));
2114
- hi.grep_dedup_min_matches = envInt("TOKEN_GOAT_GREP_DEDUP_MIN_MATCHES", hi.grep_dedup_min_matches, ...boundsOf("hints.grep_dedup_min_matches"));
2115
- hi.glob_dedup_min_matches = validatedInt(hi_raw["glob_dedup_min_matches"], hi.glob_dedup_min_matches, ...boundsOf("hints.glob_dedup_min_matches"));
2116
- hi.glob_dedup_min_matches = envInt("TOKEN_GOAT_GLOB_DEDUP_MIN_MATCHES", hi.glob_dedup_min_matches, ...boundsOf("hints.glob_dedup_min_matches"));
2117
- hi.write_rewrite_min_lines = validatedInt(hi_raw["write_rewrite_min_lines"], hi.write_rewrite_min_lines, ...boundsOf("hints.write_rewrite_min_lines"));
2118
- hi.write_rewrite_min_lines = envInt("TOKEN_GOAT_WRITE_REWRITE_MIN_LINES", hi.write_rewrite_min_lines, ...boundsOf("hints.write_rewrite_min_lines"));
2119
- hi.write_rewrite_unchanged_pct = validatedInt(hi_raw["write_rewrite_unchanged_pct"], hi.write_rewrite_unchanged_pct, ...boundsOf("hints.write_rewrite_unchanged_pct"));
2120
- hi.write_rewrite_unchanged_pct = envInt("TOKEN_GOAT_WRITE_REWRITE_UNCHANGED_PCT", hi.write_rewrite_unchanged_pct, ...boundsOf("hints.write_rewrite_unchanged_pct"));
2121
- hi.serve_diff_on_reread = validatedBool(hi_raw["serve_diff_on_reread"], hi.serve_diff_on_reread);
2122
- hi.elide_served_lines = validatedBool(hi_raw["elide_served_lines"], hi.elide_served_lines);
2123
- hi.subagent_markdown_first_read_deny = validatedBool(hi_raw["subagent_markdown_first_read_deny"], hi.subagent_markdown_first_read_deny);
2124
- hi.backoff_thresholds = validatedIntList(hi_raw["backoff_thresholds"], hi.backoff_thresholds);
2125
- hi.git_hint_max_ms = validatedInt(hi_raw["git_hint_max_ms"], hi.git_hint_max_ms, ...boundsOf("hints.git_hint_max_ms"));
2126
- hi.min_session_hint_savings_bytes = validatedInt(hi_raw["min_session_hint_savings_bytes"], hi.min_session_hint_savings_bytes, ...boundsOf("hints.min_session_hint_savings_bytes"));
2127
- hi.pre_skill_advisory = validatedBool(hi_raw["pre_skill_advisory"], hi.pre_skill_advisory);
2128
- hi.context_threshold_advisory = validatedBool(hi_raw["context_threshold_advisory"], hi.context_threshold_advisory);
2129
- hi.diff_hint_min_tokens_saved = validatedInt(hi_raw["diff_hint_min_tokens_saved"], hi.diff_hint_min_tokens_saved, ...boundsOf("hints.diff_hint_min_tokens_saved"));
2130
- hi.large_read_redirect_bytes = validatedIntWithLegacySentinel(hi_raw["large_read_redirect_bytes"], hi.large_read_redirect_bytes, 45e3, ...boundsOf("hints.large_read_redirect_bytes"));
2131
- hi.reread_deny = validatedBool(hi_raw["reread_deny"], hi.reread_deny);
2132
- hi.reread_deny_min_bytes = validatedIntWithLegacySentinel(hi_raw["reread_deny_min_bytes"], hi.reread_deny_min_bytes, 2048, ...boundsOf("hints.reread_deny_min_bytes"));
2133
- hi.stable_doc_compacts = validatedBool(hi_raw["stable_doc_compacts"], hi.stable_doc_compacts);
2134
- hi.fold_code_bodies = validatedBool(hi_raw["fold_code_bodies"], hi.fold_code_bodies);
2135
- hi.fold_comment_blocks = validatedBool(hi_raw["fold_comment_blocks"], hi.fold_comment_blocks);
2136
- hi.fold_prose_paragraphs = validatedBool(hi_raw["fold_prose_paragraphs"], hi.fold_prose_paragraphs);
2137
- hi.outline_large_documents = validatedBool(hi_raw["outline_large_documents"], hi.outline_large_documents);
2138
- hi.skeleton_large_sources = validatedBool(hi_raw["skeleton_large_sources"], hi.skeleton_large_sources);
2139
- hi.truncated_read_min_lines = validatedInt(hi_raw["truncated_read_min_lines"], hi.truncated_read_min_lines, ...boundsOf("hints.truncated_read_min_lines"));
2140
- hi.protect_recent_reads = validatedInt(hi_raw["protect_recent_reads"], hi.protect_recent_reads, ...boundsOf("hints.protect_recent_reads"));
2141
- hi.warn_unbalanced_shell_quoting = validatedBool(hi_raw["warn_unbalanced_shell_quoting"], hi.warn_unbalanced_shell_quoting);
2142
- hi.log_large_file_hint_outcomes = validatedBool(hi_raw["log_large_file_hint_outcomes"], hi.log_large_file_hint_outcomes);
2143
- hi.warn_unbalanced_shell_quoting = envBool("TOKEN_GOAT_WARN_UNBALANCED_SHELL_QUOTING", hi.warn_unbalanced_shell_quoting);
2144
- hi.serve_diff_on_reread = envBool("TOKEN_GOAT_SERVE_DIFF_ON_REREAD", hi.serve_diff_on_reread);
2145
- hi.elide_served_lines = envBool("TOKEN_GOAT_ELIDE_SERVED_LINES", hi.elide_served_lines);
2146
- hi.subagent_markdown_first_read_deny = envBool("TOKEN_GOAT_SUBAGENT_MARKDOWN_FIRST_READ_DENY", hi.subagent_markdown_first_read_deny);
2147
- hi.log_large_file_hint_outcomes = envBool("TOKEN_GOAT_LOG_LARGE_FILE_HINT_OUTCOMES", hi.log_large_file_hint_outcomes);
2148
- hi.json_sidecar = envBool("TOKEN_GOAT_HINT_JSON_SIDECAR", hi.json_sidecar);
2149
- hi.large_read_redirect_bytes = envInt("TOKEN_GOAT_LARGE_READ_BYTES", hi.large_read_redirect_bytes, ...boundsOf("hints.large_read_redirect_bytes"));
2150
- hi.cross_session_read_dedup = validatedBool(hi_raw["cross_session_read_dedup"], hi.cross_session_read_dedup);
2151
- hi.cross_session_read_dedup_ttl_secs = validatedInt(hi_raw["cross_session_read_dedup_ttl_secs"], hi.cross_session_read_dedup_ttl_secs, ...boundsOf("hints.cross_session_read_dedup_ttl_secs"));
2152
- hi.cross_session_read_dedup = envBool("TOKEN_GOAT_CROSS_SESSION_READ_DEDUP", hi.cross_session_read_dedup);
2153
- hi.cross_session_read_dedup_ttl_secs = envInt("TOKEN_GOAT_CROSS_SESSION_READ_DEDUP_TTL_SECS", hi.cross_session_read_dedup_ttl_secs, ...boundsOf("hints.cross_session_read_dedup_ttl_secs"));
2154
- hi.mcp_dedup_ttl_secs = validatedInt(hi_raw["mcp_dedup_ttl_secs"], hi.mcp_dedup_ttl_secs, ...boundsOf("hints.mcp_dedup_ttl_secs"));
2155
- hi.mcp_dedup_ttl_secs = envInt("TOKEN_GOAT_MCP_DEDUP_TTL_SECS", hi.mcp_dedup_ttl_secs, ...boundsOf("hints.mcp_dedup_ttl_secs"));
2156
- hi.session_start_reminder = validatedBool(hi_raw["session_start_reminder"], hi.session_start_reminder);
2157
- hi.session_start_reminder = envBool("TOKEN_GOAT_SESSION_START_REMINDER", hi.session_start_reminder);
2158
- hi.min_session_hint_savings_bytes = envInt("TOKEN_GOAT_SESSION_HINT_MIN_BYTES", hi.min_session_hint_savings_bytes, ...boundsOf("hints.min_session_hint_savings_bytes"));
2159
- hi.reread_deny = envBool("TOKEN_GOAT_REREAD_DENY", hi.reread_deny);
2160
- hi.reread_deny_min_bytes = envInt("TOKEN_GOAT_REREAD_DENY_MIN_BYTES", hi.reread_deny_min_bytes, ...boundsOf("hints.reread_deny_min_bytes"));
2161
- hi.protect_recent_reads = envInt("TOKEN_GOAT_PROTECT_RECENT_READS", hi.protect_recent_reads, ...boundsOf("hints.protect_recent_reads"));
2162
- hi.truncated_read_min_lines = envInt("TOKEN_GOAT_TRUNCATED_READ_MIN_LINES", hi.truncated_read_min_lines, ...boundsOf("hints.truncated_read_min_lines"));
2163
- hi.diff_hint_min_tokens_saved = envInt("TOKEN_GOAT_DIFF_HINT_MIN_TOKENS_SAVED", hi.diff_hint_min_tokens_saved, ...boundsOf("hints.diff_hint_min_tokens_saved"));
2164
- hi.min_file_lines_for_hint = envInt("TOKEN_GOAT_MIN_FILE_LINES_FOR_HINT", hi.min_file_lines_for_hint, ...boundsOf("hints.min_file_lines_for_hint"));
2165
- hi.git_hint_max_ms = envInt("TOKEN_GOAT_GIT_HINT_MAX_MS", hi.git_hint_max_ms, ...boundsOf("hints.git_hint_max_ms"));
2166
- hi.stable_doc_compacts = envBool("TOKEN_GOAT_STABLE_DOC_COMPACTS", hi.stable_doc_compacts);
2167
- hi.fold_code_bodies = envBool("TOKEN_GOAT_FOLD_CODE_BODIES", hi.fold_code_bodies);
2168
- hi.fold_comment_blocks = envBool("TOKEN_GOAT_FOLD_COMMENT_BLOCKS", hi.fold_comment_blocks);
2169
- hi.fold_prose_paragraphs = envBool("TOKEN_GOAT_FOLD_PROSE_PARAGRAPHS", hi.fold_prose_paragraphs);
2170
- hi.outline_large_documents = envBool("TOKEN_GOAT_OUTLINE_LARGE_DOCUMENTS", hi.outline_large_documents);
2171
- hi.skeleton_large_sources = envBool("TOKEN_GOAT_SKELETON_LARGE_SOURCES", hi.skeleton_large_sources);
2172
- hi.context_threshold_advisory = envBool("TOKEN_GOAT_CONTEXT_THRESHOLD_ADVISORY", hi.context_threshold_advisory);
2173
- hi.pre_skill_advisory = envBool("TOKEN_GOAT_PRE_SKILL_ADVISORY", hi.pre_skill_advisory);
2174
- hi.quiet_hours = envStr("TOKEN_GOAT_QUIET_HOURS", hi.quiet_hours);
2175
- const triggers_raw = hi_raw["prompt_triggers"];
2176
- if (Array.isArray(triggers_raw)) {
2177
- hi.prompt_triggers = triggers_raw.filter((t) => t !== null && typeof t === "object" && !Array.isArray(t)).map((t) => ({
2178
- keywords: validatedStrList(t["keywords"], []),
2179
- hint: validatedStr(t["hint"], "")
2180
- })).filter((t) => t.keywords.length > 0 && t.hint.length > 0);
2181
- }
2182
- const hk_raw = section(raw, "hooks");
2183
- const hk = getDefaultConfig("hooks");
2184
- hk.watchdog_ms = validatedInt(hk_raw["watchdog_ms"], hk.watchdog_ms, ...boundsOf("hooks.watchdog_ms"));
2185
- hk.watchdog_ms = envInt("TOKEN_GOAT_HOOK_WATCHDOG_MS", hk.watchdog_ms, ...boundsOf("hooks.watchdog_ms"));
2186
- const wf_raw = section(raw, "webfetch");
2187
- const wf = getDefaultConfig("webfetch");
2188
- wf.allow = validatedStrList(wf_raw["allow"], wf.allow);
2189
- wf.deny = validatedStrList(wf_raw["deny"], wf.deny);
2190
- wf.allow = envStrList("TOKEN_GOAT_WEBFETCH_ALLOW", wf.allow, ",");
2191
- wf.deny = envStrList("TOKEN_GOAT_WEBFETCH_DENY", wf.deny, ",");
2192
- wf.max_file_count = validatedInt(wf_raw["max_file_count"], wf.max_file_count, ...boundsOf("webfetch.max_file_count"));
2193
- wf.max_file_count = envInt("TOKEN_GOAT_WEB_CACHE_MAX_FILES", wf.max_file_count, ...boundsOf("webfetch.max_file_count"));
2194
- wf.max_bytes = validatedInt(wf_raw["max_bytes"], wf.max_bytes, ...boundsOf("webfetch.max_bytes"));
2195
- wf.max_bytes = envInt("TOKEN_GOAT_WEB_CACHE_MAX_BYTES", wf.max_bytes, ...boundsOf("webfetch.max_bytes"));
2196
- wf.compress_bodies = validatedBool(wf_raw["compress_bodies"], wf.compress_bodies);
2197
- wf.compress_min_bytes = validatedInt(wf_raw["compress_min_bytes"], wf.compress_min_bytes, ...boundsOf("webfetch.compress_min_bytes"));
2198
- wf.compress_bodies = envBool("TOKEN_GOAT_WEB_COMPRESS", wf.compress_bodies);
2199
- const wk_raw = section(raw, "worker");
2200
- const wk = getDefaultConfig("worker");
2201
- wk.blocked_roots = validatedStrList(wk_raw["blocked_roots"], wk.blocked_roots);
2202
- wk.max_pool_workers = validatedInt(wk_raw["max_pool_workers"], wk.max_pool_workers, ...boundsOf("worker.max_pool_workers"));
2203
- wk.max_pool_workers = envInt("TOKEN_GOAT_WORKER_MAX_POOL", wk.max_pool_workers, ...boundsOf("worker.max_pool_workers"));
2204
- wk.embed_threads = validatedInt(wk_raw["embed_threads"], wk.embed_threads, ...boundsOf("worker.embed_threads"));
2205
- wk.embed_threads = envInt("TOKEN_GOAT_EMBED_THREADS", wk.embed_threads, ...boundsOf("worker.embed_threads"));
2206
- wk.priority = validatedStr(wk_raw["priority"], wk.priority);
2207
- wk.priority = envStr("TOKEN_GOAT_WORKER_PRIORITY", wk.priority);
2208
- const ix_raw = section(raw, "indexing");
2209
- const ix = getDefaultConfig("indexing");
2210
- ix.large_file_symbol_only_kb = validatedInt(ix_raw["large_file_symbol_only_kb"], ix.large_file_symbol_only_kb, ...boundsOf("indexing.large_file_symbol_only_kb"));
2211
- ix.large_file_skip_kb = validatedInt(ix_raw["large_file_skip_kb"], ix.large_file_skip_kb, ...boundsOf("indexing.large_file_skip_kb"));
2212
- ix.large_file_symbol_only_kb = Math.min(ix.large_file_symbol_only_kb, ix.large_file_skip_kb);
2213
- ix.skip_dirs = validatedStrList(ix_raw["skip_dirs"], ix.skip_dirs);
2214
- ix.skip_files = validatedStrList(ix_raw["skip_files"], ix.skip_files);
2215
- ix.embeddings_enabled = validatedBool(ix_raw["embeddings_enabled"], ix.embeddings_enabled);
2216
- ix.embeddings_enabled = envBool("TOKEN_GOAT_EMBEDDINGS_ENABLED", ix.embeddings_enabled);
2217
- ix.cross_project_symbols = validatedBool(ix_raw["cross_project_symbols"], ix.cross_project_symbols);
2218
- ix.cross_project_symbols = envBool("TOKEN_GOAT_CROSS_PROJECT_SYMBOLS", ix.cross_project_symbols);
2219
- const cpr_raw = section(raw, "compression");
2220
- const cpr = getDefaultConfig("compression");
2221
- cpr.profile = validatedStr(cpr_raw["profile"], cpr.profile);
2222
- cpr.profile = envStr("TOKEN_GOAT_COMPRESS_PROFILE", cpr.profile);
2223
- const ctx_raw = section(raw, "context");
2224
- const ctx = getDefaultConfig("context");
2225
- ctx.model_window_tokens = validatedInt(ctx_raw["model_window_tokens"], ctx.model_window_tokens, ...boundsOf("context.model_window_tokens"));
2226
- ctx.model_window_tokens = envInt("TOKEN_GOAT_MODEL_WINDOW_TOKENS", ctx.model_window_tokens, ...boundsOf("context.model_window_tokens"));
2227
- const inj_raw = section(raw, "injection");
2228
- const inj = getDefaultConfig("injection");
2229
- inj.enabled = validatedBool(inj_raw["enabled"], inj.enabled);
2230
- inj.enabled = envBool("TOKEN_GOAT_INJECTION_ENABLED", inj.enabled);
2231
- const gd_raw = section(raw, "gdrive");
2232
- const gd = getDefaultConfig("gdrive");
2233
- gd.enabled = validatedBool(gd_raw["enabled"], gd.enabled);
2234
- gd.enabled = envBool("TOKEN_GOAT_GDRIVE_ENABLED", gd.enabled);
2235
- const red_raw = section(raw, "redaction");
2236
- const red = getDefaultConfig("redaction");
2237
- red.custom_patterns = validatedStrList(red_raw["custom_patterns"], red.custom_patterns);
2238
- red.custom_patterns = envStrList("TOKEN_GOAT_REDACTION_CUSTOM_PATTERNS", red.custom_patterns, "\n");
2239
- red.strict = validatedBool(red_raw["strict"], red.strict);
2240
- red.strict = envBool("TOKEN_GOAT_REDACTION_STRICT", red.strict);
2241
- const net_raw = section(raw, "network");
2242
- const net = getDefaultConfig("network");
2243
- net.offline = validatedBool(net_raw["offline"], net.offline);
2244
- net.offline = envBool("TOKEN_GOAT_OFFLINE", net.offline);
2245
- const mcp_raw = section(raw, "mcp");
2246
- const mcp = getDefaultConfig("mcp");
2247
- mcp.confine_reads_to_project_root = validatedBool(mcp_raw["confine_reads_to_project_root"], mcp.confine_reads_to_project_root);
2248
- mcp.confine_reads_to_project_root = envBool("TOKEN_GOAT_MCP_CONFINE_READS", mcp.confine_reads_to_project_root);
2249
- mcp.allowed_roots = validatedStrList(mcp_raw["allowed_roots"], mcp.allowed_roots);
2250
- mcp.allowed_roots = envStrList("TOKEN_GOAT_MCP_ALLOWED_ROOTS", mcp.allowed_roots, path2.delimiter);
2251
- const hs_raw = section(raw, "hint_stats");
2252
- const hs = getDefaultConfig("hint_stats");
2253
- hs.suppress_threshold_pct = validatedInt(hs_raw["suppress_threshold_pct"], hs.suppress_threshold_pct, ...boundsOf("hint_stats.suppress_threshold_pct"));
2254
- hs.min_sample_size = validatedInt(hs_raw["min_sample_size"], hs.min_sample_size, ...boundsOf("hint_stats.min_sample_size"));
2255
- const sem_raw = section(raw, "semantic");
2256
- const sem = getDefaultConfig("semantic");
2257
- sem.archive_weight = validatedFloat(sem_raw["archive_weight"], sem.archive_weight, ...boundsOf("semantic.archive_weight"));
2258
- sem.docs_weight = validatedFloat(sem_raw["docs_weight"], sem.docs_weight, ...boundsOf("semantic.docs_weight"));
2259
- return {
2260
- compact_assist: ca,
2261
- bash_compress: bc,
2262
- agent_report: ar,
2263
- bash_diff: bd,
2264
- bash_severity_log: sl,
2265
- post_read_code_compress: cc,
2266
- session_brief: sb,
2267
- skill_preservation: sp,
2268
- image_shrink: is_cfg,
2269
- screenshot: sc_cfg,
2270
- repomap: rm,
2271
- overflow_guard: og,
2272
- stats: st,
2273
- hints: hi,
2274
- hooks: hk,
2275
- webfetch: wf,
2276
- worker: wk,
2277
- indexing: ix,
2278
- compression: cpr,
2279
- context: ctx,
2280
- injection: inj,
2281
- gdrive: gd,
2282
- redaction: red,
2283
- network: net,
2284
- mcp,
2285
- hint_stats: hs,
2286
- semantic: sem
2287
- };
2288
- }
2289
- var CONFIG_KEY_ENV_OVERRIDES = {
2290
- "compact_assist.enabled": ["TOKEN_GOAT_COMPACT_ASSIST", "TOKENWISE_COMPACT_ASSIST"],
2291
- "bash_compress.enabled": ["TOKEN_GOAT_BASH_COMPRESS"],
2292
- "bash_compress.cache_min_bytes": ["TOKEN_GOAT_BASH_CACHE_MIN_BYTES"],
2293
- "bash_compress.cache_max_file_count": ["TOKEN_GOAT_BASH_CACHE_MAX_FILES"],
2294
- "bash_compress.cache_max_bytes": ["TOKEN_GOAT_BASH_CACHE_MAX_BYTES"],
2295
- "bash_compress.cache_max_bytes_per_output": ["TOKEN_GOAT_BASH_CACHE_MAX_BYTES_PER_OUTPUT"],
2296
- "bash_compress.min_net_savings_bytes": ["TOKEN_GOAT_BASH_MIN_NET_SAVINGS_BYTES"],
2297
- "agent_report.min_bytes": ["TOKEN_GOAT_AGENT_REPORT_MIN_BYTES"],
2298
- "agent_report.fence_collapse_min_lines": ["TOKEN_GOAT_AGENT_REPORT_FENCE_MIN_LINES"],
2299
- "agent_report.fence_collapse_keep_lines": ["TOKEN_GOAT_AGENT_REPORT_FENCE_KEEP_LINES"],
2300
- "session_brief.enabled": ["TOKEN_GOAT_SESSION_BRIEF"],
2301
- "skill_preservation.enabled": ["TOKEN_GOAT_SKILL_PRESERVATION"],
2302
- "skill_preservation.compress_bodies": ["TOKEN_GOAT_SKILL_COMPRESS"],
2303
- "skill_preservation.pre_skill_enabled": ["TOKEN_GOAT_PRE_SKILL"],
2304
- "skill_preservation.orphan_sweep_enabled": ["TOKEN_GOAT_ORPHAN_SWEEP"],
2305
- "image_shrink.max_image_pixels": ["TOKEN_GOAT_MAX_IMAGE_PIXELS"],
2306
- "image_shrink.ocr_enabled": ["TOKEN_GOAT_OCR_ENABLED"],
2307
- "image_shrink.ocr_lang": ["TOKEN_GOAT_OCR_LANG"],
2308
- "image_shrink.vision_tier": ["TOKEN_GOAT_VISION_TIER"],
2309
- "screenshot.block_private_targets": ["TOKEN_GOAT_SCREENSHOT_BLOCK_PRIVATE_TARGETS"],
2310
- "repomap.compact_file_threshold": ["TOKEN_GOAT_REPOMAP_COMPACT_THRESHOLD"],
2311
- "repomap.exclude_tests": ["TOKEN_GOAT_REPOMAP_EXCLUDE_TESTS"],
2312
- "overflow_guard.enabled": ["TOKEN_GOAT_OVERFLOW_GUARD"],
2313
- "overflow_guard.max_tokens": ["TOKEN_GOAT_OVERFLOW_MAX_TOKENS"],
2314
- "hints.json_sidecar": ["TOKEN_GOAT_HINT_JSON_SIDECAR"],
2315
- "hints.bash_dedup_min_bytes": ["TOKEN_GOAT_BASH_DEDUP_MIN_BYTES"],
2316
- "hints.web_dedup_min_bytes": ["TOKEN_GOAT_WEB_DEDUP_MIN_BYTES"],
2317
- "hints.grep_dedup_min_matches": ["TOKEN_GOAT_GREP_DEDUP_MIN_MATCHES"],
2318
- "hints.glob_dedup_min_matches": ["TOKEN_GOAT_GLOB_DEDUP_MIN_MATCHES"],
2319
- "hints.write_rewrite_min_lines": ["TOKEN_GOAT_WRITE_REWRITE_MIN_LINES"],
2320
- "hints.write_rewrite_unchanged_pct": ["TOKEN_GOAT_WRITE_REWRITE_UNCHANGED_PCT"],
2321
- "hints.large_read_redirect_bytes": ["TOKEN_GOAT_LARGE_READ_BYTES"],
2322
- "hints.warn_unbalanced_shell_quoting": ["TOKEN_GOAT_WARN_UNBALANCED_SHELL_QUOTING"],
2323
- "hints.serve_diff_on_reread": ["TOKEN_GOAT_SERVE_DIFF_ON_REREAD"],
2324
- "hints.elide_served_lines": ["TOKEN_GOAT_ELIDE_SERVED_LINES"],
2325
- "hints.subagent_markdown_first_read_deny": ["TOKEN_GOAT_SUBAGENT_MARKDOWN_FIRST_READ_DENY"],
2326
- "hints.log_large_file_hint_outcomes": ["TOKEN_GOAT_LOG_LARGE_FILE_HINT_OUTCOMES"],
2327
- "hints.cross_session_read_dedup": ["TOKEN_GOAT_CROSS_SESSION_READ_DEDUP"],
2328
- "hints.cross_session_read_dedup_ttl_secs": ["TOKEN_GOAT_CROSS_SESSION_READ_DEDUP_TTL_SECS"],
2329
- "hints.mcp_dedup_ttl_secs": ["TOKEN_GOAT_MCP_DEDUP_TTL_SECS"],
2330
- "hints.session_start_reminder": ["TOKEN_GOAT_SESSION_START_REMINDER"],
2331
- "hints.min_session_hint_savings_bytes": ["TOKEN_GOAT_SESSION_HINT_MIN_BYTES"],
2332
- "hints.reread_deny": ["TOKEN_GOAT_REREAD_DENY"],
2333
- "hints.reread_deny_min_bytes": ["TOKEN_GOAT_REREAD_DENY_MIN_BYTES"],
2334
- "hints.protect_recent_reads": ["TOKEN_GOAT_PROTECT_RECENT_READS"],
2335
- "hints.truncated_read_min_lines": ["TOKEN_GOAT_TRUNCATED_READ_MIN_LINES"],
2336
- "hints.diff_hint_min_tokens_saved": ["TOKEN_GOAT_DIFF_HINT_MIN_TOKENS_SAVED"],
2337
- "hints.min_file_lines_for_hint": ["TOKEN_GOAT_MIN_FILE_LINES_FOR_HINT"],
2338
- "hints.git_hint_max_ms": ["TOKEN_GOAT_GIT_HINT_MAX_MS"],
2339
- "hints.stable_doc_compacts": ["TOKEN_GOAT_STABLE_DOC_COMPACTS"],
2340
- "hints.fold_code_bodies": ["TOKEN_GOAT_FOLD_CODE_BODIES"],
2341
- "hints.fold_comment_blocks": ["TOKEN_GOAT_FOLD_COMMENT_BLOCKS"],
2342
- "hints.fold_prose_paragraphs": ["TOKEN_GOAT_FOLD_PROSE_PARAGRAPHS"],
2343
- "hints.outline_large_documents": ["TOKEN_GOAT_OUTLINE_LARGE_DOCUMENTS"],
2344
- "hints.skeleton_large_sources": ["TOKEN_GOAT_SKELETON_LARGE_SOURCES"],
2345
- "hints.context_threshold_advisory": ["TOKEN_GOAT_CONTEXT_THRESHOLD_ADVISORY"],
2346
- "hints.pre_skill_advisory": ["TOKEN_GOAT_PRE_SKILL_ADVISORY"],
2347
- "hints.quiet_hours": ["TOKEN_GOAT_QUIET_HOURS"],
2348
- "hooks.watchdog_ms": ["TOKEN_GOAT_HOOK_WATCHDOG_MS"],
2349
- "webfetch.max_file_count": ["TOKEN_GOAT_WEB_CACHE_MAX_FILES"],
2350
- "webfetch.max_bytes": ["TOKEN_GOAT_WEB_CACHE_MAX_BYTES"],
2351
- "webfetch.compress_bodies": ["TOKEN_GOAT_WEB_COMPRESS"],
2352
- "worker.max_pool_workers": ["TOKEN_GOAT_WORKER_MAX_POOL"],
2353
- "worker.embed_threads": ["TOKEN_GOAT_EMBED_THREADS"],
2354
- "worker.priority": ["TOKEN_GOAT_WORKER_PRIORITY"],
2355
- "compression.profile": ["TOKEN_GOAT_COMPRESS_PROFILE"],
2356
- "context.model_window_tokens": ["TOKEN_GOAT_MODEL_WINDOW_TOKENS"],
2357
- "indexing.cross_project_symbols": ["TOKEN_GOAT_CROSS_PROJECT_SYMBOLS"],
2358
- "injection.enabled": ["TOKEN_GOAT_INJECTION_ENABLED"],
2359
- "gdrive.enabled": ["TOKEN_GOAT_GDRIVE_ENABLED"],
2360
- "redaction.custom_patterns": ["TOKEN_GOAT_REDACTION_CUSTOM_PATTERNS"],
2361
- "redaction.strict": ["TOKEN_GOAT_REDACTION_STRICT"],
2362
- "network.offline": ["TOKEN_GOAT_OFFLINE"],
2363
- "mcp.confine_reads_to_project_root": ["TOKEN_GOAT_MCP_CONFINE_READS"],
2364
- "mcp.allowed_roots": ["TOKEN_GOAT_MCP_ALLOWED_ROOTS"],
2365
- "webfetch.allow": ["TOKEN_GOAT_WEBFETCH_ALLOW"],
2366
- "webfetch.deny": ["TOKEN_GOAT_WEBFETCH_DENY"],
2367
- "indexing.embeddings_enabled": ["TOKEN_GOAT_EMBEDDINGS_ENABLED"]
2368
- };
2369
- function saveConfig(config) {
2370
- const ca = config.compact_assist;
2371
- const bc = config.bash_compress;
2372
- const sp = config.skill_preservation;
2373
- const is_cfg = config.image_shrink;
2374
- const wasExplicit = isAutoTriggerMultiplierExplicit();
2375
- const defaultMultiplier = getDefaultConfig("compact_assist").auto_trigger_multiplier;
2376
- const keepsMultiplierDefault = !wasExplicit && ca.auto_trigger_multiplier === defaultMultiplier;
2377
- const data = {
2378
- compact_assist: {
2379
- enabled: ca.enabled,
2380
- triggers: ca.triggers,
2381
- min_events: ca.min_events,
2382
- max_manifest_tokens: ca.max_manifest_tokens,
2383
- ...keepsMultiplierDefault ? {} : { auto_trigger_multiplier: ca.auto_trigger_multiplier },
2384
- compact_skip_ttl_secs: ca.compact_skip_ttl_secs,
2385
- noise_floor_tokens: ca.noise_floor_tokens,
2386
- edited_dir_group_threshold: ca.edited_dir_group_threshold,
2387
- max_section_lines: ca.max_section_lines,
2388
- wide_session_threshold: ca.wide_session_threshold,
2389
- orchestrator_commit_threshold: ca.orchestrator_commit_threshold,
2390
- max_manifest_chars: ca.max_manifest_chars,
2391
- summary_budget_chars: ca.summary_budget_chars,
2392
- harness: ca.harness
2393
- },
2394
- bash_compress: {
2395
- enabled: bc.enabled,
2396
- disabled_filters: bc.disabled_filters,
2397
- max_lines: bc.max_lines,
2398
- max_bytes: bc.max_bytes,
2399
- timeout_seconds: bc.timeout_seconds,
2400
- cache_min_bytes: bc.cache_min_bytes,
2401
- cache_max_file_count: bc.cache_max_file_count,
2402
- cache_max_bytes: bc.cache_max_bytes,
2403
- cache_max_bytes_per_output: bc.cache_max_bytes_per_output,
2404
- min_net_savings_bytes: bc.min_net_savings_bytes,
2405
- elide_served_shell_output: bc.elide_served_shell_output
2406
- },
2407
- agent_report: {
2408
- min_bytes: config.agent_report.min_bytes,
2409
- fence_collapse_min_lines: config.agent_report.fence_collapse_min_lines,
2410
- fence_collapse_keep_lines: config.agent_report.fence_collapse_keep_lines
2411
- },
2412
- bash_diff: {
2413
- max_hunks_per_file: config.bash_diff.max_hunks_per_file
2414
- },
2415
- bash_severity_log: {
2416
- context_lines: config.bash_severity_log.context_lines,
2417
- score_threshold: config.bash_severity_log.score_threshold
2418
- },
2419
- post_read_code_compress: {
2420
- min_lines: config.post_read_code_compress.min_lines
2421
- },
2422
- session_brief: {
2423
- enabled: config.session_brief.enabled
2424
- },
2425
- skill_preservation: {
2426
- enabled: sp.enabled,
2427
- max_cache_bytes: sp.max_cache_bytes,
2428
- orphan_sweep_enabled: sp.orphan_sweep_enabled,
2429
- orphan_age_secs: sp.orphan_age_secs,
2430
- truncation_budget_tokens: sp.truncation_budget_tokens,
2431
- compress_bodies: sp.compress_bodies,
2432
- compress_min_bytes: sp.compress_min_bytes,
2433
- inline_snippets: sp.inline_snippets,
2434
- pre_skill_enabled: sp.pre_skill_enabled,
2435
- first_load_compact: sp.first_load_compact,
2436
- post_compact_full_loads: sp.post_compact_full_loads
2437
- },
2438
- image_shrink: {
2439
- enabled: is_cfg.enabled,
2440
- jpeg_quality: is_cfg.jpeg_quality,
2441
- max_image_pixels: is_cfg.max_image_pixels,
2442
- screenshot_redirect: is_cfg.screenshot_redirect,
2443
- ocr_enabled: is_cfg.ocr_enabled,
2444
- ocr_min_confidence: is_cfg.ocr_min_confidence,
2445
- ocr_lang: is_cfg.ocr_lang,
2446
- vision_tier: is_cfg.vision_tier
2447
- },
2448
- screenshot: {
2449
- chrome_path: config.screenshot.chrome_path,
2450
- block_private_targets: config.screenshot.block_private_targets
2451
- },
2452
- repomap: {
2453
- compact_file_threshold: config.repomap.compact_file_threshold,
2454
- exclude_tests: config.repomap.exclude_tests
2455
- },
2456
- overflow_guard: {
2457
- enabled: config.overflow_guard.enabled,
2458
- max_tokens: config.overflow_guard.max_tokens
2459
- },
2460
- stats: {
2461
- record_zero_savings: config.stats.record_zero_savings
2462
- },
2463
- hints: {
2464
- quiet_hours: config.hints.quiet_hours,
2465
- json_sidecar: config.hints.json_sidecar,
2466
- min_file_lines_for_hint: config.hints.min_file_lines_for_hint,
2467
- bash_dedup_min_bytes: config.hints.bash_dedup_min_bytes,
2468
- web_dedup_min_bytes: config.hints.web_dedup_min_bytes,
2469
- grep_dedup_min_matches: config.hints.grep_dedup_min_matches,
2470
- glob_dedup_min_matches: config.hints.glob_dedup_min_matches,
2471
- write_rewrite_min_lines: config.hints.write_rewrite_min_lines,
2472
- write_rewrite_unchanged_pct: config.hints.write_rewrite_unchanged_pct,
2473
- serve_diff_on_reread: config.hints.serve_diff_on_reread,
2474
- elide_served_lines: config.hints.elide_served_lines,
2475
- subagent_markdown_first_read_deny: config.hints.subagent_markdown_first_read_deny,
2476
- backoff_thresholds: config.hints.backoff_thresholds,
2477
- git_hint_max_ms: config.hints.git_hint_max_ms,
2478
- min_session_hint_savings_bytes: config.hints.min_session_hint_savings_bytes,
2479
- pre_skill_advisory: config.hints.pre_skill_advisory,
2480
- context_threshold_advisory: config.hints.context_threshold_advisory,
2481
- diff_hint_min_tokens_saved: config.hints.diff_hint_min_tokens_saved,
2482
- large_read_redirect_bytes: config.hints.large_read_redirect_bytes,
2483
- reread_deny: config.hints.reread_deny,
2484
- reread_deny_min_bytes: config.hints.reread_deny_min_bytes,
2485
- stable_doc_compacts: config.hints.stable_doc_compacts,
2486
- fold_code_bodies: config.hints.fold_code_bodies,
2487
- fold_comment_blocks: config.hints.fold_comment_blocks,
2488
- fold_prose_paragraphs: config.hints.fold_prose_paragraphs,
2489
- outline_large_documents: config.hints.outline_large_documents,
2490
- skeleton_large_sources: config.hints.skeleton_large_sources,
2491
- truncated_read_min_lines: config.hints.truncated_read_min_lines,
2492
- protect_recent_reads: config.hints.protect_recent_reads,
2493
- prompt_triggers: config.hints.prompt_triggers,
2494
- warn_unbalanced_shell_quoting: config.hints.warn_unbalanced_shell_quoting,
2495
- log_large_file_hint_outcomes: config.hints.log_large_file_hint_outcomes,
2496
- cross_session_read_dedup: config.hints.cross_session_read_dedup,
2497
- cross_session_read_dedup_ttl_secs: config.hints.cross_session_read_dedup_ttl_secs,
2498
- mcp_dedup_ttl_secs: config.hints.mcp_dedup_ttl_secs,
2499
- session_start_reminder: config.hints.session_start_reminder
2500
- },
2501
- hooks: {
2502
- watchdog_ms: config.hooks.watchdog_ms
2503
- },
2504
- webfetch: {
2505
- allow: config.webfetch.allow,
2506
- deny: config.webfetch.deny,
2507
- max_file_count: config.webfetch.max_file_count,
2508
- max_bytes: config.webfetch.max_bytes,
2509
- compress_bodies: config.webfetch.compress_bodies,
2510
- compress_min_bytes: config.webfetch.compress_min_bytes
2511
- },
2512
- worker: {
2513
- blocked_roots: config.worker.blocked_roots,
2514
- max_pool_workers: config.worker.max_pool_workers,
2515
- embed_threads: config.worker.embed_threads,
2516
- priority: config.worker.priority
2517
- },
2518
- indexing: {
2519
- large_file_symbol_only_kb: config.indexing.large_file_symbol_only_kb,
2520
- large_file_skip_kb: config.indexing.large_file_skip_kb,
2521
- skip_dirs: config.indexing.skip_dirs,
2522
- skip_files: config.indexing.skip_files,
2523
- embeddings_enabled: config.indexing.embeddings_enabled,
2524
- cross_project_symbols: config.indexing.cross_project_symbols
2525
- },
2526
- compression: {
2527
- profile: config.compression.profile
2528
- },
2529
- context: {
2530
- model_window_tokens: config.context.model_window_tokens
2531
- },
2532
- injection: {
2533
- enabled: config.injection.enabled
2534
- },
2535
- gdrive: {
2536
- enabled: config.gdrive.enabled
2537
- },
2538
- redaction: {
2539
- custom_patterns: config.redaction.custom_patterns,
2540
- strict: config.redaction.strict
2541
- },
2542
- network: {
2543
- offline: config.network.offline
2544
- },
2545
- mcp: {
2546
- confine_reads_to_project_root: config.mcp.confine_reads_to_project_root
2547
- },
2548
- hint_stats: {
2549
- suppress_threshold_pct: config.hint_stats.suppress_threshold_pct,
2550
- min_sample_size: config.hint_stats.min_sample_size
2551
- },
2552
- semantic: {
2553
- archive_weight: config.semantic.archive_weight,
2554
- docs_weight: config.semantic.docs_weight
2555
- }
2556
- };
2557
- const toml = stringify(data);
2558
- atomicWriteText(configPath(), toml);
2559
- _cached2 = null;
2560
- }
4
+ getHarnessName,
5
+ loadConfig
6
+ } from "./token-goat-chunk-SAQ5PG4L.mjs";
7
+ import {
8
+ registerReset
9
+ } from "./token-goat-chunk-EEIDFMEM.mjs";
10
+ import {
11
+ _detectOpenQuote,
12
+ _lineClosesQuote,
13
+ isAblSource,
14
+ isLatexClassFile,
15
+ isMatlabSource,
16
+ isObjcHeader,
17
+ isObjcSource,
18
+ isPascalSource,
19
+ isPerlSource,
20
+ isPrologSource
21
+ } from "./token-goat-chunk-POBYR64E.mjs";
22
+ import {
23
+ SYMBOL_BODY_CHAR_CAP,
24
+ VERSION,
25
+ atomicWriteText,
26
+ countNoun,
27
+ dataDir,
28
+ dataDirForHome,
29
+ displaySafeText,
30
+ ensureDirSync,
31
+ foldCase,
32
+ foldPath,
33
+ safeJoin,
34
+ sanitizeIdForFilename,
35
+ sleepSync,
36
+ tokenGoatHome
37
+ } from "./token-goat-chunk-AMYCQJX4.mjs";
38
+ import {
39
+ growsExponentially,
40
+ hasNestedQuantifier
41
+ } from "./token-goat-chunk-GMOUBOX4.mjs";
42
+ import {
43
+ init_define_import_meta_env
44
+ } from "./token-goat-chunk-A37V4PBF.mjs";
2561
45
 
2562
46
  // src/parser_types.ts
2563
47
  init_define_import_meta_env();
2564
- import * as fs4 from "node:fs";
2565
- import * as path3 from "node:path";
48
+ import * as fs from "node:fs";
49
+ import * as path from "node:path";
2566
50
 
2567
51
  // src/language_specs.ts
2568
52
  init_define_import_meta_env();
@@ -2744,7 +228,7 @@ function isVb6ClassModule(content) {
2744
228
  return lines.some((l) => /^Attribute\s+VB_Name\s*=\s*"/i.test(l.trim()));
2745
229
  }
2746
230
  function refineLanguageByContent(filePath, language, content) {
2747
- const sniff = CONTENT_SNIFFS.get(path3.extname(filePath).toLowerCase());
231
+ const sniff = CONTENT_SNIFFS.get(path.extname(filePath).toLowerCase());
2748
232
  if (sniff === void 0 || sniff.from !== language) return language;
2749
233
  return sniff.refine(content) ?? language;
2750
234
  }
@@ -2772,26 +256,26 @@ var CONTENT_SNIFFS = /* @__PURE__ */ new Map([
2772
256
  [".t", { from: "unknown", refine: (c) => isPerlSource(sniffHead(c)) ? "perl" : void 0 }]
2773
257
  ]);
2774
258
  function needsContentSniff(filePath, language) {
2775
- return CONTENT_SNIFFS.get(path3.extname(filePath).toLowerCase())?.from === language;
259
+ return CONTENT_SNIFFS.get(path.extname(filePath).toLowerCase())?.from === language;
2776
260
  }
2777
261
  function detectLanguageOfFile(filePath) {
2778
262
  const language = detectLanguage(filePath);
2779
263
  if (!needsContentSniff(filePath, language)) return language;
2780
264
  try {
2781
- const fd = fs4.openSync(filePath, "r");
265
+ const fd = fs.openSync(filePath, "r");
2782
266
  try {
2783
267
  const buf = Buffer.alloc(LANGUAGE_SNIFF_BYTES);
2784
- const n = fs4.readSync(fd, buf, 0, buf.length, 0);
268
+ const n = fs.readSync(fd, buf, 0, buf.length, 0);
2785
269
  return refineLanguageByContent(filePath, language, buf.subarray(0, n).toString("utf8"));
2786
270
  } finally {
2787
- fs4.closeSync(fd);
271
+ fs.closeSync(fd);
2788
272
  }
2789
273
  } catch {
2790
274
  return language;
2791
275
  }
2792
276
  }
2793
277
  function detectLanguage(filePath) {
2794
- const exactBase = path3.basename(filePath);
278
+ const exactBase = path.basename(filePath);
2795
279
  const base = exactBase.toLowerCase();
2796
280
  if (DOTENV_VARIANT_RE.test(base)) return "env_file";
2797
281
  const byName = EXACT_FILENAME_LANGUAGE.get(exactBase) ?? FILENAME_LANGUAGE.get(base);
@@ -2799,7 +283,7 @@ function detectLanguage(filePath) {
2799
283
  if (base.endsWith("-meta.xml")) {
2800
284
  return "salesforce_metadata";
2801
285
  }
2802
- const ext = path3.extname(base).toLowerCase();
286
+ const ext = path.extname(base).toLowerCase();
2803
287
  return EXTENSION_LANGUAGE.get(ext) ?? "unknown";
2804
288
  }
2805
289
  var UNSUPPORTED_LANGUAGE_EXTENSIONS = /* @__PURE__ */ new Map([
@@ -2811,7 +295,7 @@ function nonTreeSitterLanguageCount() {
2811
295
  return LANGUAGE_SPECS.filter((s) => s.extraction !== "tree-sitter" && s.id !== "ipynb").length;
2812
296
  }
2813
297
  function unsupportedLanguageName(filePath) {
2814
- const ext = path3.extname(filePath).toLowerCase();
298
+ const ext = path.extname(filePath).toLowerCase();
2815
299
  return UNSUPPORTED_LANGUAGE_EXTENSIONS.get(ext);
2816
300
  }
2817
301
 
@@ -2860,13 +344,13 @@ function redactIfDotenv(filePath, text) {
2860
344
 
2861
345
  // src/db.ts
2862
346
  init_define_import_meta_env();
2863
- import * as fs6 from "node:fs";
347
+ import * as fs3 from "node:fs";
2864
348
  import { createRequire as createRequire2 } from "node:module";
2865
- import * as path4 from "node:path";
349
+ import * as path2 from "node:path";
2866
350
 
2867
351
  // src/sqlite_driver.ts
2868
352
  init_define_import_meta_env();
2869
- import * as fs5 from "node:fs";
353
+ import * as fs2 from "node:fs";
2870
354
  import { createRequire } from "node:module";
2871
355
  var _require = createRequire(import.meta.url);
2872
356
  function suppressSqliteExperimentalWarning() {
@@ -3081,7 +565,7 @@ var Database = class {
3081
565
  #savepoints = 0;
3082
566
  constructor(dbPath, options = {}) {
3083
567
  const wantsExisting = options.readonly === true || options.fileMustExist === true;
3084
- if (wantsExisting && dbPath !== ":memory:" && !fs5.existsSync(dbPath)) {
568
+ if (wantsExisting && dbPath !== ":memory:" && !fs2.existsSync(dbPath)) {
3085
569
  throw new Error("unable to open database file");
3086
570
  }
3087
571
  this.#db = attempt(() => new DatabaseSync(dbPath, {
@@ -3222,6 +706,7 @@ CREATE INDEX IF NOT EXISTS idx_symbols_name ON symbols(name);
3222
706
  CREATE INDEX IF NOT EXISTS idx_symbols_file ON symbols(file_path);
3223
707
  CREATE INDEX IF NOT EXISTS idx_symbols_name_kind ON symbols(name, kind);
3224
708
  CREATE INDEX IF NOT EXISTS idx_symbols_file_folded ON symbols(TG_LOWER(file_path));
709
+ CREATE INDEX IF NOT EXISTS idx_symbols_file_name_folded ON symbols(TG_LOWER(file_path), name);
3225
710
  -- Partial index backing checkSymbolBodySize (cli_doctor.ts), which every SessionStart hook runs.
3226
711
  -- Its predicate cannot be served by any index above, so the check had to read the whole symbols
3227
712
  -- table -- 226 MB / 231324 rows here, 229 ms per session start, and the early-exit LIMIT 1 never
@@ -3247,6 +732,7 @@ CREATE TABLE IF NOT EXISTS refs (
3247
732
  CREATE INDEX IF NOT EXISTS idx_refs_name ON refs(name);
3248
733
  CREATE INDEX IF NOT EXISTS idx_refs_file ON refs(file_path);
3249
734
  CREATE INDEX IF NOT EXISTS idx_refs_file_folded ON refs(TG_LOWER(file_path));
735
+ CREATE INDEX IF NOT EXISTS idx_refs_file_name_folded ON refs(TG_LOWER(file_path), name);
3250
736
 
3251
737
  CREATE TABLE IF NOT EXISTS chunks (
3252
738
  id INTEGER PRIMARY KEY AUTOINCREMENT,
@@ -3258,6 +744,7 @@ CREATE TABLE IF NOT EXISTS chunks (
3258
744
  );
3259
745
  CREATE INDEX IF NOT EXISTS idx_chunks_file ON chunks(file_path);
3260
746
  CREATE INDEX IF NOT EXISTS idx_chunks_file_folded ON chunks(TG_LOWER(file_path));
747
+ CREATE INDEX IF NOT EXISTS idx_chunks_file_kind_folded ON chunks(TG_LOWER(file_path), kind);
3261
748
 
3262
749
  -- Tracks every project root a hook has ever seen an edit for, so the worker's periodic sweep
3263
750
  -- (sweepKnownRoots in index_prune.ts) knows which roots to auto-prune without scanning the
@@ -3595,8 +1082,8 @@ function initConnection(conn) {
3595
1082
  }
3596
1083
  }
3597
1084
  function resolveDbPath(dbPath) {
3598
- if (path4.isAbsolute(dbPath)) return dbPath;
3599
- if (dbPath.includes("/") || dbPath.includes("\\")) return path4.resolve(dbPath);
1085
+ if (path2.isAbsolute(dbPath)) return dbPath;
1086
+ if (dbPath.includes("/") || dbPath.includes("\\")) return path2.resolve(dbPath);
3600
1087
  return safeJoin(dataDir(), dbPath);
3601
1088
  }
3602
1089
  function connectionKey(dbPath) {
@@ -3607,11 +1094,11 @@ function getDb(dbPath) {
3607
1094
  const { resolved, key } = connectionKey(dbPath);
3608
1095
  const existing = _connections.get(key);
3609
1096
  if (existing !== void 0) return existing;
3610
- const dir = path4.dirname(resolved);
1097
+ const dir = path2.dirname(resolved);
3611
1098
  try {
3612
1099
  ensureDirSync(dir);
3613
1100
  } catch (e) {
3614
- if (e.code !== "EEXIST" || !fs6.existsSync(dir)) throw e;
1101
+ if (e.code !== "EEXIST" || !fs3.existsSync(dir)) throw e;
3615
1102
  }
3616
1103
  const conn = new Database(resolved);
3617
1104
  try {
@@ -3714,7 +1201,7 @@ var C = {
3714
1201
 
3715
1202
  // src/stats.ts
3716
1203
  init_define_import_meta_env();
3717
- import * as path5 from "node:path";
1204
+ import * as path3 from "node:path";
3718
1205
 
3719
1206
  // src/render/stats_renderer.ts
3720
1207
  init_define_import_meta_env();
@@ -4842,7 +2329,7 @@ function statsHasVersionColumn(db) {
4842
2329
  }
4843
2330
  function getGlobalDb(homeDir) {
4844
2331
  const basePath = homeDir ? dataDirForHome(homeDir) : dataDir();
4845
- const dbPath = path5.join(basePath, "global.db");
2332
+ const dbPath = path3.join(basePath, "global.db");
4846
2333
  const db = getDb(dbPath);
4847
2334
  if (!_globalSchemaApplied.has(dbPath)) {
4848
2335
  db.exec(GLOBAL_SCHEMA_SQL);
@@ -5406,44 +2893,221 @@ function redactSecrets(text, config = loadConfig()) {
5406
2893
  return { text: out, count };
5407
2894
  }
5408
2895
 
2896
+ // src/disk_cache.ts
2897
+ init_define_import_meta_env();
2898
+ import * as fs4 from "node:fs";
2899
+ import * as path4 from "node:path";
2900
+ var DEFAULT_MAX_COUNT = 200;
2901
+ var DEFAULT_MAX_AGE_MS = 24 * 3600 * 1e3;
2902
+ function sanitizeId(id) {
2903
+ return sanitizeIdForFilename(id, 64);
2904
+ }
2905
+ function blobDir(subdir) {
2906
+ return path4.join(tokenGoatHome(), subdir);
2907
+ }
2908
+ function blobPath(subdir, id) {
2909
+ const safe = sanitizeId(id);
2910
+ if (!safe) return null;
2911
+ const dir = blobDir(subdir);
2912
+ const candidate = path4.join(dir, `${safe}.json`);
2913
+ try {
2914
+ const rel = path4.relative(dir, candidate);
2915
+ if (rel.startsWith("..")) return null;
2916
+ } catch {
2917
+ return null;
2918
+ }
2919
+ return candidate;
2920
+ }
2921
+ function isBlobStale(subdir, id) {
2922
+ const p = blobPath(subdir, id);
2923
+ if (p === null) return false;
2924
+ try {
2925
+ const stat = fs4.statSync(p);
2926
+ return Date.now() - stat.mtimeMs > DEFAULT_MAX_AGE_MS;
2927
+ } catch {
2928
+ return false;
2929
+ }
2930
+ }
2931
+ function subdirCacheDefaults(subdir) {
2932
+ try {
2933
+ if (subdir === "bash_outputs") {
2934
+ const bc = loadConfig().bash_compress;
2935
+ return { maxCount: bc.cache_max_file_count, maxBytes: bc.cache_max_bytes, maxBytesPerItem: bc.cache_max_bytes_per_output };
2936
+ }
2937
+ if (subdir === "web_outputs") {
2938
+ const wf = loadConfig().webfetch;
2939
+ return { maxCount: wf.max_file_count, maxBytes: wf.max_bytes, maxBytesPerItem: Number.POSITIVE_INFINITY };
2940
+ }
2941
+ } catch {
2942
+ }
2943
+ return { maxCount: DEFAULT_MAX_COUNT, maxBytes: Number.POSITIVE_INFINITY, maxBytesPerItem: Number.POSITIVE_INFINITY };
2944
+ }
2945
+ function storeBlob(subdir, id, value, opts = {}) {
2946
+ const p = blobPath(subdir, id);
2947
+ if (!p) return false;
2948
+ const defaults = subdirCacheDefaults(subdir);
2949
+ const maxBytesPerItem = opts.maxBytesPerItem ?? defaults.maxBytesPerItem;
2950
+ let rawJson;
2951
+ try {
2952
+ rawJson = JSON.stringify(value);
2953
+ } catch {
2954
+ return false;
2955
+ }
2956
+ let json;
2957
+ try {
2958
+ const result = redactSecrets(rawJson);
2959
+ json = result.text;
2960
+ if (result.count > 0) recordStat("secret_redacted", 0, result.count, void 0, subdir);
2961
+ } catch {
2962
+ return false;
2963
+ }
2964
+ if (Number.isFinite(maxBytesPerItem) && Buffer.byteLength(json, "utf-8") > maxBytesPerItem) return false;
2965
+ try {
2966
+ const dir = path4.dirname(p);
2967
+ if (!fs4.existsSync(dir)) ensureDirSync(dir);
2968
+ atomicWriteText(p, json);
2969
+ } catch {
2970
+ return false;
2971
+ }
2972
+ pruneBlobs(
2973
+ subdir,
2974
+ opts.maxCount ?? defaults.maxCount,
2975
+ opts.maxAgeMs ?? DEFAULT_MAX_AGE_MS,
2976
+ opts.maxBytes ?? defaults.maxBytes,
2977
+ p
2978
+ );
2979
+ return true;
2980
+ }
2981
+ function loadBlob(subdir, id) {
2982
+ const p = blobPath(subdir, id);
2983
+ if (!p) return null;
2984
+ try {
2985
+ if (!fs4.existsSync(p)) return null;
2986
+ return JSON.parse(fs4.readFileSync(p, "utf8"));
2987
+ } catch {
2988
+ return null;
2989
+ }
2990
+ }
2991
+ function listBlobs(subdir) {
2992
+ const dir = blobDir(subdir);
2993
+ const out = [];
2994
+ try {
2995
+ if (!fs4.existsSync(dir)) return out;
2996
+ for (const file of fs4.readdirSync(dir)) {
2997
+ if (!file.endsWith(".json")) continue;
2998
+ const id = file.slice(0, -5);
2999
+ let mtime = 0;
3000
+ try {
3001
+ mtime = fs4.statSync(path4.join(dir, file)).mtimeMs;
3002
+ } catch {
3003
+ }
3004
+ const value = loadBlob(subdir, id);
3005
+ if (value !== null) out.push({ id, mtime, value });
3006
+ }
3007
+ } catch {
3008
+ return out;
3009
+ }
3010
+ return out;
3011
+ }
3012
+ function pruneBlobs(subdir, maxCount = DEFAULT_MAX_COUNT, maxAgeMs = DEFAULT_MAX_AGE_MS, maxBytes = Number.POSITIVE_INFINITY, protectedPath) {
3013
+ return pruneBlobDir(blobDir(subdir), maxCount, maxAgeMs, maxBytes, protectedPath);
3014
+ }
3015
+ function pruneBlobDir(dir, maxCount = DEFAULT_MAX_COUNT, maxAgeMs = DEFAULT_MAX_AGE_MS, maxBytes = Number.POSITIVE_INFINITY, protectedPath) {
3016
+ let removed = 0;
3017
+ try {
3018
+ if (!fs4.existsSync(dir)) return 0;
3019
+ const cutoff = Date.now() - maxAgeMs;
3020
+ let kept = [];
3021
+ let protectedEntry;
3022
+ for (const file of fs4.readdirSync(dir)) {
3023
+ const full = path4.join(dir, file);
3024
+ let stat;
3025
+ try {
3026
+ stat = fs4.statSync(full);
3027
+ } catch {
3028
+ continue;
3029
+ }
3030
+ if (!stat.isFile()) continue;
3031
+ if (protectedPath !== void 0 && full === protectedPath) {
3032
+ protectedEntry = [full, stat.mtimeMs, stat.size];
3033
+ continue;
3034
+ }
3035
+ if (stat.mtimeMs < cutoff) {
3036
+ try {
3037
+ fs4.unlinkSync(full);
3038
+ removed++;
3039
+ } catch {
3040
+ continue;
3041
+ }
3042
+ } else if (file.endsWith(".json")) {
3043
+ kept.push([full, stat.mtimeMs, stat.size]);
3044
+ }
3045
+ }
3046
+ const countBudget = protectedEntry ? Math.max(0, maxCount - 1) : maxCount;
3047
+ if (kept.length > countBudget) {
3048
+ kept.sort((a, b) => a[1] - b[1]);
3049
+ const excess = kept.slice(0, kept.length - countBudget);
3050
+ kept = kept.slice(kept.length - countBudget);
3051
+ for (const [full] of excess) {
3052
+ try {
3053
+ fs4.unlinkSync(full);
3054
+ removed++;
3055
+ } catch {
3056
+ continue;
3057
+ }
3058
+ }
3059
+ }
3060
+ if (Number.isFinite(maxBytes)) {
3061
+ kept.sort((a, b) => a[1] - b[1]);
3062
+ let total = kept.reduce((sum, [, , size]) => sum + size, 0) + (protectedEntry ? protectedEntry[2] : 0);
3063
+ while (total > maxBytes && kept.length > 0) {
3064
+ const oldest = kept.shift();
3065
+ if (!oldest) break;
3066
+ const [full, , size] = oldest;
3067
+ try {
3068
+ fs4.unlinkSync(full);
3069
+ removed++;
3070
+ total -= size;
3071
+ } catch {
3072
+ break;
3073
+ }
3074
+ }
3075
+ }
3076
+ } catch {
3077
+ return removed;
3078
+ }
3079
+ return removed;
3080
+ }
3081
+ var SWEEPABLE_CACHE_SUBDIRS = [
3082
+ { subdir: "bash_outputs", countCapped: true },
3083
+ { subdir: "web_outputs", countCapped: true },
3084
+ { subdir: "mcp_outputs", countCapped: true },
3085
+ { subdir: "sessions", countCapped: false }
3086
+ ];
3087
+ function sweepCacheRoots(extraRoots = []) {
3088
+ let removed = 0;
3089
+ const roots = [tokenGoatHome(), ...extraRoots];
3090
+ const seen = /* @__PURE__ */ new Set();
3091
+ for (const root of roots) {
3092
+ if (!root || seen.has(root)) continue;
3093
+ seen.add(root);
3094
+ for (const { subdir, countCapped } of SWEEPABLE_CACHE_SUBDIRS) {
3095
+ try {
3096
+ const defaults = subdirCacheDefaults(subdir);
3097
+ removed += pruneBlobDir(
3098
+ path4.join(root, subdir),
3099
+ countCapped ? defaults.maxCount : Number.POSITIVE_INFINITY,
3100
+ DEFAULT_MAX_AGE_MS,
3101
+ countCapped ? defaults.maxBytes : Number.POSITIVE_INFINITY
3102
+ );
3103
+ } catch {
3104
+ }
3105
+ }
3106
+ }
3107
+ return removed;
3108
+ }
3109
+
5409
3110
  export {
5410
- parse,
5411
- stringify,
5412
- detectHarness,
5413
- getHarnessName,
5414
- envBool,
5415
- envInt,
5416
- envStrList,
5417
- fingerprintContent,
5418
- shortFingerprint,
5419
- fingerprintFile,
5420
- fileIsAbsent,
5421
- makeProjectAt,
5422
- findProject,
5423
- getDisplayRoot,
5424
- isUnderSystemTemp,
5425
- resolveProjectRoot,
5426
- DEFAULT_OCR_LANG,
5427
- SUPPORTED_OCR_LANG_CODES,
5428
- isSupportedOcrLang,
5429
- resolveOcrLangs,
5430
- defaultConfig,
5431
- validateNumericField,
5432
- validateEnumField,
5433
- getLastConfigParseError,
5434
- getLastProjectConfigParseError,
5435
- PROJECT_LOCKED_SECTIONS,
5436
- PROJECT_LOCKED_KEYS,
5437
- lastProjectConfigLockedKeys,
5438
- getProjectConfigInfo,
5439
- resolveConfigKeyLayer,
5440
- readConfigSource,
5441
- isAutoTriggerMultiplierExplicit,
5442
- loadConfig,
5443
- invalidateConfigCache,
5444
- loadPersistedConfig,
5445
- CONFIG_KEY_ENV_OVERRIDES,
5446
- saveConfig,
5447
3111
  Database,
5448
3112
  FILENAME_LANGUAGE,
5449
3113
  TREE_SITTER_LANGUAGES,
@@ -5478,44 +3142,14 @@ export {
5478
3142
  renderStats2 as renderStats,
5479
3143
  countRedactionPlaceholders,
5480
3144
  compileCustomPatterns,
5481
- redactSecrets
3145
+ redactSecrets,
3146
+ DEFAULT_MAX_COUNT,
3147
+ DEFAULT_MAX_AGE_MS,
3148
+ blobPath,
3149
+ isBlobStale,
3150
+ storeBlob,
3151
+ loadBlob,
3152
+ listBlobs,
3153
+ pruneBlobs,
3154
+ sweepCacheRoots
5482
3155
  };
5483
- /*! Bundled license information:
5484
-
5485
- smol-toml/dist/date.js:
5486
- smol-toml/dist/error.js:
5487
- smol-toml/dist/util.js:
5488
- smol-toml/dist/primitive.js:
5489
- smol-toml/dist/extract.js:
5490
- smol-toml/dist/struct.js:
5491
- smol-toml/dist/parse.js:
5492
- smol-toml/dist/stringify.js:
5493
- smol-toml/dist/index.js:
5494
- (*!
5495
- * Copyright (c) Squirrel Chat et al., All rights reserved.
5496
- * SPDX-License-Identifier: BSD-3-Clause
5497
- *
5498
- * Redistribution and use in source and binary forms, with or without
5499
- * modification, are permitted provided that the following conditions are met:
5500
- *
5501
- * 1. Redistributions of source code must retain the above copyright notice, this
5502
- * list of conditions and the following disclaimer.
5503
- * 2. Redistributions in binary form must reproduce the above copyright notice,
5504
- * this list of conditions and the following disclaimer in the
5505
- * documentation and/or other materials provided with the distribution.
5506
- * 3. Neither the name of the copyright holder nor the names of its contributors
5507
- * may be used to endorse or promote products derived from this software without
5508
- * specific prior written permission.
5509
- *
5510
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
5511
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
5512
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
5513
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
5514
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5515
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
5516
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
5517
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
5518
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
5519
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5520
- *)
5521
- */