token-goat 2.9.28 → 2.9.30

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 (134) hide show
  1. package/README.md +36 -40
  2. package/SECURITY.md +28 -10
  3. package/THIRD_PARTY_NOTICES.md +40 -3
  4. package/dist/native/linux-arm64/tg-hook +0 -0
  5. package/dist/native/linux-x64/tg-hook +0 -0
  6. package/dist/ort-wasm-simd-threaded.mjs +59 -0
  7. package/dist/token-goat-chunk-3CHUNJ2O.mjs +53 -0
  8. package/dist/token-goat-chunk-3Z5S4KGM.mjs +918 -0
  9. package/dist/token-goat-chunk-4FVIAHSI.mjs +211 -0
  10. package/dist/{token-goat-chunk-66LODAUT.mjs → token-goat-chunk-4JJS54TR.mjs} +4 -3
  11. package/dist/token-goat-chunk-4LCCNRTG.mjs +313 -0
  12. package/dist/token-goat-chunk-54K3EUV3.mjs +35 -0
  13. package/dist/token-goat-chunk-56EIMS3E.mjs +159 -0
  14. package/dist/token-goat-chunk-5BCIJXMO.mjs +609 -0
  15. package/dist/token-goat-chunk-5KDMCMF2.mjs +362 -0
  16. package/dist/token-goat-chunk-5RG5SBL6.mjs +221 -0
  17. package/dist/{token-goat-chunk-RRNZMM3A.mjs → token-goat-chunk-5Y6ZYL6U.mjs} +21 -2
  18. package/dist/{token-goat-chunk-NILVK7XM.mjs → token-goat-chunk-64FBPDTK.mjs} +12 -6
  19. package/dist/{token-goat-chunk-LEG3JNJ6.mjs → token-goat-chunk-664RTTUV.mjs} +31 -15
  20. package/dist/token-goat-chunk-67TQJ76B.mjs +57 -0
  21. package/dist/token-goat-chunk-6QMAS7AB.mjs +42 -0
  22. package/dist/token-goat-chunk-7BXSNBY5.mjs +253 -0
  23. package/dist/{token-goat-chunk-F7QZRIWM.mjs → token-goat-chunk-7F2UBPD3.mjs} +42 -35
  24. package/dist/{token-goat-chunk-CC2PYJM7.mjs → token-goat-chunk-7IN2MKDS.mjs} +718 -595
  25. package/dist/token-goat-chunk-7NADEDKJ.mjs +124 -0
  26. package/dist/{token-goat-chunk-6SGLIPQB.mjs → token-goat-chunk-A3CK6N5Z.mjs} +621 -72
  27. package/dist/{token-goat-chunk-HXNAC4ZF.mjs → token-goat-chunk-AFLYLHDH.mjs} +48 -33
  28. package/dist/token-goat-chunk-AM5V6GSX.mjs +367 -0
  29. package/dist/{token-goat-chunk-I7CB3X4K.mjs → token-goat-chunk-APGZXSPS.mjs} +44 -148
  30. package/dist/{token-goat-chunk-BJBRGPBX.mjs → token-goat-chunk-ARDNEC2U.mjs} +11 -7
  31. package/dist/token-goat-chunk-ATCPY7EQ.mjs +134 -0
  32. package/dist/token-goat-chunk-B2RZZCSS.mjs +354 -0
  33. package/dist/{token-goat-chunk-QM76S6YS.mjs → token-goat-chunk-B45VMIIH.mjs} +6 -5
  34. package/dist/token-goat-chunk-BPGCUMR7.mjs +30 -0
  35. package/dist/{token-goat-chunk-GGLEE35R.mjs → token-goat-chunk-C63JQV5K.mjs} +49 -10
  36. package/dist/{token-goat-chunk-RJH64KQH.mjs → token-goat-chunk-COBQGL5S.mjs} +2661 -2440
  37. package/dist/token-goat-chunk-COTXZHTS.mjs +39 -0
  38. package/dist/token-goat-chunk-CYCEYAEO.mjs +265 -0
  39. package/dist/token-goat-chunk-CZ3LUXYZ.mjs +4115 -0
  40. package/dist/token-goat-chunk-DZX2YDPT.mjs +15 -0
  41. package/dist/token-goat-chunk-E3OQX2XT.mjs +824 -0
  42. package/dist/token-goat-chunk-EFHMMIGP.mjs +68 -0
  43. package/dist/token-goat-chunk-ETBHVDB6.mjs +328 -0
  44. package/dist/token-goat-chunk-EVMZJ27Z.mjs +147 -0
  45. package/dist/token-goat-chunk-EXKGNHEG.mjs +2096 -0
  46. package/dist/{token-goat-chunk-6Z5ULNE5.mjs → token-goat-chunk-FBNQNSJK.mjs} +2490 -4957
  47. package/dist/{token-goat-chunk-NMTKNYGF.mjs → token-goat-chunk-FNFBKLRD.mjs} +74 -9
  48. package/dist/{token-goat-chunk-XI2VFAV6.mjs → token-goat-chunk-FZ3NEW5O.mjs} +33 -19
  49. package/dist/token-goat-chunk-G5PJ7AGM.mjs +36 -0
  50. package/dist/{token-goat-chunk-VE27HPIF.mjs → token-goat-chunk-GFBSN7BD.mjs} +30 -398
  51. package/dist/{token-goat-chunk-L45ZQRT7.mjs → token-goat-chunk-GOLEOXZP.mjs} +780 -786
  52. package/dist/token-goat-chunk-H2K3QP6H.mjs +24 -0
  53. package/dist/token-goat-chunk-H2PHHGM5.mjs +188 -0
  54. package/dist/token-goat-chunk-HAVAOB3S.mjs +87 -0
  55. package/dist/token-goat-chunk-HG45AF2B.mjs +2228 -0
  56. package/dist/{token-goat-chunk-CBMY2FGI.mjs → token-goat-chunk-HOJLCGDP.mjs} +17113 -15554
  57. package/dist/{token-goat-chunk-HUDC5GS5.mjs → token-goat-chunk-HYBFA5X3.mjs} +120 -19
  58. package/dist/token-goat-chunk-IVALLT3S.mjs +48 -0
  59. package/dist/token-goat-chunk-IVE6U7KV.mjs +53 -0
  60. package/dist/{token-goat-chunk-UBUKHVYW.mjs → token-goat-chunk-IVKIZWAB.mjs} +3 -3
  61. package/dist/{token-goat-chunk-4JMWPWCS.mjs → token-goat-chunk-JB6QN6VF.mjs} +6 -4
  62. package/dist/{token-goat-chunk-Q4S3UQGO.mjs → token-goat-chunk-JDHE26RP.mjs} +10 -3
  63. package/dist/{token-goat-chunk-7R2XYKC5.mjs → token-goat-chunk-JDU3EXSU.mjs} +14 -10
  64. package/dist/token-goat-chunk-JDWCRD6M.mjs +253 -0
  65. package/dist/{token-goat-chunk-XBESNWEX.mjs → token-goat-chunk-JN4XMLSD.mjs} +7 -4
  66. package/dist/token-goat-chunk-JTQQGXZH.mjs +733 -0
  67. package/dist/token-goat-chunk-KKUFXAPD.mjs +25 -0
  68. package/dist/token-goat-chunk-KQNZDCBD.mjs +47 -0
  69. package/dist/{token-goat-chunk-4RN64ZND.mjs → token-goat-chunk-KWPNJBDH.mjs} +28 -3
  70. package/dist/token-goat-chunk-LOBGHXPB.mjs +242 -0
  71. package/dist/token-goat-chunk-MKPF4CL5.mjs +37 -0
  72. package/dist/token-goat-chunk-MNWKPRAL.mjs +13 -0
  73. package/dist/{token-goat-chunk-YWSP6IU7.mjs → token-goat-chunk-N2NMER56.mjs} +25 -15
  74. package/dist/token-goat-chunk-NYKZLXMK.mjs +218 -0
  75. package/dist/token-goat-chunk-OJBNYTJP.mjs +3087 -0
  76. package/dist/token-goat-chunk-P4QMM4WK.mjs +295 -0
  77. package/dist/token-goat-chunk-PD5VKH46.mjs +184 -0
  78. package/dist/token-goat-chunk-PEPTHRFF.mjs +129 -0
  79. package/dist/{token-goat-chunk-VWZKZPSR.mjs → token-goat-chunk-PU7V3FD6.mjs} +8752 -11098
  80. package/dist/token-goat-chunk-PY533T7F.mjs +46 -0
  81. package/dist/token-goat-chunk-Q5VTGRH7.mjs +761 -0
  82. package/dist/{token-goat-chunk-IHKZ3QNA.mjs → token-goat-chunk-QCLDAQTS.mjs} +33 -19
  83. package/dist/{token-goat-chunk-LKSXAMJB.mjs → token-goat-chunk-QSBRTGM2.mjs} +9 -2
  84. package/dist/{token-goat-chunk-4STDIGYC.mjs → token-goat-chunk-RC35RBUL.mjs} +7 -5
  85. package/dist/{token-goat-chunk-D5ICEPSB.mjs → token-goat-chunk-RHXKCZX3.mjs} +887 -507
  86. package/dist/{token-goat-chunk-RSS3TLXU.mjs → token-goat-chunk-RZRTDST7.mjs} +17 -7
  87. package/dist/{token-goat-chunk-MAMQPC43.mjs → token-goat-chunk-SJHWVNDQ.mjs} +15 -21
  88. package/dist/token-goat-chunk-SMVRN2HU.mjs +188 -0
  89. package/dist/{token-goat-chunk-EL7M26WP.mjs → token-goat-chunk-SQSSNQPE.mjs} +2100 -1442
  90. package/dist/{token-goat-chunk-OZRSREKR.mjs → token-goat-chunk-T4FK7VOV.mjs} +3 -3
  91. package/dist/token-goat-chunk-U4N3BN2W.mjs +92 -0
  92. package/dist/token-goat-chunk-UA5V6P3P.mjs +122 -0
  93. package/dist/{token-goat-chunk-XKY4VKJ4.mjs → token-goat-chunk-UQ5UK2T7.mjs} +15 -4
  94. package/dist/token-goat-chunk-USILZ3T3.mjs +53 -0
  95. package/dist/token-goat-chunk-VES7EL7O.mjs +205 -0
  96. package/dist/{token-goat-chunk-M56BWPBN.mjs → token-goat-chunk-VL3YIFHZ.mjs} +550 -49
  97. package/dist/{token-goat-chunk-IZXKVT4A.mjs → token-goat-chunk-VPBBTSJR.mjs} +362 -128
  98. package/dist/{token-goat-chunk-F2ARFHLJ.mjs → token-goat-chunk-W3QCJS6G.mjs} +10 -2
  99. package/dist/{token-goat-chunk-FSTWAOW6.mjs → token-goat-chunk-WY3L4DVT.mjs} +11 -5
  100. package/dist/{token-goat-chunk-OSUFN2FV.mjs → token-goat-chunk-XB5KKOCG.mjs} +5 -25
  101. package/dist/token-goat-chunk-XKI4SEMX.mjs +66 -0
  102. package/dist/token-goat-chunk-XU4P6Z24.mjs +133 -0
  103. package/dist/{token-goat-chunk-6CCQDAYY.mjs → token-goat-chunk-Y776AENC.mjs} +138 -33
  104. package/dist/token-goat-chunk-YARZFCZS.mjs +359 -0
  105. package/dist/{token-goat-chunk-EEIDFMEM.mjs → token-goat-chunk-YZAAZU2S.mjs} +12 -3
  106. package/dist/{token-goat-chunk-E3K3BTEQ.mjs → token-goat-chunk-Z44YO3QZ.mjs} +12 -6
  107. package/dist/token-goat-chunk-Z57YODA2.mjs +35 -0
  108. package/dist/{token-goat-chunk-DA43OE7L.mjs → token-goat-chunk-ZCDTCVIS.mjs} +49 -30
  109. package/dist/token-goat-chunk-ZEJVMUQH.mjs +48 -0
  110. package/dist/{token-goat-chunk-BGHSSJUA.mjs → token-goat-chunk-ZFOBKUWH.mjs} +1 -1
  111. package/dist/token-goat-chunk-ZMBL6UVV.mjs +110 -0
  112. package/dist/{token-goat-chunk-SJEKA7Y2.mjs → token-goat-chunk-ZQSJMO2R.mjs} +381 -201
  113. package/dist/token-goat-hook-client.cjs +539 -0
  114. package/dist/token-goat-hook-client.mjs +26 -0
  115. package/dist/token-goat-hook.mjs +48 -28
  116. package/dist/token-goat.core.mjs +10 -45
  117. package/docs/C4_RUNTIME_ARCHITECTURE.md +3 -3
  118. package/docs/cli.md +82 -47
  119. package/docs/install.md +58 -23
  120. package/docs/security.md +7 -7
  121. package/package.json +17 -7
  122. package/scripts/verify-native-dist.mjs +386 -0
  123. package/dist/token-goat-chunk-4JJBFT7V.mjs +0 -20
  124. package/dist/token-goat-chunk-5NNYIUGV.mjs +0 -143
  125. package/dist/token-goat-chunk-6DQNNFJ6.mjs +0 -294
  126. package/dist/token-goat-chunk-7MAFDRVR.mjs +0 -47
  127. package/dist/token-goat-chunk-BCN2YQC6.mjs +0 -32
  128. package/dist/token-goat-chunk-D7GHQKQD.mjs +0 -30
  129. package/dist/token-goat-chunk-GMOUBOX4.mjs +0 -386
  130. package/dist/token-goat-chunk-IFORDBGC.mjs +0 -192
  131. package/dist/token-goat-chunk-JXK2HQXS.mjs +0 -318
  132. package/dist/token-goat-chunk-L7SDVGBT.mjs +0 -430
  133. package/dist/token-goat-chunk-MMLMALWK.mjs +0 -1381
  134. package/dist/token-goat-chunk-MVSWBNMD.mjs +0 -1985
@@ -1,130 +1,40 @@
1
1
  import { createRequire as __cjsRequire } from 'node:module';
2
2
  const require = __cjsRequire(import.meta.url);
3
+ import {
4
+ KNOWN_HARNESS_NAMES
5
+ } from "./token-goat-chunk-U4N3BN2W.mjs";
3
6
  import {
4
7
  registerReset
5
- } from "./token-goat-chunk-EEIDFMEM.mjs";
8
+ } from "./token-goat-chunk-YZAAZU2S.mjs";
9
+ import {
10
+ FALSY_ENV_VALUES,
11
+ TRUTHY_ENV_VALUES,
12
+ envBool,
13
+ envInt,
14
+ envStr,
15
+ envStrList
16
+ } from "./token-goat-chunk-IVE6U7KV.mjs";
6
17
  import {
7
- ENV_KEYS,
8
18
  atomicWriteText,
9
- canonicalize,
10
- configPath,
11
19
  decodeSource,
12
20
  extractErrorMessage,
13
- foldPath,
14
- projectConfigPath,
15
21
  runGit
16
- } from "./token-goat-chunk-L45ZQRT7.mjs";
22
+ } from "./token-goat-chunk-GOLEOXZP.mjs";
23
+ import {
24
+ canonicalize,
25
+ foldPath
26
+ } from "./token-goat-chunk-AM5V6GSX.mjs";
17
27
  import {
18
28
  normalizeDarwinSystemAlias
19
- } from "./token-goat-chunk-NMTKNYGF.mjs";
29
+ } from "./token-goat-chunk-FNFBKLRD.mjs";
30
+ import {
31
+ configPath,
32
+ projectConfigPath
33
+ } from "./token-goat-chunk-VES7EL7O.mjs";
20
34
  import {
21
35
  init_define_import_meta_env
22
36
  } from "./token-goat-chunk-A37V4PBF.mjs";
23
37
 
