token-goat 2.9.18 → 2.9.20

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 (55) hide show
  1. package/README.md +5 -1
  2. package/dist/token-goat-chunk-2CLWWRFR.mjs +26 -0
  3. package/dist/{token-goat-chunk-LTYWLKAG.mjs → token-goat-chunk-2Q3N5KUQ.mjs} +1283 -1012
  4. package/dist/{token-goat-chunk-6LGVCCMY.mjs → token-goat-chunk-3OGZOFLS.mjs} +26 -16
  5. package/dist/{token-goat-chunk-QML7ITHJ.mjs → token-goat-chunk-3VTJC7KU.mjs} +693 -438
  6. package/dist/{token-goat-chunk-QIDLJGXZ.mjs → token-goat-chunk-6LJNM4ZZ.mjs} +29 -5
  7. package/dist/{token-goat-chunk-CA6V36KW.mjs → token-goat-chunk-74ADIZZX.mjs} +68 -50
  8. package/dist/{token-goat-chunk-52IMXJ2L.mjs → token-goat-chunk-ASTBLE2R.mjs} +4 -4
  9. package/dist/token-goat-chunk-AU2K2QHR.mjs +20 -0
  10. package/dist/token-goat-chunk-BQIC3AVL.mjs +292 -0
  11. package/dist/token-goat-chunk-CBXLE54Q.mjs +30 -0
  12. package/dist/{token-goat-chunk-LMFO66YD.mjs → token-goat-chunk-DA43OE7L.mjs} +1 -1
  13. package/dist/{token-goat-chunk-ARNRFR6M.mjs → token-goat-chunk-DNAF26L4.mjs} +1 -1
  14. package/dist/{token-goat-chunk-BFEWOMA3.mjs → token-goat-chunk-DPHJU3P7.mjs} +1186 -4573
  15. package/dist/{token-goat-chunk-OWSJJY5R.mjs → token-goat-chunk-DW4VKU7D.mjs} +5 -5
  16. package/dist/token-goat-chunk-DYUBZZNP.mjs +198 -0
  17. package/dist/{token-goat-chunk-W3E65QOW.mjs → token-goat-chunk-ERGHDBC6.mjs} +310 -47
  18. package/dist/token-goat-chunk-EUZKG7ZO.mjs +304 -0
  19. package/dist/{token-goat-chunk-5MMJAJF3.mjs → token-goat-chunk-FWYZVS3E.mjs} +324 -31
  20. package/dist/token-goat-chunk-G6SYQQO7.mjs +41 -0
  21. package/dist/{token-goat-chunk-YQZE5NS6.mjs → token-goat-chunk-GIPMOGOI.mjs} +6 -6
  22. package/dist/{token-goat-chunk-BWCRC23L.mjs → token-goat-chunk-H4VC5TR6.mjs} +29 -20
  23. package/dist/{token-goat-chunk-V3ZWBEHM.mjs → token-goat-chunk-I5PQRHFE.mjs} +103 -24
  24. package/dist/token-goat-chunk-ITWYDOKP.mjs +341 -0
  25. package/dist/{token-goat-chunk-I67CPTDD.mjs → token-goat-chunk-K3ZNBN4U.mjs} +19 -14
  26. package/dist/{token-goat-chunk-HPOFR6QX.mjs → token-goat-chunk-K5XPIUVB.mjs} +222 -61
  27. package/dist/token-goat-chunk-KT75DZK4.mjs +1989 -0
  28. package/dist/{token-goat-chunk-H3FONFBO.mjs → token-goat-chunk-MNJWG2ZO.mjs} +3 -3
  29. package/dist/{token-goat-chunk-GRI6HWX3.mjs → token-goat-chunk-MUJV7BR3.mjs} +1 -1
  30. package/dist/{token-goat-chunk-ERTXEKB6.mjs → token-goat-chunk-NMTKNYGF.mjs} +2 -0
  31. package/dist/{token-goat-chunk-LA3O4JGD.mjs → token-goat-chunk-ODF7H7WS.mjs} +3 -3
  32. package/dist/{token-goat-chunk-K4DG6EEF.mjs → token-goat-chunk-ONMU7BON.mjs} +7 -8
  33. package/dist/{token-goat-chunk-4EXFN2AW.mjs → token-goat-chunk-OZRSREKR.mjs} +2 -2
  34. package/dist/{token-goat-chunk-EPXNOKIV.mjs → token-goat-chunk-P4XBHZXU.mjs} +2 -2
  35. package/dist/{token-goat-chunk-CTOYJ232.mjs → token-goat-chunk-PAVWB4L4.mjs} +173 -1840
  36. package/dist/{token-goat-chunk-UENEL6KX.mjs → token-goat-chunk-PTW22MRC.mjs} +2 -2
  37. package/dist/token-goat-chunk-SL454EN5.mjs +1816 -0
  38. package/dist/token-goat-chunk-SP5QR2HN.mjs +1379 -0
  39. package/dist/{token-goat-chunk-7VLWNQDQ.mjs → token-goat-chunk-T46UKRFM.mjs} +1 -1
  40. package/dist/{token-goat-chunk-L7VCX33I.mjs → token-goat-chunk-T63VHOL3.mjs} +40 -10
  41. package/dist/token-goat-chunk-VSJGPEBB.mjs +248 -0
  42. package/dist/{token-goat-chunk-HIZXQVNU.mjs → token-goat-chunk-VYXGHGUY.mjs} +4 -4
  43. package/dist/token-goat-chunk-W6QYCWAT.mjs +128 -0
  44. package/dist/{token-goat-chunk-WFX2V3OF.mjs → token-goat-chunk-Z4ALQADF.mjs} +579 -422
  45. package/dist/token-goat-chunk-ZHFM4DHJ.mjs +324 -0
  46. package/dist/token-goat-hook.mjs +18 -12
  47. package/dist/token-goat.core.mjs +29 -20
  48. package/docs/C4_RUNTIME_ARCHITECTURE.md +1 -1
  49. package/docs/cli.md +15 -13
  50. package/docs/install.md +1 -1
  51. package/docs/security.md +2 -2
  52. package/package.json +3 -2
  53. package/dist/token-goat-chunk-2KTZ6J7T.mjs +0 -173
  54. package/dist/token-goat-chunk-34OUJ2IE.mjs +0 -35
  55. package/dist/token-goat-chunk-RHHFEXKF.mjs +0 -93
