context-compress 2026.3.22 → 2026.6.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 +275 -44
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +2 -10
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/filter.d.ts +52 -0
- package/dist/cli/filter.d.ts.map +1 -0
- package/dist/cli/filter.js +200 -0
- package/dist/cli/filter.js.map +1 -0
- package/dist/cli/index.d.ts +8 -4
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +19 -6
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/lite.d.ts +15 -0
- package/dist/cli/lite.d.ts.map +1 -0
- package/dist/cli/lite.js +37 -0
- package/dist/cli/lite.js.map +1 -0
- package/dist/cli/setup.d.ts +23 -1
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +122 -21
- package/dist/cli/setup.js.map +1 -1
- package/dist/executor.d.ts.map +1 -1
- package/dist/executor.js +7 -4
- package/dist/executor.js.map +1 -1
- package/dist/filters.d.ts +39 -5
- package/dist/filters.d.ts.map +1 -1
- package/dist/filters.js +577 -25
- package/dist/filters.js.map +1 -1
- package/dist/hooks/pretooluse.js +57 -0
- package/dist/hooks/pretooluse.js.map +1 -1
- package/dist/network.d.ts.map +1 -1
- package/dist/network.js +11 -0
- package/dist/network.js.map +1 -1
- package/dist/server.bundle.mjs +1140 -641
- package/dist/server.bundle.mjs.map +4 -4
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +36 -612
- package/dist/server.js.map +1 -1
- package/dist/stats.js +1 -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 +15 -2
- package/dist/store.js.map +1 -1
- package/dist/tools/batch-execute.d.ts +4 -0
- package/dist/tools/batch-execute.d.ts.map +1 -0
- package/dist/tools/batch-execute.js +75 -0
- package/dist/tools/batch-execute.js.map +1 -0
- package/dist/tools/context.d.ts +17 -0
- package/dist/tools/context.d.ts.map +1 -0
- package/dist/tools/context.js +2 -0
- package/dist/tools/context.js.map +1 -0
- package/dist/tools/discover.d.ts +4 -0
- package/dist/tools/discover.d.ts.map +1 -0
- package/dist/tools/discover.js +65 -0
- package/dist/tools/discover.js.map +1 -0
- package/dist/tools/execute-file.d.ts +4 -0
- package/dist/tools/execute-file.d.ts.map +1 -0
- package/dist/tools/execute-file.js +66 -0
- package/dist/tools/execute-file.js.map +1 -0
- package/dist/tools/execute.d.ts +4 -0
- package/dist/tools/execute.d.ts.map +1 -0
- package/dist/tools/execute.js +54 -0
- package/dist/tools/execute.js.map +1 -0
- package/dist/tools/fetch-and-index.d.ts +4 -0
- package/dist/tools/fetch-and-index.d.ts.map +1 -0
- package/dist/tools/fetch-and-index.js +91 -0
- package/dist/tools/fetch-and-index.js.map +1 -0
- package/dist/tools/index-content.d.ts +4 -0
- package/dist/tools/index-content.d.ts.map +1 -0
- package/dist/tools/index-content.js +85 -0
- package/dist/tools/index-content.js.map +1 -0
- package/dist/tools/search.d.ts +4 -0
- package/dist/tools/search.d.ts.map +1 -0
- package/dist/tools/search.js +57 -0
- package/dist/tools/search.js.map +1 -0
- package/dist/tools/stats.d.ts +4 -0
- package/dist/tools/stats.d.ts.map +1 -0
- package/dist/tools/stats.js +10 -0
- package/dist/tools/stats.js.map +1 -0
- package/dist/types.d.ts +0 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/util/auto-mode.d.ts +40 -0
- package/dist/util/auto-mode.d.ts.map +1 -0
- package/dist/util/auto-mode.js +181 -0
- package/dist/util/auto-mode.js.map +1 -0
- package/dist/util/fetch-code.d.ts +10 -0
- package/dist/util/fetch-code.d.ts.map +1 -0
- package/dist/util/fetch-code.js +87 -0
- package/dist/util/fetch-code.js.map +1 -0
- package/dist/util/intent-filter.d.ts +17 -0
- package/dist/util/intent-filter.d.ts.map +1 -0
- package/dist/util/intent-filter.js +28 -0
- package/dist/util/intent-filter.js.map +1 -0
- package/dist/util/label.d.ts +4 -0
- package/dist/util/label.d.ts.map +1 -0
- package/dist/util/label.js +14 -0
- package/dist/util/label.js.map +1 -0
- package/dist/util/path.d.ts +8 -0
- package/dist/util/path.d.ts.map +1 -0
- package/dist/util/path.js +21 -0
- package/dist/util/path.js.map +1 -0
- package/dist/util/stream-compress.d.ts +36 -0
- package/dist/util/stream-compress.d.ts.map +1 -0
- package/dist/util/stream-compress.js +104 -0
- package/dist/util/stream-compress.js.map +1 -0
- package/dist/util/version.d.ts +2 -0
- package/dist/util/version.d.ts.map +1 -0
- package/dist/util/version.js +15 -0
- package/dist/util/version.js.map +1 -0
- package/docs/agentic-benchmark.md +110 -0
- package/docs/token-reduction-report.md +47 -18
- package/hooks/claude-codex-hooks.json +19 -0
- package/hooks/pretooluse.mjs +38 -0
- package/package.json +12 -8
- package/skills/context-compress-audit/SKILL.md +49 -0
- package/skills/context-compress-audit/agents/openai.yaml +13 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { ALL_LANGUAGES } from "../types.js";
|
|
3
|
+
const LANGUAGE_ENUM = ALL_LANGUAGES;
|
|
4
|
+
export function registerExecuteTool(server, ctx) {
|
|
5
|
+
const { executor, tracker, withExecutionLimit, applyIntentFilter, bunDetected } = ctx;
|
|
6
|
+
server.tool("execute", `Execute code in a sandboxed subprocess. Only stdout enters context — raw data stays in the subprocess. Use instead of bash/cat when output would exceed ~5KB. ${bunDetected ? "(Bun detected — JS/TS runs 3-5x faster) " : ""}Available: ${ALL_LANGUAGES.join(", ")}.
|
|
7
|
+
|
|
8
|
+
PREFER THIS OVER BASH for: API calls (gh, curl, aws), test runners (npm test, pytest), git queries (git log, git diff), data processing, and ANY CLI command that may produce large output. Bash should only be used for file mutations, git writes, and navigation.`, {
|
|
9
|
+
language: z.enum(LANGUAGE_ENUM).describe("Runtime language"),
|
|
10
|
+
code: z
|
|
11
|
+
.string()
|
|
12
|
+
.describe("Source code to execute. Use console.log (JS/TS), print (Python/Ruby/Perl/R), echo (Shell), echo (PHP), fmt.Println (Go), or IO.puts (Elixir) to output a summary to context."),
|
|
13
|
+
intent: z
|
|
14
|
+
.string()
|
|
15
|
+
.optional()
|
|
16
|
+
.describe("What you're looking for in the output. When provided and output is large (>5KB), indexes output into knowledge base and returns section titles + previews — not full content. Use search(queries: [...]) to retrieve specific sections."),
|
|
17
|
+
timeout: z.number().default(30000).describe("Max execution time in ms"),
|
|
18
|
+
}, async ({ language, code, intent, timeout }) => {
|
|
19
|
+
const codeBytes = Buffer.byteLength(code);
|
|
20
|
+
if (codeBytes > 1_024_000) {
|
|
21
|
+
return {
|
|
22
|
+
content: [
|
|
23
|
+
{
|
|
24
|
+
type: "text",
|
|
25
|
+
text: `Error: code too large (${(codeBytes / 1024).toFixed(0)}KB). Max 1MB.`,
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
isError: true,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
let result;
|
|
32
|
+
try {
|
|
33
|
+
result = await withExecutionLimit(() => executor.execute({ language, code, timeout }));
|
|
34
|
+
}
|
|
35
|
+
catch (e) {
|
|
36
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
37
|
+
return { content: [{ type: "text", text: msg }], isError: true };
|
|
38
|
+
}
|
|
39
|
+
if (result.networkBytes) {
|
|
40
|
+
tracker.trackSandboxed(result.networkBytes);
|
|
41
|
+
}
|
|
42
|
+
let output = result.stdout;
|
|
43
|
+
if (result.stderr && result.exitCode !== 0) {
|
|
44
|
+
output += `\n\nSTDERR:\n${result.stderr}`;
|
|
45
|
+
}
|
|
46
|
+
if (intent) {
|
|
47
|
+
output = applyIntentFilter(output, intent, `execute:${language}`);
|
|
48
|
+
}
|
|
49
|
+
const responseBytes = Buffer.byteLength(output);
|
|
50
|
+
tracker.trackCall("execute", responseBytes);
|
|
51
|
+
return { content: [{ type: "text", text: output }] };
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=execute.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execute.js","sourceRoot":"","sources":["../../src/tools/execute.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetch-and-index.d.ts","sourceRoot":"","sources":["../../src/tools/fetch-and-index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAMzE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,WAAW,GAAG,IAAI,CAmGnF"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { isPrivateHost, resolveAndValidate } from "../network.js";
|
|
3
|
+
import { buildFetchCode } from "../util/fetch-code.js";
|
|
4
|
+
import { detectInjectionPatterns } from "../utils.js";
|
|
5
|
+
export function registerFetchAndIndexTool(server, ctx) {
|
|
6
|
+
const { executor, store, tracker, withExecutionLimit } = ctx;
|
|
7
|
+
server.tool("fetch_and_index", "Fetches URL content, converts HTML to markdown, indexes into searchable knowledge base, and returns a ~3KB preview. Full content stays in sandbox — use search() for deeper lookups.\n\nBetter than WebFetch: preview is immediate, full content is searchable, raw HTML never enters context.", {
|
|
8
|
+
url: z.string().describe("The URL to fetch and index"),
|
|
9
|
+
source: z.string().optional().describe("Label for the indexed content"),
|
|
10
|
+
}, async ({ url, source }) => {
|
|
11
|
+
try {
|
|
12
|
+
const parsed = new URL(url);
|
|
13
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
14
|
+
return {
|
|
15
|
+
content: [{ type: "text", text: "Error: only http/https URLs are allowed" }],
|
|
16
|
+
isError: true,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
if (isPrivateHost(parsed.hostname)) {
|
|
20
|
+
return {
|
|
21
|
+
content: [
|
|
22
|
+
{ type: "text", text: "Error: internal/private URLs are not allowed" },
|
|
23
|
+
],
|
|
24
|
+
isError: true,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return {
|
|
30
|
+
content: [{ type: "text", text: `Error: invalid URL "${url}"` }],
|
|
31
|
+
isError: true,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
let resolvedIp = null;
|
|
35
|
+
try {
|
|
36
|
+
const validated = await resolveAndValidate(url);
|
|
37
|
+
resolvedIp = validated.resolvedIp;
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
return {
|
|
41
|
+
content: [
|
|
42
|
+
{
|
|
43
|
+
type: "text",
|
|
44
|
+
text: `Error: ${err instanceof Error ? err.message : "DNS validation failed"}`,
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
isError: true,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
const label = source ?? url;
|
|
51
|
+
const fetchCode = buildFetchCode(url, resolvedIp);
|
|
52
|
+
let result;
|
|
53
|
+
try {
|
|
54
|
+
result = await withExecutionLimit(() => executor.execute({
|
|
55
|
+
language: "javascript",
|
|
56
|
+
code: fetchCode,
|
|
57
|
+
timeout: 30_000,
|
|
58
|
+
}));
|
|
59
|
+
}
|
|
60
|
+
catch (e) {
|
|
61
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
62
|
+
return { content: [{ type: "text", text: msg }], isError: true };
|
|
63
|
+
}
|
|
64
|
+
if (result.exitCode !== 0 || !result.stdout.trim()) {
|
|
65
|
+
const errMsg = `Failed to fetch ${url}: ${result.stderr || "empty response"}`;
|
|
66
|
+
tracker.trackCall("fetch_and_index", Buffer.byteLength(errMsg));
|
|
67
|
+
return { content: [{ type: "text", text: errMsg }], isError: true };
|
|
68
|
+
}
|
|
69
|
+
const markdown = result.stdout;
|
|
70
|
+
tracker.trackSandboxed(result.networkBytes ?? 0);
|
|
71
|
+
const injectionWarnings = detectInjectionPatterns(markdown);
|
|
72
|
+
const indexed = store.index(markdown, label);
|
|
73
|
+
tracker.trackIndexed(Buffer.byteLength(markdown));
|
|
74
|
+
const preview = markdown.slice(0, 3072);
|
|
75
|
+
const terms = store.getDistinctiveTerms(indexed.sourceId);
|
|
76
|
+
let output = `Indexed "${label}": ${indexed.totalChunks} chunks.\n\n`;
|
|
77
|
+
output += `**Preview:**\n${preview}`;
|
|
78
|
+
if (markdown.length > 3072)
|
|
79
|
+
output += "\n…(truncated)";
|
|
80
|
+
if (terms.length > 0) {
|
|
81
|
+
output += `\n\nSearchable terms: ${terms.join(", ")}`;
|
|
82
|
+
}
|
|
83
|
+
output += "\n\nUse search(queries: [...]) to retrieve full content of any section.";
|
|
84
|
+
if (injectionWarnings.length > 0) {
|
|
85
|
+
output += `\n\n⚠ Content safety notice: detected patterns (${injectionWarnings.join(", ")}). Review indexed content before relying on it.`;
|
|
86
|
+
}
|
|
87
|
+
tracker.trackCall("fetch_and_index", Buffer.byteLength(output));
|
|
88
|
+
return { content: [{ type: "text", text: output }] };
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=fetch-and-index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetch-and-index.js","sourceRoot":"","sources":["../../src/tools/fetch-and-index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAElE,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAGtD,MAAM,UAAU,yBAAyB,CAAC,MAAiB,EAAE,GAAgB;IAC5E,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,kBAAkB,EAAE,GAAG,GAAG,CAAC;IAE7D,MAAM,CAAC,IAAI,CACV,iBAAiB,EACjB,gSAAgS,EAChS;QACC,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,4BAA4B,CAAC;QACtD,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,+BAA+B,CAAC;KACvE,EACD,KAAK,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE;QACzB,IAAI,CAAC;YACJ,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;YAC5B,IAAI,MAAM,CAAC,QAAQ,KAAK,OAAO,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;gBACjE,OAAO;oBACN,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,yCAAyC,EAAE,CAAC;oBACrF,OAAO,EAAE,IAAI;iBACb,CAAC;YACH,CAAC;YACD,IAAI,aAAa,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACpC,OAAO;oBACN,OAAO,EAAE;wBACR,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,8CAA8C,EAAE;qBAC/E;oBACD,OAAO,EAAE,IAAI;iBACb,CAAC;YACH,CAAC;QACF,CAAC;QAAC,MAAM,CAAC;YACR,OAAO;gBACN,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,uBAAuB,GAAG,GAAG,EAAE,CAAC;gBACzE,OAAO,EAAE,IAAI;aACb,CAAC;QACH,CAAC;QAED,IAAI,UAAU,GAAkB,IAAI,CAAC;QACrC,IAAI,CAAC;YACJ,MAAM,SAAS,GAAG,MAAM,kBAAkB,CAAC,GAAG,CAAC,CAAC;YAChD,UAAU,GAAG,SAAS,CAAC,UAAU,CAAC;QACnC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,OAAO;gBACN,OAAO,EAAE;oBACR;wBACC,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,UAAU,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,uBAAuB,EAAE;qBAC9E;iBACD;gBACD,OAAO,EAAE,IAAI;aACb,CAAC;QACH,CAAC;QAED,MAAM,KAAK,GAAG,MAAM,IAAI,GAAG,CAAC;QAC5B,MAAM,SAAS,GAAG,cAAc,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC;QAClD,IAAI,MAAkB,CAAC;QACvB,IAAI,CAAC;YACJ,MAAM,GAAG,MAAM,kBAAkB,CAAC,GAAG,EAAE,CACtC,QAAQ,CAAC,OAAO,CAAC;gBAChB,QAAQ,EAAE,YAAY;gBACtB,IAAI,EAAE,SAAS;gBACf,OAAO,EAAE,MAAM;aACf,CAAC,CACF,CAAC;QACH,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACZ,MAAM,GAAG,GAAG,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YACvD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QAC3E,CAAC;QAED,IAAI,MAAM,CAAC,QAAQ,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;YACpD,MAAM,MAAM,GAAG,mBAAmB,GAAG,KAAK,MAAM,CAAC,MAAM,IAAI,gBAAgB,EAAE,CAAC;YAC9E,OAAO,CAAC,SAAS,CAAC,iBAAiB,EAAE,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;YAChE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QAC9E,CAAC;QAED,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC;QAC/B,OAAO,CAAC,cAAc,CAAC,MAAM,CAAC,YAAY,IAAI,CAAC,CAAC,CAAC;QAEjD,MAAM,iBAAiB,GAAG,uBAAuB,CAAC,QAAQ,CAAC,CAAC;QAE5D,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QAC7C,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC;QAElD,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;QACxC,MAAM,KAAK,GAAG,KAAK,CAAC,mBAAmB,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAE1D,IAAI,MAAM,GAAG,YAAY,KAAK,MAAM,OAAO,CAAC,WAAW,cAAc,CAAC;QACtE,MAAM,IAAI,iBAAiB,OAAO,EAAE,CAAC;QACrC,IAAI,QAAQ,CAAC,MAAM,GAAG,IAAI;YAAE,MAAM,IAAI,gBAAgB,CAAC;QACvD,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACtB,MAAM,IAAI,yBAAyB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACvD,CAAC;QACD,MAAM,IAAI,yEAAyE,CAAC;QACpF,IAAI,iBAAiB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAClC,MAAM,IAAI,mDAAmD,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,iDAAiD,CAAC;QAC5I,CAAC;QAED,OAAO,CAAC,SAAS,CAAC,iBAAiB,EAAE,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;QAEhE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;IAC/D,CAAC,CACD,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-content.d.ts","sourceRoot":"","sources":["../../src/tools/index-content.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAGzE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,WAAW,GAAG,IAAI,CAsF3E"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { readFileSync, statSync } from "node:fs";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { isWithinProject } from "../util/path.js";
|
|
5
|
+
export function registerIndexTool(server, ctx) {
|
|
6
|
+
const { store, tracker, projectDir } = ctx;
|
|
7
|
+
server.tool("index", "Index documentation or knowledge content into a searchable BM25 knowledge base. Chunks markdown by headings (keeping code blocks intact) and stores in ephemeral FTS5 database. The full content does NOT stay in context — only a brief summary is returned.\n\nWHEN TO USE:\n- Documentation (API docs, framework guides, code examples)\n- README files, migration guides, changelog entries\n- Any content with code examples you may need to reference precisely\n\nAfter indexing, use 'search' to retrieve specific sections on-demand.", {
|
|
8
|
+
content: z
|
|
9
|
+
.string()
|
|
10
|
+
.optional()
|
|
11
|
+
.describe("Raw text/markdown to index. Provide this OR path, not both."),
|
|
12
|
+
path: z
|
|
13
|
+
.string()
|
|
14
|
+
.optional()
|
|
15
|
+
.describe("File path to read and index (content never enters context)."),
|
|
16
|
+
source: z.string().optional().describe("Label for the indexed content"),
|
|
17
|
+
}, async ({ content, path: filePath, source }) => {
|
|
18
|
+
let text;
|
|
19
|
+
let label = source ?? "indexed content";
|
|
20
|
+
if (filePath) {
|
|
21
|
+
const absPath = resolve(projectDir, filePath);
|
|
22
|
+
if (!isWithinProject(absPath, projectDir)) {
|
|
23
|
+
return {
|
|
24
|
+
content: [
|
|
25
|
+
{
|
|
26
|
+
type: "text",
|
|
27
|
+
text: `Error: path "${filePath}" is outside the project directory`,
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
isError: true,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
const fileStat = statSync(absPath);
|
|
35
|
+
if (fileStat.size > 50 * 1024 * 1024) {
|
|
36
|
+
return {
|
|
37
|
+
content: [
|
|
38
|
+
{
|
|
39
|
+
type: "text",
|
|
40
|
+
text: `Error: file "${filePath}" is too large (${(fileStat.size / 1024 / 1024).toFixed(1)}MB). Max 50MB.`,
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
isError: true,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
text = readFileSync(absPath, "utf-8");
|
|
47
|
+
label = source ?? filePath;
|
|
48
|
+
}
|
|
49
|
+
catch (e) {
|
|
50
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
51
|
+
return {
|
|
52
|
+
content: [{ type: "text", text: `Error reading "${filePath}": ${msg}` }],
|
|
53
|
+
isError: true,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
else if (content) {
|
|
58
|
+
const contentBytes = Buffer.byteLength(content);
|
|
59
|
+
if (contentBytes > 50 * 1024 * 1024) {
|
|
60
|
+
return {
|
|
61
|
+
content: [
|
|
62
|
+
{
|
|
63
|
+
type: "text",
|
|
64
|
+
text: `Error: content too large (${(contentBytes / 1024 / 1024).toFixed(1)}MB). Max 50MB.`,
|
|
65
|
+
},
|
|
66
|
+
],
|
|
67
|
+
isError: true,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
text = content;
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
return {
|
|
74
|
+
content: [{ type: "text", text: "Error: provide either 'content' or 'path'" }],
|
|
75
|
+
isError: true,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
const result = store.index(text, label);
|
|
79
|
+
tracker.trackIndexed(Buffer.byteLength(text));
|
|
80
|
+
const summary = `Indexed "${label}": ${result.totalChunks} chunks (${result.codeChunks} with code). Use search(queries: [...]) to retrieve sections.`;
|
|
81
|
+
tracker.trackCall("index", Buffer.byteLength(summary));
|
|
82
|
+
return { content: [{ type: "text", text: summary }] };
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=index-content.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-content.js","sourceRoot":"","sources":["../../src/tools/index-content.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,WAAW,GAAG,IAAI,CA0E5E"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export function registerSearchTool(server, ctx) {
|
|
3
|
+
const { store, tracker, config } = ctx;
|
|
4
|
+
// Per-server-instance throttling state
|
|
5
|
+
const searchCalls = [];
|
|
6
|
+
server.tool("search", "Search indexed content. Pass ALL search questions as queries array in ONE call.\n\nTIPS: 2-4 specific terms per query. Use 'source' to scope results.", {
|
|
7
|
+
queries: z
|
|
8
|
+
.array(z.string())
|
|
9
|
+
.describe("Array of search queries. Batch ALL questions in one call."),
|
|
10
|
+
source: z
|
|
11
|
+
.string()
|
|
12
|
+
.optional()
|
|
13
|
+
.describe("Filter to a specific indexed source (partial match)."),
|
|
14
|
+
limit: z.number().default(3).describe("Results per query (default: 3)"),
|
|
15
|
+
}, async ({ queries, source, limit }) => {
|
|
16
|
+
const now = Date.now();
|
|
17
|
+
searchCalls.push(now);
|
|
18
|
+
while (searchCalls.length > 0 && searchCalls[0] < now - config.searchWindowMs) {
|
|
19
|
+
searchCalls.shift();
|
|
20
|
+
}
|
|
21
|
+
const callCount = searchCalls.length;
|
|
22
|
+
if (callCount > config.searchBlockAfter) {
|
|
23
|
+
const msg = "Too many search calls in quick succession. Use batch_execute instead to run commands and search in one call.";
|
|
24
|
+
tracker.trackCall("search", Buffer.byteLength(msg));
|
|
25
|
+
return { content: [{ type: "text", text: msg }] };
|
|
26
|
+
}
|
|
27
|
+
const effectiveLimit = callCount > config.searchReduceAfter ? 1 : Math.min(limit, config.searchLimit);
|
|
28
|
+
const allResults = [];
|
|
29
|
+
let totalBytes = 0;
|
|
30
|
+
for (const query of queries) {
|
|
31
|
+
if (totalBytes > config.searchMaxBytes)
|
|
32
|
+
break;
|
|
33
|
+
const result = store.search(query, { source, limit: effectiveLimit });
|
|
34
|
+
let block = `## ${query}\n`;
|
|
35
|
+
if (result.corrected) {
|
|
36
|
+
block += `(corrected to: "${result.corrected}")\n`;
|
|
37
|
+
}
|
|
38
|
+
if (result.results.length === 0) {
|
|
39
|
+
block += "No results found.\n";
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
for (const hit of result.results) {
|
|
43
|
+
block += `\n--- [${hit.source}] ---\n### ${hit.title}\n\n${hit.snippet}\n`;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
allResults.push(block);
|
|
47
|
+
totalBytes += Buffer.byteLength(block);
|
|
48
|
+
}
|
|
49
|
+
if (callCount > config.searchReduceAfter) {
|
|
50
|
+
allResults.push(`\n⚠ Search rate limited (${callCount} calls in ${config.searchWindowMs / 1000}s). Results reduced to 1 per query.`);
|
|
51
|
+
}
|
|
52
|
+
const output = allResults.join("\n---\n\n");
|
|
53
|
+
tracker.trackCall("search", Buffer.byteLength(output));
|
|
54
|
+
return { content: [{ type: "text", text: output }] };
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stats.d.ts","sourceRoot":"","sources":["../../src/tools/stats.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,WAAW,GAAG,IAAI,CAc3E"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export function registerStatsTool(server, ctx) {
|
|
2
|
+
const { tracker } = ctx;
|
|
3
|
+
server.tool("stats", "Returns context consumption statistics for the current session. Shows total bytes returned to context, breakdown by tool, call counts, estimated token usage, context savings ratio, and visual charts.", {}, async () => {
|
|
4
|
+
tracker.saveCumulative();
|
|
5
|
+
const report = tracker.formatReport();
|
|
6
|
+
tracker.trackCall("stats", Buffer.byteLength(report));
|
|
7
|
+
return { content: [{ type: "text", text: report }] };
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=stats.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stats.js","sourceRoot":"","sources":["../../src/tools/stats.ts"],"names":[],"mappings":"AAGA,MAAM,UAAU,iBAAiB,CAAC,MAAiB,EAAE,GAAgB;IACpE,MAAM,EAAE,OAAO,EAAE,GAAG,GAAG,CAAC;IAExB,MAAM,CAAC,IAAI,CACV,OAAO,EACP,yMAAyM,EACzM,EAAE,EACF,KAAK,IAAI,EAAE;QACV,OAAO,CAAC,cAAc,EAAE,CAAC;QACzB,MAAM,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;QACtC,OAAO,CAAC,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;QACtD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;IAC/D,CAAC,CACD,CAAC;AACH,CAAC"}
|
package/dist/types.d.ts
CHANGED
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GACjB,YAAY,GACZ,YAAY,GACZ,QAAQ,GACR,OAAO,GACP,MAAM,GACN,IAAI,GACJ,MAAM,GACN,KAAK,GACL,MAAM,GACN,GAAG,GACH,QAAQ,CAAC;AAEZ,eAAO,MAAM,aAAa,EAAE,SAAS,QAAQ,EAYnC,CAAC;AAEX,MAAM,WAAW,WAAW;IAC3B,QAAQ,EAAE,QAAQ,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,eAAgB,SAAQ,WAAW;IACnD,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,OAAO,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,SAAS;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,UAAU;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,KAAK;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC5B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,eAAe;IAC/B,eAAe,EAAE,MAAM,CAAC;IACxB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GACjB,YAAY,GACZ,YAAY,GACZ,QAAQ,GACR,OAAO,GACP,MAAM,GACN,IAAI,GACJ,MAAM,GACN,KAAK,GACL,MAAM,GACN,GAAG,GACH,QAAQ,CAAC;AAEZ,eAAO,MAAM,aAAa,EAAE,SAAS,QAAQ,EAYnC,CAAC;AAEX,MAAM,WAAW,WAAW;IAC3B,QAAQ,EAAE,QAAQ,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,eAAgB,SAAQ,WAAW;IACnD,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,OAAO,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,SAAS;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,UAAU;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,KAAK;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC5B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,eAAe;IAC/B,eAAe,EAAE,MAAM,CAAC;IACxB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC9C"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto mode: ask an LLM to pick the best compression mode for a given output.
|
|
3
|
+
*
|
|
4
|
+
* Backends, in priority order:
|
|
5
|
+
* 1. Anthropic API (fastest; needs ANTHROPIC_API_KEY)
|
|
6
|
+
* 2. `claude -p` CLI (works in Claude Code environments; ~3s per call)
|
|
7
|
+
* 3. Heuristic (last resort, no LLM)
|
|
8
|
+
*
|
|
9
|
+
* Decisions are cached per command fingerprint with a 24h TTL so repeated
|
|
10
|
+
* commands don't pay the LLM round-trip cost. Cache lives at
|
|
11
|
+
* ~/.context-compress/auto-cache.json so it survives across sessions.
|
|
12
|
+
*/
|
|
13
|
+
import type { FilterMode } from "../filters.js";
|
|
14
|
+
export interface AutoOptions {
|
|
15
|
+
apiKey?: string;
|
|
16
|
+
model?: string;
|
|
17
|
+
timeoutMs?: number;
|
|
18
|
+
/** When true, do not read or write the cache. Useful for benchmarks. */
|
|
19
|
+
noCache?: boolean;
|
|
20
|
+
/** When true, skip API + CLI and use the heuristic. Useful for tests. */
|
|
21
|
+
noLlm?: boolean;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Heuristic last-resort: pick a sensible mode without touching the LLM.
|
|
25
|
+
* This is what auto mode degrades to when both API and CLI are unavailable
|
|
26
|
+
* (or when AutoOptions.noLlm is true).
|
|
27
|
+
*
|
|
28
|
+
* Exported so callers / tests can use the heuristic directly.
|
|
29
|
+
*/
|
|
30
|
+
export declare function heuristicMode(cmd: string, output: string): FilterMode;
|
|
31
|
+
export interface AutoResult {
|
|
32
|
+
mode: FilterMode;
|
|
33
|
+
source: "cache" | "api" | "cli" | "heuristic";
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Pick a compression mode for the given command + output. Tries the LLM
|
|
37
|
+
* (API → CLI), falls back to a heuristic. Caches per-command-fingerprint.
|
|
38
|
+
*/
|
|
39
|
+
export declare function pickModeAuto(cmd: string, output: string, opts?: AutoOptions): Promise<AutoResult>;
|
|
40
|
+
//# sourceMappingURL=auto-mode.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto-mode.d.ts","sourceRoot":"","sources":["../../src/util/auto-mode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAMH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAchD,MAAM,WAAW,WAAW;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wEAAwE;IACxE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,yEAAyE;IACzE,KAAK,CAAC,EAAE,OAAO,CAAC;CAChB;AAsGD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,UAAU,CAQrE;AAED,MAAM,WAAW,UAAU;IAC1B,IAAI,EAAE,UAAU,CAAC;IACjB,MAAM,EAAE,OAAO,GAAG,KAAK,GAAG,KAAK,GAAG,WAAW,CAAC;CAC9C;AAED;;;GAGG;AACH,wBAAsB,YAAY,CACjC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,EACd,IAAI,GAAE,WAAgB,GACpB,OAAO,CAAC,UAAU,CAAC,CAoCrB"}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto mode: ask an LLM to pick the best compression mode for a given output.
|
|
3
|
+
*
|
|
4
|
+
* Backends, in priority order:
|
|
5
|
+
* 1. Anthropic API (fastest; needs ANTHROPIC_API_KEY)
|
|
6
|
+
* 2. `claude -p` CLI (works in Claude Code environments; ~3s per call)
|
|
7
|
+
* 3. Heuristic (last resort, no LLM)
|
|
8
|
+
*
|
|
9
|
+
* Decisions are cached per command fingerprint with a 24h TTL so repeated
|
|
10
|
+
* commands don't pay the LLM round-trip cost. Cache lives at
|
|
11
|
+
* ~/.context-compress/auto-cache.json so it survives across sessions.
|
|
12
|
+
*/
|
|
13
|
+
import { spawnSync } from "node:child_process";
|
|
14
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
15
|
+
import { homedir } from "node:os";
|
|
16
|
+
import { dirname, join } from "node:path";
|
|
17
|
+
const CACHE_PATH = join(homedir(), ".context-compress", "auto-cache.json");
|
|
18
|
+
const TTL_MS = 24 * 60 * 60 * 1000;
|
|
19
|
+
const DEFAULT_TIMEOUT_MS = 8_000;
|
|
20
|
+
const SAMPLE_BYTES = 500;
|
|
21
|
+
function loadCache() {
|
|
22
|
+
if (!existsSync(CACHE_PATH))
|
|
23
|
+
return {};
|
|
24
|
+
try {
|
|
25
|
+
return JSON.parse(readFileSync(CACHE_PATH, "utf-8"));
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return {};
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function saveCache(cache) {
|
|
32
|
+
try {
|
|
33
|
+
mkdirSync(dirname(CACHE_PATH), { recursive: true });
|
|
34
|
+
writeFileSync(CACHE_PATH, JSON.stringify(cache, null, 2));
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
/* ignore — cache is best-effort */
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Cache key: the first two whitespace-separated tokens of the command.
|
|
42
|
+
* "git log -10 --abbrev-commit" → "git log"
|
|
43
|
+
* Coarse enough to share decisions across argument variants, fine enough
|
|
44
|
+
* that "git log" and "git diff" are tracked separately.
|
|
45
|
+
*/
|
|
46
|
+
function fingerprint(cmd) {
|
|
47
|
+
return cmd.trim().split(/\s+/).slice(0, 2).join(" ");
|
|
48
|
+
}
|
|
49
|
+
function buildPrompt(cmd, sample) {
|
|
50
|
+
return [
|
|
51
|
+
"You pick the best output-compression mode for an AI coding agent.",
|
|
52
|
+
"",
|
|
53
|
+
`Command: ${cmd}`,
|
|
54
|
+
"",
|
|
55
|
+
"Output sample (first 500 chars, may be truncated):",
|
|
56
|
+
"---",
|
|
57
|
+
sample,
|
|
58
|
+
"---",
|
|
59
|
+
"",
|
|
60
|
+
"Modes:",
|
|
61
|
+
"- conservative: preserve everything verbatim (almost no compression)",
|
|
62
|
+
"- balanced: drop universal noise (progress bars, hint lines, ./.., total N), truncate git log bodies past 3 lines, summarize find/ls -R past 20 entries; keeps all metadata",
|
|
63
|
+
"- aggressive: drop metadata too (git log → one-line, ls -la → name+size, find → directory summary, drops file perms/dates)",
|
|
64
|
+
"",
|
|
65
|
+
"Pick whichever fits this output best. Reply with EXACTLY ONE WORD: conservative, balanced, or aggressive.",
|
|
66
|
+
].join("\n");
|
|
67
|
+
}
|
|
68
|
+
function parseMode(text) {
|
|
69
|
+
const t = text.toLowerCase();
|
|
70
|
+
if (t.includes("aggressive"))
|
|
71
|
+
return "aggressive";
|
|
72
|
+
if (t.includes("conservative"))
|
|
73
|
+
return "conservative";
|
|
74
|
+
if (t.includes("balanced"))
|
|
75
|
+
return "balanced";
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
async function callAnthropic(prompt, opts) {
|
|
79
|
+
const apiKey = opts.apiKey ?? process.env.ANTHROPIC_API_KEY;
|
|
80
|
+
if (!apiKey)
|
|
81
|
+
throw new Error("no API key");
|
|
82
|
+
const r = await fetch("https://api.anthropic.com/v1/messages", {
|
|
83
|
+
method: "POST",
|
|
84
|
+
headers: {
|
|
85
|
+
"content-type": "application/json",
|
|
86
|
+
"x-api-key": apiKey,
|
|
87
|
+
"anthropic-version": "2023-06-01",
|
|
88
|
+
},
|
|
89
|
+
body: JSON.stringify({
|
|
90
|
+
model: opts.model ?? "claude-haiku-4-5-20251001",
|
|
91
|
+
max_tokens: 16,
|
|
92
|
+
messages: [{ role: "user", content: prompt }],
|
|
93
|
+
}),
|
|
94
|
+
signal: AbortSignal.timeout(opts.timeoutMs ?? DEFAULT_TIMEOUT_MS),
|
|
95
|
+
});
|
|
96
|
+
if (!r.ok)
|
|
97
|
+
throw new Error(`Anthropic API ${r.status}`);
|
|
98
|
+
const data = (await r.json());
|
|
99
|
+
const text = data.content?.[0]?.text ?? "";
|
|
100
|
+
const mode = parseMode(text);
|
|
101
|
+
if (!mode)
|
|
102
|
+
throw new Error(`could not parse mode from: ${text}`);
|
|
103
|
+
return mode;
|
|
104
|
+
}
|
|
105
|
+
function callClaudeCli(prompt, timeoutMs) {
|
|
106
|
+
const r = spawnSync("claude", ["-p", prompt], {
|
|
107
|
+
encoding: "utf-8",
|
|
108
|
+
timeout: timeoutMs,
|
|
109
|
+
// Avoid inheriting interactive/tty state that the CLI might react to.
|
|
110
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
111
|
+
});
|
|
112
|
+
if (r.status !== 0 || r.signal)
|
|
113
|
+
throw new Error("claude CLI failed");
|
|
114
|
+
const mode = parseMode(r.stdout);
|
|
115
|
+
if (!mode)
|
|
116
|
+
throw new Error(`could not parse mode from: ${r.stdout}`);
|
|
117
|
+
return mode;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Heuristic last-resort: pick a sensible mode without touching the LLM.
|
|
121
|
+
* This is what auto mode degrades to when both API and CLI are unavailable
|
|
122
|
+
* (or when AutoOptions.noLlm is true).
|
|
123
|
+
*
|
|
124
|
+
* Exported so callers / tests can use the heuristic directly.
|
|
125
|
+
*/
|
|
126
|
+
export function heuristicMode(cmd, output) {
|
|
127
|
+
const len = output.length;
|
|
128
|
+
if (len < 1000)
|
|
129
|
+
return "conservative";
|
|
130
|
+
if (/^git\s+log\b/.test(cmd) && !cmd.includes("--oneline"))
|
|
131
|
+
return "aggressive";
|
|
132
|
+
if (/(test|jest|pytest|vitest)\b/.test(cmd) && len > 5000)
|
|
133
|
+
return "aggressive";
|
|
134
|
+
if (/^find\b/.test(cmd) && len > 2000)
|
|
135
|
+
return "aggressive";
|
|
136
|
+
if (/^ls\b/.test(cmd) && /-l/.test(cmd))
|
|
137
|
+
return "aggressive";
|
|
138
|
+
return "balanced";
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Pick a compression mode for the given command + output. Tries the LLM
|
|
142
|
+
* (API → CLI), falls back to a heuristic. Caches per-command-fingerprint.
|
|
143
|
+
*/
|
|
144
|
+
export async function pickModeAuto(cmd, output, opts = {}) {
|
|
145
|
+
const fp = fingerprint(cmd);
|
|
146
|
+
const cache = opts.noCache ? {} : loadCache();
|
|
147
|
+
const cached = cache[fp];
|
|
148
|
+
if (cached && cached.expires > Date.now()) {
|
|
149
|
+
return { mode: cached.mode, source: "cache" };
|
|
150
|
+
}
|
|
151
|
+
let mode;
|
|
152
|
+
let source;
|
|
153
|
+
if (opts.noLlm) {
|
|
154
|
+
mode = heuristicMode(cmd, output);
|
|
155
|
+
source = "heuristic";
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
const sample = output.slice(0, SAMPLE_BYTES);
|
|
159
|
+
const prompt = buildPrompt(cmd, sample);
|
|
160
|
+
try {
|
|
161
|
+
mode = await callAnthropic(prompt, opts);
|
|
162
|
+
source = "api";
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
try {
|
|
166
|
+
mode = callClaudeCli(prompt, opts.timeoutMs ?? DEFAULT_TIMEOUT_MS);
|
|
167
|
+
source = "cli";
|
|
168
|
+
}
|
|
169
|
+
catch {
|
|
170
|
+
mode = heuristicMode(cmd, output);
|
|
171
|
+
source = "heuristic";
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
if (!opts.noCache) {
|
|
176
|
+
cache[fp] = { mode, expires: Date.now() + TTL_MS };
|
|
177
|
+
saveCache(cache);
|
|
178
|
+
}
|
|
179
|
+
return { mode, source };
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=auto-mode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto-mode.js","sourceRoot":"","sources":["../../src/util/auto-mode.ts"],"names":[],"mappings":"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"}
|