context-compress 2026.5.0 → 2026.7.0

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 (79) hide show
  1. package/.claude-plugin/marketplace.json +17 -0
  2. package/.claude-plugin/plugin.json +12 -0
  3. package/.codex-plugin/plugin.json +40 -0
  4. package/.mcp.json +11 -0
  5. package/README.md +43 -12
  6. package/dist/bench/quality.d.ts +46 -0
  7. package/dist/bench/quality.d.ts.map +1 -0
  8. package/dist/bench/quality.js +118 -0
  9. package/dist/bench/quality.js.map +1 -0
  10. package/dist/bench/run.d.ts +2 -0
  11. package/dist/bench/run.d.ts.map +1 -0
  12. package/dist/bench/run.js +4 -0
  13. package/dist/bench/run.js.map +1 -0
  14. package/dist/cli/filter.d.ts.map +1 -1
  15. package/dist/cli/filter.js +13 -1
  16. package/dist/cli/filter.js.map +1 -1
  17. package/dist/cli/index.js +0 -0
  18. package/dist/cli/uninstall.d.ts.map +1 -1
  19. package/dist/cli/uninstall.js +4 -2
  20. package/dist/cli/uninstall.js.map +1 -1
  21. package/dist/config.d.ts +2 -0
  22. package/dist/config.d.ts.map +1 -1
  23. package/dist/config.js +11 -0
  24. package/dist/config.js.map +1 -1
  25. package/dist/executor.d.ts.map +1 -1
  26. package/dist/executor.js +32 -8
  27. package/dist/executor.js.map +1 -1
  28. package/dist/format-filter.d.ts +63 -0
  29. package/dist/format-filter.d.ts.map +1 -0
  30. package/dist/format-filter.js +331 -0
  31. package/dist/format-filter.js.map +1 -0
  32. package/dist/logger.d.ts +4 -0
  33. package/dist/logger.d.ts.map +1 -1
  34. package/dist/logger.js +14 -1
  35. package/dist/logger.js.map +1 -1
  36. package/dist/runtime/index.d.ts +2 -2
  37. package/dist/runtime/index.d.ts.map +1 -1
  38. package/dist/runtime/index.js +37 -20
  39. package/dist/runtime/index.js.map +1 -1
  40. package/dist/server.bundle.mjs +479 -110
  41. package/dist/server.bundle.mjs.map +4 -4
  42. package/dist/server.d.ts.map +1 -1
  43. package/dist/server.js +5 -2
  44. package/dist/server.js.map +1 -1
  45. package/dist/stats.d.ts.map +1 -1
  46. package/dist/stats.js +19 -1
  47. package/dist/stats.js.map +1 -1
  48. package/dist/store.d.ts +1 -0
  49. package/dist/store.d.ts.map +1 -1
  50. package/dist/store.js +20 -2
  51. package/dist/store.js.map +1 -1
  52. package/dist/tools/batch-execute.d.ts.map +1 -1
  53. package/dist/tools/batch-execute.js +20 -2
  54. package/dist/tools/batch-execute.js.map +1 -1
  55. package/dist/util/auto-mode.d.ts +8 -0
  56. package/dist/util/auto-mode.d.ts.map +1 -1
  57. package/dist/util/auto-mode.js +40 -26
  58. package/dist/util/auto-mode.js.map +1 -1
  59. package/dist/util/fetch-code.d.ts.map +1 -1
  60. package/dist/util/fetch-code.js +2 -48
  61. package/dist/util/fetch-code.js.map +1 -1
  62. package/dist/util/html-to-markdown.d.ts +17 -0
  63. package/dist/util/html-to-markdown.d.ts.map +1 -0
  64. package/dist/util/html-to-markdown.js +66 -0
  65. package/dist/util/html-to-markdown.js.map +1 -0
  66. package/dist/util/intent-filter.d.ts +12 -3
  67. package/dist/util/intent-filter.d.ts.map +1 -1
  68. package/dist/util/intent-filter.js +61 -8
  69. package/dist/util/intent-filter.js.map +1 -1
  70. package/dist/util/regret.d.ts +54 -0
  71. package/dist/util/regret.d.ts.map +1 -0
  72. package/dist/util/regret.js +107 -0
  73. package/dist/util/regret.js.map +1 -0
  74. package/docs/agentic-benchmark.md +110 -0
  75. package/docs/quality-regression-report.md +20 -0
  76. package/hooks/claude-codex-hooks.json +19 -0
  77. package/package.json +9 -5
  78. package/skills/context-compress-audit/SKILL.md +49 -0
  79. package/skills/context-compress-audit/agents/openai.yaml +13 -0
@@ -406,11 +406,11 @@ var require_codegen = __commonJS({
406
406
  const rhs = this.rhs === void 0 ? "" : ` = ${this.rhs}`;
407
407
  return `${varKind} ${this.name}${rhs};` + _n;
408
408
  }
409
- optimizeNames(names, constants) {
409
+ optimizeNames(names, constants2) {
410
410
  if (!names[this.name.str])
411
411
  return;
412
412
  if (this.rhs)
413
- this.rhs = optimizeExpr(this.rhs, names, constants);
413
+ this.rhs = optimizeExpr(this.rhs, names, constants2);
414
414
  return this;
415
415
  }
416
416
  get names() {
@@ -427,10 +427,10 @@ var require_codegen = __commonJS({
427
427
  render({ _n }) {
428
428
  return `${this.lhs} = ${this.rhs};` + _n;
429
429
  }
430
- optimizeNames(names, constants) {
430
+ optimizeNames(names, constants2) {
431
431
  if (this.lhs instanceof code_1.Name && !names[this.lhs.str] && !this.sideEffects)
432
432
  return;
433
- this.rhs = optimizeExpr(this.rhs, names, constants);
433
+ this.rhs = optimizeExpr(this.rhs, names, constants2);
434
434
  return this;
435
435
  }
436
436
  get names() {
@@ -491,8 +491,8 @@ var require_codegen = __commonJS({
491
491
  optimizeNodes() {
492
492
  return `${this.code}` ? this : void 0;
493
493
  }
494
- optimizeNames(names, constants) {
495
- this.code = optimizeExpr(this.code, names, constants);
494
+ optimizeNames(names, constants2) {
495
+ this.code = optimizeExpr(this.code, names, constants2);
496
496
  return this;
497
497
  }
498
498
  get names() {
@@ -521,12 +521,12 @@ var require_codegen = __commonJS({
521
521
  }
522
522
  return nodes.length > 0 ? this : void 0;
523
523
  }
524
- optimizeNames(names, constants) {
524
+ optimizeNames(names, constants2) {
525
525
  const { nodes } = this;
526
526
  let i = nodes.length;
527
527
  while (i--) {
528
528
  const n = nodes[i];
529
- if (n.optimizeNames(names, constants))
529
+ if (n.optimizeNames(names, constants2))
530
530
  continue;
531
531
  subtractNames(names, n.names);
532
532
  nodes.splice(i, 1);
@@ -579,12 +579,12 @@ var require_codegen = __commonJS({
579
579
  return void 0;
580
580
  return this;
581
581
  }
582
- optimizeNames(names, constants) {
582
+ optimizeNames(names, constants2) {
583
583
  var _a;
584
- this.else = (_a = this.else) === null || _a === void 0 ? void 0 : _a.optimizeNames(names, constants);
585
- if (!(super.optimizeNames(names, constants) || this.else))
584
+ this.else = (_a = this.else) === null || _a === void 0 ? void 0 : _a.optimizeNames(names, constants2);
585
+ if (!(super.optimizeNames(names, constants2) || this.else))
586
586
  return;
587
- this.condition = optimizeExpr(this.condition, names, constants);
587
+ this.condition = optimizeExpr(this.condition, names, constants2);
588
588
  return this;
589
589
  }
590
590
  get names() {
@@ -607,10 +607,10 @@ var require_codegen = __commonJS({
607
607
  render(opts) {
608
608
  return `for(${this.iteration})` + super.render(opts);
609
609
  }
610
- optimizeNames(names, constants) {
611
- if (!super.optimizeNames(names, constants))
610
+ optimizeNames(names, constants2) {
611
+ if (!super.optimizeNames(names, constants2))
612
612
  return;
613
- this.iteration = optimizeExpr(this.iteration, names, constants);
613
+ this.iteration = optimizeExpr(this.iteration, names, constants2);
614
614
  return this;
615
615
  }
616
616
  get names() {
@@ -646,10 +646,10 @@ var require_codegen = __commonJS({
646
646
  render(opts) {
647
647
  return `for(${this.varKind} ${this.name} ${this.loop} ${this.iterable})` + super.render(opts);
648
648
  }
649
- optimizeNames(names, constants) {
650
- if (!super.optimizeNames(names, constants))
649
+ optimizeNames(names, constants2) {
650
+ if (!super.optimizeNames(names, constants2))
651
651
  return;
652
- this.iterable = optimizeExpr(this.iterable, names, constants);
652
+ this.iterable = optimizeExpr(this.iterable, names, constants2);
653
653
  return this;
654
654
  }
655
655
  get names() {
@@ -691,11 +691,11 @@ var require_codegen = __commonJS({
691
691
  (_b = this.finally) === null || _b === void 0 ? void 0 : _b.optimizeNodes();
692
692
  return this;
693
693
  }
694
- optimizeNames(names, constants) {
694
+ optimizeNames(names, constants2) {
695
695
  var _a, _b;
696
- super.optimizeNames(names, constants);
697
- (_a = this.catch) === null || _a === void 0 ? void 0 : _a.optimizeNames(names, constants);
698
- (_b = this.finally) === null || _b === void 0 ? void 0 : _b.optimizeNames(names, constants);
696
+ super.optimizeNames(names, constants2);
697
+ (_a = this.catch) === null || _a === void 0 ? void 0 : _a.optimizeNames(names, constants2);
698
+ (_b = this.finally) === null || _b === void 0 ? void 0 : _b.optimizeNames(names, constants2);
699
699
  return this;
700
700
  }
701
701
  get names() {
@@ -996,7 +996,7 @@ var require_codegen = __commonJS({
996
996
  function addExprNames(names, from) {
997
997
  return from instanceof code_1._CodeOrName ? addNames(names, from.names) : names;
998
998
  }
999
- function optimizeExpr(expr, names, constants) {
999
+ function optimizeExpr(expr, names, constants2) {
1000
1000
  if (expr instanceof code_1.Name)
1001
1001
  return replaceName(expr);
1002
1002
  if (!canOptimize(expr))
@@ -1011,14 +1011,14 @@ var require_codegen = __commonJS({
1011
1011
  return items;
1012
1012
  }, []));
1013
1013
  function replaceName(n) {
1014
- const c = constants[n.str];
1014
+ const c = constants2[n.str];
1015
1015
  if (c === void 0 || names[n.str] !== 1)
1016
1016
  return n;
1017
1017
  delete names[n.str];
1018
1018
  return c;
1019
1019
  }
1020
1020
  function canOptimize(e) {
1021
- return e instanceof code_1._Code && e._items.some((c) => c instanceof code_1.Name && names[c.str] === 1 && constants[c.str] !== void 0);
1021
+ return e instanceof code_1._Code && e._items.some((c) => c instanceof code_1.Name && names[c.str] === 1 && constants2[c.str] !== void 0);
1022
1022
  }
1023
1023
  }
1024
1024
  function subtractNames(names, from) {
@@ -10853,6 +10853,7 @@ var DEFAULTS = {
10853
10853
  nudgeOnRead: true,
10854
10854
  nudgeOnGrep: true,
10855
10855
  intentSearchThreshold: 5e3,
10856
+ intentBudgetBytes: 1800,
10856
10857
  maxOutputBytes: 102400,
10857
10858
  hardCapBytes: 100 * 1024 * 1024,
10858
10859
  searchMaxBytes: 40960,
@@ -10872,14 +10873,16 @@ var LEVEL_OVERRIDES = {
10872
10873
  searchMaxBytes: 20480,
10873
10874
  batchMaxBytes: 40960,
10874
10875
  searchLimit: 2,
10875
- intentSearchThreshold: 3e3
10876
+ intentSearchThreshold: 3e3,
10877
+ intentBudgetBytes: 1e3
10876
10878
  },
10877
10879
  ultra: {
10878
10880
  maxOutputBytes: 25600,
10879
10881
  searchMaxBytes: 10240,
10880
10882
  batchMaxBytes: 20480,
10881
10883
  searchLimit: 1,
10882
- intentSearchThreshold: 2e3
10884
+ intentSearchThreshold: 2e3,
10885
+ intentBudgetBytes: 500
10883
10886
  }
10884
10887
  };
10885
10888
  var ConfigSchema = external_exports.object({
@@ -10890,6 +10893,7 @@ var ConfigSchema = external_exports.object({
10890
10893
  nudgeOnRead: external_exports.boolean().optional(),
10891
10894
  nudgeOnGrep: external_exports.boolean().optional(),
10892
10895
  intentSearchThreshold: external_exports.number().int().positive().optional(),
10896
+ intentBudgetBytes: external_exports.number().int().positive().optional(),
10893
10897
  maxOutputBytes: external_exports.number().int().positive().optional(),
10894
10898
  hardCapBytes: external_exports.number().int().positive().optional(),
10895
10899
  searchMaxBytes: external_exports.number().int().positive().optional(),
@@ -10965,6 +10969,8 @@ function loadEnvConfig() {
10965
10969
  if (searchBlock !== void 0) partial2.searchBlockAfter = searchBlock;
10966
10970
  const intentThreshold = parseIntEnv("CONTEXT_COMPRESS_INTENT_SEARCH_THRESHOLD");
10967
10971
  if (intentThreshold !== void 0) partial2.intentSearchThreshold = intentThreshold;
10972
+ const intentBudget = parseIntEnv("CONTEXT_COMPRESS_INTENT_BUDGET_BYTES");
10973
+ if (intentBudget !== void 0) partial2.intentBudgetBytes = intentBudget;
10968
10974
  const level = process.env.CONTEXT_COMPRESS_LEVEL;
10969
10975
  if (level === "normal" || level === "compact" || level === "ultra") {
10970
10976
  partial2.compressionLevel = level;
@@ -11008,6 +11014,12 @@ function loadConfig(projectDir2) {
11008
11014
  );
11009
11015
  merged.intentSearchThreshold = 0;
11010
11016
  }
11017
+ if (merged.intentBudgetBytes < 0) {
11018
+ console.error(
11019
+ `[context-compress] Config: intentBudgetBytes clamped from ${merged.intentBudgetBytes} to 0`
11020
+ );
11021
+ merged.intentBudgetBytes = 0;
11022
+ }
11011
11023
  if (merged.searchLimit < 1) {
11012
11024
  console.error(`[context-compress] Config: searchLimit clamped from ${merged.searchLimit} to 1`);
11013
11025
  merged.searchLimit = 1;
@@ -11053,15 +11065,20 @@ function getConfig() {
11053
11065
  }
11054
11066
 
11055
11067
  // src/logger.ts
11068
+ var debugOverride = null;
11069
+ function configureLogger(debugEnabled) {
11070
+ debugOverride = debugEnabled;
11071
+ }
11056
11072
  function debug(...args) {
11057
- if (getConfig().debug) {
11073
+ const enabled = debugOverride ?? getConfig().debug;
11074
+ if (enabled) {
11058
11075
  process.stderr.write(`[context-compress] ${args.map(String).join(" ")}
11059
11076
  `);
11060
11077
  }
11061
11078
  }
11062
11079
 
11063
11080
  // src/server.ts
11064
- import { join as join4 } from "node:path";
11081
+ import { join as join6 } from "node:path";
11065
11082
 
11066
11083
  // node_modules/zod/v4/core/core.js
11067
11084
  var NEVER2 = Object.freeze({
@@ -21719,6 +21736,228 @@ function filterPs(stdout) {
21719
21736
  return { output: out.join("\n"), filtered: true };
21720
21737
  }
21721
21738
 
21739
+ // src/format-filter.ts
21740
+ var MIN_BYTES_JSON = 1e3;
21741
+ var MIN_LINES_LOGS = 30;
21742
+ var ARRAY_COLLAPSE_THRESHOLD = 20;
21743
+ var ARRAY_KEEP_HEAD = 3;
21744
+ var LONG_STRING_LIMIT = 500;
21745
+ function detectFormat(text) {
21746
+ const trimmed = text.trim();
21747
+ if (!trimmed) return "plain";
21748
+ if (isWholeJson(trimmed)) return "json";
21749
+ const lines = trimmed.split("\n");
21750
+ if (isNdjson(lines)) return "ndjson";
21751
+ if (isLogs(lines)) return "logs";
21752
+ return "plain";
21753
+ }
21754
+ function isWholeJson(trimmed) {
21755
+ const wrapped = trimmed.startsWith("{") && trimmed.endsWith("}") || trimmed.startsWith("[") && trimmed.endsWith("]");
21756
+ return wrapped && tryParse(trimmed);
21757
+ }
21758
+ function isNdjson(lines) {
21759
+ if (lines.length < 3) return false;
21760
+ let jsonLines = 0;
21761
+ let sampled = 0;
21762
+ for (const line of lines) {
21763
+ const l = line.trim();
21764
+ if (!l) continue;
21765
+ sampled++;
21766
+ if (sampled > 50) break;
21767
+ if ((l.startsWith("{") || l.startsWith("[")) && tryParse(l)) jsonLines++;
21768
+ }
21769
+ return sampled > 0 && jsonLines / sampled >= 0.8;
21770
+ }
21771
+ function isLogs(lines) {
21772
+ if (lines.length < MIN_LINES_LOGS) return false;
21773
+ const templates = /* @__PURE__ */ new Set();
21774
+ let counted = 0;
21775
+ let logLike = 0;
21776
+ for (const line of lines) {
21777
+ if (!line.trim()) continue;
21778
+ counted++;
21779
+ templates.add(maskVariables(line));
21780
+ if (LOG_LINE.test(line)) logLike++;
21781
+ if (counted > 200) break;
21782
+ }
21783
+ const repetitive = counted >= MIN_LINES_LOGS && templates.size <= counted * 0.5;
21784
+ const structured = counted > 0 && logLike / counted >= 0.5;
21785
+ return repetitive && structured;
21786
+ }
21787
+ var LOG_LINE = /^\s*(?:\[?\d{4}-\d{2}-\d{2}|\[?\d{2}:\d{2}:\d{2})|\b(?:TRACE|DEBUG|INFO|WARN(?:ING)?|ERROR|FATAL|PANIC)\b/;
21788
+ function tryParse(s) {
21789
+ try {
21790
+ JSON.parse(s);
21791
+ return true;
21792
+ } catch {
21793
+ return false;
21794
+ }
21795
+ }
21796
+ function maskVariables(line) {
21797
+ return line.replace(/\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}(?:[.,]\d+)?(?:Z|[+-]\d{2}:?\d{2})?/g, "<TS>").replace(/\b\d{2}:\d{2}:\d{2}(?:[.,]\d+)?\b/g, "<TIME>").replace(
21798
+ /\b[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\b/g,
21799
+ "<UUID>"
21800
+ ).replace(/\b0x[0-9a-fA-F]+\b/g, "<HEX>").replace(/\b[0-9a-fA-F]{7,}\b/g, "<HASH>").replace(/\b\d{1,3}(?:\.\d{1,3}){3}(?::\d+)?\b/g, "<IP>").replace(/(?:\/[\w.\-]+){2,}/g, "<PATH>").replace(/"[^"]*"/g, '"<STR>"').replace(/'[^']*'/g, "'<STR>'").replace(/\d+/g, "<N>");
21801
+ }
21802
+ var ERROR_LINE = /\b(error|err|fatal|panic|exception|traceback|warn|warning|failed|failure)\b/i;
21803
+ var KEEP_VERBATIM = ERROR_LINE;
21804
+ function extractErrorLines(text, max = 5) {
21805
+ const out = [];
21806
+ const seen = /* @__PURE__ */ new Set();
21807
+ for (const line of text.split("\n")) {
21808
+ const t = line.trim();
21809
+ if (!t || !ERROR_LINE.test(t) || seen.has(t)) continue;
21810
+ seen.add(t);
21811
+ out.push(t);
21812
+ if (out.length >= max) break;
21813
+ }
21814
+ return out;
21815
+ }
21816
+ function compressLogs(text) {
21817
+ const lines = text.split("\n");
21818
+ const order = [];
21819
+ const groups = /* @__PURE__ */ new Map();
21820
+ const verbatim = [];
21821
+ lines.forEach((line, index) => {
21822
+ if (!line.trim()) return;
21823
+ if (KEEP_VERBATIM.test(line)) {
21824
+ verbatim.push({ index, line });
21825
+ return;
21826
+ }
21827
+ const key = maskVariables(line);
21828
+ const g = groups.get(key);
21829
+ if (g) {
21830
+ g.count++;
21831
+ } else {
21832
+ groups.set(key, { first: line, count: 1 });
21833
+ order.push(key);
21834
+ }
21835
+ });
21836
+ const parts = [];
21837
+ for (const key of order) {
21838
+ const g = groups.get(key);
21839
+ if (!g) continue;
21840
+ if (g.count === 1) {
21841
+ parts.push(g.first);
21842
+ } else {
21843
+ parts.push(`${g.first}
21844
+ \u2026 \xD7${g.count} similar lines (template: ${truncate(key, 120)})`);
21845
+ }
21846
+ }
21847
+ let out = parts.join("\n");
21848
+ if (verbatim.length > 0) {
21849
+ out += `
21850
+
21851
+ ${verbatim.length} error/warning line(s) preserved verbatim:
21852
+ `;
21853
+ out += verbatim.map((v) => v.line).join("\n");
21854
+ }
21855
+ return { output: out, filtered: out.length < text.length, format: "logs" };
21856
+ }
21857
+ function compressNdjson(text, mode) {
21858
+ const lines = text.split("\n").filter((l) => l.trim());
21859
+ const shapes = /* @__PURE__ */ new Map();
21860
+ const order = [];
21861
+ let parsedAll = true;
21862
+ for (const line of lines) {
21863
+ let obj;
21864
+ try {
21865
+ obj = JSON.parse(line);
21866
+ } catch {
21867
+ parsedAll = false;
21868
+ break;
21869
+ }
21870
+ const shape = shapeOf(obj);
21871
+ const s = shapes.get(shape);
21872
+ if (s) {
21873
+ s.count++;
21874
+ } else {
21875
+ shapes.set(shape, { first: line, count: 1 });
21876
+ order.push(shape);
21877
+ }
21878
+ }
21879
+ if (!parsedAll) return { output: text, filtered: false, format: "ndjson" };
21880
+ const parts = [`NDJSON: ${lines.length} records, ${order.length} distinct shape(s).`];
21881
+ for (const shape of order) {
21882
+ const g = shapes.get(shape);
21883
+ if (!g) continue;
21884
+ const keep = mode === "aggressive" ? 1 : ARRAY_KEEP_HEAD;
21885
+ parts.push(`
21886
+ shape ${shape} \u2014 ${g.count} record(s). Example:`);
21887
+ parts.push(minifyJson(g.first, mode));
21888
+ if (g.count > keep) parts.push(`\u2026 (${g.count - 1} more of this shape)`);
21889
+ }
21890
+ const out = parts.join("\n");
21891
+ return { output: out, filtered: out.length < text.length, format: "ndjson" };
21892
+ }
21893
+ function compressJson(text, mode) {
21894
+ let parsed;
21895
+ try {
21896
+ parsed = JSON.parse(text);
21897
+ } catch {
21898
+ return { output: text, filtered: false, format: "json" };
21899
+ }
21900
+ const value = mode === "aggressive" ? summarizeValue(parsed) : parsed;
21901
+ const out = JSON.stringify(value);
21902
+ if (out.length >= text.length) return { output: text, filtered: false, format: "json" };
21903
+ return { output: out, filtered: true, format: "json" };
21904
+ }
21905
+ function summarizeValue(value) {
21906
+ if (Array.isArray(value)) {
21907
+ const mapped = value.slice(0, ARRAY_COLLAPSE_THRESHOLD).map(summarizeValue);
21908
+ if (value.length > ARRAY_COLLAPSE_THRESHOLD) {
21909
+ mapped.splice(ARRAY_KEEP_HEAD);
21910
+ mapped.push({ "\u2026": `${value.length - ARRAY_KEEP_HEAD} more items (search to retrieve)` });
21911
+ }
21912
+ return mapped;
21913
+ }
21914
+ if (value && typeof value === "object") {
21915
+ const out = {};
21916
+ for (const [k, v] of Object.entries(value)) out[k] = summarizeValue(v);
21917
+ return out;
21918
+ }
21919
+ if (typeof value === "string" && value.length > LONG_STRING_LIMIT) {
21920
+ return `${value.slice(0, LONG_STRING_LIMIT)}\u2026(${value.length} chars)`;
21921
+ }
21922
+ return value;
21923
+ }
21924
+ function shapeOf(value) {
21925
+ if (Array.isArray(value)) return `[${value.length ? shapeOf(value[0]) : ""}]`;
21926
+ if (value && typeof value === "object") {
21927
+ return `{${Object.keys(value).sort().join(",")}}`;
21928
+ }
21929
+ return typeof value;
21930
+ }
21931
+ function minifyJson(line, mode) {
21932
+ try {
21933
+ const v = mode === "aggressive" ? summarizeValue(JSON.parse(line)) : JSON.parse(line);
21934
+ return JSON.stringify(v);
21935
+ } catch {
21936
+ return line;
21937
+ }
21938
+ }
21939
+ function truncate(s, n) {
21940
+ return s.length > n ? `${s.slice(0, n)}\u2026` : s;
21941
+ }
21942
+ function applyFormatFilter(text, mode) {
21943
+ if (mode === "conservative") return { output: text, filtered: false, format: "plain" };
21944
+ const format = detectFormat(text);
21945
+ switch (format) {
21946
+ case "json":
21947
+ if (Buffer.byteLength(text) < MIN_BYTES_JSON)
21948
+ return { output: text, filtered: false, format };
21949
+ return compressJson(text, mode);
21950
+ case "ndjson":
21951
+ if (Buffer.byteLength(text) < MIN_BYTES_JSON)
21952
+ return { output: text, filtered: false, format };
21953
+ return compressNdjson(text, mode);
21954
+ case "logs":
21955
+ return compressLogs(text);
21956
+ default:
21957
+ return { output: text, filtered: false, format: "plain" };
21958
+ }
21959
+ }
21960
+
21722
21961
  // src/utils.ts
21723
21962
  function detectInjectionPatterns(content) {
21724
21963
  const warnings = [];
@@ -21795,8 +22034,9 @@ var SAFE_ENV_KEYS = [
21795
22034
  function buildEnv(config3) {
21796
22035
  const env = {};
21797
22036
  for (const key of SAFE_ENV_KEYS) {
21798
- if (process.env[key]) {
21799
- env[key] = process.env[key];
22037
+ const value = process.env[key];
22038
+ if (value) {
22039
+ env[key] = value;
21800
22040
  }
21801
22041
  }
21802
22042
  env.LANG = "en_US.UTF-8";
@@ -21804,8 +22044,9 @@ function buildEnv(config3) {
21804
22044
  env.PYTHONUNBUFFERED = "1";
21805
22045
  env.NO_COLOR = "1";
21806
22046
  for (const key of config3.passthroughEnvVars) {
21807
- if (process.env[key]) {
21808
- env[key] = process.env[key];
22047
+ const value = process.env[key];
22048
+ if (value) {
22049
+ env[key] = value;
21809
22050
  }
21810
22051
  }
21811
22052
  return env;
@@ -22030,7 +22271,7 @@ var SubprocessExecutor = class {
22030
22271
  opts.language === "shell" ? opts.code : void 0
22031
22272
  );
22032
22273
  } finally {
22033
- setTimeout(() => this.cleanupTempDir(tmpDir), 100).unref();
22274
+ this.cleanupTempDir(tmpDir);
22034
22275
  }
22035
22276
  }
22036
22277
  /**
@@ -22120,12 +22361,18 @@ var SubprocessExecutor = class {
22120
22361
  [output capped at ${formatBytes(hardCap)} \u2014 process killed]`;
22121
22362
  }
22122
22363
  stdout = stripAnsi(stdout);
22364
+ let commandFiltered = false;
22123
22365
  if (shellCode && stdout) {
22124
22366
  const filtered = applyCommandFilter(shellCode, stdout);
22125
22367
  if (filtered.filtered) {
22126
22368
  stdout = filtered.output;
22369
+ commandFiltered = true;
22127
22370
  }
22128
22371
  }
22372
+ if (!commandFiltered && stdout) {
22373
+ const fmt = applyFormatFilter(stdout, "balanced");
22374
+ if (fmt.filtered) stdout = fmt.output;
22375
+ }
22129
22376
  if (stdout.length > 1e4) {
22130
22377
  stdout = stripProgressLines(stdout);
22131
22378
  stdout = deduplicateLines(stdout);
@@ -22154,8 +22401,14 @@ var SubprocessExecutor = class {
22154
22401
  cleanupTempDir(dir) {
22155
22402
  try {
22156
22403
  rmSync(dir, { recursive: true, force: true });
22157
- } catch (e) {
22158
- debug("Failed to cleanup temp dir:", dir, e);
22404
+ } catch {
22405
+ setTimeout(() => {
22406
+ try {
22407
+ rmSync(dir, { recursive: true, force: true });
22408
+ } catch (e) {
22409
+ debug("Failed to cleanup temp dir:", dir, e);
22410
+ }
22411
+ }, 100).unref();
22159
22412
  }
22160
22413
  }
22161
22414
  };
@@ -22169,8 +22422,8 @@ __cm_main().then(()=>{${epilogue}}).catch(e=>{console.error(e);${epilogue}proces
22169
22422
  }
22170
22423
 
22171
22424
  // src/runtime/index.ts
22172
- import { exec } from "node:child_process";
22173
- import { promisify } from "node:util";
22425
+ import { constants, accessSync } from "node:fs";
22426
+ import { delimiter, join as join3 } from "node:path";
22174
22427
 
22175
22428
  // src/runtime/languages/elixir.ts
22176
22429
  var elixirPlugin = {
@@ -22436,7 +22689,6 @@ ${code}`;
22436
22689
  };
22437
22690
 
22438
22691
  // src/runtime/index.ts
22439
- var execAsync = promisify(exec);
22440
22692
  var ALL_PLUGINS = [
22441
22693
  javascriptPlugin,
22442
22694
  typescriptPlugin,
@@ -22450,31 +22702,38 @@ var ALL_PLUGINS = [
22450
22702
  rPlugin,
22451
22703
  elixirPlugin
22452
22704
  ];
22453
- async function commandExists(cmd) {
22454
- const checkCmd = process.platform === "win32" ? `where ${cmd} 2>nul` : `command -v ${cmd} 2>/dev/null`;
22705
+ var PATH_DIRS = (process.env.PATH ?? "").split(delimiter).filter(Boolean);
22706
+ var WIN_EXTS = (process.env.PATHEXT ?? ".EXE;.CMD;.BAT;.COM").split(";").filter(Boolean);
22707
+ function commandExists(cmd) {
22708
+ if (cmd.includes("/") || cmd.includes("\\")) {
22709
+ return isExecutable(cmd);
22710
+ }
22711
+ const exts = process.platform === "win32" ? WIN_EXTS : [""];
22712
+ for (const dir of PATH_DIRS) {
22713
+ for (const ext of exts) {
22714
+ if (isExecutable(join3(dir, cmd + ext))) return true;
22715
+ }
22716
+ }
22717
+ return false;
22718
+ }
22719
+ function isExecutable(filePath) {
22455
22720
  try {
22456
- await execAsync(checkCmd, { timeout: 3e3 });
22721
+ accessSync(filePath, process.platform === "win32" ? constants.F_OK : constants.X_OK);
22457
22722
  return true;
22458
22723
  } catch {
22459
22724
  return false;
22460
22725
  }
22461
22726
  }
22462
- async function detectRuntimes() {
22727
+ function detectRuntimes() {
22463
22728
  const map = /* @__PURE__ */ new Map();
22464
- const tasks = ALL_PLUGINS.map(async (plugin) => {
22729
+ for (const plugin of ALL_PLUGINS) {
22465
22730
  for (const candidate of plugin.runtimeCandidates) {
22466
- if (await commandExists(candidate)) {
22467
- return { plugin, runtime: candidate };
22731
+ if (commandExists(candidate)) {
22732
+ map.set(plugin.language, { plugin, runtime: candidate });
22733
+ debug(`Detected ${plugin.language}: ${candidate}`);
22734
+ break;
22468
22735
  }
22469
22736
  }
22470
- return null;
22471
- });
22472
- const results = await Promise.all(tasks);
22473
- for (const result of results) {
22474
- if (result) {
22475
- map.set(result.plugin.language, result);
22476
- debug(`Detected ${result.plugin.language}: ${result.runtime}`);
22477
- }
22478
22737
  }
22479
22738
  return map;
22480
22739
  }
@@ -22484,7 +22743,32 @@ function hasBun(runtimes) {
22484
22743
  }
22485
22744
 
22486
22745
  // src/stats.ts
22487
- import { readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
22746
+ import { readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "node:fs";
22747
+
22748
+ // src/util/regret.ts
22749
+ import { existsSync, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "node:fs";
22750
+ import { homedir as homedir2 } from "node:os";
22751
+ import { dirname, join as join4 } from "node:path";
22752
+ var DEFAULT_PATH = join4(homedir2(), ".context-compress", "regret.json");
22753
+ function load(path) {
22754
+ if (!existsSync(path)) return {};
22755
+ try {
22756
+ return JSON.parse(readFileSync2(path, "utf-8"));
22757
+ } catch {
22758
+ return {};
22759
+ }
22760
+ }
22761
+ function regretSummary(opts = {}) {
22762
+ const map = load(opts.path ?? DEFAULT_PATH);
22763
+ return Object.entries(map).map(([fingerprint, r]) => ({
22764
+ fingerprint,
22765
+ observations: r.observations,
22766
+ regrets: r.regrets,
22767
+ regretRate: r.observations > 0 ? r.regrets / r.observations : 0
22768
+ })).filter((r) => r.regrets > 0).sort((a, b) => b.regretRate - a.regretRate);
22769
+ }
22770
+
22771
+ // src/stats.ts
22488
22772
  var BAR_WIDTH = 20;
22489
22773
  function asciiBar(ratio, width = BAR_WIDTH) {
22490
22774
  const filled = Math.round(ratio * width);
@@ -22519,13 +22803,17 @@ var SessionTracker = class {
22519
22803
  this.stats.bytesSandboxed += bytes;
22520
22804
  }
22521
22805
  getSnapshot() {
22522
- return { ...this.stats };
22806
+ return {
22807
+ ...this.stats,
22808
+ calls: { ...this.stats.calls },
22809
+ bytesReturned: { ...this.stats.bytesReturned }
22810
+ };
22523
22811
  }
22524
22812
  /** Load cumulative stats from disk */
22525
22813
  loadCumulative() {
22526
22814
  if (!this.cumulativeFile) return null;
22527
22815
  try {
22528
- const data = readFileSync2(this.cumulativeFile, "utf-8");
22816
+ const data = readFileSync3(this.cumulativeFile, "utf-8");
22529
22817
  return JSON.parse(data);
22530
22818
  } catch {
22531
22819
  return null;
@@ -22558,7 +22846,7 @@ var SessionTracker = class {
22558
22846
  cumulative.perCommand[name].calls += calls;
22559
22847
  }
22560
22848
  try {
22561
- writeFileSync2(this.cumulativeFile, JSON.stringify(cumulative, null, 2));
22849
+ writeFileSync3(this.cumulativeFile, JSON.stringify(cumulative, null, 2));
22562
22850
  } catch {
22563
22851
  }
22564
22852
  }
@@ -22634,14 +22922,25 @@ Context-compress kept ${formatBytes(keptOut)} out of context (${reductionPct}% s
22634
22922
  lines.push(`| Est. total tokens saved | ~${cumTokensMid.toLocaleString()} |`);
22635
22923
  lines.push(`| Tracking since | ${cumulative.firstSeen.split("T")[0]} |`);
22636
22924
  }
22925
+ const regrets = regretSummary();
22926
+ if (regrets.length > 0) {
22927
+ lines.push("\n## Auto-Mode Self-Tuning (regret-adjusted)\n");
22928
+ lines.push("| Command | Re-runs / Obs | Regret |");
22929
+ lines.push("|---------|---------------|--------|");
22930
+ for (const r of regrets.slice(0, 10)) {
22931
+ lines.push(
22932
+ `| \`${r.fingerprint}\` | ${r.regrets}/${r.observations} | ${(r.regretRate * 100).toFixed(0)}% |`
22933
+ );
22934
+ }
22935
+ }
22637
22936
  return lines.join("\n");
22638
22937
  }
22639
22938
  };
22640
22939
 
22641
22940
  // src/store.ts
22642
- import { mkdirSync as mkdirSync2, readdirSync, unlinkSync } from "node:fs";
22941
+ import { mkdirSync as mkdirSync3, readdirSync, unlinkSync } from "node:fs";
22643
22942
  import { tmpdir as tmpdir2 } from "node:os";
22644
- import { join as join3 } from "node:path";
22943
+ import { join as join5 } from "node:path";
22645
22944
  import Database from "better-sqlite3";
22646
22945
 
22647
22946
  // src/snippet.ts
@@ -22825,6 +23124,7 @@ function levenshtein(a, b, maxDist) {
22825
23124
  var ContentStore = class {
22826
23125
  db;
22827
23126
  hasTrigramTable = false;
23127
+ closed = false;
22828
23128
  // Cached prepared statements (initialized in initSchema, always available after constructor)
22829
23129
  insertSourceStmt;
22830
23130
  insertChunkStmt;
@@ -22838,12 +23138,12 @@ var ContentStore = class {
22838
23138
  if (typeof options === "string") {
22839
23139
  path = options;
22840
23140
  } else if (options?.persistDb || options?.dbDir) {
22841
- const dir = options.dbDir ?? join3(process.env.CLAUDE_PROJECT_DIR ?? process.cwd(), ".context-compress");
22842
- mkdirSync2(dir, { recursive: true });
22843
- path = join3(dir, "store.db");
23141
+ const dir = options.dbDir ?? join5(process.env.CLAUDE_PROJECT_DIR ?? process.cwd(), ".context-compress");
23142
+ mkdirSync3(dir, { recursive: true });
23143
+ path = join5(dir, "store.db");
22844
23144
  debug("Using persistent DB at", path);
22845
23145
  } else {
22846
- path = (typeof options === "object" ? options?.dbPath : void 0) ?? join3(tmpdir2(), `context-compress-${process.pid}.db`);
23146
+ path = (typeof options === "object" ? options?.dbPath : void 0) ?? join5(tmpdir2(), `context-compress-${process.pid}.db`);
22847
23147
  }
22848
23148
  this.db = new Database(path);
22849
23149
  this.db.pragma("journal_mode = WAL");
@@ -22894,9 +23194,20 @@ var ContentStore = class {
22894
23194
  tokenize='trigram'
22895
23195
  );
22896
23196
  `);
22897
- this.db.exec(
22898
- "INSERT INTO chunks_trigram (title, content, source_id, content_type) SELECT title, content, source_id, content_type FROM chunks"
23197
+ const BATCH = 5e3;
23198
+ const backfill = this.db.prepare(
23199
+ "INSERT INTO chunks_trigram (title, content, source_id, content_type) SELECT title, content, source_id, content_type FROM chunks WHERE rowid > ? ORDER BY rowid LIMIT ?"
23200
+ );
23201
+ const windowMaxStmt = this.db.prepare(
23202
+ "SELECT MAX(rowid) AS maxRowid FROM (SELECT rowid FROM chunks WHERE rowid > ? ORDER BY rowid LIMIT ?)"
22899
23203
  );
23204
+ let lastRowid = 0;
23205
+ for (; ; ) {
23206
+ const window = windowMaxStmt.get(lastRowid, BATCH);
23207
+ if (window.maxRowid == null) break;
23208
+ backfill.run(lastRowid, BATCH);
23209
+ lastRowid = window.maxRowid;
23210
+ }
22900
23211
  this.hasTrigramTable = true;
22901
23212
  }
22902
23213
  /**
@@ -23117,6 +23428,8 @@ var ContentStore = class {
23117
23428
  };
23118
23429
  }
23119
23430
  close() {
23431
+ if (this.closed) return;
23432
+ this.closed = true;
23120
23433
  this.db.close();
23121
23434
  }
23122
23435
  };
@@ -23214,7 +23527,7 @@ function cleanupStaleDbs() {
23214
23527
  try {
23215
23528
  process.kill(pid, 0);
23216
23529
  } catch {
23217
- const basePath = join3(dir, file);
23530
+ const basePath = join5(dir, file);
23218
23531
  for (const suffix of ["", "-wal", "-shm"]) {
23219
23532
  try {
23220
23533
  unlinkSync(basePath + suffix);
@@ -23263,20 +23576,28 @@ function registerBatchExecuteTool(server2, ctx) {
23263
23576
  }),
23264
23577
  4
23265
23578
  );
23579
+ const COMBINED_CAP = config3.batchMaxBytes;
23580
+ const PER_COMMAND_CAP = Math.max(64e3, Math.floor(COMBINED_CAP / 4));
23266
23581
  let combined = "";
23267
23582
  const inventory = [];
23583
+ let truncatedCommands = 0;
23268
23584
  for (let i = 0; i < commandResults.length; i++) {
23269
23585
  const settled = commandResults[i];
23270
23586
  const label = commands[i].label;
23271
23587
  if (settled.status === "fulfilled") {
23272
23588
  const { result } = settled.value;
23273
- const output2 = result.stdout || "(no output)";
23589
+ let output2 = result.stdout || "(no output)";
23590
+ const lineCount = output2.split("\n").length;
23591
+ if (Buffer.byteLength(output2) > PER_COMMAND_CAP) {
23592
+ output2 = `${output2.slice(0, PER_COMMAND_CAP)}
23593
+ \u2026(output truncated)`;
23594
+ truncatedCommands++;
23595
+ }
23274
23596
  combined += `## ${label}
23275
23597
 
23276
23598
  ${output2}
23277
23599
 
23278
23600
  `;
23279
- const lineCount = output2.split("\n").length;
23280
23601
  inventory.push(`- **${label}**: ${lineCount} lines`);
23281
23602
  } else {
23282
23603
  combined += `## ${label}
@@ -23286,6 +23607,11 @@ ${output2}
23286
23607
  `;
23287
23608
  inventory.push(`- **${label}**: error`);
23288
23609
  }
23610
+ if (Buffer.byteLength(combined) >= COMBINED_CAP) {
23611
+ combined += "\n\u2026(remaining command output omitted: combined size limit reached)\n";
23612
+ truncatedCommands += commandResults.length - i - 1;
23613
+ break;
23614
+ }
23289
23615
  }
23290
23616
  const indexed = store.index(combined, "batch_execute");
23291
23617
  tracker.trackIndexed(Buffer.byteLength(combined));
@@ -23320,6 +23646,11 @@ ${hit.snippet}
23320
23646
  ${inventory.join("\n")}
23321
23647
 
23322
23648
  `;
23649
+ if (truncatedCommands > 0) {
23650
+ output += `_Note: ${truncatedCommands} command output(s) truncated to stay within size limits; use search() to retrieve indexed content._
23651
+
23652
+ `;
23653
+ }
23323
23654
  output += searchResults.join("\n---\n\n");
23324
23655
  if (terms.length > 0) {
23325
23656
  output += `
@@ -23646,33 +23977,9 @@ async function resolveAndValidate(url) {
23646
23977
  return { url, resolvedIp };
23647
23978
  }
23648
23979
 
23649
- // src/util/fetch-code.ts
23650
- function buildFetchCode(url, resolvedIp) {
23651
- let fetchSetup;
23652
- if (resolvedIp) {
23653
- const pinnedUrl = new URL(url);
23654
- const originalHost = pinnedUrl.host;
23655
- const hostnameValue = resolvedIp.includes(":") && !resolvedIp.startsWith("[") ? `[${resolvedIp}]` : resolvedIp;
23656
- pinnedUrl.hostname = hostnameValue;
23657
- fetchSetup = `
23658
- const url = ${JSON.stringify(pinnedUrl.toString())};
23659
- const resp = await fetch(url, { headers: { 'Host': ${JSON.stringify(originalHost)} }, redirect: 'error' });`;
23660
- } else {
23661
- fetchSetup = `
23662
- const url = ${JSON.stringify(url)};
23663
- const resp = await fetch(url, { redirect: 'error' });`;
23664
- }
23665
- return `${fetchSetup}
23666
- if (!resp.ok) { console.error("HTTP " + resp.status); process.exit(1); }
23667
- const cl = resp.headers.get('content-length');
23668
- if (cl && parseInt(cl, 10) > 10 * 1024 * 1024) {
23669
- console.error("Response too large: " + cl + " bytes"); process.exit(1);
23670
- }
23671
- const html = await resp.text();
23672
- if (html.length > 10 * 1024 * 1024) {
23673
- console.error("Response body too large: " + html.length + " chars"); process.exit(1);
23674
- }
23675
-
23980
+ // src/util/html-to-markdown.ts
23981
+ function htmlToMarkdownSnippet() {
23982
+ return `
23676
23983
  // Strip unwanted tags
23677
23984
  let md = html
23678
23985
  .replace(/<script[^>]*>[\\s\\S]*?<\\/script>/gi, "")
@@ -23704,7 +24011,7 @@ md = md.replace(/<br\\s*\\/?>/gi, "\\n");
23704
24011
  // Strip remaining tags
23705
24012
  md = md.replace(/<[^>]+>/g, "");
23706
24013
 
23707
- // Decode entities
24014
+ // Decode entities (&amp; LAST so we don't double-decode)
23708
24015
  md = md.replace(/&lt;/g, "<")
23709
24016
  .replace(/&gt;/g, ">")
23710
24017
  .replace(/&quot;/g, '"')
@@ -23722,6 +24029,35 @@ console.log(md);
23722
24029
  `;
23723
24030
  }
23724
24031
 
24032
+ // src/util/fetch-code.ts
24033
+ function buildFetchCode(url, resolvedIp) {
24034
+ let fetchSetup;
24035
+ if (resolvedIp) {
24036
+ const pinnedUrl = new URL(url);
24037
+ const originalHost = pinnedUrl.host;
24038
+ const hostnameValue = resolvedIp.includes(":") && !resolvedIp.startsWith("[") ? `[${resolvedIp}]` : resolvedIp;
24039
+ pinnedUrl.hostname = hostnameValue;
24040
+ fetchSetup = `
24041
+ const url = ${JSON.stringify(pinnedUrl.toString())};
24042
+ const resp = await fetch(url, { headers: { 'Host': ${JSON.stringify(originalHost)} }, redirect: 'error' });`;
24043
+ } else {
24044
+ fetchSetup = `
24045
+ const url = ${JSON.stringify(url)};
24046
+ const resp = await fetch(url, { redirect: 'error' });`;
24047
+ }
24048
+ return `${fetchSetup}
24049
+ if (!resp.ok) { console.error("HTTP " + resp.status); process.exit(1); }
24050
+ const cl = resp.headers.get('content-length');
24051
+ if (cl && parseInt(cl, 10) > 10 * 1024 * 1024) {
24052
+ console.error("Response too large: " + cl + " bytes"); process.exit(1);
24053
+ }
24054
+ const html = await resp.text();
24055
+ if (html.length > 10 * 1024 * 1024) {
24056
+ console.error("Response body too large: " + html.length + " chars"); process.exit(1);
24057
+ }
24058
+ ${htmlToMarkdownSnippet()}`;
24059
+ }
24060
+
23725
24061
  // src/tools/fetch-and-index.ts
23726
24062
  function registerFetchAndIndexTool(server2, ctx) {
23727
24063
  const { executor, store, tracker, withExecutionLimit } = ctx;
@@ -23821,7 +24157,7 @@ Searchable terms: ${terms.join(", ")}`;
23821
24157
  }
23822
24158
 
23823
24159
  // src/tools/index-content.ts
23824
- import { readFileSync as readFileSync3, statSync } from "node:fs";
24160
+ import { readFileSync as readFileSync4, statSync } from "node:fs";
23825
24161
  import { resolve as resolve3 } from "node:path";
23826
24162
  function registerIndexTool(server2, ctx) {
23827
24163
  const { store, tracker, projectDir: projectDir2 } = ctx;
@@ -23862,7 +24198,7 @@ function registerIndexTool(server2, ctx) {
23862
24198
  isError: true
23863
24199
  };
23864
24200
  }
23865
- text = readFileSync3(absPath, "utf-8");
24201
+ text = readFileSync4(absPath, "utf-8");
23866
24202
  label = source ?? filePath;
23867
24203
  } catch (e) {
23868
24204
  const msg = e instanceof Error ? e.message : String(e);
@@ -23995,22 +24331,31 @@ function compactLabel(normal, level) {
23995
24331
  }
23996
24332
 
23997
24333
  // src/util/intent-filter.ts
24334
+ var INTENT_SEARCH_LIMIT = 6;
24335
+ var PER_HIT_CAP = 700;
24336
+ var PER_HIT_FLOOR = 120;
23998
24337
  function createIntentFilter(deps) {
23999
24338
  const { config: config3, store, tracker } = deps;
24000
24339
  return function applyIntentFilter(output, intent, sourceLabel) {
24001
- if (Buffer.byteLength(output) <= config3.intentSearchThreshold) return output;
24340
+ const outputBytes = Buffer.byteLength(output);
24341
+ if (outputBytes <= config3.intentSearchThreshold) return output;
24002
24342
  const indexed = store.index(output, sourceLabel);
24003
- tracker.trackIndexed(Buffer.byteLength(output));
24004
- const searchResults = store.search(intent, { limit: 3 });
24343
+ tracker.trackIndexed(outputBytes);
24344
+ const searchResults = store.search(intent, { limit: INTENT_SEARCH_LIMIT });
24005
24345
  const terms = store.getDistinctiveTerms(indexed.sourceId);
24346
+ const errorLines = extractErrorLines(output);
24006
24347
  let filtered = `Indexed ${indexed.totalChunks} sections from ${sourceLabel}.
24007
24348
  `;
24008
24349
  filtered += `${searchResults.results.length} sections matched "${intent}":
24009
24350
 
24010
24351
  `;
24011
- for (const hit of searchResults.results) {
24012
- filtered += ` - **${hit.title}**: ${hit.snippet.slice(0, 200)}
24352
+ filtered += renderHits(searchResults.results, config3.intentBudgetBytes);
24353
+ if (errorLines.length > 0) {
24354
+ filtered += `
24355
+ \u26A0 ${errorLines.length} error/warning line(s) in output:
24013
24356
  `;
24357
+ filtered += errorLines.map((l) => ` ${l}`).join("\n");
24358
+ filtered += "\n";
24014
24359
  }
24015
24360
  if (terms.length > 0 && config3.compressionLevel !== "ultra") {
24016
24361
  filtered += `
@@ -24021,16 +24366,39 @@ Searchable terms: ${terms.join(", ")}
24021
24366
  return compactLabel(filtered, config3.compressionLevel);
24022
24367
  };
24023
24368
  }
24369
+ function renderHits(hits, budget) {
24370
+ if (hits.length === 0) return " (no matching sections \u2014 try search() with different terms)\n";
24371
+ const lines = [];
24372
+ let remaining = budget;
24373
+ for (let i = 0; i < hits.length; i++) {
24374
+ const hit = hits[i];
24375
+ const hitsLeft = hits.length - i;
24376
+ const share = Math.min(PER_HIT_CAP, Math.floor(remaining / hitsLeft));
24377
+ if (share < PER_HIT_FLOOR) {
24378
+ lines.push(` - **${hit.title}** (search to view)`);
24379
+ continue;
24380
+ }
24381
+ const snippet = clip(hit.snippet.trim(), share);
24382
+ remaining -= Buffer.byteLength(snippet);
24383
+ lines.push(` - **${hit.title}**: ${snippet}`);
24384
+ }
24385
+ return `${lines.join("\n")}
24386
+ `;
24387
+ }
24388
+ function clip(s, max) {
24389
+ if (Buffer.byteLength(s) <= max) return s;
24390
+ return `${s.slice(0, Math.max(0, max - 1))}\u2026`;
24391
+ }
24024
24392
 
24025
24393
  // src/util/version.ts
24026
- import { readFileSync as readFileSync4 } from "node:fs";
24027
- import { dirname, resolve as resolve4 } from "node:path";
24394
+ import { readFileSync as readFileSync5 } from "node:fs";
24395
+ import { dirname as dirname2, resolve as resolve4 } from "node:path";
24028
24396
  import { fileURLToPath } from "node:url";
24029
- var __dirname = dirname(fileURLToPath(import.meta.url));
24397
+ var __dirname = dirname2(fileURLToPath(import.meta.url));
24030
24398
  function getVersion(fallback = "1.0.0") {
24031
24399
  try {
24032
24400
  const pkgPath = resolve4(__dirname, "..", "..", "package.json");
24033
- const pkg = JSON.parse(readFileSync4(pkgPath, "utf-8"));
24401
+ const pkg = JSON.parse(readFileSync5(pkgPath, "utf-8"));
24034
24402
  return pkg.version ?? fallback;
24035
24403
  } catch {
24036
24404
  return fallback;
@@ -24042,10 +24410,11 @@ var projectDir = process.env.CLAUDE_PROJECT_DIR ?? process.cwd();
24042
24410
  var MAX_CONCURRENT_EXECUTIONS = 8;
24043
24411
  var EXECUTION_LIMIT_ERROR = "Error: too many concurrent executions. Try again shortly.";
24044
24412
  async function createServer(config3) {
24413
+ configureLogger(config3.debug);
24045
24414
  const version2 = getVersion();
24046
24415
  debug("Version:", version2);
24047
24416
  cleanupStaleDbs();
24048
- const runtimes = await detectRuntimes();
24417
+ const runtimes = detectRuntimes();
24049
24418
  const bunDetected = hasBun(runtimes);
24050
24419
  debug("Runtimes detected:", runtimes.size);
24051
24420
  const executor = new SubprocessExecutor(runtimes, config3);
@@ -24058,7 +24427,7 @@ async function createServer(config3) {
24058
24427
  store = new ContentStore(":memory:");
24059
24428
  dbFallback = true;
24060
24429
  }
24061
- const cumulativeFile = config3.persistDb ? join4(config3.dbDir ?? join4(projectDir, ".context-compress"), "stats.json") : void 0;
24430
+ const cumulativeFile = config3.persistDb ? join6(config3.dbDir ?? join6(projectDir, ".context-compress"), "stats.json") : void 0;
24062
24431
  const tracker = new SessionTracker(cumulativeFile);
24063
24432
  let activeExecutions = 0;
24064
24433
  async function withExecutionLimit(fn) {