24
- // src/bridges/registry.ts
25
- init_define_import_meta_env();
26
- var KNOWN_HARNESS_NAMES = /* @__PURE__ */ new Set([
27
- "claudecode",
28
- "codex",
29
- "opencode",
30
- "gemini",
31
- "hermes",
32
- "openclaw",
33
- "pi",
34
- "copilot_cli",
35
- "grok",
36
- "qwen",
37
- "kimi",
38
- "vscode",
39
- "visualstudio",
40
- "generic"
41
- ]);
42
- function detectHarness() {
43
- const env = process.env;
44
- const override = (env[ENV_KEYS.HARNESS_OVERRIDE] ?? "").toLowerCase().trim();
45
- if (override && KNOWN_HARNESS_NAMES.has(override)) {
46
- return override;
47
- }
48
- if (env["HERMES_SESSION_ID"] || env["HERMES_HOME"]) {
49
- return "hermes";
50
- }
51
- if (env["TERM_PROGRAM"] === "claude-code" || env["CLAUDE_CODE_VERSION"] !== void 0 || env["CLAUDE_CODE_SESSION_ID"]) {
52
- return "claudecode";
53
- }
54
- if (env["CODEX_SESSION_ID"] !== void 0 || env["CODEX_SESSION"]) {
55
- return "codex";
56
- }
57
- if (env["OPENCODE_SESSION_ID"] !== void 0 || env["OPENCODE_SESSION"]) {
58
- return "opencode";
59
- }
60
- if (env["GROK_SESSION_ID"] !== void 0) {
61
- return "grok";
62
- }
63
- if (env["OPENCLAW_SESSION_ID"] !== void 0) {
64
- return "openclaw";
65
- }
66
- if (env["ANTHROPIC_API_KEY"]) {
67
- return "claudecode";
68
- }
69
- if (env["OPENAI_API_KEY"] && !env["ANTHROPIC_API_KEY"]) {
70
- return "codex";
71
- }
72
- if ((env["GEMINI_API_KEY"] || env["GOOGLE_API_KEY"]) && !env["ANTHROPIC_API_KEY"]) {
73
- return "gemini";
74
- }
75
- return "generic";
76
- }
77
- var _cached = null;
78
- function getHarnessName() {
79
- if (_cached === null) {
80
- _cached = detectHarness();
81
- }
82
- return _cached;
83
- }
84
- function resetHarnessCache() {
85
- _cached = null;
86
- }
87
- registerReset(resetHarnessCache);
88
-
89
- // src/env.ts
90
- init_define_import_meta_env();
91
- var FALSY_ENV_VALUES = /* @__PURE__ */ new Set(["0", "false", "no", "off"]);
92
- var TRUTHY_ENV_VALUES = /* @__PURE__ */ new Set(["1", "true", "yes", "on"]);
93
- function envStr(key, defaultVal) {
94
- const raw = process.env[key];
95
- if (raw === void 0) return defaultVal;
96
- const trimmed = raw.trim();
97
- return trimmed === "" ? defaultVal : trimmed;
98
- }
99
- function envBool(key, defaultVal) {
100
- const raw = process.env[key];
101
- if (raw === void 0) return defaultVal;
102
- const norm = raw.trim().toLowerCase();
103
- if (norm === "") return defaultVal;
104
- if (TRUTHY_ENV_VALUES.has(norm)) return true;
105
- if (FALSY_ENV_VALUES.has(norm)) return false;
106
- return defaultVal;
107
- }
108
- function envInt(key, defaultVal, min, max) {
109
- const raw = process.env[key];
110
- if (raw === void 0) return defaultVal;
111
- const norm = raw.trim();
112
- if (norm === "") return defaultVal;
113
- if (!/^[+-]?\d+$/.test(norm)) return defaultVal;
114
- const val = parseInt(norm, 10);
115
- if (!Number.isFinite(val)) return defaultVal;
116
- let clamped = val;
117
- if (min !== void 0) clamped = Math.max(min, clamped);
118
- if (max !== void 0) clamped = Math.min(max, clamped);
119
- return clamped;
120
- }
121
- function envStrList(key, defaultVal, delimiter2) {
122
- const raw = process.env[key];
123
- if (raw === void 0) return defaultVal;
124
- const entries = raw.split(delimiter2).map((s) => s.trim()).filter((s) => s !== "");
125
- return entries.length > 0 ? entries : defaultVal;
126
- }
127
-
128
38
  // src/fingerprint.ts
129
39
  init_define_import_meta_env();
130
40
  import { createHash } from "node:crypto";