@@ -8,7 +8,7 @@ import {
8
8
  lowercaseDriveLetter,
9
9
  normalizeDarwinSystemAlias,
10
10
  normalizePath
11
- } from "./token-goat-chunk-ERTXEKB6.mjs";
11
+ } from "./token-goat-chunk-NMTKNYGF.mjs";
12
12
  import {
13
13
  compileGuardedRegex
14
14
  } from "./token-goat-chunk-GMOUBOX4.mjs";
@@ -21,7 +21,7 @@ init_define_import_meta_env();
21
21
  import { createRequire } from "node:module";
22
22
  function resolveVersion() {
23
23
  if (true) {
24
- return "2.9.18";
24
+ return "2.9.20";
25
25
  }
26
26
  const require2 = createRequire(import.meta.url);
27
27
  const pkg = require2("../package.json");
@@ -222,6 +222,10 @@ function isCaseInsensitiveFs() {
222
222
  function foldPath(p) {
223
223
  return isCaseInsensitiveFs() ? foldCase(p) : p;
224
224
  }
225
+ function isNodeModulesPath(p) {
226
+ const check = foldPath(p);
227
+ return check.includes("/node_modules/") || check.includes("\\node_modules\\");
228
+ }
225
229
  function foldCase(s) {
226
230
  return s.toLowerCase();
227
231
  }
@@ -599,7 +603,7 @@ function encodeUtf32(text, littleEndian) {
599
603
  // src/util.ts
600
604
  init_define_import_meta_env();
601
605
  import { spawn } from "node:child_process";
602
- import { chmodSync as chmodSync2, closeSync, constants as fsConstants, copyFileSync, existsSync as existsSync3, mkdirSync as mkdirSync2, openSync, readFileSync as readFileSync3, renameSync, statSync as statSync3, unlinkSync, writeFileSync, writeSync } from "node:fs";
606
+ import { chmodSync as chmodSync2, closeSync, constants as fsConstants, copyFileSync, existsSync as existsSync3, mkdirSync as mkdirSync2, openSync, readdirSync, readFileSync as readFileSync3, renameSync, rmdirSync, statSync as statSync3, unlinkSync, writeFileSync, writeSync } from "node:fs";
603
607
  import * as path7 from "node:path";
604
608
 
605
609
  // src/bridges/created_configs.ts
@@ -734,7 +738,7 @@ function stripOwnHooksFromMap(hooks, isOurs) {
734
738
  const kept = [];
735
739
  for (const group of groups) {
736
740
  const keptHooks = (group.hooks ?? []).filter((h) => {
737
- const isOur = isOurs(h.command);
741
+ const isOur = isOurs(h.command, h.args);
738
742
  if (isOur) removed = true;
739
743
  return !isOur;
740
744
  });
@@ -760,7 +764,7 @@ function stripStaleGroupHooks(groups, isOurs, matcherFilter) {
760
764
  next.push(group);
761
765
  continue;
762
766
  }
763
- const keptHooks = (group.hooks ?? []).filter((h) => !isOurs(h.command));
767
+ const keptHooks = (group.hooks ?? []).filter((h) => !isOurs(h.command, h.args));
764
768
  if (keptHooks.length > 0) {
765
769
  next.push({ ...group, hooks: keptHooks });
766
770
  } else if ((group.hooks ?? []).length === 0) {
@@ -982,6 +986,19 @@ function removeFileInScope(p) {
982
986
  return false;
983
987
  }
984
988
  }
989
+ function removeEmptyDirInScope(dirPath) {
990
+ assertWriteInScope(dirPath);
991
+ try {
992
+ const entries = readdirSync(dirPath);
993
+ if (entries.length === 0) {
994
+ rmdirSync(dirPath);
995
+ return true;
996
+ }
997
+ return false;
998
+ } catch {
999
+ return false;
1000
+ }
1001
+ }
985
1002
  function uninstallSingleFilePlugin(filePath, sidecarPath) {
986
1003
  removeFileInScope(sidecarPath);
987
1004
  return removeFileInScope(filePath);
@@ -1243,6 +1260,10 @@ function hookCommandFor(scriptPath, event) {
1243
1260
  const entryArg = entryPath ? ` ${quoteShellPath(entryPath)}` : "";
1244
1261
  return `${quoteShellPath(process.execPath)} ${quoteShellPath(scriptPath)} ${event}${entryArg}`;
1245
1262
  }
1263
+ function hookExecPartsFor(scriptPath, event) {
1264
+ const entryPath = process.argv[1];
1265
+ return { command: process.execPath, args: entryPath ? [scriptPath, event, entryPath] : [scriptPath, event] };
1266
+ }
1246
1267
  function hookPowershellCommand(scriptPath, event) {
1247
1268
  const entryPath = process.argv[1];
1248
1269
  const entryArg = entryPath ? ` ${quotePowershellPath(entryPath)}` : "";
@@ -1269,6 +1290,7 @@ export {
1269
1290
  removeCreatedBackups,
1270
1291
  isCaseInsensitiveFs,
1271
1292
  foldPath,
1293
+ isNodeModulesPath,
1272
1294
  foldCase,
1273
1295
  foldCaseForContainment,
1274
1296
  foldPathForContainment,
@@ -1304,6 +1326,7 @@ export {
1304
1326
  atomicWriteBytes,
1305
1327
  installSingleFilePlugin,
1306
1328
  removeFileInScope,
1329
+ removeEmptyDirInScope,
1307
1330
  uninstallSingleFilePlugin,
1308
1331
  backupFile,
1309
1332
  PER_FILE_COUNTERFACTUAL_CEILING,
@@ -1337,5 +1360,6 @@ export {
1337
1360
  isUnderBlockedRoot,
1338
1361
  isWithinQuietHours,
1339
1362
  hookCommandFor,
1363
+ hookExecPartsFor,
1340
1364
  hookPowershellCommand
1341
1365
  };
@@ -13,10 +13,10 @@ import {
13
13
  foldPath,
14
14
  projectConfigPath,
15
15
  runGit
16
- } from "./token-goat-chunk-QIDLJGXZ.mjs";
16
+ } from "./token-goat-chunk-6LJNM4ZZ.mjs";
17
17
  import {
18
18
  normalizeDarwinSystemAlias
19
- } from "./token-goat-chunk-ERTXEKB6.mjs";
19
+ } from "./token-goat-chunk-NMTKNYGF.mjs";
20
20
  import {
21
21
  init_define_import_meta_env
22
22
  } from "./token-goat-chunk-A37V4PBF.mjs";
@@ -1202,8 +1202,17 @@ var PROJECT_LOCKED_KEYS = [
1202
1202
  "indexing.skip_files",
1203
1203
  "indexing.large_file_skip_kb",
1204
1204
  "indexing.large_file_symbol_only_kb",
1205
+ // 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.
1206
+ "indexing.max_chunks_per_file",
1205
1207
  "indexing.cross_project_symbols",
1206
- "worker.blocked_roots"
1208
+ // 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
+ "semantic.max_distance",
1210
+ "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.
1214
+ "indexing.max_db_size_mb",
1215
+ "indexing.auto_reclaim_embeddings"
1207
1216
  ];
1208
1217
  var _lastProjectConfigLockedKeys = [];
1209
1218
  function lastProjectConfigLockedKeys() {
@@ -1342,6 +1351,13 @@ function isAutoTriggerMultiplierExplicit() {
1342
1351
  init_define_import_meta_env();
1343
1352
  import * as path2 from "node:path";
1344
1353
 
1354
+ // src/own_lookup.ts
1355
+ init_define_import_meta_env();
1356
+ function ownGet(map, key) {
1357
+ if (!map || !Object.hasOwn(map, key)) return void 0;
1358
+ return map[key];
1359
+ }
1360
+
1345
1361
  // src/config_types.ts
1346
1362
  init_define_import_meta_env();
1347
1363
 
@@ -1350,16 +1366,7 @@ init_define_import_meta_env();
1350
1366
  var CONFIG_DEFAULTS = {
1351
1367
  compact_assist: {
1352
1368
  enabled: true,
1353
- triggers: ["manual", "auto"],
1354
- min_events: 3,
1355
- max_manifest_tokens: 400,
1356
1369
  auto_trigger_multiplier: 2,
1357
- compact_skip_ttl_secs: 300,
1358
- noise_floor_tokens: 0,
1359
- edited_dir_group_threshold: 3,
1360
- max_section_lines: 0,
1361
- wide_session_threshold: 15,
1362
- orchestrator_commit_threshold: 5,
1363
1370
  max_manifest_chars: 1600,
1364
1371
  summary_budget_chars: 24e3,
1365
1372
  harness: "auto"
@@ -1514,7 +1521,8 @@ var CONFIG_DEFAULTS = {
1514
1521
  session_start_reminder: true
1515
1522
  },
1516
1523
  hooks: {
1517
- watchdog_ms: 700
1524
+ watchdog_ms: 700,
1525
+ latency_budget_ms: 1500
1518
1526
  },
1519
1527
  webfetch: {
1520
1528
  allow: [],
@@ -1542,10 +1550,14 @@ var CONFIG_DEFAULTS = {
1542
1550
  indexing: {
1543
1551
  large_file_symbol_only_kb: 500,
1544
1552
  large_file_skip_kb: 2048,
1553
+ // 600 comes from a census of one real machine-wide index: 243,603 chunks over 62 projects and roughly 4,400 files. The largest hand-written source file anywhere in it produced 387 chunks (a 4,000-line test file); the next tier up starts at 513 and is entirely generated data snapshots, minified vendor assets and one HTML draft. 600 sits in that gap with about 1.5x headroom over the largest real file, and above it 32 files held 54,674 chunks -- 22% of the whole index from 0.7% of its files.
1554
+ max_chunks_per_file: 600,
1545
1555
  skip_dirs: [],
1546
1556
  skip_files: ["coverage.json", "coverage-final.json"],
1547
1557
  embeddings_enabled: true,
1548
- cross_project_symbols: true
1558
+ cross_project_symbols: true,
1559
+ max_db_size_mb: 1500,
1560
+ auto_reclaim_embeddings: false
1549
1561
  },
1550
1562
  compression: {
1551
1563
  profile: "auto"
@@ -1572,11 +1584,14 @@ var CONFIG_DEFAULTS = {
1572
1584
  },
1573
1585
  hint_stats: {
1574
1586
  suppress_threshold_pct: 15,
1587
+ defiance_threshold_pct: 85,
1575
1588
  min_sample_size: 5
1576
1589
  },
1577
1590
  semantic: {
1578
1591
  archive_weight: 0.7,
1579
- docs_weight: 0.92
1592
+ docs_weight: 0.92,
1593
+ // 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
1580
1595
  }
1581
1596
  };
1582
1597
  function getDefaultConfig(section2) {
@@ -1657,15 +1672,7 @@ function section(raw, key) {
1657
1672
  return val !== null && typeof val === "object" && !Array.isArray(val) ? val : {};
1658
1673
  }
1659
1674
  var NUMERIC_FIELD_BOUNDS = {
1660
- "compact_assist.min_events": { min: 0, max: 1e3 },
1661
- "compact_assist.max_manifest_tokens": { min: 50, max: 1e4 },
1662
1675
  "compact_assist.auto_trigger_multiplier": { min: 1, max: 10 },
1663
- "compact_assist.compact_skip_ttl_secs": { min: 1, max: 3600 },
1664
- "compact_assist.noise_floor_tokens": { min: 0, max: 1e4 },
1665
- "compact_assist.edited_dir_group_threshold": { min: 0, max: 100 },
1666
- "compact_assist.max_section_lines": { min: 0, max: 1e4 },
1667
- "compact_assist.wide_session_threshold": { min: 1, max: 1e4 },
1668
- "compact_assist.orchestrator_commit_threshold": { min: 1, max: 1e4 },
1669
1676
  "compact_assist.max_manifest_chars": { min: 0, max: 16e3 },
1670
1677
  "compact_assist.summary_budget_chars": { min: 0, max: 2e5 },
1671
1678
  "bash_compress.max_lines": { min: 50, max: 1e5 },
@@ -1710,6 +1717,7 @@ var NUMERIC_FIELD_BOUNDS = {
1710
1717
  "hints.cross_session_read_dedup_ttl_secs": { min: 1, max: 86400 },
1711
1718
  "hints.mcp_dedup_ttl_secs": { min: 1, max: 3600 },
1712
1719
  "hooks.watchdog_ms": { min: 100, max: 3e4 },
1720
+ "hooks.latency_budget_ms": { min: 1, max: 6e5 },
1713
1721
  "webfetch.max_file_count": { min: 0, max: 1e7 },
1714
1722
  "webfetch.max_bytes": { min: 0, max: 100 * 1024 * 1024 * 1024 },
1715
1723
  "webfetch.compress_min_bytes": { min: 1024, max: 10 * 1024 * 1024 },
@@ -1717,14 +1725,19 @@ var NUMERIC_FIELD_BOUNDS = {
1717
1725
  "worker.embed_threads": { min: 1, max: 16 },
1718
1726
  "indexing.large_file_symbol_only_kb": { min: 1, max: 1048576, clampTo: "indexing.large_file_skip_kb" },
1719
1727
  "indexing.large_file_skip_kb": { min: 1, max: 1048576 },
1728
+ "indexing.max_chunks_per_file": { min: 1, max: 1e6 },
1729
+ "indexing.max_db_size_mb": { min: 1, max: 1e5 },
1720
1730
  "context.model_window_tokens": { min: 1e4, max: 1e7 },
1721
1731
  "hint_stats.suppress_threshold_pct": { min: 0, max: 100 },
1732
+ "hint_stats.defiance_threshold_pct": { min: 0, max: 100 },
1722
1733
  "hint_stats.min_sample_size": { min: 1, max: 1e4 },
1723
1734
  "semantic.archive_weight": { min: 0.05, max: 1 },
1724
- "semantic.docs_weight": { min: 0.05, max: 1 }
1735
+ "semantic.docs_weight": { min: 0.05, max: 1 },
1736
+ // 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 }
1725
1738
  };
1726
1739
  function boundsOf(key) {
1727
- const b = NUMERIC_FIELD_BOUNDS[key];
1740
+ const b = ownGet(NUMERIC_FIELD_BOUNDS, key);
1728
1741
  if (!b) throw new Error(`token-goat: no NUMERIC_FIELD_BOUNDS entry for '${key}'`);
1729
1742
  return [b.min, b.max];
1730
1743
  }
@@ -1738,7 +1751,7 @@ function walkGetNumeric(obj, parts) {
1738
1751
  return typeof cur === "number" ? cur : void 0;
1739
1752
  }
1740
1753
  function validateNumericField(fieldKey, value, cfg) {
1741
- const bounds = NUMERIC_FIELD_BOUNDS[fieldKey];
1754
+ const bounds = ownGet(NUMERIC_FIELD_BOUNDS, fieldKey);
1742
1755
  if (!bounds) return void 0;
1743
1756
  let clamped = Math.max(bounds.min, Math.min(bounds.max, value));
1744
1757
  if (bounds.clampTo) {
@@ -1764,7 +1777,7 @@ function validateEnumField(fieldKey, value) {
1764
1777
  const allowed2 = [...SUPPORTED_OCR_LANG_CODES];
1765
1778
  return tokens.length > 0 && tokens.every((t) => isSupportedOcrLang(t)) ? void 0 : allowed2;
1766
1779
  }
1767
- const allowed = ENUM_FIELD_VALUES[fieldKey];
1780
+ const allowed = ownGet(ENUM_FIELD_VALUES, fieldKey);
1768
1781
  if (!allowed) return void 0;
1769
1782
  return allowed.includes(value) ? void 0 : allowed;
1770
1783
  }
@@ -1813,7 +1826,9 @@ var ENV_KEYS2 = [
1813
1826
  "TOKEN_GOAT_WEB_CACHE_MAX_FILES",
1814
1827
  "TOKEN_GOAT_WEB_CACHE_MAX_BYTES",
1815
1828
  "TOKEN_GOAT_WRITE_REWRITE_MIN_LINES",
1816
- "TOKEN_GOAT_WRITE_REWRITE_UNCHANGED_PCT"
1829
+ "TOKEN_GOAT_WRITE_REWRITE_UNCHANGED_PCT",
1830
+ "TOKEN_GOAT_INDEXING_MAX_DB_SIZE_MB",
1831
+ "TOKEN_GOAT_INDEXING_AUTO_RECLAIM_EMBEDDINGS"
1817
1832
  ];
1818
1833
  function allEnvKeys() {
1819
1834
  return [.../* @__PURE__ */ new Set([...ENV_KEYS2, ...Object.values(CONFIG_KEY_ENV_OVERRIDES).flat()])];
@@ -1859,7 +1874,7 @@ function rawValueEquals(a, b) {
1859
1874
  }
1860
1875
  function rejectionReason(key, rawValue, effectiveValue, cfg) {
1861
1876
  if (typeof rawValue === "number") {
1862
- const bounds = NUMERIC_FIELD_BOUNDS[key];
1877
+ const bounds = ownGet(NUMERIC_FIELD_BOUNDS, key);
1863
1878
  if (bounds !== void 0) {
1864
1879
  if (rawValue < bounds.min || rawValue > bounds.max) return `outside the allowed range ${bounds.min}-${bounds.max}`;
1865
1880
  if (!Number.isInteger(rawValue) && Number.isInteger(effectiveValue)) return "not a whole number";
@@ -1992,16 +2007,7 @@ function _buildConfig(raw, projectRaw = {}) {
1992
2007
  const ca_raw = section(raw, "compact_assist");
1993
2008
  const ca = getDefaultConfig("compact_assist");
1994
2009
  ca.enabled = validatedBool(ca_raw["enabled"], ca.enabled);
1995
- ca.triggers = validatedStrList(ca_raw["triggers"], ca.triggers);
1996
- ca.min_events = validatedInt(ca_raw["min_events"], ca.min_events, ...boundsOf("compact_assist.min_events"));
1997
- ca.max_manifest_tokens = validatedInt(ca_raw["max_manifest_tokens"], ca.max_manifest_tokens, ...boundsOf("compact_assist.max_manifest_tokens"));
1998
2010
  ca.auto_trigger_multiplier = validatedFloat(ca_raw["auto_trigger_multiplier"], ca.auto_trigger_multiplier, ...boundsOf("compact_assist.auto_trigger_multiplier"));
1999
- ca.compact_skip_ttl_secs = validatedFloat(ca_raw["compact_skip_ttl_secs"], ca.compact_skip_ttl_secs, ...boundsOf("compact_assist.compact_skip_ttl_secs"));
2000
- ca.noise_floor_tokens = validatedInt(ca_raw["noise_floor_tokens"], ca.noise_floor_tokens, ...boundsOf("compact_assist.noise_floor_tokens"));
2001
- ca.edited_dir_group_threshold = validatedInt(ca_raw["edited_dir_group_threshold"], ca.edited_dir_group_threshold, ...boundsOf("compact_assist.edited_dir_group_threshold"));
2002
- ca.max_section_lines = validatedInt(ca_raw["max_section_lines"], ca.max_section_lines, ...boundsOf("compact_assist.max_section_lines"));
2003
- ca.wide_session_threshold = validatedInt(ca_raw["wide_session_threshold"], ca.wide_session_threshold, ...boundsOf("compact_assist.wide_session_threshold"));
2004
- ca.orchestrator_commit_threshold = validatedInt(ca_raw["orchestrator_commit_threshold"], ca.orchestrator_commit_threshold, ...boundsOf("compact_assist.orchestrator_commit_threshold"));
2005
2011
  ca.max_manifest_chars = validatedInt(ca_raw["max_manifest_chars"], ca.max_manifest_chars, ...boundsOf("compact_assist.max_manifest_chars"));
2006
2012
  ca.summary_budget_chars = validatedInt(ca_raw["summary_budget_chars"], ca.summary_budget_chars, ...boundsOf("compact_assist.summary_budget_chars"));
2007
2013
  ca.harness = validatedStr(ca_raw["harness"], ca.harness);
@@ -2182,6 +2188,8 @@ function _buildConfig(raw, projectRaw = {}) {
2182
2188
  const hk = getDefaultConfig("hooks");
2183
2189
  hk.watchdog_ms = validatedInt(hk_raw["watchdog_ms"], hk.watchdog_ms, ...boundsOf("hooks.watchdog_ms"));
2184
2190
  hk.watchdog_ms = envInt("TOKEN_GOAT_HOOK_WATCHDOG_MS", hk.watchdog_ms, ...boundsOf("hooks.watchdog_ms"));
2191
+ hk.latency_budget_ms = validatedInt(hk_raw["latency_budget_ms"], hk.latency_budget_ms, ...boundsOf("hooks.latency_budget_ms"));
2192
+ hk.latency_budget_ms = envInt("TOKEN_GOAT_HOOK_LATENCY_BUDGET_MS", hk.latency_budget_ms, ...boundsOf("hooks.latency_budget_ms"));
2185
2193
  const wf_raw = section(raw, "webfetch");
2186
2194
  const wf = getDefaultConfig("webfetch");
2187
2195
  wf.allow = validatedStrList(wf_raw["allow"], wf.allow);
@@ -2209,12 +2217,17 @@ function _buildConfig(raw, projectRaw = {}) {
2209
2217
  ix.large_file_symbol_only_kb = validatedInt(ix_raw["large_file_symbol_only_kb"], ix.large_file_symbol_only_kb, ...boundsOf("indexing.large_file_symbol_only_kb"));
2210
2218
  ix.large_file_skip_kb = validatedInt(ix_raw["large_file_skip_kb"], ix.large_file_skip_kb, ...boundsOf("indexing.large_file_skip_kb"));
2211
2219
  ix.large_file_symbol_only_kb = Math.min(ix.large_file_symbol_only_kb, ix.large_file_skip_kb);
2220
+ ix.max_chunks_per_file = validatedInt(ix_raw["max_chunks_per_file"], ix.max_chunks_per_file, ...boundsOf("indexing.max_chunks_per_file"));
2212
2221
  ix.skip_dirs = validatedStrList(ix_raw["skip_dirs"], ix.skip_dirs);
2213
2222
  ix.skip_files = validatedStrList(ix_raw["skip_files"], ix.skip_files);
2214
2223
  ix.embeddings_enabled = validatedBool(ix_raw["embeddings_enabled"], ix.embeddings_enabled);
2215
2224
  ix.embeddings_enabled = envBool("TOKEN_GOAT_EMBEDDINGS_ENABLED", ix.embeddings_enabled);
2216
2225
  ix.cross_project_symbols = validatedBool(ix_raw["cross_project_symbols"], ix.cross_project_symbols);
2217
2226
  ix.cross_project_symbols = envBool("TOKEN_GOAT_CROSS_PROJECT_SYMBOLS", ix.cross_project_symbols);
2227
+ ix.max_db_size_mb = validatedInt(ix_raw["max_db_size_mb"], ix.max_db_size_mb, ...boundsOf("indexing.max_db_size_mb"));
2228
+ ix.max_db_size_mb = envInt("TOKEN_GOAT_INDEXING_MAX_DB_SIZE_MB", ix.max_db_size_mb, ...boundsOf("indexing.max_db_size_mb"));
2229
+ ix.auto_reclaim_embeddings = validatedBool(ix_raw["auto_reclaim_embeddings"], ix.auto_reclaim_embeddings);
2230
+ ix.auto_reclaim_embeddings = envBool("TOKEN_GOAT_INDEXING_AUTO_RECLAIM_EMBEDDINGS", ix.auto_reclaim_embeddings);
2218
2231
  const cpr_raw = section(raw, "compression");
2219
2232
  const cpr = getDefaultConfig("compression");
2220
2233
  cpr.profile = validatedStr(cpr_raw["profile"], cpr.profile);
@@ -2250,11 +2263,14 @@ function _buildConfig(raw, projectRaw = {}) {
2250
2263
  const hs_raw = section(raw, "hint_stats");
2251
2264
  const hs = getDefaultConfig("hint_stats");
2252
2265
  hs.suppress_threshold_pct = validatedInt(hs_raw["suppress_threshold_pct"], hs.suppress_threshold_pct, ...boundsOf("hint_stats.suppress_threshold_pct"));
2266
+ hs.defiance_threshold_pct = validatedInt(hs_raw["defiance_threshold_pct"], 100 - hs.suppress_threshold_pct, ...boundsOf("hint_stats.defiance_threshold_pct"));
2267
+ hs.defiance_threshold_pct = envInt("TOKEN_GOAT_HINT_DEFIANCE_THRESHOLD_PCT", hs.defiance_threshold_pct, ...boundsOf("hint_stats.defiance_threshold_pct"));
2253
2268
  hs.min_sample_size = validatedInt(hs_raw["min_sample_size"], hs.min_sample_size, ...boundsOf("hint_stats.min_sample_size"));
2254
2269
  const sem_raw = section(raw, "semantic");
2255
2270
  const sem = getDefaultConfig("semantic");
2256
2271
  sem.archive_weight = validatedFloat(sem_raw["archive_weight"], sem.archive_weight, ...boundsOf("semantic.archive_weight"));
2257
2272
  sem.docs_weight = validatedFloat(sem_raw["docs_weight"], sem.docs_weight, ...boundsOf("semantic.docs_weight"));
2273
+ sem.max_distance = validatedFloat(sem_raw["max_distance"], sem.max_distance, ...boundsOf("semantic.max_distance"));
2258
2274
  return {
2259
2275
  compact_assist: ca,
2260
2276
  bash_compress: bc,
@@ -2345,6 +2361,7 @@ var CONFIG_KEY_ENV_OVERRIDES = {
2345
2361
  "hints.pre_skill_advisory": ["TOKEN_GOAT_PRE_SKILL_ADVISORY"],
2346
2362
  "hints.quiet_hours": ["TOKEN_GOAT_QUIET_HOURS"],
2347
2363
  "hooks.watchdog_ms": ["TOKEN_GOAT_HOOK_WATCHDOG_MS"],
2364
+ "hooks.latency_budget_ms": ["TOKEN_GOAT_HOOK_LATENCY_BUDGET_MS"],
2348
2365
  "webfetch.max_file_count": ["TOKEN_GOAT_WEB_CACHE_MAX_FILES"],
2349
2366
  "webfetch.max_bytes": ["TOKEN_GOAT_WEB_CACHE_MAX_BYTES"],
2350
2367
  "webfetch.compress_bodies": ["TOKEN_GOAT_WEB_COMPRESS"],
@@ -2359,11 +2376,14 @@ var CONFIG_KEY_ENV_OVERRIDES = {
2359
2376
  "redaction.custom_patterns": ["TOKEN_GOAT_REDACTION_CUSTOM_PATTERNS"],
2360
2377
  "redaction.strict": ["TOKEN_GOAT_REDACTION_STRICT"],
2361
2378
  "network.offline": ["TOKEN_GOAT_OFFLINE"],
2379
+ "hint_stats.defiance_threshold_pct": ["TOKEN_GOAT_HINT_DEFIANCE_THRESHOLD_PCT"],
2362
2380
  "mcp.confine_reads_to_project_root": ["TOKEN_GOAT_MCP_CONFINE_READS"],
2363
2381
  "mcp.allowed_roots": ["TOKEN_GOAT_MCP_ALLOWED_ROOTS"],
2364
2382
  "webfetch.allow": ["TOKEN_GOAT_WEBFETCH_ALLOW"],
2365
2383
  "webfetch.deny": ["TOKEN_GOAT_WEBFETCH_DENY"],
2366
- "indexing.embeddings_enabled": ["TOKEN_GOAT_EMBEDDINGS_ENABLED"]
2384
+ "indexing.embeddings_enabled": ["TOKEN_GOAT_EMBEDDINGS_ENABLED"],
2385
+ "indexing.max_db_size_mb": ["TOKEN_GOAT_INDEXING_MAX_DB_SIZE_MB"],
2386
+ "indexing.auto_reclaim_embeddings": ["TOKEN_GOAT_INDEXING_AUTO_RECLAIM_EMBEDDINGS"]
2367
2387
  };
2368
2388
  function saveConfig(config) {
2369
2389
  const ca = config.compact_assist;
@@ -2376,16 +2396,7 @@ function saveConfig(config) {
2376
2396
  const data = {
2377
2397
  compact_assist: {
2378
2398
  enabled: ca.enabled,
2379
- triggers: ca.triggers,
2380
- min_events: ca.min_events,
2381
- max_manifest_tokens: ca.max_manifest_tokens,
2382
2399
  ...keepsMultiplierDefault ? {} : { auto_trigger_multiplier: ca.auto_trigger_multiplier },
2383
- compact_skip_ttl_secs: ca.compact_skip_ttl_secs,
2384
- noise_floor_tokens: ca.noise_floor_tokens,
2385
- edited_dir_group_threshold: ca.edited_dir_group_threshold,
2386
- max_section_lines: ca.max_section_lines,
2387
- wide_session_threshold: ca.wide_session_threshold,
2388
- orchestrator_commit_threshold: ca.orchestrator_commit_threshold,
2389
2400
  max_manifest_chars: ca.max_manifest_chars,
2390
2401
  summary_budget_chars: ca.summary_budget_chars,
2391
2402
  harness: ca.harness
@@ -2498,7 +2509,8 @@ function saveConfig(config) {
2498
2509
  session_start_reminder: config.hints.session_start_reminder
2499
2510
  },
2500
2511
  hooks: {
2501
- watchdog_ms: config.hooks.watchdog_ms
2512
+ watchdog_ms: config.hooks.watchdog_ms,
2513
+ latency_budget_ms: config.hooks.latency_budget_ms
2502
2514
  },
2503
2515
  webfetch: {
2504
2516
  allow: config.webfetch.allow,
@@ -2517,10 +2529,13 @@ function saveConfig(config) {
2517
2529
  indexing: {
2518
2530
  large_file_symbol_only_kb: config.indexing.large_file_symbol_only_kb,
2519
2531
  large_file_skip_kb: config.indexing.large_file_skip_kb,
2532
+ max_chunks_per_file: config.indexing.max_chunks_per_file,
2520
2533
  skip_dirs: config.indexing.skip_dirs,
2521
2534
  skip_files: config.indexing.skip_files,
2522
2535
  embeddings_enabled: config.indexing.embeddings_enabled,
2523
- cross_project_symbols: config.indexing.cross_project_symbols
2536
+ cross_project_symbols: config.indexing.cross_project_symbols,
2537
+ max_db_size_mb: config.indexing.max_db_size_mb,
2538
+ auto_reclaim_embeddings: config.indexing.auto_reclaim_embeddings
2524
2539
  },
2525
2540
  compression: {
2526
2541
  profile: config.compression.profile
@@ -2546,10 +2561,12 @@ function saveConfig(config) {
2546
2561
  },
2547
2562
  hint_stats: {
2548
2563
  suppress_threshold_pct: config.hint_stats.suppress_threshold_pct,
2564
+ defiance_threshold_pct: config.hint_stats.defiance_threshold_pct,
2549
2565
  min_sample_size: config.hint_stats.min_sample_size
2550
2566
  },
2551
2567
  semantic: {
2552
2568
  archive_weight: config.semantic.archive_weight,
2569
+ max_distance: config.semantic.max_distance,
2553
2570
  docs_weight: config.semantic.docs_weight
2554
2571
  }
2555
2572
  };
@@ -2574,6 +2591,7 @@ export {
2574
2591
  SUPPORTED_OCR_LANG_CODES,
2575
2592
  isSupportedOcrLang,
2576
2593
  resolveOcrLangs,
2594
+ ownGet,
2577
2595
  defaultConfig,
2578
2596
  makeProjectAt,
2579
2597
  findProject,
@@ -6,12 +6,12 @@ import {
6
6
  pptxOutline,
7
7
  pptxSlideText,
8
8
  pptxTextGrep
9
- } from "./token-goat-chunk-ARNRFR6M.mjs";
10
- import "./token-goat-chunk-7VLWNQDQ.mjs";
9
+ } from "./token-goat-chunk-DNAF26L4.mjs";
10
+ import "./token-goat-chunk-T46UKRFM.mjs";
11
11
  import "./token-goat-chunk-XTQAOTSO.mjs";
12
12
  import "./token-goat-chunk-AH6QILZM.mjs";
13
- import "./token-goat-chunk-QIDLJGXZ.mjs";
14
- import "./token-goat-chunk-ERTXEKB6.mjs";
13
+ import "./token-goat-chunk-6LJNM4ZZ.mjs";
14
+ import "./token-goat-chunk-NMTKNYGF.mjs";
15
15
  import "./token-goat-chunk-Y4AFKTHK.mjs";
16
16
  import "./token-goat-chunk-GMOUBOX4.mjs";
17
17
  import "./token-goat-chunk-A37V4PBF.mjs";
@@ -0,0 +1,20 @@
1
+ import { createRequire as __cjsRequire } from 'node:module';
2
+ const require = __cjsRequire(import.meta.url);
3
+ import {
4
+ checkUpdateStatus,
5
+ cmdUpgrade,
6
+ compareSemver,
7
+ fetchLatestVersion
8
+ } from "./token-goat-chunk-ONMU7BON.mjs";
9
+ import "./token-goat-chunk-74ADIZZX.mjs";
10
+ import "./token-goat-chunk-EEIDFMEM.mjs";
11
+ import "./token-goat-chunk-6LJNM4ZZ.mjs";
12
+ import "./token-goat-chunk-NMTKNYGF.mjs";
13
+ import "./token-goat-chunk-GMOUBOX4.mjs";
14
+ import "./token-goat-chunk-A37V4PBF.mjs";
15
+ export {
16
+ checkUpdateStatus,
17
+ cmdUpgrade,
18
+ compareSemver,
19
+ fetchLatestVersion
20
+ };