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.
- package/.claude-plugin/marketplace.json +17 -0
- package/.claude-plugin/plugin.json +12 -0
- package/.codex-plugin/plugin.json +40 -0
- package/.mcp.json +11 -0
- package/README.md +43 -12
- package/dist/bench/quality.d.ts +46 -0
- package/dist/bench/quality.d.ts.map +1 -0
- package/dist/bench/quality.js +118 -0
- package/dist/bench/quality.js.map +1 -0
- package/dist/bench/run.d.ts +2 -0
- package/dist/bench/run.d.ts.map +1 -0
- package/dist/bench/run.js +4 -0
- package/dist/bench/run.js.map +1 -0
- package/dist/cli/filter.d.ts.map +1 -1
- package/dist/cli/filter.js +13 -1
- package/dist/cli/filter.js.map +1 -1
- package/dist/cli/index.js +0 -0
- package/dist/cli/uninstall.d.ts.map +1 -1
- package/dist/cli/uninstall.js +4 -2
- package/dist/cli/uninstall.js.map +1 -1
- package/dist/config.d.ts +2 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +11 -0
- package/dist/config.js.map +1 -1
- package/dist/executor.d.ts.map +1 -1
- package/dist/executor.js +32 -8
- package/dist/executor.js.map +1 -1
- package/dist/format-filter.d.ts +63 -0
- package/dist/format-filter.d.ts.map +1 -0
- package/dist/format-filter.js +331 -0
- package/dist/format-filter.js.map +1 -0
- package/dist/logger.d.ts +4 -0
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +14 -1
- package/dist/logger.js.map +1 -1
- package/dist/runtime/index.d.ts +2 -2
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/index.js +37 -20
- package/dist/runtime/index.js.map +1 -1
- package/dist/server.bundle.mjs +479 -110
- package/dist/server.bundle.mjs.map +4 -4
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +5 -2
- package/dist/server.js.map +1 -1
- package/dist/stats.d.ts.map +1 -1
- package/dist/stats.js +19 -1
- package/dist/stats.js.map +1 -1
- package/dist/store.d.ts +1 -0
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +20 -2
- package/dist/store.js.map +1 -1
- package/dist/tools/batch-execute.d.ts.map +1 -1
- package/dist/tools/batch-execute.js +20 -2
- package/dist/tools/batch-execute.js.map +1 -1
- package/dist/util/auto-mode.d.ts +8 -0
- package/dist/util/auto-mode.d.ts.map +1 -1
- package/dist/util/auto-mode.js +40 -26
- package/dist/util/auto-mode.js.map +1 -1
- package/dist/util/fetch-code.d.ts.map +1 -1
- package/dist/util/fetch-code.js +2 -48
- package/dist/util/fetch-code.js.map +1 -1
- package/dist/util/html-to-markdown.d.ts +17 -0
- package/dist/util/html-to-markdown.d.ts.map +1 -0
- package/dist/util/html-to-markdown.js +66 -0
- package/dist/util/html-to-markdown.js.map +1 -0
- package/dist/util/intent-filter.d.ts +12 -3
- package/dist/util/intent-filter.d.ts.map +1 -1
- package/dist/util/intent-filter.js +61 -8
- package/dist/util/intent-filter.js.map +1 -1
- package/dist/util/regret.d.ts +54 -0
- package/dist/util/regret.d.ts.map +1 -0
- package/dist/util/regret.js +107 -0
- package/dist/util/regret.js.map +1 -0
- package/docs/agentic-benchmark.md +110 -0
- package/docs/quality-regression-report.md +20 -0
- package/hooks/claude-codex-hooks.json +19 -0
- package/package.json +9 -5
- package/skills/context-compress-audit/SKILL.md +49 -0
- package/skills/context-compress-audit/agents/openai.yaml +13 -0
package/dist/server.bundle.mjs
CHANGED
|
@@ -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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
495
|
-
this.code = optimizeExpr(this.code, names,
|
|
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,
|
|
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,
|
|
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,
|
|
582
|
+
optimizeNames(names, constants2) {
|
|
583
583
|
var _a;
|
|
584
|
-
this.else = (_a = this.else) === null || _a === void 0 ? void 0 : _a.optimizeNames(names,
|
|
585
|
-
if (!(super.optimizeNames(names,
|
|
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,
|
|
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,
|
|
611
|
-
if (!super.optimizeNames(names,
|
|
610
|
+
optimizeNames(names, constants2) {
|
|
611
|
+
if (!super.optimizeNames(names, constants2))
|
|
612
612
|
return;
|
|
613
|
-
this.iteration = optimizeExpr(this.iteration, names,
|
|
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,
|
|
650
|
-
if (!super.optimizeNames(names,
|
|
649
|
+
optimizeNames(names, constants2) {
|
|
650
|
+
if (!super.optimizeNames(names, constants2))
|
|
651
651
|
return;
|
|
652
|
-
this.iterable = optimizeExpr(this.iterable, names,
|
|
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,
|
|
694
|
+
optimizeNames(names, constants2) {
|
|
695
695
|
var _a, _b;
|
|
696
|
-
super.optimizeNames(names,
|
|
697
|
-
(_a = this.catch) === null || _a === void 0 ? void 0 : _a.optimizeNames(names,
|
|
698
|
-
(_b = this.finally) === null || _b === void 0 ? void 0 : _b.optimizeNames(names,
|
|
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,
|
|
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 =
|
|
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 &&
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
21799
|
-
|
|
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
|
-
|
|
21808
|
-
|
|
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
|
-
|
|
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
|
|
22158
|
-
|
|
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 {
|
|
22173
|
-
import {
|
|
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
|
-
|
|
22454
|
-
|
|
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
|
-
|
|
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
|
-
|
|
22727
|
+
function detectRuntimes() {
|
|
22463
22728
|
const map = /* @__PURE__ */ new Map();
|
|
22464
|
-
const
|
|
22729
|
+
for (const plugin of ALL_PLUGINS) {
|
|
22465
22730
|
for (const candidate of plugin.runtimeCandidates) {
|
|
22466
|
-
if (
|
|
22467
|
-
|
|
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
|
|
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 {
|
|
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 =
|
|
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
|
-
|
|
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
|
|
22941
|
+
import { mkdirSync as mkdirSync3, readdirSync, unlinkSync } from "node:fs";
|
|
22643
22942
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
22644
|
-
import { join as
|
|
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 ??
|
|
22842
|
-
|
|
22843
|
-
path =
|
|
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) ??
|
|
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
|
-
|
|
22898
|
-
|
|
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 =
|
|
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
|
-
|
|
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/
|
|
23650
|
-
function
|
|
23651
|
-
|
|
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 (& LAST so we don't double-decode)
|
|
23708
24015
|
md = md.replace(/</g, "<")
|
|
23709
24016
|
.replace(/>/g, ">")
|
|
23710
24017
|
.replace(/"/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
|
|
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 =
|
|
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
|
-
|
|
24340
|
+
const outputBytes = Buffer.byteLength(output);
|
|
24341
|
+
if (outputBytes <= config3.intentSearchThreshold) return output;
|
|
24002
24342
|
const indexed = store.index(output, sourceLabel);
|
|
24003
|
-
tracker.trackIndexed(
|
|
24004
|
-
const searchResults = store.search(intent, { limit:
|
|
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
|
-
|
|
24012
|
-
|
|
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
|
|
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 =
|
|
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(
|
|
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 =
|
|
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 ?
|
|
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) {
|