@@ -137,6 +47,14 @@ function fingerprintContent(content) {
137
47
  function shortFingerprint(content) {
138
48
  return fingerprintContent(content).slice(0, 16);
139
49
  }
50
+ function indexedFileIsGone(filePath) {
51
+ try {
52
+ return !fs.statSync(filePath).isFile();
53
+ } catch (err) {
54
+ const code = err?.code;
55
+ return code === "ENOENT" || code === "ENOTDIR";
56
+ }
57
+ }
140
58
  function fingerprintFile(filePath) {
141
59
  let data;
142
60
  try {
@@ -328,7 +246,7 @@ function getDisplayRoot(explicitRoot) {
328
246
  }
329
247
  registerReset(() => {
330
248
  _displayRootCache = null;
331
- });
249
+ }, { perRequest: true });
332
250
  function isUnderSystemTemp(filePath) {
333
251
  let sysTemp;
334
252
  try {
@@ -361,6 +279,7 @@ function resolveProjectRoot(opts) {
361
279
  // src/config_project.ts
362
280
  init_define_import_meta_env();
363
281
  import * as fs3 from "node:fs";
282
+ import * as path2 from "node:path";
364
283
 
365
284
  // node_modules/smol-toml/dist/index.js
366
285
  init_define_import_meta_env();
@@ -374,107 +293,14 @@ init_define_import_meta_env();
374
293
  // node_modules/smol-toml/dist/primitive.js
375
294
  init_define_import_meta_env();
376
295
 
377
- // node_modules/smol-toml/dist/date.js
378
- init_define_import_meta_env();
379
- var DATE_TIME_RE = /^(\d{4}-\d{2}-\d{2})?[T ]?(?:(\d{2}):\d{2}(?::\d{2}(?:\.\d+)?)?)?(Z|[-+]\d{2}:\d{2})?$/i;
380
- var TomlDate = class _TomlDate extends Date {
381
- #hasDate = false;
382
- #hasTime = false;
383
- #offset = null;
384
- constructor(date) {
385
- let hasDate = true;
386
- let hasTime = true;
387
- let offset = "Z";
388
- if (typeof date === "string") {
389
- let match = date.match(DATE_TIME_RE);
390
- if (match) {
391
- if (!match[1]) {
392
- hasDate = false;
393
- date = `0000-01-01T${date}`;
394
- }
395
- hasTime = !!match[2];
396
- hasTime && date[10] === " " && (date = date.replace(" ", "T"));
397
- if (match[2] && +match[2] > 23) {
398
- date = "";
399
- } else {
400
- offset = match[3] || null;
401
- date = date.toUpperCase();
402
- if (!offset && hasTime)
403
- date += "Z";
404
- }
405
- } else {
406
- date = "";
407
- }
408
- }
409
- super(date);
410
- if (!isNaN(this.getTime())) {
411
- this.#hasDate = hasDate;
412
- this.#hasTime = hasTime;
413
- this.#offset = offset;
414
- }
415
- }
416
- isDateTime() {
417
- return this.#hasDate && this.#hasTime;
418
- }
419
- isLocal() {
420
- return !this.#hasDate || !this.#hasTime || !this.#offset;
421
- }
422
- isDate() {
423
- return this.#hasDate && !this.#hasTime;
424
- }
425
- isTime() {
426
- return this.#hasTime && !this.#hasDate;
427
- }
428
- isValid() {
429
- return this.#hasDate || this.#hasTime;
430
- }
431
- toISOString() {
432
- let iso = super.toISOString();
433
- if (this.isDate())
434
- return iso.slice(0, 10);
435
- if (this.isTime())
436
- return iso.slice(11, 23);
437
- if (this.#offset === null)
438
- return iso.slice(0, -1);
439
- if (this.#offset === "Z")
440
- return iso;
441
- let offset = +this.#offset.slice(1, 3) * 60 + +this.#offset.slice(4, 6);
442
- offset = this.#offset[0] === "-" ? offset : -offset;
443
- let offsetDate = new Date(this.getTime() - offset * 6e4);
444
- return offsetDate.toISOString().slice(0, -1) + this.#offset;
445
- }
446
- static wrapAsOffsetDateTime(jsDate, offset = "Z") {
447
- let date = new _TomlDate(jsDate);
448
- date.#offset = offset;
449
- return date;
450
- }
451
- static wrapAsLocalDateTime(jsDate) {
452
- let date = new _TomlDate(jsDate);
453
- date.#offset = null;
454
- return date;
455
- }
456
- static wrapAsLocalDate(jsDate) {
457
- let date = new _TomlDate(jsDate);
458
- date.#hasTime = false;
459
- date.#offset = null;
460
- return date;
461
- }
462
- static wrapAsLocalTime(jsDate) {
463
- let date = new _TomlDate(jsDate);
464
- date.#hasDate = false;
465
- date.#offset = null;
466
- return date;
467
- }
468
- };
469
-
470
296
  // node_modules/smol-toml/dist/error.js
471
297
  init_define_import_meta_env();
472
298
  function getLineColFromPtr(string, ptr) {
473
- let lines = string.slice(0, ptr).split(/\r\n|\n|\r/g);
299
+ let lines = string.slice(0, ptr).split(/\r?\n/);
474
300
  return [lines.length, lines.pop().length + 1];
475
301
  }
476
302
  function makeCodeBlock(string, line, column) {
477
- let lines = string.split(/\r\n|\n|\r/g);
303
+ let lines = string.split(/\r?\n/);
478
304
  let codeblock = "";
479
305
  let numberLen = (Math.log10(line + 1) | 0) + 1;
480
306
  for (let i = line - 1; i <= line + 1; i++) {
@@ -492,7 +318,7 @@ function makeCodeBlock(string, line, column) {
492
318
  }
493
319
  return codeblock;
494
320
  }
495
- var TomlError = class extends Error {
321
+ var TomlError = class _TomlError extends Error {
496
322
  line;
497
323
  column;
498
324
  codeblock;
@@ -506,70 +332,15 @@ ${codeblock}`, options);
506
332
  this.column = column;
507
333
  this.codeblock = codeblock;
508
334
  }
509
- };
510
-
511
- // node_modules/smol-toml/dist/util.js
512
- init_define_import_meta_env();
513
- function indexOfNewline(str, start = 0) {
514
- let idx = str.indexOf("\n", start);
515
- if (str.charCodeAt(idx - 1) === 13)
516
- idx--;
517
- return idx;
518
- }
519
- function skipComment(ctx) {
520
- for (; ctx.p < ctx.s.length; ctx.p++) {
521
- let c = ctx.s.charCodeAt(ctx.p);
522
- if (c === 10)
523
- break;
524
- if (c === 13 && ctx.s.charCodeAt(ctx.p + 1) === 10) {
525
- ctx.p++;
526
- break;
527
- }
528
- if (c < 32 && c !== 9 || c === 127) {
529
- throw new TomlError("control characters are not allowed in comments", {
530
- toml: ctx.s,
531
- ptr: ctx.p
532
- });
533
- }
534
- }
535
- }
536
- function skipVoid(ctx, banNewLines, banComments) {
537
- let c;
538
- while (1) {
539
- while ((c = ctx.s.charCodeAt(ctx.p)) === 32 || c === 9 || !banNewLines && (c === 10 || c === 13 && ctx.s.charCodeAt(ctx.p + 1) === 10))
540
- ctx.p++;
541
- if (banComments || c !== 35)
542
- break;
543
- skipComment(ctx);
335
+ /** @internal */
336
+ static x(message, ctx, ptr) {
337
+ throw new _TomlError(message, { toml: ctx.s, ptr: ptr ?? ctx.p });
544
338
  }
545
- }
546
- function skipUntil(ctx, sep, end) {
547
- let ptr = ctx.p;
548
- if (!end) {
549
- ptr = indexOfNewline(ctx.s, ptr);
550
- ctx.p = ptr < 0 ? ctx.s.length : ptr;
551
- return;
552
- }
553
- for (; ctx.p < ctx.s.length; ctx.p++) {
554
- let c = ctx.s.charCodeAt(ctx.p);
555
- if (c === 35) {
556
- skipComment(ctx);
557
- } else if (c === end || c === sep) {
558
- return;
559
- }
560
- }
561
- throw new TomlError("cannot find end of structure", {
562
- toml: ctx.s,
563
- ptr
564
- });
565
- }
339
+ };
566
340
 
567
341
  // node_modules/smol-toml/dist/primitive.js
568
- var INT_REGEX = /^((0x[0-9a-fA-F](_?[0-9a-fA-F])*)|(([+-]|0[ob])?\d(_?\d)*))$/;
569
- var FLOAT_REGEX = /^[+-]?\d(_?\d)*(\.\d(_?\d)*)?([eE][+-]?\d(_?\d)*)?$/;
570
- var LEADING_ZERO = /^[+-]?0[0-9_]/;
571
342
  function parseString(ctx) {
572
- let start = ctx.p;
343
+ let startPtr = ctx.p;
573
344
  let c = ctx.s.charCodeAt(ctx.p++);
574
345
  let first = c;
575
346
  let isLiteral = c === 39;
@@ -588,10 +359,7 @@ function parseString(ctx) {
588
359
  if (isMultiline && (c === 10 || c === 13 && ctx.s.charCodeAt(ctx.p + 1) === 10)) {
589
360
  state = state && 3;
590
361
  } else if (c < 32 && c !== 9 || c === 127) {
591
- throw new TomlError("control characters are not allowed in strings", {
592
- toml: ctx.s,
593
- ptr: ctx.p
594
- });
362
+ TomlError.x("control characters are not allowed in strings", ctx);
595
363
  } else if ((!state || state === 3) && c === first && (!isMultiline || ctx.s.charCodeAt(ctx.p + 1) === first && ctx.s.charCodeAt(ctx.p + 2) === first)) {
596
364
  if (isMultiline) {
597
365
  if (ctx.s.charCodeAt(ctx.p + 3) === first)
@@ -599,8 +367,10 @@ function parseString(ctx) {
599
367
  if (ctx.s.charCodeAt(ctx.p + 3) === first)
600
368
  ctx.p++;
601
369
  }
602
- if (!state)
603
- parsed += ctx.s.slice(sliceStart, ctx.p);
370
+ if (!state) {
371
+ let s = ctx.s.slice(sliceStart, ctx.p);
372
+ parsed = parsed ? parsed + s : s;
373
+ }
604
374
  ctx.p += isMultiline ? 3 : 1;
605
375
  return parsed;
606
376
  } else if (!state) {
@@ -610,10 +380,11 @@ function parseString(ctx) {
610
380
  }
611
381
  } else if (state === 1) {
612
382
  if (c === 120 || c === 117 || c === 85) {
383
+ let errPtr = ctx.p++ - 1;
613
384
  let value = 0;
614
385
  let len = c === 120 ? 2 : c === 117 ? 4 : 8;
615
386
  for (let j = 0; j < len; j++, ctx.p++) {
616
- let hex = ctx.s.charCodeAt(ctx.p + 1);
387
+ let hex = ctx.s.charCodeAt(ctx.p);
617
388
  let digit = (
618
389
  /* 0-9 */
619
390
  hex >= 48 && hex <= 57 ? hex - 48 : (
@@ -625,16 +396,16 @@ function parseString(ctx) {
625
396
  )
626
397
  );
627
398
  if (digit < 0)
628
- throw new TomlError("invalid non-hex character in unicode escape", { toml: ctx.s, ptr: ctx.p + 1 });
399
+ TomlError.x("invalid non-hex character in unicode escape", ctx);
629
400
  value = value << 4 | digit;
630
401
  }
631
402
  if (value < 0 || value > 1114111 || value >= 55296 && value <= 57343) {
632
- throw new TomlError("invalid unicode escape", { toml: ctx.s, ptr: ctx.p });
403
+ TomlError.x("invalid unicode escape", ctx, errPtr);
633
404
  }
634
405
  parsed += String.fromCodePoint(value);
635
- sliceStart = ctx.p + 1;
406
+ sliceStart = ctx.p--;
636
407
  state = 0;
637
- } else if (c === 32 || c === 9) {
408
+ } else if (isMultiline && (c === 32 || c === 9)) {
638
409
  state = 2;
639
410
  } else {
640
411
  if (c === 98)
@@ -654,85 +425,154 @@ function parseString(ctx) {
654
425
  else if (c === 92)
655
426
  parsed += "\\";
656
427
  else
657
- throw new TomlError("unrecognized escape sequence", { toml: ctx.s, ptr: ctx.p });
428
+ TomlError.x("unrecognised escape sequence", ctx);
658
429
  sliceStart = ctx.p + 1;
659
430
  state = 0;
660
431
  }
661
432
  } else if (c !== 32 && c !== 9) {
662
- if (state === 2) {
663
- throw new TomlError("invalid escape: only line-ending whitespace may be escaped", {
664
- toml: ctx.s,
665
- ptr: sliceStart
666
- });
667
- }
433
+ if (state === 2)
434
+ TomlError.x("invalid escape: only line-ending whitespace may be escaped", ctx, sliceStart);
668
435
  state = !isLiteral && c === 92 ? 1 : 0;
669
436
  sliceStart = ctx.p;
670
437
  }
671
438
  }
672
- throw new TomlError("unfinished string", { toml: ctx.s, ptr: start });
673
- }
674
- function sliceAndTrimEndOf(ctx, start, end) {
675
- let value = ctx.s.slice(start, end);
676
- let commentIdx = value.indexOf("#");
677
- if (commentIdx > 0) {
678
- skipComment({ s: value, p: commentIdx, d: 0 });
679
- value = value.slice(0, commentIdx);
680
- }
681
- return value.trimEnd();
682
- }
683
- function parseValue(ctx, integersAsBigInt, end) {
684
- let ptr = ctx.p;
685
- let err = { toml: ctx.s, ptr };
686
- skipUntil(ctx, 44, end);
687
- let value = sliceAndTrimEndOf(ctx, ptr, ctx.p);
688
- if (!value)
689
- throw new TomlError("incomplete declaration: value expected", err);
690
- if (value === "-inf")
691
- return -Infinity;
692
- if (value === "inf" || value === "+inf")
693
- return Infinity;
694
- if (value === "nan" || value === "+nan" || value === "-nan")
695
- return NaN;
696
- if (value === "-0")
697
- return integersAsBigInt ? 0n : 0;
698
- let isInt = INT_REGEX.test(value);
699
- if (isInt || FLOAT_REGEX.test(value)) {
700
- if (LEADING_ZERO.test(value)) {
701
- throw new TomlError("leading zeroes are not allowed", err);
702
- }
703
- value = value.replace(/_/g, "");
704
- let numeric = +value;
705
- if (isNaN(numeric)) {
706
- throw new TomlError("invalid number", err);
707
- }
708
- if (isInt) {
709
- if ((isInt = !Number.isSafeInteger(numeric)) && !integersAsBigInt) {
710
- throw new TomlError("integer value cannot be represented losslessly", err);
439
+ TomlError.x("unfinished string", ctx, startPtr);
440
+ }
441
+
442
+ // node_modules/smol-toml/dist/extract.js
443
+ init_define_import_meta_env();
444
+
445
+ // node_modules/smol-toml/dist/date.js
446
+ init_define_import_meta_env();
447
+ var DATE_TIME_RE = /^(\d{4}-\d{2}-\d{2})?[Tt ]?(?:(\d{2}):\d{2}(?::\d{2}(?:\.\d+)?)?)?(Z|z|[-+]\d{2}:\d{2})?$/i;
448
+ var TomlDate = class _TomlDate extends Date {
449
+ #hasDate = false;
450
+ #hasTime = false;
451
+ #offset = null;
452
+ constructor(date, fasttype, unsafeDelim) {
453
+ let hasDate = true;
454
+ let hasTime = true;
455
+ let offset = "Z";
456
+ let c;
457
+ if (typeof date === "string") {
458
+ if (fasttype)
459
+ prep: {
460
+ if (fasttype < 3) {
461
+ if (+date.slice(11, 13) > 23) {
462
+ date = "";
463
+ break prep;
464
+ }
465
+ if (fasttype === 2) {
466
+ offset = null;
467
+ date += "Z";
468
+ } else if ((c = date.charCodeAt(date.length - 1)) !== 90 && c !== 122) {
469
+ offset = date.slice(date.length - 6);
470
+ }
471
+ if (unsafeDelim)
472
+ date = date.slice(0, 10) + "T" + date.slice(11);
473
+ } else if (fasttype === 4) {
474
+ date = +date.slice(0, 2) > 23 ? "" : `0000-01-01T${date}Z`;
475
+ }
476
+ hasDate = fasttype !== 4;
477
+ hasTime = fasttype !== 3;
478
+ }
479
+ else {
480
+ let match = date.match(DATE_TIME_RE);
481
+ if (match) {
482
+ if (!match[1]) {
483
+ hasDate = false;
484
+ date = `0000-01-01T${date}`;
485
+ }
486
+ hasTime = !!match[2];
487
+ hasTime && date[10] === " " && (date = date.replace(" ", "T"));
488
+ if (match[2] && +match[2] > 23) {
489
+ date = "";
490
+ } else {
491
+ offset = match[3] || null;
492
+ if (!offset && hasTime)
493
+ date += "Z";
494
+ }
495
+ } else {
496
+ date = "";
497
+ }
711
498
  }
712
- if (isInt || integersAsBigInt === true)
713
- numeric = BigInt(value);
714
499
  }
715
- return numeric;
500
+ super(date);
501
+ if (!isNaN(this.getTime())) {
502
+ this.#hasDate = hasDate;
503
+ this.#hasTime = hasTime;
504
+ this.#offset = offset;
505
+ }
716
506
  }
717
- const date = new TomlDate(value);
718
- if (!date.isValid())
719
- throw new TomlError("invalid value", err);
720
- return date;
721
- }
507
+ isDateTime() {
508
+ return this.#hasDate && this.#hasTime;
509
+ }
510
+ isLocal() {
511
+ return !this.#hasDate || !this.#hasTime || !this.#offset;
512
+ }
513
+ isDate() {
514
+ return this.#hasDate && !this.#hasTime;
515
+ }
516
+ isTime() {
517
+ return this.#hasTime && !this.#hasDate;
518
+ }
519
+ isValid() {
520
+ return this.#hasDate || this.#hasTime;
521
+ }
522
+ toISOString() {
523
+ let iso = super.toISOString();
524
+ if (this.isDate())
525
+ return iso.slice(0, 10);
526
+ if (this.isTime())
527
+ return iso.slice(11, 23);
528
+ if (this.#offset === null)
529
+ return iso.slice(0, -1);
530
+ if (this.#offset === "Z" || this.#offset === "z")
531
+ return iso;
532
+ let offset = +this.#offset.slice(1, 3) * 60 + +this.#offset.slice(4, 6);
533
+ offset = this.#offset[0] === "-" ? offset : -offset;
534
+ let offsetDate = new Date(this.getTime() - offset * 6e4);
535
+ return offsetDate.toISOString().slice(0, -1) + this.#offset;
536
+ }
537
+ static wrapAsOffsetDateTime(jsDate, offset = "Z") {
538
+ let date = new _TomlDate(jsDate);
539
+ date.#offset = offset;
540
+ return date;
541
+ }
542
+ static wrapAsLocalDateTime(jsDate) {
543
+ let date = new _TomlDate(jsDate);
544
+ date.#offset = null;
545
+ return date;
546
+ }
547
+ static wrapAsLocalDate(jsDate) {
548
+ let date = new _TomlDate(jsDate);
549
+ date.#hasTime = false;
550
+ date.#offset = null;
551
+ return date;
552
+ }
553
+ static wrapAsLocalTime(jsDate) {
554
+ let date = new _TomlDate(jsDate);
555
+ date.#hasDate = false;
556
+ date.#offset = null;
557
+ return date;
558
+ }
559
+ };
722
560
 
723
561
  // node_modules/smol-toml/dist/extract.js
724
- init_define_import_meta_env();
725
- function extractValue(ctx, end, integersAsBigInt) {
726
- let ptr = ctx.p;
727
- let c = ctx.s.charCodeAt(ptr);
562
+ function isDigit(char, base = 10) {
563
+ return base === 16 ? char > 47 && char < 58 || char > 64 && char < 71 || char > 96 && char < 103 : char > 47 && char < 48 + base;
564
+ }
565
+ function isEndOfValue(char, delim) {
566
+ return char === 32 || char === 9 || char === 10 || char === 13 || // Structure end or next value delimiter
567
+ delim && (char === delim || char === 44) || // Comment
568
+ char === 35;
569
+ }
570
+ function extractValue(ctx, end) {
571
+ let errPtr = ctx.p;
572
+ let c = ctx.s.charCodeAt(ctx.p);
728
573
  if (c === 91 || c === 123) {
729
- if (!ctx.d--) {
730
- throw new TomlError("document contains excessively nested structures. aborting.", {
731
- toml: ctx.s,
732
- ptr
733
- });
734
- }
735
- let value = c === 91 ? parseArray(ctx, integersAsBigInt) : parseInlineTable(ctx, integersAsBigInt);
574
+ ctx.d-- || TomlError.x("document contains excessively nested structures. aborting.", ctx);
575
+ let value = c === 91 ? parseArray(ctx) : parseInlineTable(ctx);
736
576
  ctx.d++;
737
577
  return value;
738
578
  }
@@ -741,90 +581,263 @@ function extractValue(ctx, end, integersAsBigInt) {
741
581
  }
742
582
  if (c === 116) {
743
583
  if (ctx.s.charCodeAt(++ctx.p) !== 114 || ctx.s.charCodeAt(++ctx.p) !== 117 || ctx.s.charCodeAt(++ctx.p) !== 101)
744
- throw new TomlError("invalid value", { toml: ctx.s, ptr });
745
- ctx.p++;
746
- return true;
584
+ TomlError.x("invalid value", ctx, errPtr);
585
+ return ctx.p++, true;
747
586
  }
748
587
  if (c === 102) {
749
588
  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)
750
- throw new TomlError("invalid value", { toml: ctx.s, ptr });
751
- ctx.p++;
752
- return false;
589
+ TomlError.x("invalid value", ctx, errPtr);
590
+ return ctx.p++, false;
591
+ }
592
+ if (c === 43 || c === 45) {
593
+ return parseNumber(ctx, ctx.p, ctx.s.charCodeAt(++ctx.p), 44 - c, end);
594
+ }
595
+ if (ctx.s.charCodeAt(ctx.p + 4) === 45 && ctx.s.charCodeAt(ctx.p + 7) === 45) {
596
+ return parseDate(ctx, c, end);
597
+ }
598
+ if (ctx.s.charCodeAt(ctx.p + 2) === 58) {
599
+ return parseTime(ctx, c, end);
600
+ }
601
+ return parseNumber(ctx, ctx.p, c, 0, end);
602
+ }
603
+ function parseNumber(ctx, startPtr, startChr, sign, endChr) {
604
+ let c = startChr;
605
+ let state = 0;
606
+ let hasUnderscores = false;
607
+ if (c === 105) {
608
+ if (ctx.s.charCodeAt(++ctx.p) !== 110 || ctx.s.charCodeAt(++ctx.p) !== 102)
609
+ TomlError.x("invalid value", ctx, startPtr);
610
+ return ctx.p++, (sign || 1) / 0;
611
+ }
612
+ if (c === 110) {
613
+ if (ctx.s.charCodeAt(++ctx.p) !== 97 || ctx.s.charCodeAt(++ctx.p) !== 110)
614
+ TomlError.x("invalid value", ctx, startPtr);
615
+ return ctx.p++, NaN;
616
+ }
617
+ if (c === 48) {
618
+ if (++ctx.p >= ctx.s.length || isEndOfValue(c = ctx.s.charCodeAt(ctx.p), endChr))
619
+ return ctx.bi === true ? 0n : 0;
620
+ if (!sign) {
621
+ if (c === 120)
622
+ return parseIntegerBaseN(ctx, startPtr, 16, endChr);
623
+ else if (c === 98)
624
+ return parseIntegerBaseN(ctx, startPtr, 2, endChr);
625
+ else if (c === 111)
626
+ return parseIntegerBaseN(ctx, startPtr, 8, endChr);
627
+ }
628
+ if (c === 46)
629
+ state = 2;
630
+ else if (c === 101 || c === 69)
631
+ state = 4;
632
+ else
633
+ TomlError.x("illegal leading zero", ctx, startPtr);
634
+ } else if (!isDigit(c))
635
+ TomlError.x("invalid value", ctx, startPtr);
636
+ while (++ctx.p < ctx.s.length && (c = ctx.s.charCodeAt(ctx.p), !isEndOfValue(c, endChr))) {
637
+ if (!state)
638
+ state = 1;
639
+ if (c === 95) {
640
+ if (!(state & 1))
641
+ TomlError.x("illegal underscore", ctx);
642
+ state += 11;
643
+ hasUnderscores = true;
644
+ } else if (state === 1 && c === 46)
645
+ state = 2;
646
+ else if ((state === 1 || state === 3) && (c === 101 || c === 69))
647
+ state = 4;
648
+ else if (state === 4 && (c === 43 || c === 45)) {
649
+ } else if (!isDigit(c))
650
+ TomlError.x(`illegal character in numeric literal`, ctx);
651
+ else if (state > 9)
652
+ state -= 11;
653
+ else if (!(state & 1))
654
+ state++;
655
+ }
656
+ if (!state) {
657
+ let val = (startChr - 48) * (sign || 1);
658
+ return ctx.bi === true ? BigInt(val) : val;
659
+ }
660
+ if (!(state & 1))
661
+ TomlError.x("unfinished numeric value", ctx, startPtr);
662
+ let str = ctx.s.slice(startPtr, ctx.p);
663
+ if (hasUnderscores)
664
+ str = str.replaceAll("_", "");
665
+ return state > 1 ? parseFloat(str) : parseInteger(ctx, str, 10, startPtr);
666
+ }
667
+ function parseIntegerBaseN(ctx, startPtr, base, endChr) {
668
+ let c, underscore = 1;
669
+ while (++ctx.p < ctx.s.length && (c = ctx.s.charCodeAt(ctx.p), !isEndOfValue(c, endChr))) {
670
+ if (c === 95) {
671
+ if (underscore & 1)
672
+ TomlError.x("illegal underscore", ctx);
673
+ underscore = 3;
674
+ } else if (!isDigit(c, base))
675
+ TomlError.x(`illegal character in numeric literal`, ctx);
676
+ else if (underscore & 1)
677
+ underscore--;
678
+ }
679
+ if (underscore & 1)
680
+ TomlError.x("unfinished numeric value", ctx);
681
+ let str = ctx.s.slice(startPtr + 2, ctx.p);
682
+ if (underscore)
683
+ str = str.replaceAll("_", "");
684
+ return parseInteger(ctx, str, base, startPtr);
685
+ }
686
+ function parseInteger(ctx, str, base, startPtr) {
687
+ if (ctx.bi !== true)
688
+ int: {
689
+ let val = parseInt(str, base);
690
+ if (!Number.isSafeInteger(val)) {
691
+ if (ctx.bi)
692
+ break int;
693
+ TomlError.x("integer value cannot be represented losslessly", ctx, startPtr);
694
+ }
695
+ return val;
696
+ }
697
+ return base === 10 ? BigInt(str) : BigInt((base === 2 ? "0b" : base === 8 ? "0o" : "0x") + str);
698
+ }
699
+ function parseDate(ctx, c, endChr) {
700
+ let startPtr = ctx.p++, unsafeSeparator;
701
+ if (!isDigit(c) || !isDigit(ctx.s.charCodeAt(ctx.p++)) || !isDigit(ctx.s.charCodeAt(ctx.p++)) || !isDigit(ctx.s.charCodeAt(ctx.p++))) {
702
+ return parseNumber(ctx, ctx.p = startPtr, c, 0, endChr);
703
+ }
704
+ ctx.p += 5;
705
+ if (!isDigit(ctx.s.charCodeAt(ctx.p++)))
706
+ TomlError.x("invalid date-time: date part is malformed", ctx, startPtr);
707
+ if (ctx.p >= ctx.s.length || ((c = ctx.s.charCodeAt(ctx.p)) !== 32 || (unsafeSeparator = true, !isDigit(ctx.s.charCodeAt(ctx.p + 1)))) && c !== 84 && c !== 116) {
708
+ let t2 = ctx.s.slice(startPtr, ctx.p);
709
+ return readDate(ctx, t2, 3, false, startPtr);
710
+ }
711
+ if (ctx.s.charCodeAt(ctx.p += 3) !== 58)
712
+ TomlError.x("invalid date-time: time part is malformed", ctx, startPtr);
713
+ if (ctx.s.charCodeAt(ctx.p += 3) === 58)
714
+ ctx.p += 3;
715
+ if (ctx.s.charCodeAt(ctx.p) === 46)
716
+ while (isDigit(ctx.s.charCodeAt(++ctx.p)))
717
+ ;
718
+ if (c = ctx.s.charCodeAt(ctx.p)) {
719
+ if (c === 90 || c === 122) {
720
+ let t2 = ctx.s.slice(startPtr, ++ctx.p);
721
+ return readDate(ctx, t2, 1, unsafeSeparator, startPtr, "[+00:00]");
722
+ }
723
+ if (c === 43 || c === 45) {
724
+ let t2 = ctx.s.slice(startPtr, ctx.p += 6);
725
+ return readDate(ctx, t2, 1, unsafeSeparator, startPtr, !ctx.ld && "[" + ctx.s.slice(ctx.p - 6, ctx.p) + "]");
726
+ }
727
+ }
728
+ let t = ctx.s.slice(startPtr, ctx.p);
729
+ return readDate(ctx, t, 2, unsafeSeparator, startPtr);
730
+ }
731
+ function parseTime(ctx, c, endChr) {
732
+ let start = ctx.p;
733
+ if (!isDigit(c) || !isDigit(ctx.s.charCodeAt(++ctx.p))) {
734
+ return parseNumber(ctx, --ctx.p, c, 0, endChr);
735
+ }
736
+ if (ctx.s.charCodeAt(ctx.p += 4) === 58)
737
+ ctx.p += 3;
738
+ if (ctx.s.charCodeAt(ctx.p) === 46)
739
+ while (isDigit(ctx.s.charCodeAt(++ctx.p)))
740
+ ;
741
+ let t = ctx.s.slice(start, ctx.p);
742
+ return readDate(ctx, t, 4, false, start);
743
+ }
744
+ function readDate(ctx, str, type, unsafeDelim, errPtr, temporalSuffix) {
745
+ if (ctx.ld) {
746
+ let date = new TomlDate(str, type, unsafeDelim);
747
+ if (!date.isValid())
748
+ TomlError.x("invalid date", ctx, errPtr);
749
+ return date;
750
+ }
751
+ try {
752
+ if (temporalSuffix)
753
+ str += temporalSuffix;
754
+ switch (type) {
755
+ case 1:
756
+ return Temporal.ZonedDateTime.from(str);
757
+ case 2:
758
+ return Temporal.PlainDateTime.from(str);
759
+ case 3:
760
+ return Temporal.PlainDate.from(str);
761
+ case 4:
762
+ return Temporal.PlainTime.from(str);
763
+ }
764
+ } catch (e) {
765
+ TomlError.x(e instanceof Error ? e.message : "" + e, ctx, errPtr);
766
+ }
767
+ }
768
+
769
+ // node_modules/smol-toml/dist/util.js
770
+ init_define_import_meta_env();
771
+ function skipComment(ctx) {
772
+ for (; ctx.p < ctx.s.length; ctx.p++) {
773
+ let c = ctx.s.charCodeAt(ctx.p);
774
+ if (c === 10)
775
+ break;
776
+ if (c === 13 && ctx.s.charCodeAt(ctx.p + 1) === 10) {
777
+ ctx.p++;
778
+ break;
779
+ }
780
+ if (c < 32 && c !== 9 || c === 127) {
781
+ TomlError.x("control characters are not allowed in comments", ctx);
782
+ }
783
+ }
784
+ }
785
+ function skipVoid(ctx, banNewLines, banComments) {
786
+ let c;
787
+ while (ctx.p < ctx.s.length) {
788
+ while (ctx.p < ctx.s.length && ((c = ctx.s.charCodeAt(ctx.p)) === 32 || c === 9 || !banNewLines && (c === 10 || c === 13 && ctx.s.charCodeAt(ctx.p + 1) === 10)))
789
+ ctx.p++;
790
+ if (banComments || c !== 35)
791
+ break;
792
+ skipComment(ctx);
753
793
  }
754
- return parseValue(ctx, integersAsBigInt, end);
755
794
  }
756
795
 
757
796
  // node_modules/smol-toml/dist/struct.js
758
- var KEY_PART_RE = /^[a-zA-Z0-9-_]+[ \t]*$/;
759
- function parseKey(ctx, end = "=") {
760
- let start = ctx.p;
761
- let dot = start - 1;
797
+ function parseKey(ctx, end = 61) {
798
+ let startPtr;
799
+ let state = 0;
762
800
  let parsed = [];
763
- let endPtr = ctx.s.indexOf(end, start);
764
- if (endPtr < 0) {
765
- throw new TomlError("incomplete key-value: cannot find end of key", {
766
- toml: ctx.s,
767
- ptr: start
768
- });
769
- }
801
+ let sliceStart;
802
+ let c = ctx.s.charCodeAt(startPtr = ctx.p);
770
803
  do {
771
- let c = ctx.s.charCodeAt(ctx.p = ++dot);
772
- if (c !== 32 && c !== 9) {
773
- if (c === 34 || c === 39) {
774
- if (c === ctx.s.charCodeAt(ctx.p + 1) && c === ctx.s.charCodeAt(ctx.p + 2)) {
775
- throw new TomlError("multiline strings are not allowed in keys", {
776
- toml: ctx.s,
777
- ptr: ctx.p
778
- });
779
- }
780
- let part = parseString(ctx);
781
- dot = ctx.s.indexOf(".", ctx.p);
782
- let strEnd = ctx.s.slice(ctx.p, dot < 0 || dot > endPtr ? endPtr : dot);
783
- let newLine = indexOfNewline(strEnd);
784
- if (newLine > -1) {
785
- throw new TomlError("newlines are not allowed in keys", {
786
- toml: ctx.s,
787
- ptr: newLine
788
- });
789
- }
790
- if (strEnd.trimStart()) {
791
- throw new TomlError("found extra tokens after the string part", {
792
- toml: ctx.s,
793
- ptr: ctx.p
794
- });
795
- }
796
- if (endPtr < ctx.p) {
797
- endPtr = ctx.s.indexOf(end, ctx.p);
798
- if (endPtr < 0) {
799
- throw new TomlError("incomplete key-value: cannot find end of key", {
800
- toml: ctx.s,
801
- ptr: start
802
- });
803
- }
804
- }
805
- parsed.push(part);
806
- } else {
807
- dot = ctx.s.indexOf(".", ctx.p);
808
- let part = ctx.s.slice(ctx.p, dot < 0 || dot > endPtr ? endPtr : dot);
809
- if (!KEY_PART_RE.test(part)) {
810
- throw new TomlError("only letter, numbers, dashes and underscores are allowed in keys", {
811
- toml: ctx.s,
812
- ptr: ctx.p
813
- });
814
- }
815
- parsed.push(part.trimEnd());
804
+ if (c === end) {
805
+ if (!state)
806
+ TomlError.x("unexpected end of key", ctx);
807
+ if (state === 1)
808
+ parsed.push(ctx.s.slice(sliceStart, ctx.p));
809
+ return ctx.p++, parsed;
810
+ } else if (c === 46) {
811
+ if (!state)
812
+ TomlError.x("illegal empty bare key", ctx);
813
+ if (state === 1)
814
+ parsed.push(ctx.s.slice(sliceStart, ctx.p));
815
+ state = 0;
816
+ } else if (!state && (c === 34 || c === 39)) {
817
+ if (c === ctx.s.charCodeAt(ctx.p + 1) && c === ctx.s.charCodeAt(ctx.p + 2))
818
+ TomlError.x("illegal quoted key: multiline strings are not allowed", ctx);
819
+ parsed.push(parseString(ctx));
820
+ state = 2;
821
+ ctx.p--;
822
+ } else if (c === 32 || c === 9) {
823
+ if (state === 1) {
824
+ parsed.push(ctx.s.slice(sliceStart, ctx.p));
825
+ state = 2;
816
826
  }
827
+ } else if (state === 2 || c < 48 && c !== 45 || c > 57 && c < 65 || c > 90 && c < 97 && c !== 95 || c > 122) {
828
+ TomlError.x("illegal character in key", ctx);
829
+ } else if (!state) {
830
+ state = 1;
831
+ sliceStart = ctx.p;
817
832
  }
818
- } while (dot + 1 && dot < endPtr);
819
- ctx.p = endPtr + 1;
820
- skipVoid(ctx, true, true);
821
- return parsed;
833
+ } while (c = ctx.s.charCodeAt(++ctx.p));
834
+ TomlError.x("incomplete key-value: cannot find end of key", ctx, startPtr);
822
835
  }
823
- function parseInlineTable(ctx, integersAsBigInt) {
824
- let res = {};
836
+ function parseInlineTable(ctx) {
837
+ let startPtr = ctx.p++;
838
+ let res = /* @__PURE__ */ Object.create(null);
825
839
  let seen = /* @__PURE__ */ new Set();
826
840
  let c;
827
- ctx.p++;
828
841
  while (ctx.p < ctx.s.length) {
829
842
  skipVoid(ctx);
830
843
  if ((c = ctx.s.charCodeAt(ctx.p)) === 125) {
@@ -834,70 +847,71 @@ function parseInlineTable(ctx, integersAsBigInt) {
834
847
  let k;
835
848
  let t = res;
836
849
  let hasOwn = false;
837
- let p = ctx.p;
850
+ let errPtr = ctx.p;
838
851
  let key = parseKey(ctx);
839
852
  for (let i = 0; i < key.length; i++) {
840
853
  if (i)
841
- t = hasOwn ? t[k] : t[k] = {};
854
+ t = hasOwn ? t[k] : t[k] = /* @__PURE__ */ Object.create(null);
842
855
  k = key[i];
843
856
  if ((hasOwn = Object.hasOwn(t, k)) && (typeof t[k] !== "object" || seen.has(t[k]))) {
844
- throw new TomlError("trying to redefine an already defined value", {
845
- toml: ctx.s,
846
- ptr: p
847
- });
857
+ TomlError.x("trying to redefine an already defined value", ctx, errPtr);
858
+ }
859
+ let unsafe = k === "__proto__";
860
+ if (ctx.uk && (unsafe || k === "constructor")) {
861
+ t = ctx.uk !== 1 && TomlError.x("document contains an unsafe property", ctx, errPtr);
862
+ break;
848
863
  }
849
- if (!hasOwn && k === "__proto__") {
864
+ if (!hasOwn && unsafe) {
850
865
  Object.defineProperty(t, k, { enumerable: true, configurable: true, writable: true });
851
866
  }
852
867
  }
853
868
  if (hasOwn) {
854
- throw new TomlError("trying to redefine an already defined value", {
855
- toml: ctx.s,
856
- ptr: ctx.p
857
- });
869
+ TomlError.x("trying to redefine an already defined value", ctx, errPtr);
858
870
  }
859
- let value = extractValue(ctx, 125, integersAsBigInt);
860
- seen.add(t[k] = value);
871
+ skipVoid(ctx, true, true);
872
+ let value = extractValue(
873
+ ctx,
874
+ 125
875
+ /* } */
876
+ );
877
+ if (t && typeof (t[k] = value) === "object")
878
+ seen.add(value);
861
879
  skipVoid(ctx);
862
880
  if ((c = ctx.s.charCodeAt(ctx.p++)) === 125) {
863
881
  return res;
864
882
  }
865
- if (c !== 44) {
866
- throw new TomlError("expected comma or end of structure", { toml: ctx.s, ptr: ctx.p - 1 });
867
- }
883
+ if (c !== 44)
884
+ TomlError.x("expected comma or end of structure", ctx, ctx.p - 1);
868
885
  }
869
- throw new TomlError("unfinished table encountered", {
870
- toml: ctx.s,
871
- ptr: ctx.p
872
- });
886
+ TomlError.x("unfinished table", ctx, startPtr);
873
887
  }
874
- function parseArray(ctx, integersAsBigInt) {
888
+ function parseArray(ctx) {
889
+ let startPtr = ctx.p++;
875
890
  let res = [];
876
891
  let c;
877
- ctx.p++;
878
892
  while (ctx.p < ctx.s.length) {
879
893
  skipVoid(ctx);
880
894
  if ((c = ctx.s.charCodeAt(ctx.p)) === 93) {
881
895
  ctx.p++;
882
896
  return res;
883
897
  }
884
- res.push(extractValue(ctx, 93, integersAsBigInt));
898
+ res.push(extractValue(
899
+ ctx,
900
+ 93
901
+ /* ] */
902
+ ));
885
903
  skipVoid(ctx);
886
904
  if ((c = ctx.s.charCodeAt(ctx.p++)) === 93) {
887
905
  return res;
888
906
  }
889
- if (c !== 44) {
890
- throw new TomlError("expected comma or end of structure", { toml: ctx.s, ptr: ctx.p - 1 });
891
- }
907
+ if (c !== 44)
908
+ TomlError.x("expected comma or end of structure", ctx, ctx.p - 1);
892
909
  }
893
- throw new TomlError("unfinished array encountered", {
894
- toml: ctx.s,
895
- ptr: ctx.p
896
- });
910
+ TomlError.x("unfinished array", ctx, startPtr);
897
911
  }
898
912
 
899
913
  // node_modules/smol-toml/dist/parse.js
900
- function peekTable(key, table, meta, type) {
914
+ function peekTable(ctx, key, table, meta, type) {
901
915
  let t = table;
902
916
  let m = meta;
903
917
  let k;
@@ -905,7 +919,7 @@ function peekTable(key, table, meta, type) {
905
919
  let state;
906
920
  for (let i = 0; i < key.length; i++) {
907
921
  if (i) {
908
- t = hasOwn ? t[k] : t[k] = {};
922
+ t = hasOwn ? t[k] : t[k] = /* @__PURE__ */ Object.create(null);
909
923
  m = (state = m[k]).c;
910
924
  if (type === 0 && (state.t === 1 || state.t === 2)) {
911
925
  return null;
@@ -921,7 +935,10 @@ function peekTable(key, table, meta, type) {
921
935
  return null;
922
936
  }
923
937
  if (!hasOwn) {
924
- if (k === "__proto__") {
938
+ let unsafe = k === "__proto__";
939
+ if (ctx.uk && (unsafe || k === "constructor"))
940
+ return false;
941
+ if (unsafe) {
925
942
  Object.defineProperty(t, k, { enumerable: true, configurable: true, writable: true });
926
943
  Object.defineProperty(m, k, { enumerable: true, configurable: true, writable: true });
927
944
  }
@@ -929,7 +946,7 @@ function peekTable(key, table, meta, type) {
929
946
  t: i < key.length - 1 && type === 2 ? 3 : type,
930
947
  d: false,
931
948
  i: 0,
932
- c: {}
949
+ c: /* @__PURE__ */ Object.create(null)
933
950
  };
934
951
  }
935
952
  }
@@ -942,43 +959,60 @@ function peekTable(key, table, meta, type) {
942
959
  state.d = true;
943
960
  t[k] = [];
944
961
  }
945
- t[k].push(t = {});
946
- state.c[state.i++] = state = { t: 1, d: false, i: 0, c: {} };
962
+ t[k].push(t = /* @__PURE__ */ Object.create(null));
963
+ state.c[state.i++] = state = { t: 1, d: false, i: 0, c: /* @__PURE__ */ Object.create(null) };
947
964
  }
948
965
  if (state.d) {
949
966
  return null;
950
967
  }
951
968
  state.d = true;
952
969
  if (type === 1) {
953
- t = hasOwn ? t[k] : t[k] = {};
970
+ t = hasOwn ? t[k] : t[k] = /* @__PURE__ */ Object.create(null);
954
971
  } else if (type === 0 && hasOwn) {
955
972
  return null;
956
973
  }
957
974
  return [k, t, state.c];
958
975
  }
959
- function parse(toml, { maxDepth = 1e3, integersAsBigInt } = {}) {
960
- let ctx = { s: toml, p: 0, d: maxDepth };
961
- let res = {};
962
- let meta = {};
976
+ function validateTablePeek(ctx, peek, ptr) {
977
+ if (peek === null || ctx.uk === 2)
978
+ TomlError.x(peek === null ? "trying to redefine an already defined table or value" : "document contains an unsafe property", ctx, ptr);
979
+ }
980
+ function parse(toml, options = {}) {
981
+ let ctx = {
982
+ s: toml,
983
+ p: 0,
984
+ d: options.maxDepth ?? 1e3,
985
+ bi: options.integersAsBigInt ?? false,
986
+ ld: options.useLegacyDate ?? true,
987
+ uk: options.unsafeKeyBehaviour === "throw" ? 2 : options.unsafeKeyBehaviour === "drop" ? 1 : 0
988
+ };
989
+ let res = /* @__PURE__ */ Object.create(null);
990
+ let meta = /* @__PURE__ */ Object.create(null);
963
991
  let tmp;
992
+ let skipping = false;
964
993
  let tbl = res;
965
994
  let m = meta;
995
+ if (toml.charCodeAt(0) === 65279)
996
+ ctx.p++;
966
997
  skipVoid(ctx);
967
998
  while (ctx.p < toml.length) {
968
999
  if (toml.charCodeAt(ctx.p) === 91) {
969
1000
  let isTableArray = toml.charCodeAt(++ctx.p) === 91;
970
1001
  tmp = ctx.p += +isTableArray;
971
- let k = parseKey(ctx, "]");
1002
+ skipping = false;
1003
+ let k = parseKey(
1004
+ ctx,
1005
+ 93
1006
+ /* ] */
1007
+ );
972
1008
  if (isTableArray) {
973
- if (toml.charCodeAt(ctx.p - 1) !== 93) {
974
- throw new TomlError("expected end of table declaration", {
975
- toml,
976
- ptr: ctx.p - 1
977
- });
1009
+ if (toml.charCodeAt(ctx.p) !== 93) {
1010
+ TomlError.x("expected end of table array declaration", ctx);
978
1011
  }
979
1012
  ctx.p++;
980
1013
  }
981
1014
  let p = peekTable(
1015
+ ctx,
982
1016
  k,
983
1017
  res,
984
1018
  meta,
@@ -986,37 +1020,33 @@ function parse(toml, { maxDepth = 1e3, integersAsBigInt } = {}) {
986
1020
  /* Type.EXPLICIT */
987
1021
  );
988
1022
  if (!p) {
989
- throw new TomlError("trying to redefine an already defined table or value", {
990
- toml,
991
- ptr: tmp
992
- });
1023
+ validateTablePeek(ctx, p, tmp);
1024
+ skipping = true;
1025
+ } else {
1026
+ m = p[2];
1027
+ tbl = p[1];
993
1028
  }
994
- m = p[2];
995
- tbl = p[1];
996
1029
  } else {
997
1030
  tmp = ctx.p;
998
1031
  let k = parseKey(ctx);
999
1032
  let p = peekTable(
1033
+ ctx,
1000
1034
  k,
1001
1035
  tbl,
1002
1036
  m,
1003
1037
  0
1004
1038
  /* Type.DOTTED */
1005
1039
  );
1006
- if (!p) {
1007
- throw new TomlError("trying to redefine an already defined table or value", {
1008
- toml,
1009
- ptr: tmp
1010
- });
1011
- }
1012
- p[1][p[0]] = extractValue(ctx, void 0, integersAsBigInt);
1040
+ if (!p && !skipping)
1041
+ validateTablePeek(ctx, p, tmp);
1042
+ skipVoid(ctx, true, true);
1043
+ let v = extractValue(ctx, void 0);
1044
+ if (p && !skipping)
1045
+ p[1][p[0]] = v;
1013
1046
  }
1014
1047
  skipVoid(ctx, true);
1015
- if (ctx.p < toml.length && (tmp = toml.charCodeAt(ctx.p)) !== 10 && tmp !== 13) {
1016
- throw new TomlError("each key-value declaration must be followed by an end-of-line", {
1017
- toml,
1018
- ptr: ctx.p
1019
- });
1048
+ if (ctx.p < toml.length && (tmp = toml.charCodeAt(ctx.p)) !== 10 && (tmp !== 13 || toml.charCodeAt(ctx.p + 1) !== 10)) {
1049
+ TomlError.x("each key-value declaration must be followed by an end-of-line", ctx);
1020
1050
  }
1021
1051
  skipVoid(ctx);
1022
1052
  }
@@ -1026,16 +1056,27 @@ function parse(toml, { maxDepth = 1e3, integersAsBigInt } = {}) {
1026
1056
  // node_modules/smol-toml/dist/stringify.js
1027
1057
  init_define_import_meta_env();
1028
1058
  var BARE_KEY = /^[a-z0-9-_]+$/i;
1059
+ var HAS_WELLFORMED = !!"".isWellFormed;
1029
1060
  function extendedTypeOf(obj) {
1030
1061
  let type = typeof obj;
1031
1062
  if (type === "object") {
1032
1063
  if (Array.isArray(obj))
1033
1064
  return "array";
1034
- if (typeof obj?.getUTCDate === "function" && obj instanceof Date)
1065
+ if (typeof obj.getUTCDate === "function" && obj instanceof Date)
1035
1066
  return "date";
1036
- if (globalThis.Temporal && // check for the 'since' property as an early bailout that avoids running all 5 instanceof checks
1037
- typeof obj?.since === "function" && (obj instanceof Temporal.Instant || obj instanceof Temporal.PlainDate || obj instanceof Temporal.PlainDateTime || obj instanceof Temporal.PlainTime || obj instanceof Temporal.ZonedDateTime)) {
1038
- return "temporal";
1067
+ if (globalThis.Temporal) {
1068
+ if (obj.until) {
1069
+ if (obj instanceof Temporal.ZonedDateTime)
1070
+ return "temporal/tz+uc";
1071
+ if (obj instanceof Temporal.PlainDateTime || obj instanceof Temporal.PlainDate)
1072
+ return "temporal/uc";
1073
+ if (obj instanceof Temporal.PlainTime || obj instanceof Temporal.Instant)
1074
+ return "temporal";
1075
+ if (obj instanceof Temporal.PlainYearMonth)
1076
+ return "temporal/x";
1077
+ } else if (obj.toPlainDate && obj instanceof Temporal.PlainMonthDay || obj.negated && obj instanceof Temporal.Duration) {
1078
+ return "temporal/x";
1079
+ }
1039
1080
  }
1040
1081
  }
1041
1082
  return type;
@@ -1047,16 +1088,20 @@ function isArrayOfTables(obj) {
1047
1088
  }
1048
1089
  return obj.length != 0;
1049
1090
  }
1091
+ function formatWellFormedStringUnchecked(s) {
1092
+ return JSON.stringify(s).replaceAll("\x7F", "\\u007f");
1093
+ }
1050
1094
  function formatString(s) {
1051
- return JSON.stringify(s).replace(/\x7f/g, "\\u007f");
1095
+ return formatWellFormedStringUnchecked(HAS_WELLFORMED ? s.toWellFormed() : s);
1052
1096
  }
1053
- function stringifyTemporal(temporal) {
1054
- return temporal.toString({
1055
- calendarName: "never",
1056
- timeZoneName: "never"
1057
- });
1097
+ function formatKey(s) {
1098
+ if (BARE_KEY.test(s))
1099
+ return s;
1100
+ if (HAS_WELLFORMED && !s.isWellFormed())
1101
+ throw new RangeError("key contains illegal lone surrogates");
1102
+ return formatWellFormedStringUnchecked(s);
1058
1103
  }
1059
- function stringifyValue(val, type, depth, numberAsFloat) {
1104
+ function stringifyValue(val, type, depth, numberAsFloat, strictTemporal) {
1060
1105
  if (depth === 0) {
1061
1106
  throw new Error("Could not stringify the object: maximum object depth exceeded");
1062
1107
  }
@@ -1073,6 +1118,7 @@ function stringifyValue(val, type, depth, numberAsFloat) {
1073
1118
  return val.toFixed(1);
1074
1119
  case "bigint":
1075
1120
  case "boolean":
1121
+ case "temporal":
1076
1122
  return val.toString();
1077
1123
  case "string":
1078
1124
  return formatString(val);
@@ -1081,14 +1127,37 @@ function stringifyValue(val, type, depth, numberAsFloat) {
1081
1127
  throw new TypeError("cannot serialize invalid date");
1082
1128
  return val.toISOString();
1083
1129
  case "object":
1084
- return stringifyInlineTable(val, depth, numberAsFloat);
1130
+ return stringifyInlineTable(val, depth, numberAsFloat, strictTemporal);
1085
1131
  case "array":
1086
- return stringifyArray(val, depth, numberAsFloat);
1087
- case "temporal":
1088
- return stringifyTemporal(val);
1132
+ return stringifyArray(val, depth, numberAsFloat, strictTemporal);
1133
+ // @ts-expect-error -- intentional fallthrough case
1134
+ case "temporal/tz+uc":
1135
+ if (strictTemporal) {
1136
+ let tz = val.timeZoneId;
1137
+ let tzc = tz.charCodeAt(0);
1138
+ if (
1139
+ // Classic offset
1140
+ tzc !== 43 && tzc !== 45 && // Fast pre-check pass; see below for the actually accepted values
1141
+ (tzc !== 85 && tzc !== 71 && tzc !== 90 && tzc !== 69 || // UTC and its aliases; Temporal implementations don't all canonicalise unfortunately
1142
+ tz !== "UTC" && tz !== "UCT" && tz !== "Universal" && tz !== "Zulu" && // GMT is a TZ but it's for all intents and purposes equivalent to UTC. Safe to downgrade.
1143
+ !tz.startsWith("GMT") && tz !== "Greenwich" && // Etc/* are all safe to downgrade to offset (either UTC, GMT, or offset)
1144
+ !tz.startsWith("Etc/"))
1145
+ ) {
1146
+ throw new TypeError("Temporal objects with an IANA timezone are not allowed in Temporal strict mode");
1147
+ }
1148
+ }
1149
+ case "temporal/uc":
1150
+ if (strictTemporal && val.calendarId !== "iso8601")
1151
+ throw new TypeError("Temporal objects with a non-default calendar are not allowed in Temporal strict mode");
1152
+ return val.toString({
1153
+ calendarName: "never",
1154
+ timeZoneName: "never"
1155
+ });
1156
+ case "temporal/x":
1157
+ throw new TypeError("Unsupported " + val[Symbol.toStringTag]);
1089
1158
  }
1090
1159
  }
1091
- function stringifyInlineTable(obj, depth, numberAsFloat) {
1160
+ function stringifyInlineTable(obj, depth, numberAsFloat, strictTemporal) {
1092
1161
  let keys = Object.keys(obj);
1093
1162
  if (keys.length === 0)
1094
1163
  return "{}";
@@ -1097,13 +1166,11 @@ function stringifyInlineTable(obj, depth, numberAsFloat) {
1097
1166
  let k = keys[i];
1098
1167
  if (i)
1099
1168
  res += ", ";
1100
- res += BARE_KEY.test(k) ? k : formatString(k);
1101
- res += " = ";
1102
- res += stringifyValue(obj[k], extendedTypeOf(obj[k]), depth - 1, numberAsFloat);
1169
+ res += formatKey(k) + " = " + stringifyValue(obj[k], extendedTypeOf(obj[k]), depth - 1, numberAsFloat, strictTemporal);
1103
1170
  }
1104
1171
  return res + " }";
1105
1172
  }
1106
- function stringifyArray(array, depth, numberAsFloat) {
1173
+ function stringifyArray(array, depth, numberAsFloat, strictTemporal) {
1107
1174
  if (array.length === 0)
1108
1175
  return "[]";
1109
1176
  let res = "[ ";
@@ -1113,11 +1180,11 @@ function stringifyArray(array, depth, numberAsFloat) {
1113
1180
  if (array[i] === null || array[i] === void 0) {
1114
1181
  throw new TypeError("arrays cannot contain null or undefined values");
1115
1182
  }
1116
- res += stringifyValue(array[i], extendedTypeOf(array[i]), depth - 1, numberAsFloat);
1183
+ res += stringifyValue(array[i], extendedTypeOf(array[i]), depth - 1, numberAsFloat, strictTemporal);
1117
1184
  }
1118
1185
  return res + " ]";
1119
1186
  }
1120
- function stringifyArrayTable(array, key, depth, numberAsFloat) {
1187
+ function stringifyArrayTable(array, key, depth, numberAsFloat, strictTemporal) {
1121
1188
  if (depth === 0) {
1122
1189
  throw new Error("Could not stringify the object: maximum object depth exceeded");
1123
1190
  }
@@ -1125,11 +1192,11 @@ function stringifyArrayTable(array, key, depth, numberAsFloat) {
1125
1192
  for (let i = 0; i < array.length; i++) {
1126
1193
  res += `${res && "\n"}[[${key}]]
1127
1194
  `;
1128
- res += stringifyTable(0, array[i], key, depth, numberAsFloat);
1195
+ res += stringifyTable(0, array[i], key, depth, numberAsFloat, strictTemporal);
1129
1196
  }
1130
1197
  return res;
1131
1198
  }
1132
- function stringifyTable(tableKey, obj, prefix, depth, numberAsFloat) {
1199
+ function stringifyTable(tableKey, obj, prefix, depth, numberAsFloat, strictTemporal) {
1133
1200
  if (depth === 0) {
1134
1201
  throw new Error("Could not stringify the object: maximum object depth exceeded");
1135
1202
  }
@@ -1143,16 +1210,16 @@ function stringifyTable(tableKey, obj, prefix, depth, numberAsFloat) {
1143
1210
  if (type === "symbol" || type === "function") {
1144
1211
  throw new TypeError(`cannot serialize values of type '${type}'`);
1145
1212
  }
1146
- let key = BARE_KEY.test(k) ? k : formatString(k);
1213
+ let key = formatKey(k);
1147
1214
  if (type === "array" && isArrayOfTables(obj[k])) {
1148
- tables += (tables && "\n") + stringifyArrayTable(obj[k], prefix ? `${prefix}.${key}` : key, depth - 1, numberAsFloat);
1215
+ tables += (tables && "\n") + stringifyArrayTable(obj[k], prefix ? `${prefix}.${key}` : key, depth - 1, numberAsFloat, strictTemporal);
1149
1216
  } else if (type === "object") {
1150
1217
  let tblKey = prefix ? `${prefix}.${key}` : key;
1151
- tables += (tables && "\n") + stringifyTable(tblKey, obj[k], tblKey, depth - 1, numberAsFloat);
1218
+ tables += (tables && "\n") + stringifyTable(tblKey, obj[k], tblKey, depth - 1, numberAsFloat, strictTemporal);
1152
1219
  } else {
1153
1220
  preamble += key;
1154
1221
  preamble += " = ";
1155
- preamble += stringifyValue(obj[k], type, depth, numberAsFloat);
1222
+ preamble += stringifyValue(obj[k], type, depth, numberAsFloat, strictTemporal);
1156
1223
  preamble += "\n";
1157
1224
  }
1158
1225
  }
@@ -1163,11 +1230,11 @@ ${preamble}` : `[${tableKey}]`;
1163
1230
  return preamble && tables ? `${preamble}
1164
1231
  ${tables}` : preamble || tables;
1165
1232
  }
1166
- function stringify(obj, { maxDepth = 1e3, numbersAsFloat = false } = {}) {
1233
+ function stringify(obj, { maxDepth = 1e3, numbersAsFloat = false, strictTemporal = false } = {}) {
1167
1234
  if (extendedTypeOf(obj) !== "object") {
1168
1235
  throw new TypeError("stringify can only be called with an object");
1169
1236
  }
1170
- let str = stringifyTable(0, obj, "", maxDepth, numbersAsFloat);
1237
+ let str = stringifyTable(0, obj, "", maxDepth, numbersAsFloat, strictTemporal);
1171
1238
  if (str[str.length - 1] !== "\n")
1172
1239
  return str + "\n";
1173
1240
  return str;
@@ -1200,6 +1267,7 @@ var PROJECT_LOCKED_KEYS = [
1200
1267
  // 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.
1201
1268
  "indexing.skip_dirs",
1202
1269
  "indexing.skip_files",
1270
+ "indexing.skip_minified",
1203
1271
  "indexing.large_file_skip_kb",
1204
1272
  "indexing.large_file_symbol_only_kb",
1205
1273
  // Same reasoning as the two thresholds above, on the chunk axis: a checked-in `.token-goat.toml` dropping this to 1 would take every file in the repository out of `semantic` for a reviewing agent, and `semantic` would answer "no matches" in the words it uses for a genuine absence.
@@ -1207,12 +1275,14 @@ var PROJECT_LOCKED_KEYS = [
1207
1275
  "indexing.cross_project_symbols",
1208
1276
  // The same blast radius as the indexing keys above, applied to retrieval rather than to what gets indexed: `semantic` drops a dense hit whose distance exceeds this, so a checked-in `.token-goat.toml` setting it near the floor removes this repository's own code from the vector half of every search a reviewing agent runs, and the command then answers "no matches" in the words it uses for a name that genuinely is not there. The keyword pass would still answer, which makes it worse rather than better -- the result looks like a working search. The user's own global config still sets it freely; only the project-supplied layer is refused.
1209
1277
  "semantic.max_distance",
1278
+ // The advisory twin of the floor above: a checked-in `.token-goat.toml` raising it to the 1.2 maximum would make every poor hit read as confident, silencing the one warning that says a result is probably unrelated. The user's own global config still sets it freely.
1279
+ "semantic.weak_distance",
1210
1280
  "worker.blocked_roots",
1211
- // global.db is a machine-wide shared database across every project on the host. A checked-in
1212
- // per-project .token-goat.toml must not be able to lower the size warning threshold or trigger
1213
- // auto-reclaim/purging of embeddings across other repositories sharing the same database.
1281
+ // global.db is a machine-wide shared database across every project on the host. A checked-in per-project .token-goat.toml must not be able to lower the size warning threshold or trigger auto-reclaim/purging of embeddings across other repositories sharing the same database.
1214
1282
  "indexing.max_db_size_mb",
1215
- "indexing.auto_reclaim_embeddings"
1283
+ "indexing.auto_reclaim_embeddings",
1284
+ // Which executable every harness runs on every tool call. `install` writes that choice into user-scope harness configs that every project on the machine then runs, so a checked-in `.token-goat.toml` must not be the layer that makes it. The user's global config and TOKEN_GOAT_NATIVE_HOOKS still set it freely.
1285
+ "hooks.native"
1216
1286
  ];
1217
1287
  var _lastProjectConfigLockedKeys = [];
1218
1288
  function lastProjectConfigLockedKeys() {
@@ -1308,7 +1378,28 @@ function mergeRawConfig(base, override) {
1308
1378
  return merged;
1309
1379
  }
1310
1380
  var _projectRootCache = null;
1381
+ var _projectRootOverride = null;
1382
+ function withConfigProjectRoot(root, fn) {
1383
+ const prior = _projectRootOverride;
1384
+ _projectRootOverride = root;
1385
+ try {
1386
+ return fn();
1387
+ } finally {
1388
+ _projectRootOverride = prior;
1389
+ }
1390
+ }
1391
+ function configProjectRootFor(dir) {
1392
+ const own = findProject(dir);
1393
+ let project = own;
1394
+ while (project !== null) {
1395
+ if (fs3.existsSync(projectConfigPath(project.root))) return project.root;
1396
+ const parent = path2.dirname(project.root);
1397
+ project = parent === project.root ? null : findProject(parent);
1398
+ }
1399
+ return own?.root ?? dir;
1400
+ }
1311
1401
  function resolveConfigProjectRoot() {
1402
+ if (_projectRootOverride !== null) return _projectRootOverride;
1312
1403
  const cwd = process.cwd();
1313
1404
  if (_projectRootCache !== null && _projectRootCache.cwd === cwd) return _projectRootCache.root;
1314
1405
  const project = findProject(cwd);
@@ -1318,7 +1409,7 @@ function resolveConfigProjectRoot() {
1318
1409
  }
1319
1410
  registerReset(() => {
1320
1411
  _projectRootCache = null;
1321
- });
1412
+ }, { perRequest: true });
1322
1413
  function getProjectConfigInfo(projectRoot) {
1323
1414
  const root = projectRoot ?? resolveConfigProjectRoot();
1324
1415
  const p = projectConfigPath(root);
@@ -1349,7 +1440,7 @@ function isAutoTriggerMultiplierExplicit() {
1349
1440
 
1350
1441
  // src/config.ts
1351
1442
  init_define_import_meta_env();
1352
- import * as path2 from "node:path";
1443
+ import * as path3 from "node:path";
1353
1444
 
1354
1445
  // src/own_lookup.ts
1355
1446
  init_define_import_meta_env();
@@ -1377,18 +1468,12 @@ var CONFIG_DEFAULTS = {
1377
1468
  max_lines: 1e3,
1378
1469
  max_bytes: 64 * 1024,
1379
1470
  timeout_seconds: 600,
1380
- // Matches the hardcoded MIN_CACHE_BYTES floor hooks_bash.ts used before this
1381
- // knob was wired to a real consumer, so untouched-config installs see no
1382
- // behavior change now that hooks_bash.ts reads this value instead.
1471
+ // Matches the hardcoded MIN_CACHE_BYTES floor hooks_bash.ts used before this knob was wired to a real consumer, so untouched-config installs see no behavior change now that hooks_bash_post.ts reads this value instead.
1383
1472
  cache_min_bytes: 512,
1384
1473
  cache_max_file_count: 4096,
1385
1474
  cache_max_bytes: 16 * 1024 * 1024,
1386
1475
  cache_max_bytes_per_output: 50 * 1024 * 1024,
1387
- // Measured against the filter test-fixture corpus (424 apply() calls, 298 with
1388
- // bytesSaved > 0): net-of-marker savings (bytesSaved - ~70-79B marker cost) is
1389
- // <= 0 for 130/298 (44%) of "compressed" results and <= 100 for 170/298 (57%),
1390
- // while the real-win half sits at p75=393B / p90=952B net. 100 kills the
1391
- // marker-doesn't-even-pay-for-itself tier without touching genuine wins.
1476
+ // Measured against the filter test-fixture corpus (424 apply() calls, 298 with bytesSaved > 0): net-of-marker savings (bytesSaved - ~70-79B marker cost) is <= 0 for 130/298 (44%) of "compressed" results and <= 100 for 170/298 (57%), while the real-win half sits at p75=393B / p90=952B net. 100 kills the marker-doesn't-even-pay-for-itself tier without touching genuine wins.
1392
1477
  min_net_savings_bytes: 100,
1393
1478
  // 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.
1394
1479
  elide_served_shell_output: true
@@ -1432,20 +1517,10 @@ var CONFIG_DEFAULTS = {
1432
1517
  max_image_pixels: 64e6,
1433
1518
  screenshot_redirect: true,
1434
1519
  ocr_enabled: true,
1435
- // Confidence is Tesseract's own 0-100 mean-word-confidence score. 65 is a deliberately
1436
- // conservative floor: a real screenshot of terminal/code/prose text routinely scores
1437
- // 85+, while a photo with an incidental sign or logo in frame scores much lower and
1438
- // noisier -- padding the threshold below the terminal/code norm still comfortably
1439
- // excludes photographic false positives without needing a second heuristic.
1520
+ // Confidence is Tesseract's own 0-100 mean-word-confidence score. 65 is a deliberately conservative floor: a real screenshot of terminal/code/prose text routinely scores 85+, while a photo with an incidental sign or logo in frame scores much lower and noisier -- padding the threshold below the terminal/code norm still comfortably excludes photographic false positives without needing a second heuristic.
1440
1521
  ocr_min_confidence: 65,
1441
1522
  ocr_lang: DEFAULT_OCR_LANG,
1442
- // Which resolution tier the model being shown the image is on, which decides what its pixels
1443
- // cost. 'standard' (1568px long edge, 1568 visual tokens) is every model before Claude 4.7;
1444
- // 'high' (2576px, 4784 tokens) is 4.7 and later, and bills the same large image up to roughly
1445
- // three times higher. Only the saving *reported* by `token-goat stats` depends on this -- no
1446
- // image is encoded differently -- and 'standard' is the default because it is the floor: it
1447
- // caps the counterfactual at the smaller of the two bills and so can never credit a saving
1448
- // that was not there. Set it to 'high' on a Claude 4.7+ model to see the larger real figure.
1523
+ // Which resolution tier the model being shown the image is on, which decides what its pixels cost. 'standard' (1568px long edge, 1568 visual tokens) is every model before Claude 4.7; 'high' (2576px, 4784 tokens) is 4.7 and later, and bills the same large image up to roughly three times higher. Only the saving *reported* by `token-goat stats` depends on this -- no image is encoded differently -- and 'standard' is the default because it is the floor: it caps the counterfactual at the smaller of the two bills and so can never credit a saving that was not there. Set it to 'high' on a Claude 4.7+ model to see the larger real figure.
1449
1524
  vision_tier: "standard"
1450
1525
  },
1451
1526
  screenshot: {
@@ -1471,33 +1546,24 @@ var CONFIG_DEFAULTS = {
1471
1546
  web_dedup_min_bytes: 200,
1472
1547
  grep_dedup_min_matches: 5,
1473
1548
  glob_dedup_min_matches: 5,
1474
- // Existing on-disk file must have at least this many lines before a Write rewrite is even
1475
- // considered -- rewriting a small file whole is fine, so hooks_write.ts's detector skips
1476
- // comparison entirely below this floor rather than firing on trivial files.
1549
+ // Existing on-disk file must have at least this many lines before a Write rewrite is even considered -- rewriting a small file whole is fine, so hooks_write.ts's detector skips comparison entirely below this floor rather than firing on trivial files.
1477
1550
  write_rewrite_min_lines: 40,
1478
- // Minimum percentage of the existing file's lines that must survive unchanged (by LCS) in
1479
- // the incoming Write content for hooks_write.ts to advise Edit instead. High by design: this
1480
- // is only meant to catch the "mostly untouched, a few lines changed" case, not a genuine
1481
- // rewrite that happens to share some boilerplate.
1551
+ // Minimum percentage of the existing file's lines that must survive unchanged (by LCS) in the incoming Write content for hooks_write.ts to advise Edit instead. High by design: this is only meant to catch the "mostly untouched, a few lines changed" case, not a genuine rewrite that happens to share some boilerplate.
1482
1552
  write_rewrite_unchanged_pct: 75,
1483
1553
  serve_diff_on_reread: true,
1484
1554
  elide_served_lines: true,
1485
1555
  subagent_markdown_first_read_deny: false,
1556
+ agent_scoped_spawn_deny: false,
1486
1557
  backoff_thresholds: [1, 3, 10, 30],
1487
1558
  git_hint_max_ms: 50,
1488
1559
  min_session_hint_savings_bytes: 512,
1489
1560
  pre_skill_advisory: true,
1490
1561
  context_threshold_advisory: true,
1491
1562
  diff_hint_min_tokens_saved: 1e3,
1492
- // Base for the pressure-scaled first-read deny gate in hooks_read.ts (large file, never read
1493
- // before). Matches that gate's long-tuned 500KB threshold at 'cool' context pressure; warm/hot/
1494
- // critical scale it down from there so the same read gets redirected to a surgical read sooner
1495
- // once the context window is nearly full.
1563
+ // Base for the pressure-scaled first-read deny gate in hooks_read.ts (large file, never read before). Matches that gate's long-tuned 500KB threshold at 'cool' context pressure; warm/hot/ critical scale it down from there so the same read gets redirected to a surgical read sooner once the context window is nearly full.
1496
1564
  large_read_redirect_bytes: 512e3,
1497
1565
  reread_deny: true,
1498
- // Matches hooks_read.ts's previously-hardcoded REREAD_DENY_BYTES (50 * 1024) so wiring this
1499
- // key up as the real gate for that logic does not silently change default behavior for
1500
- // existing users -- see the reread_deny/reread_deny_min_bytes fix's commit message.
1566
+ // Matches hooks_read.ts's previously-hardcoded REREAD_DENY_BYTES (50 * 1024) so wiring this key up as the real gate for that logic does not silently change default behavior for existing users -- see the reread_deny/reread_deny_min_bytes fix's commit message.
1501
1567
  reread_deny_min_bytes: 51200,
1502
1568
  stable_doc_compacts: true,
1503
1569
  // 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.
@@ -1513,6 +1579,8 @@ var CONFIG_DEFAULTS = {
1513
1579
  truncated_read_min_lines: 200,
1514
1580
  protect_recent_reads: 4,
1515
1581
  warn_unbalanced_shell_quoting: true,
1582
+ // On. Claude Code's Bash tool on Windows hands the command to Git Bash as a `-c` argument, and the argv quoting plus the MSYS2 runtime's decoding turn every run of two or more backslashes into half as many, so `printf 'a\\nb'` or a `C:\\Users` path arrives changed and nothing says so. Only that pairing is denied: another platform, another harness, or a command without a doubled backslash passes untouched.
1583
+ deny_bash_double_backslash: true,
1516
1584
  prompt_triggers: [],
1517
1585
  log_large_file_hint_outcomes: false,
1518
1586
  cross_session_read_dedup: false,
@@ -1521,8 +1589,9 @@ var CONFIG_DEFAULTS = {
1521
1589
  session_start_reminder: true
1522
1590
  },
1523
1591
  hooks: {
1524
- watchdog_ms: 700,
1525
- latency_budget_ms: 1500
1592
+ latency_budget_ms: 1500,
1593
+ server: true,
1594
+ native: "auto"
1526
1595
  },
1527
1596
  webfetch: {
1528
1597
  allow: [],
@@ -1535,15 +1604,7 @@ var CONFIG_DEFAULTS = {
1535
1604
  worker: {
1536
1605
  blocked_roots: [],
1537
1606
  max_pool_workers: 4,
1538
- // 4, not 2. Measured on a 26-core Windows host with a foreground CPU probe: at `priority`
1539
- // below_normal, 2, 4 and 6 threads are all indistinguishable from an idle machine, including
1540
- // when the indexer and the probe are pinned to the same 4 cores, and including 4 threads pinned
1541
- // to 2 cores, which is genuine oversubscription. The same probe reads -10% at 16 threads and
1542
- // -69% with a 292 ms stall at 4 threads on 2 cores once the priority is normal instead. So the
1543
- // priority below is what keeps the foreground responsive, not this number, and 4 buys a
1544
- // measured 1.77x on indexing for no foreground cost. It stays a cap rather than tracking the
1545
- // core count, because where the platform refuses the priority change (some hardened Linux
1546
- // setups, sandboxes) this is the only thing left holding indexing back.
1607
+ // 4, not 2. Measured on a 26-core Windows host with a foreground CPU probe: at `priority` below_normal, 2, 4 and 6 threads are all indistinguishable from an idle machine, including when the indexer and the probe are pinned to the same 4 cores, and including 4 threads pinned to 2 cores, which is genuine oversubscription. The same probe reads -10% at 16 threads and -69% with a 292 ms stall at 4 threads on 2 cores once the priority is normal instead. So the priority below is what keeps the foreground responsive, not this number, and 4 buys a measured 1.77x on indexing for no foreground cost. It stays a cap rather than tracking the core count, because where the platform refuses the priority change (some hardened Linux setups, sandboxes) this is the only thing left holding indexing back.
1547
1608
  embed_threads: 4,
1548
1609
  priority: "below_normal"
1549
1610
  },
@@ -1554,6 +1615,7 @@ var CONFIG_DEFAULTS = {
1554
1615
  max_chunks_per_file: 600,
1555
1616
  skip_dirs: [],
1556
1617
  skip_files: ["coverage.json", "coverage-final.json"],
1618
+ skip_minified: true,
1557
1619
  embeddings_enabled: true,
1558
1620
  cross_project_symbols: true,
1559
1621
  max_db_size_mb: 1500,
@@ -1591,7 +1653,9 @@ var CONFIG_DEFAULTS = {
1591
1653
  archive_weight: 0.7,
1592
1654
  docs_weight: 0.92,
1593
1655
  // Deliberately loose enough to admit everything this metric produces, which is a measured conclusion rather than a placeholder. Against a large index, 12 genuine questions about code that is present had best hits from 0.635 to 0.813 and 11 off-corpus ones (nonsense strings, digits, a cake recipe) from 0.820 to 1.017, which looks separable at about 0.9. It is not: on a small corpus the nearest genuine match is much further away, and a two-file project in this repo's own suite matches its target at 0.934 -- above that cut and inside the noise band. So the two populations overlap across corpus sizes and no fixed distance tells them apart, while getting it wrong removes real answers and says nothing. Left at the retrieval bound's value so the default filters nothing; it exists to be lowered per-project by someone who has measured their own corpus, and runSemantic says which distance it refused when a lowered value empties the vector half.
1594
- max_distance: 1.2
1656
+ max_distance: 1.2,
1657
+ // Best surviving dense distance above which runSemantic says its closest match is weak. Measured on this repo's index on 2026-09-24: 38 questions about code that is present had best hits from 0.565 to 0.800, and 12 nonsense or off-topic ones from 0.863 to 1.043 (8 questions from other programming domains spread over 0.718-0.952, the low ones landing on code that is genuinely related, so those are not separable by distance), so the cut sits in that gap nearer the noise edge, because a small corpus pushes genuine matches farther out (0.934 in a two-file project, see semantic.max_distance) and a false alarm on a right answer costs more than a missed one. Advisory only: it removes nothing, unlike that floor.
1658
+ weak_distance: 0.85
1595
1659
  }
1596
1660
  };
1597
1661
  function getDefaultConfig(section2) {
@@ -1647,6 +1711,18 @@ function validatedFloat(raw, def, min, max) {
1647
1711
  function validatedVisionTier(raw, def) {
1648
1712
  return raw === "standard" || raw === "high" ? raw : def;
1649
1713
  }
1714
+ function validatedNativeHooksMode(raw, def) {
1715
+ return raw === "auto" || raw === "off" ? raw : def;
1716
+ }
1717
+ function nativeHooksModeFromEnv(raw) {
1718
+ const norm = raw?.trim().toLowerCase() ?? "";
1719
+ if (TRUTHY_ENV_VALUES.has(norm)) return "auto";
1720
+ if (FALSY_ENV_VALUES.has(norm)) return "off";
1721
+ return void 0;
1722
+ }
1723
+ var ENV_VALUE_COERCERS = {
1724
+ "hooks.native": nativeHooksModeFromEnv
1725
+ };
1650
1726
  function validatedOcrLang(raw, def) {
1651
1727
  if (typeof raw !== "string") return def;
1652
1728
  const tokens = raw.split(/[+,;\s]+/).map((s) => s.trim().toLowerCase()).filter(Boolean);
@@ -1716,7 +1792,6 @@ var NUMERIC_FIELD_BOUNDS = {
1716
1792
  "hints.protect_recent_reads": { min: 0, max: 100 },
1717
1793
  "hints.cross_session_read_dedup_ttl_secs": { min: 1, max: 86400 },
1718
1794
  "hints.mcp_dedup_ttl_secs": { min: 1, max: 3600 },
1719
- "hooks.watchdog_ms": { min: 100, max: 3e4 },
1720
1795
  "hooks.latency_budget_ms": { min: 1, max: 6e5 },
1721
1796
  "webfetch.max_file_count": { min: 0, max: 1e7 },
1722
1797
  "webfetch.max_bytes": { min: 0, max: 100 * 1024 * 1024 * 1024 },
@@ -1734,7 +1809,9 @@ var NUMERIC_FIELD_BOUNDS = {
1734
1809
  "semantic.archive_weight": { min: 0.05, max: 1 },
1735
1810
  "semantic.docs_weight": { min: 0.05, max: 1 },
1736
1811
  // Upper bound is DEFAULT_DISTANCE_THRESHOLD, not the metric's own ceiling of 2. An L2 distance between unit vectors cannot exceed 2, so 2 reads like 'admit everything' -- but this floor only ever narrows what searchSemantic already returned, and runSemantic lets that scan keep its own 1.2 bound (see the max_distance comment on SemanticConfig for why the scan is the wrong place for a relevance decision). Anything between 1.2 and 2 was therefore discarded inside the scan before the floor could see it: a user raising this to widen recall got the setting accepted, validated and persisted, and identical results, with no diagnostic able to say why. validatedFloat clamps rather than rejects, so an existing value above the new bound becomes 1.2 and behaves exactly as it already did. The lower bound is not 0: a floor of 0 admits only an exact vector match, which would disable the vector half entirely while `semantic` went on answering in the words it uses for a genuine absence.
1737
- "semantic.max_distance": { min: 0.05, max: 1.2 }
1812
+ "semantic.max_distance": { min: 0.05, max: 1.2 },
1813
+ // Same range as max_distance: both are L2 distances on the scan's own 1.2 ceiling, and a weak line above what the scan can return would never fire.
1814
+ "semantic.weak_distance": { min: 0.05, max: 1.2 }
1738
1815
  };
1739
1816
  function boundsOf(key) {
1740
1817
  const b = ownGet(NUMERIC_FIELD_BOUNDS, key);
@@ -1766,10 +1843,9 @@ var ENUM_FIELD_VALUES = {
1766
1843
  "compression.profile": ["auto", "aggressive", "balanced", "minimal"],
1767
1844
  "compact_assist.harness": ["auto", ...KNOWN_HARNESS_NAMES],
1768
1845
  "image_shrink.ocr_lang": [...SUPPORTED_OCR_LANG_CODES],
1769
- // Deliberately has no entry above `normal`. This table is what `config set` checks; a
1770
- // hand-edited TOML bypasses it, which is why resolveWorkerPriority (process_priority.ts) maps an
1771
- // unrecognized value back to the default rather than trusting whatever the file said.
1772
- "worker.priority": ["below_normal", "low", "normal"]
1846
+ // Deliberately has no entry above `normal`. This table is what `config set` checks; a hand-edited TOML bypasses it, which is why resolveWorkerPriority (process_priority.ts) maps an unrecognized value back to the default rather than trusting whatever the file said.
1847
+ "worker.priority": ["below_normal", "low", "normal"],
1848
+ "hooks.native": ["auto", "off"]
1773
1849
  };
1774
1850
  function validateEnumField(fieldKey, value) {
1775
1851
  if (fieldKey === "image_shrink.ocr_lang") {
@@ -1781,7 +1857,7 @@ function validateEnumField(fieldKey, value) {
1781
1857
  if (!allowed) return void 0;
1782
1858
  return allowed.includes(value) ? void 0 : allowed;
1783
1859
  }
1784
- var ENV_KEYS2 = [
1860
+ var ENV_KEYS = [
1785
1861
  "TOKEN_GOAT_COMPACT_ASSIST",
1786
1862
  "TOKENWISE_COMPACT_ASSIST",
1787
1863
  "TOKEN_GOAT_BASH_COMPRESS",
@@ -1796,7 +1872,6 @@ var ENV_KEYS2 = [
1796
1872
  "TOKEN_GOAT_HINT_JSON_SIDECAR",
1797
1873
  "TOKEN_GOAT_LARGE_READ_BYTES",
1798
1874
  "TOKEN_GOAT_HINT_BUDGET",
1799
- "TOKEN_GOAT_HOOK_WATCHDOG_MS",
1800
1875
  "TOKEN_GOAT_WEB_COMPRESS",
1801
1876
  "TOKEN_GOAT_WORKER_WATCHDOG",
1802
1877
  "TOKEN_GOAT_WORKER_MAX_POOL",
@@ -1815,6 +1890,7 @@ var ENV_KEYS2 = [
1815
1890
  "TOKEN_GOAT_PRE_SKILL",
1816
1891
  "TOKEN_GOAT_ORPHAN_SWEEP",
1817
1892
  "TOKEN_GOAT_WARN_UNBALANCED_SHELL_QUOTING",
1893
+ "TOKEN_GOAT_DENY_BASH_DOUBLE_BACKSLASH",
1818
1894
  "TOKEN_GOAT_LOG_LARGE_FILE_HINT_OUTCOMES",
1819
1895
  "TOKEN_GOAT_CROSS_SESSION_READ_DEDUP",
1820
1896
  "TOKEN_GOAT_CROSS_SESSION_READ_DEDUP_TTL_SECS",
@@ -1831,7 +1907,7 @@ var ENV_KEYS2 = [
1831
1907
  "TOKEN_GOAT_INDEXING_AUTO_RECLAIM_EMBEDDINGS"
1832
1908
  ];
1833
1909
  function allEnvKeys() {
1834
- return [.../* @__PURE__ */ new Set([...ENV_KEYS2, ...Object.values(CONFIG_KEY_ENV_OVERRIDES).flat()])];
1910
+ return [.../* @__PURE__ */ new Set([...ENV_KEYS, ...Object.values(CONFIG_KEY_ENV_OVERRIDES).flat()])];
1835
1911
  }
1836
1912
  function configEnvFingerprint() {
1837
1913
  const snap = {};
@@ -1840,7 +1916,7 @@ function configEnvFingerprint() {
1840
1916
  }
1841
1917
  return JSON.stringify(snap);
1842
1918
  }
1843
- var _cached2 = null;
1919
+ var _cached = null;
1844
1920
  function deepFreeze(value) {
1845
1921
  if (value !== null && typeof value === "object" && !Object.isFrozen(value)) {
1846
1922
  Object.freeze(value);
@@ -1914,7 +1990,9 @@ function resolveConfigKeyLayer(key, effectiveValue, cfg, projectInfo) {
1914
1990
  const envVar = (CONFIG_KEY_ENV_OVERRIDES[key] ?? []).find((name) => process.env[name] !== void 0);
1915
1991
  if (envVar !== void 0) {
1916
1992
  const rawStr = process.env[envVar] ?? "";
1917
- const judged = coerceEnvLike(rawStr, effectiveValue);
1993
+ const coerce = ownGet(ENV_VALUE_COERCERS, key);
1994
+ const special = coerce === void 0 ? void 0 : coerce(rawStr);
1995
+ const judged = coerce === void 0 ? coerceEnvLike(rawStr, effectiveValue) : special === void 0 ? "unusable" : { parsed: special };
1918
1996
  if (judged === null) return { layer: "env", envVar };
1919
1997
  if (judged === "unusable") {
1920
1998
  return { layer: "env-invalid", envVar, rawValue: rawStr, effectiveValue, reason: rawStr.trim() === "" ? "empty" : rejectionReason(key, rawStr, effectiveValue, cfg) };
@@ -1926,6 +2004,10 @@ function resolveConfigKeyLayer(key, effectiveValue, cfg, projectInfo) {
1926
2004
  if (projectInfo.parseError !== null) return { layer: "project-unparsed", path: projectInfo.path, parseError: projectInfo.parseError };
1927
2005
  if (!Object.prototype.hasOwnProperty.call(projectInfo.values, key)) return { layer: "global" };
1928
2006
  const rawValue = projectInfo.values[key];
2007
+ if (PROJECT_LOCKED_SECTIONS.includes(key.split(".")[0] ?? "") || PROJECT_LOCKED_KEYS.includes(key)) {
2008
+ if (rawValueEquals(rawValue, effectiveValue)) return { layer: "global" };
2009
+ return { layer: "project-invalid", path: projectInfo.path, rawValue, effectiveValue, reason: "a security setting, which only the global config or the environment may set" };
2010
+ }
1929
2011
  if (rawValueEquals(rawValue, effectiveValue)) return { layer: "project", path: projectInfo.path };
1930
2012
  return { layer: "project-invalid", path: projectInfo.path, rawValue, effectiveValue, reason: rejectionReason(key, rawValue, effectiveValue, cfg) };
1931
2013
  }
@@ -1938,8 +2020,8 @@ function loadConfig(projectRoot) {
1938
2020
  const { text: projText, readError: projReadError } = readConfigText(projPath);
1939
2021
  const projectContentFp = projText !== null ? shortFingerprint(projText) : "";
1940
2022
  const envFp = configEnvFingerprint();
1941
- if (_cached2 !== null && _cached2.contentFp === contentFp && _cached2.envFp === envFp && _cached2.projectRoot === root && _cached2.projectContentFp === projectContentFp) {
1942
- return _cached2.config;
2023
+ if (_cached !== null && _cached.contentFp === contentFp && _cached.envFp === envFp && _cached.projectRoot === root && _cached.projectContentFp === projectContentFp) {
2024
+ return _cached.config;
1943
2025
  }
1944
2026
  let raw = {};
1945
2027
  if (text !== null) {
@@ -1964,11 +2046,11 @@ function loadConfig(projectRoot) {
1964
2046
  _lastProjectConfigParseError = projReadError;
1965
2047
  }
1966
2048
  const cfg = deepFreeze(_buildConfig(raw, projectRaw));
1967
- _cached2 = { config: cfg, contentFp, envFp, projectRoot: root, projectContentFp };
2049
+ _cached = { config: cfg, contentFp, envFp, projectRoot: root, projectContentFp };
1968
2050
  return cfg;
1969
2051
  }
1970
2052
  function invalidateConfigCache() {
1971
- _cached2 = null;
2053
+ _cached = null;
1972
2054
  resetLastProjectConfigLockedKeys();
1973
2055
  }
1974
2056
  registerReset(invalidateConfigCache);
@@ -1998,6 +2080,12 @@ function loadPersistedConfig() {
1998
2080
  _lastConfigParseError = parseError;
1999
2081
  return buildPersistedConfig(raw);
2000
2082
  }
2083
+ function hookServerEnabled() {
2084
+ return envBool("TOKEN_GOAT_HOOK_SERVER", loadPersistedConfig().hooks.server);
2085
+ }
2086
+ function nativeHooksEnabled() {
2087
+ return (nativeHooksModeFromEnv(process.env["TOKEN_GOAT_NATIVE_HOOKS"]) ?? loadPersistedConfig().hooks.native) !== "off";
2088
+ }
2001
2089
  function _buildConfig(raw, projectRaw = {}) {
2002
2090
  const { cleaned: safeProjectRaw, dropped: lockedKeys } = stripLockedProjectKeys(projectRaw);
2003
2091
  setLastProjectConfigLockedKeys(lockedKeys);
@@ -2076,7 +2164,7 @@ function _buildConfig(raw, projectRaw = {}) {
2076
2164
  const is_cfg = getDefaultConfig("image_shrink");
2077
2165
  is_cfg.enabled = validatedBool(is_raw["enabled"], is_cfg.enabled);
2078
2166
  is_cfg.jpeg_quality = validatedInt(is_raw["jpeg_quality"], is_cfg.jpeg_quality, ...boundsOf("image_shrink.jpeg_quality"));
2079
- is_cfg.max_image_pixels = validatedInt(is_raw["max_image_pixels"], is_cfg.max_image_pixels, ...boundsOf("image_shrink.max_image_pixels"));
2167
+ is_cfg.max_image_pixels = validatedIntWithLegacySentinel(is_raw["max_image_pixels"], is_cfg.max_image_pixels, 16e6, ...boundsOf("image_shrink.max_image_pixels"));
2080
2168
  is_cfg.screenshot_redirect = validatedBool(is_raw["screenshot_redirect"], is_cfg.screenshot_redirect);
2081
2169
  is_cfg.ocr_enabled = validatedBool(is_raw["ocr_enabled"], is_cfg.ocr_enabled);
2082
2170
  is_cfg.ocr_min_confidence = validatedInt(is_raw["ocr_min_confidence"], is_cfg.ocr_min_confidence, ...boundsOf("image_shrink.ocr_min_confidence"));
@@ -2126,6 +2214,7 @@ function _buildConfig(raw, projectRaw = {}) {
2126
2214
  hi.serve_diff_on_reread = validatedBool(hi_raw["serve_diff_on_reread"], hi.serve_diff_on_reread);
2127
2215
  hi.elide_served_lines = validatedBool(hi_raw["elide_served_lines"], hi.elide_served_lines);
2128
2216
  hi.subagent_markdown_first_read_deny = validatedBool(hi_raw["subagent_markdown_first_read_deny"], hi.subagent_markdown_first_read_deny);
2217
+ hi.agent_scoped_spawn_deny = validatedBool(hi_raw["agent_scoped_spawn_deny"], hi.agent_scoped_spawn_deny);
2129
2218
  hi.backoff_thresholds = validatedIntList(hi_raw["backoff_thresholds"], hi.backoff_thresholds);
2130
2219
  hi.git_hint_max_ms = validatedInt(hi_raw["git_hint_max_ms"], hi.git_hint_max_ms, ...boundsOf("hints.git_hint_max_ms"));
2131
2220
  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"));
@@ -2144,11 +2233,14 @@ function _buildConfig(raw, projectRaw = {}) {
2144
2233
  hi.truncated_read_min_lines = validatedInt(hi_raw["truncated_read_min_lines"], hi.truncated_read_min_lines, ...boundsOf("hints.truncated_read_min_lines"));
2145
2234
  hi.protect_recent_reads = validatedInt(hi_raw["protect_recent_reads"], hi.protect_recent_reads, ...boundsOf("hints.protect_recent_reads"));
2146
2235
  hi.warn_unbalanced_shell_quoting = validatedBool(hi_raw["warn_unbalanced_shell_quoting"], hi.warn_unbalanced_shell_quoting);
2236
+ hi.deny_bash_double_backslash = validatedBool(hi_raw["deny_bash_double_backslash"], hi.deny_bash_double_backslash);
2147
2237
  hi.log_large_file_hint_outcomes = validatedBool(hi_raw["log_large_file_hint_outcomes"], hi.log_large_file_hint_outcomes);
2148
2238
  hi.warn_unbalanced_shell_quoting = envBool("TOKEN_GOAT_WARN_UNBALANCED_SHELL_QUOTING", hi.warn_unbalanced_shell_quoting);
2239
+ hi.deny_bash_double_backslash = envBool("TOKEN_GOAT_DENY_BASH_DOUBLE_BACKSLASH", hi.deny_bash_double_backslash);
2149
2240
  hi.serve_diff_on_reread = envBool("TOKEN_GOAT_SERVE_DIFF_ON_REREAD", hi.serve_diff_on_reread);
2150
2241
  hi.elide_served_lines = envBool("TOKEN_GOAT_ELIDE_SERVED_LINES", hi.elide_served_lines);
2151
2242
  hi.subagent_markdown_first_read_deny = envBool("TOKEN_GOAT_SUBAGENT_MARKDOWN_FIRST_READ_DENY", hi.subagent_markdown_first_read_deny);
2243
+ hi.agent_scoped_spawn_deny = envBool("TOKEN_GOAT_AGENT_SCOPED_SPAWN_DENY", hi.agent_scoped_spawn_deny);
2152
2244
  hi.log_large_file_hint_outcomes = envBool("TOKEN_GOAT_LOG_LARGE_FILE_HINT_OUTCOMES", hi.log_large_file_hint_outcomes);
2153
2245
  hi.json_sidecar = envBool("TOKEN_GOAT_HINT_JSON_SIDECAR", hi.json_sidecar);
2154
2246
  hi.large_read_redirect_bytes = envInt("TOKEN_GOAT_LARGE_READ_BYTES", hi.large_read_redirect_bytes, ...boundsOf("hints.large_read_redirect_bytes"));
@@ -2186,10 +2278,12 @@ function _buildConfig(raw, projectRaw = {}) {
2186
2278
  }
2187
2279
  const hk_raw = section(raw, "hooks");
2188
2280
  const hk = getDefaultConfig("hooks");
2189
- hk.watchdog_ms = validatedInt(hk_raw["watchdog_ms"], hk.watchdog_ms, ...boundsOf("hooks.watchdog_ms"));
2190
- hk.watchdog_ms = envInt("TOKEN_GOAT_HOOK_WATCHDOG_MS", hk.watchdog_ms, ...boundsOf("hooks.watchdog_ms"));
2191
2281
  hk.latency_budget_ms = validatedInt(hk_raw["latency_budget_ms"], hk.latency_budget_ms, ...boundsOf("hooks.latency_budget_ms"));
2192
2282
  hk.latency_budget_ms = envInt("TOKEN_GOAT_HOOK_LATENCY_BUDGET_MS", hk.latency_budget_ms, ...boundsOf("hooks.latency_budget_ms"));
2283
+ hk.server = validatedBool(hk_raw["server"], hk.server);
2284
+ hk.server = envBool("TOKEN_GOAT_HOOK_SERVER", hk.server);
2285
+ hk.native = validatedNativeHooksMode(hk_raw["native"], hk.native);
2286
+ hk.native = nativeHooksModeFromEnv(process.env["TOKEN_GOAT_NATIVE_HOOKS"]) ?? hk.native;
2193
2287
  const wf_raw = section(raw, "webfetch");
2194
2288
  const wf = getDefaultConfig("webfetch");
2195
2289
  wf.allow = validatedStrList(wf_raw["allow"], wf.allow);
@@ -2220,6 +2314,7 @@ function _buildConfig(raw, projectRaw = {}) {
2220
2314
  ix.max_chunks_per_file = validatedInt(ix_raw["max_chunks_per_file"], ix.max_chunks_per_file, ...boundsOf("indexing.max_chunks_per_file"));
2221
2315
  ix.skip_dirs = validatedStrList(ix_raw["skip_dirs"], ix.skip_dirs);
2222
2316
  ix.skip_files = validatedStrList(ix_raw["skip_files"], ix.skip_files);
2317
+ ix.skip_minified = validatedBool(ix_raw["skip_minified"], ix.skip_minified);
2223
2318
  ix.embeddings_enabled = validatedBool(ix_raw["embeddings_enabled"], ix.embeddings_enabled);
2224
2319
  ix.embeddings_enabled = envBool("TOKEN_GOAT_EMBEDDINGS_ENABLED", ix.embeddings_enabled);
2225
2320
  ix.cross_project_symbols = validatedBool(ix_raw["cross_project_symbols"], ix.cross_project_symbols);
@@ -2259,7 +2354,7 @@ function _buildConfig(raw, projectRaw = {}) {
2259
2354
  mcp.confine_reads_to_project_root = validatedBool(mcp_raw["confine_reads_to_project_root"], mcp.confine_reads_to_project_root);
2260
2355
  mcp.confine_reads_to_project_root = envBool("TOKEN_GOAT_MCP_CONFINE_READS", mcp.confine_reads_to_project_root);
2261
2356
  mcp.allowed_roots = validatedStrList(mcp_raw["allowed_roots"], mcp.allowed_roots);
2262
- mcp.allowed_roots = envStrList("TOKEN_GOAT_MCP_ALLOWED_ROOTS", mcp.allowed_roots, path2.delimiter);
2357
+ mcp.allowed_roots = envStrList("TOKEN_GOAT_MCP_ALLOWED_ROOTS", mcp.allowed_roots, path3.delimiter);
2263
2358
  const hs_raw = section(raw, "hint_stats");
2264
2359
  const hs = getDefaultConfig("hint_stats");
2265
2360
  hs.suppress_threshold_pct = validatedInt(hs_raw["suppress_threshold_pct"], hs.suppress_threshold_pct, ...boundsOf("hint_stats.suppress_threshold_pct"));
@@ -2271,6 +2366,7 @@ function _buildConfig(raw, projectRaw = {}) {
2271
2366
  sem.archive_weight = validatedFloat(sem_raw["archive_weight"], sem.archive_weight, ...boundsOf("semantic.archive_weight"));
2272
2367
  sem.docs_weight = validatedFloat(sem_raw["docs_weight"], sem.docs_weight, ...boundsOf("semantic.docs_weight"));
2273
2368
  sem.max_distance = validatedFloat(sem_raw["max_distance"], sem.max_distance, ...boundsOf("semantic.max_distance"));
2369
+ sem.weak_distance = validatedFloat(sem_raw["weak_distance"], sem.weak_distance, ...boundsOf("semantic.weak_distance"));
2274
2370
  return {
2275
2371
  compact_assist: ca,
2276
2372
  bash_compress: bc,
@@ -2335,9 +2431,11 @@ var CONFIG_KEY_ENV_OVERRIDES = {
2335
2431
  "hints.write_rewrite_unchanged_pct": ["TOKEN_GOAT_WRITE_REWRITE_UNCHANGED_PCT"],
2336
2432
  "hints.large_read_redirect_bytes": ["TOKEN_GOAT_LARGE_READ_BYTES"],
2337
2433
  "hints.warn_unbalanced_shell_quoting": ["TOKEN_GOAT_WARN_UNBALANCED_SHELL_QUOTING"],
2434
+ "hints.deny_bash_double_backslash": ["TOKEN_GOAT_DENY_BASH_DOUBLE_BACKSLASH"],
2338
2435
  "hints.serve_diff_on_reread": ["TOKEN_GOAT_SERVE_DIFF_ON_REREAD"],
2339
2436
  "hints.elide_served_lines": ["TOKEN_GOAT_ELIDE_SERVED_LINES"],
2340
2437
  "hints.subagent_markdown_first_read_deny": ["TOKEN_GOAT_SUBAGENT_MARKDOWN_FIRST_READ_DENY"],
2438
+ "hints.agent_scoped_spawn_deny": ["TOKEN_GOAT_AGENT_SCOPED_SPAWN_DENY"],
2341
2439
  "hints.log_large_file_hint_outcomes": ["TOKEN_GOAT_LOG_LARGE_FILE_HINT_OUTCOMES"],
2342
2440
  "hints.cross_session_read_dedup": ["TOKEN_GOAT_CROSS_SESSION_READ_DEDUP"],
2343
2441
  "hints.cross_session_read_dedup_ttl_secs": ["TOKEN_GOAT_CROSS_SESSION_READ_DEDUP_TTL_SECS"],
@@ -2360,8 +2458,9 @@ var CONFIG_KEY_ENV_OVERRIDES = {
2360
2458
  "hints.context_threshold_advisory": ["TOKEN_GOAT_CONTEXT_THRESHOLD_ADVISORY"],
2361
2459
  "hints.pre_skill_advisory": ["TOKEN_GOAT_PRE_SKILL_ADVISORY"],
2362
2460
  "hints.quiet_hours": ["TOKEN_GOAT_QUIET_HOURS"],
2363
- "hooks.watchdog_ms": ["TOKEN_GOAT_HOOK_WATCHDOG_MS"],
2364
2461
  "hooks.latency_budget_ms": ["TOKEN_GOAT_HOOK_LATENCY_BUDGET_MS"],
2462
+ "hooks.server": ["TOKEN_GOAT_HOOK_SERVER"],
2463
+ "hooks.native": ["TOKEN_GOAT_NATIVE_HOOKS"],
2365
2464
  "webfetch.max_file_count": ["TOKEN_GOAT_WEB_CACHE_MAX_FILES"],
2366
2465
  "webfetch.max_bytes": ["TOKEN_GOAT_WEB_CACHE_MAX_BYTES"],
2367
2466
  "webfetch.compress_bodies": ["TOKEN_GOAT_WEB_COMPRESS"],
@@ -2385,7 +2484,26 @@ var CONFIG_KEY_ENV_OVERRIDES = {
2385
2484
  "indexing.max_db_size_mb": ["TOKEN_GOAT_INDEXING_MAX_DB_SIZE_MB"],
2386
2485
  "indexing.auto_reclaim_embeddings": ["TOKEN_GOAT_INDEXING_AUTO_RECLAIM_EMBEDDINGS"]
2387
2486
  };
2388
- function saveConfig(config) {
2487
+ function isPlainObject(v) {
2488
+ return v !== null && typeof v === "object" && !Array.isArray(v);
2489
+ }
2490
+ function sparsifyAgainstDefaults(data, defaults, raw, explicit, prefix = "") {
2491
+ const out = {};
2492
+ for (const [k, v] of Object.entries(data)) {
2493
+ const dotted = prefix === "" ? k : `${prefix}.${k}`;
2494
+ const d = defaults[k];
2495
+ const r = raw[k];
2496
+ if (isPlainObject(v) && isPlainObject(d)) {
2497
+ const sub = sparsifyAgainstDefaults(v, d, isPlainObject(r) ? r : {}, explicit, dotted);
2498
+ if (Object.keys(sub).length > 0) out[k] = sub;
2499
+ continue;
2500
+ }
2501
+ const keep = d === void 0 || !rawValueEquals(v, d) || r !== void 0 || explicit.has(dotted);
2502
+ if (keep) out[k] = v;
2503
+ }
2504
+ return out;
2505
+ }
2506
+ function saveConfig(config, explicitKeys = []) {
2389
2507
  const ca = config.compact_assist;
2390
2508
  const bc = config.bash_compress;
2391
2509
  const sp = config.skill_preservation;
@@ -2483,6 +2601,7 @@ function saveConfig(config) {
2483
2601
  serve_diff_on_reread: config.hints.serve_diff_on_reread,
2484
2602
  elide_served_lines: config.hints.elide_served_lines,
2485
2603
  subagent_markdown_first_read_deny: config.hints.subagent_markdown_first_read_deny,
2604
+ agent_scoped_spawn_deny: config.hints.agent_scoped_spawn_deny,
2486
2605
  backoff_thresholds: config.hints.backoff_thresholds,
2487
2606
  git_hint_max_ms: config.hints.git_hint_max_ms,
2488
2607
  min_session_hint_savings_bytes: config.hints.min_session_hint_savings_bytes,
@@ -2502,6 +2621,7 @@ function saveConfig(config) {
2502
2621
  protect_recent_reads: config.hints.protect_recent_reads,
2503
2622
  prompt_triggers: config.hints.prompt_triggers,
2504
2623
  warn_unbalanced_shell_quoting: config.hints.warn_unbalanced_shell_quoting,
2624
+ deny_bash_double_backslash: config.hints.deny_bash_double_backslash,
2505
2625
  log_large_file_hint_outcomes: config.hints.log_large_file_hint_outcomes,
2506
2626
  cross_session_read_dedup: config.hints.cross_session_read_dedup,
2507
2627
  cross_session_read_dedup_ttl_secs: config.hints.cross_session_read_dedup_ttl_secs,
@@ -2509,8 +2629,9 @@ function saveConfig(config) {
2509
2629
  session_start_reminder: config.hints.session_start_reminder
2510
2630
  },
2511
2631
  hooks: {
2512
- watchdog_ms: config.hooks.watchdog_ms,
2513
- latency_budget_ms: config.hooks.latency_budget_ms
2632
+ latency_budget_ms: config.hooks.latency_budget_ms,
2633
+ server: config.hooks.server,
2634
+ native: config.hooks.native
2514
2635
  },
2515
2636
  webfetch: {
2516
2637
  allow: config.webfetch.allow,
@@ -2532,6 +2653,7 @@ function saveConfig(config) {
2532
2653
  max_chunks_per_file: config.indexing.max_chunks_per_file,
2533
2654
  skip_dirs: config.indexing.skip_dirs,
2534
2655
  skip_files: config.indexing.skip_files,
2656
+ skip_minified: config.indexing.skip_minified,
2535
2657
  embeddings_enabled: config.indexing.embeddings_enabled,
2536
2658
  cross_project_symbols: config.indexing.cross_project_symbols,
2537
2659
  max_db_size_mb: config.indexing.max_db_size_mb,
@@ -2567,25 +2689,21 @@ function saveConfig(config) {
2567
2689
  semantic: {
2568
2690
  archive_weight: config.semantic.archive_weight,
2569
2691
  max_distance: config.semantic.max_distance,
2692
+ weak_distance: config.semantic.weak_distance,
2570
2693
  docs_weight: config.semantic.docs_weight
2571
2694
  }
2572
2695
  };
2573
- const toml = stringify(data);
2696
+ const toml = stringify(sparsifyAgainstDefaults(data, buildPersistedConfig({}), readConfigToml(configPath()).raw, new Set(explicitKeys)));
2574
2697
  atomicWriteText(configPath(), toml);
2575
- _cached2 = null;
2698
+ _cached = null;
2576
2699
  }
2577
2700
 
2578
2701
  export {
2579
2702
  parse,
2580
2703
  stringify,
2581
- detectHarness,
2582
- getHarnessName,
2583
- FALSY_ENV_VALUES,
2584
- envBool,
2585
- envInt,
2586
- envStrList,
2587
2704
  fingerprintContent,
2588
2705
  shortFingerprint,
2706
+ indexedFileIsGone,
2589
2707
  fingerprintFile,
2590
2708
  fileIsAbsent,
2591
2709
  DEFAULT_OCR_LANG,
@@ -2594,6 +2712,7 @@ export {
2594
2712
  resolveOcrLangs,
2595
2713
  ownGet,
2596
2714
  defaultConfig,
2715
+ projectHash,
2597
2716
  makeProjectAt,
2598
2717
  findProject,
2599
2718
  getDisplayRoot,
@@ -2603,6 +2722,8 @@ export {
2603
2722
  PROJECT_LOCKED_KEYS,
2604
2723
  lastProjectConfigLockedKeys,
2605
2724
  readConfigSource,
2725
+ withConfigProjectRoot,
2726
+ configProjectRootFor,
2606
2727
  getProjectConfigInfo,
2607
2728
  isAutoTriggerMultiplierExplicit,
2608
2729
  validateNumericField,
@@ -2613,16 +2734,18 @@ export {
2613
2734
  loadConfig,
2614
2735
  invalidateConfigCache,
2615
2736
  loadPersistedConfig,
2737
+ hookServerEnabled,
2738
+ nativeHooksEnabled,
2616
2739
  CONFIG_KEY_ENV_OVERRIDES,
2617
2740
  saveConfig
2618
2741
  };
2619
2742
  /*! Bundled license information:
2620
2743
 
2621
- smol-toml/dist/date.js:
2622
2744
  smol-toml/dist/error.js:
2623
- smol-toml/dist/util.js:
2624
2745
  smol-toml/dist/primitive.js:
2746
+ smol-toml/dist/date.js:
2625
2747
  smol-toml/dist/extract.js:
2748
+ smol-toml/dist/util.js:
2626
2749
  smol-toml/dist/struct.js:
2627
2750
  smol-toml/dist/parse.js:
2628
2751
  smol-toml/dist/stringify.js: