kirograph 0.13.0 → 0.14.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/README.md +332 -93
- package/dist/bin/commands/caveman.js +19 -2
- package/dist/bin/commands/caveman.js.map +2 -2
- package/dist/bin/commands/compression.js +109 -0
- package/dist/bin/commands/compression.js.map +7 -0
- package/dist/bin/commands/context.js +31 -24
- package/dist/bin/commands/context.js.map +2 -2
- package/dist/bin/commands/exec.js +107 -0
- package/dist/bin/commands/exec.js.map +7 -0
- package/dist/bin/commands/gain.js +119 -0
- package/dist/bin/commands/gain.js.map +7 -0
- package/dist/bin/commands/help.js +16 -5
- package/dist/bin/commands/help.js.map +2 -2
- package/dist/bin/commands/install.js +8 -2
- package/dist/bin/commands/install.js.map +2 -2
- package/dist/bin/commands/query.js +5 -1
- package/dist/bin/commands/query.js.map +2 -2
- package/dist/bin/commands/serve.js +2 -2
- package/dist/bin/commands/serve.js.map +2 -2
- package/dist/bin/commands/uninit.js +65 -41
- package/dist/bin/commands/uninit.js.map +2 -2
- package/dist/bin/commands/utils.js +16 -0
- package/dist/bin/commands/utils.js.map +2 -2
- package/dist/bin/installer/cli-agent.js +5 -25
- package/dist/bin/installer/cli-agent.js.map +2 -2
- package/dist/bin/installer/common.js +154 -0
- package/dist/bin/installer/common.js.map +7 -0
- package/dist/bin/installer/config-prompt.js +9 -2
- package/dist/bin/installer/config-prompt.js.map +2 -2
- package/dist/bin/installer/hooks.js +19 -1
- package/dist/bin/installer/hooks.js.map +2 -2
- package/dist/bin/installer/index.js +104 -86
- package/dist/bin/installer/index.js.map +2 -2
- package/dist/bin/installer/instructions.js +60 -0
- package/dist/bin/installer/instructions.js.map +7 -0
- package/dist/bin/installer/mcp.js +6 -36
- package/dist/bin/installer/mcp.js.map +2 -2
- package/dist/bin/installer/steering.js +116 -40
- package/dist/bin/installer/steering.js.map +2 -2
- package/dist/bin/installer/targets/claude.js +79 -0
- package/dist/bin/installer/targets/claude.js.map +7 -0
- package/dist/bin/installer/targets/codex.js +77 -0
- package/dist/bin/installer/targets/codex.js.map +7 -0
- package/dist/bin/installer/targets/index.js +57 -0
- package/dist/bin/installer/targets/index.js.map +7 -0
- package/dist/bin/installer/targets/kiro.js +63 -0
- package/dist/bin/installer/targets/kiro.js.map +7 -0
- package/dist/bin/kirograph.js +7 -1
- package/dist/bin/kirograph.js.map +3 -3
- package/dist/compression/filters/aws.js +418 -0
- package/dist/compression/filters/aws.js.map +7 -0
- package/dist/compression/filters/docker.js +153 -0
- package/dist/compression/filters/docker.js.map +7 -0
- package/dist/compression/filters/files.js +150 -0
- package/dist/compression/filters/files.js.map +7 -0
- package/dist/compression/filters/generic.js +86 -0
- package/dist/compression/filters/generic.js.map +7 -0
- package/dist/compression/filters/git.js +272 -0
- package/dist/compression/filters/git.js.map +7 -0
- package/dist/compression/filters/github.js +137 -0
- package/dist/compression/filters/github.js.map +7 -0
- package/dist/compression/filters/lint.js +280 -0
- package/dist/compression/filters/lint.js.map +7 -0
- package/dist/compression/filters/misc.js +212 -0
- package/dist/compression/filters/misc.js.map +7 -0
- package/dist/compression/filters/package.js +151 -0
- package/dist/compression/filters/package.js.map +7 -0
- package/dist/compression/filters/test.js +266 -0
- package/dist/compression/filters/test.js.map +7 -0
- package/dist/compression/index.js +144 -0
- package/dist/compression/index.js.map +7 -0
- package/dist/compression/naive-cost.js +94 -0
- package/dist/compression/naive-cost.js.map +7 -0
- package/dist/compression/tracker.js +228 -0
- package/dist/compression/tracker.js.map +7 -0
- package/dist/compression/types.js +17 -0
- package/dist/compression/types.js.map +7 -0
- package/dist/config.js +18 -1
- package/dist/config.js.map +2 -2
- package/dist/mcp/tool-names.js +50 -0
- package/dist/mcp/tool-names.js.map +7 -0
- package/dist/mcp/tools.js +173 -4
- package/dist/mcp/tools.js.map +3 -3
- package/package.json +2 -2
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var test_exports = {};
|
|
20
|
+
__export(test_exports, {
|
|
21
|
+
testFilter: () => testFilter
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(test_exports);
|
|
24
|
+
const testFilter = {
|
|
25
|
+
name: "test",
|
|
26
|
+
matches(command) {
|
|
27
|
+
return /\b(jest|vitest|pytest|cargo\s+test|go\s+test|rspec|rake\s+test|mocha|ava|tap|npm\s+test|yarn\s+test|pnpm\s+test|npx\s+vitest|npx\s+jest)\b/.test(command);
|
|
28
|
+
},
|
|
29
|
+
filter(command, rawOutput, level) {
|
|
30
|
+
if (/vitest/i.test(command)) return filterVitest(rawOutput, level);
|
|
31
|
+
if (/jest/i.test(command)) return filterJest(rawOutput, level);
|
|
32
|
+
if (/pytest/i.test(command)) return filterPytest(rawOutput, level);
|
|
33
|
+
if (/cargo\s+test/i.test(command)) return filterCargoTest(rawOutput, level);
|
|
34
|
+
if (/go\s+test/i.test(command)) return filterGoTest(rawOutput, level);
|
|
35
|
+
if (/rspec/i.test(command)) return filterRspec(rawOutput, level);
|
|
36
|
+
if (/rake\s+test/i.test(command)) return filterMinitest(rawOutput, level);
|
|
37
|
+
return filterGenericTest(rawOutput, level);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
function filterVitest(raw, level) {
|
|
41
|
+
return filterJsTestRunner(raw, level, "vitest");
|
|
42
|
+
}
|
|
43
|
+
function filterJest(raw, level) {
|
|
44
|
+
return filterJsTestRunner(raw, level, "jest");
|
|
45
|
+
}
|
|
46
|
+
function filterJsTestRunner(raw, level, runner) {
|
|
47
|
+
const lines = raw.split("\n");
|
|
48
|
+
const summaryLine = lines.find((l) => /Tests:\s+\d+/.test(l) || /\d+\s+passed/.test(l));
|
|
49
|
+
const failedMatch = raw.match(/(\d+)\s+failed/);
|
|
50
|
+
const passedMatch = raw.match(/(\d+)\s+passed/);
|
|
51
|
+
const totalMatch = raw.match(/Tests:\s+(\d+)/);
|
|
52
|
+
const failed = failedMatch ? parseInt(failedMatch[1]) : 0;
|
|
53
|
+
const passed = passedMatch ? parseInt(passedMatch[1]) : 0;
|
|
54
|
+
const total = totalMatch ? parseInt(totalMatch[1]) : failed + passed;
|
|
55
|
+
if (failed === 0) {
|
|
56
|
+
if (level === "ultra") {
|
|
57
|
+
return { output: `\u2713 ${passed}/${total}`, strategy: `${runner}:allpass:ultra` };
|
|
58
|
+
}
|
|
59
|
+
return { output: `PASSED: ${passed}/${total} tests`, strategy: `${runner}:allpass` };
|
|
60
|
+
}
|
|
61
|
+
const failures = [];
|
|
62
|
+
let inFailure = false;
|
|
63
|
+
let failureBlock = [];
|
|
64
|
+
for (const line of lines) {
|
|
65
|
+
if (line.includes("FAIL") && line.includes("\u25CF") || line.includes("\u2715") || line.includes("\u2717") || line.match(/FAIL\s+/)) {
|
|
66
|
+
if (failureBlock.length > 0) failures.push(failureBlock.join("\n"));
|
|
67
|
+
failureBlock = [line];
|
|
68
|
+
inFailure = true;
|
|
69
|
+
} else if (inFailure) {
|
|
70
|
+
if (line.trim() === "" && failureBlock.length > 3) {
|
|
71
|
+
failures.push(failureBlock.join("\n"));
|
|
72
|
+
failureBlock = [];
|
|
73
|
+
inFailure = false;
|
|
74
|
+
} else {
|
|
75
|
+
failureBlock.push(line);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (failureBlock.length > 0) failures.push(failureBlock.join("\n"));
|
|
80
|
+
const header = `FAILED: ${failed}/${total} tests`;
|
|
81
|
+
if (level === "ultra") {
|
|
82
|
+
const shortFailures = failures.map((f) => f.split("\n")[0]).slice(0, 5);
|
|
83
|
+
return { output: `${header}
|
|
84
|
+
${shortFailures.join("\n")}`, strategy: `${runner}:failures:ultra` };
|
|
85
|
+
}
|
|
86
|
+
const maxFailures = level === "aggressive" ? 3 : 5;
|
|
87
|
+
const shown = failures.slice(0, maxFailures).join("\n\n");
|
|
88
|
+
const extra = failures.length > maxFailures ? `
|
|
89
|
+
\u2026+${failures.length - maxFailures} more failures` : "";
|
|
90
|
+
return { output: `${header}
|
|
91
|
+
|
|
92
|
+
${shown}${extra}`, strategy: `${runner}:failures` };
|
|
93
|
+
}
|
|
94
|
+
function filterPytest(raw, level) {
|
|
95
|
+
const lines = raw.split("\n");
|
|
96
|
+
const summaryLine = lines.find((l) => /\d+\s+passed/.test(l) || /\d+\s+failed/.test(l));
|
|
97
|
+
const failedMatch = raw.match(/(\d+)\s+failed/);
|
|
98
|
+
const passedMatch = raw.match(/(\d+)\s+passed/);
|
|
99
|
+
const failed = failedMatch ? parseInt(failedMatch[1]) : 0;
|
|
100
|
+
const passed = passedMatch ? parseInt(passedMatch[1]) : 0;
|
|
101
|
+
const total = failed + passed;
|
|
102
|
+
if (failed === 0) {
|
|
103
|
+
if (level === "ultra") return { output: `\u2713 ${passed}/${total}`, strategy: "pytest:allpass:ultra" };
|
|
104
|
+
return { output: `PASSED: ${passed}/${total} tests`, strategy: "pytest:allpass" };
|
|
105
|
+
}
|
|
106
|
+
const failures = [];
|
|
107
|
+
let inFailure = false;
|
|
108
|
+
let block = [];
|
|
109
|
+
for (const line of lines) {
|
|
110
|
+
if (line.startsWith("FAILED") || line.startsWith("___ ") || line.includes("FAILURES ___")) {
|
|
111
|
+
if (block.length > 0) failures.push(block.join("\n"));
|
|
112
|
+
block = [line];
|
|
113
|
+
inFailure = true;
|
|
114
|
+
} else if (inFailure) {
|
|
115
|
+
block.push(line);
|
|
116
|
+
if (block.length > 20) {
|
|
117
|
+
failures.push(block.join("\n"));
|
|
118
|
+
block = [];
|
|
119
|
+
inFailure = false;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
if (block.length > 0) failures.push(block.join("\n"));
|
|
124
|
+
const header = `FAILED: ${failed}/${total} tests`;
|
|
125
|
+
const maxFailures = level === "ultra" ? 2 : level === "aggressive" ? 3 : 5;
|
|
126
|
+
const shown = failures.slice(0, maxFailures).join("\n\n");
|
|
127
|
+
const extra = failures.length > maxFailures ? `
|
|
128
|
+
\u2026+${failures.length - maxFailures} more` : "";
|
|
129
|
+
return { output: `${header}
|
|
130
|
+
|
|
131
|
+
${shown}${extra}`, strategy: "pytest:failures" };
|
|
132
|
+
}
|
|
133
|
+
function filterCargoTest(raw, level) {
|
|
134
|
+
const lines = raw.split("\n");
|
|
135
|
+
const resultLine = lines.find((l) => l.startsWith("test result:"));
|
|
136
|
+
const failedMatch = raw.match(/(\d+)\s+failed/);
|
|
137
|
+
const passedMatch = raw.match(/(\d+)\s+passed/);
|
|
138
|
+
const failed = failedMatch ? parseInt(failedMatch[1]) : 0;
|
|
139
|
+
const passed = passedMatch ? parseInt(passedMatch[1]) : 0;
|
|
140
|
+
const total = failed + passed;
|
|
141
|
+
if (failed === 0) {
|
|
142
|
+
if (level === "ultra") return { output: `\u2713 ${passed}/${total}`, strategy: "cargo-test:allpass:ultra" };
|
|
143
|
+
return { output: `PASSED: ${passed}/${total} tests`, strategy: "cargo-test:allpass" };
|
|
144
|
+
}
|
|
145
|
+
const failures = [];
|
|
146
|
+
let inFailure = false;
|
|
147
|
+
let block = [];
|
|
148
|
+
for (const line of lines) {
|
|
149
|
+
if (line.includes("FAILED") || line.includes("panicked at") || line.includes("---- ") && line.includes(" ----")) {
|
|
150
|
+
if (block.length > 0) failures.push(block.join("\n"));
|
|
151
|
+
block = [line];
|
|
152
|
+
inFailure = true;
|
|
153
|
+
} else if (inFailure) {
|
|
154
|
+
if (line.startsWith("test ") && line.includes("...")) {
|
|
155
|
+
failures.push(block.join("\n"));
|
|
156
|
+
block = [];
|
|
157
|
+
inFailure = false;
|
|
158
|
+
} else {
|
|
159
|
+
block.push(line);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
if (block.length > 0) failures.push(block.join("\n"));
|
|
164
|
+
const header = `FAILED: ${failed}/${total} tests`;
|
|
165
|
+
const maxFailures = level === "ultra" ? 2 : level === "aggressive" ? 3 : 5;
|
|
166
|
+
const shown = failures.slice(0, maxFailures).join("\n\n");
|
|
167
|
+
const extra = failures.length > maxFailures ? `
|
|
168
|
+
\u2026+${failures.length - maxFailures} more` : "";
|
|
169
|
+
return { output: `${header}
|
|
170
|
+
|
|
171
|
+
${shown}${extra}`, strategy: "cargo-test:failures" };
|
|
172
|
+
}
|
|
173
|
+
function filterGoTest(raw, level) {
|
|
174
|
+
const lines = raw.split("\n");
|
|
175
|
+
const failLines = lines.filter((l) => l.startsWith("--- FAIL"));
|
|
176
|
+
const passLines = lines.filter((l) => l.startsWith("--- PASS") || l.startsWith("ok"));
|
|
177
|
+
if (failLines.length === 0) {
|
|
178
|
+
const passed = passLines.length || lines.filter((l) => l.startsWith("ok")).length;
|
|
179
|
+
if (level === "ultra") return { output: `\u2713 ${passed} passed`, strategy: "go-test:allpass:ultra" };
|
|
180
|
+
return { output: `PASSED: ${passed} test(s)`, strategy: "go-test:allpass" };
|
|
181
|
+
}
|
|
182
|
+
const failures = [];
|
|
183
|
+
let inFailure = false;
|
|
184
|
+
let block = [];
|
|
185
|
+
for (const line of lines) {
|
|
186
|
+
if (line.startsWith("--- FAIL")) {
|
|
187
|
+
if (block.length > 0) failures.push(block.join("\n"));
|
|
188
|
+
block = [line];
|
|
189
|
+
inFailure = true;
|
|
190
|
+
} else if (inFailure) {
|
|
191
|
+
if (line.startsWith("--- ") || line.startsWith("FAIL") || line.startsWith("ok")) {
|
|
192
|
+
failures.push(block.join("\n"));
|
|
193
|
+
block = [];
|
|
194
|
+
inFailure = false;
|
|
195
|
+
} else {
|
|
196
|
+
block.push(line);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
if (block.length > 0) failures.push(block.join("\n"));
|
|
201
|
+
const header = `FAILED: ${failLines.length} test(s)`;
|
|
202
|
+
const maxFailures = level === "ultra" ? 2 : level === "aggressive" ? 3 : 5;
|
|
203
|
+
const shown = failures.slice(0, maxFailures).join("\n\n");
|
|
204
|
+
const extra = failures.length > maxFailures ? `
|
|
205
|
+
\u2026+${failures.length - maxFailures} more` : "";
|
|
206
|
+
return { output: `${header}
|
|
207
|
+
|
|
208
|
+
${shown}${extra}`, strategy: "go-test:failures" };
|
|
209
|
+
}
|
|
210
|
+
function filterRspec(raw, level) {
|
|
211
|
+
const lines = raw.split("\n");
|
|
212
|
+
const summaryMatch = raw.match(/(\d+)\s+examples?,\s+(\d+)\s+failures?/);
|
|
213
|
+
if (!summaryMatch) return { output: raw, strategy: "rspec:passthrough" };
|
|
214
|
+
const total = parseInt(summaryMatch[1]);
|
|
215
|
+
const failed = parseInt(summaryMatch[2]);
|
|
216
|
+
if (failed === 0) {
|
|
217
|
+
if (level === "ultra") return { output: `\u2713 ${total}/${total}`, strategy: "rspec:allpass:ultra" };
|
|
218
|
+
return { output: `PASSED: ${total}/${total} examples`, strategy: "rspec:allpass" };
|
|
219
|
+
}
|
|
220
|
+
const failures = lines.filter((l) => l.includes("Failure/Error") || l.includes("expected") || l.includes("got:"));
|
|
221
|
+
const header = `FAILED: ${failed}/${total} examples`;
|
|
222
|
+
const maxLines = level === "ultra" ? 5 : level === "aggressive" ? 10 : 20;
|
|
223
|
+
const shown = failures.slice(0, maxLines).join("\n");
|
|
224
|
+
return { output: `${header}
|
|
225
|
+
|
|
226
|
+
${shown}`, strategy: "rspec:failures" };
|
|
227
|
+
}
|
|
228
|
+
function filterMinitest(raw, level) {
|
|
229
|
+
const lines = raw.split("\n");
|
|
230
|
+
const summaryMatch = raw.match(/(\d+)\s+runs?,\s+\d+\s+assertions?,\s+(\d+)\s+failures?/);
|
|
231
|
+
if (!summaryMatch) return { output: raw, strategy: "minitest:passthrough" };
|
|
232
|
+
const total = parseInt(summaryMatch[1]);
|
|
233
|
+
const failed = parseInt(summaryMatch[2]);
|
|
234
|
+
if (failed === 0) {
|
|
235
|
+
if (level === "ultra") return { output: `\u2713 ${total}/${total}`, strategy: "minitest:allpass:ultra" };
|
|
236
|
+
return { output: `PASSED: ${total}/${total} tests`, strategy: "minitest:allpass" };
|
|
237
|
+
}
|
|
238
|
+
const failures = lines.filter((l) => l.includes("Failure:") || l.includes("Error:") || l.includes("Expected"));
|
|
239
|
+
const header = `FAILED: ${failed}/${total} tests`;
|
|
240
|
+
const maxLines = level === "ultra" ? 5 : level === "aggressive" ? 10 : 20;
|
|
241
|
+
const shown = failures.slice(0, maxLines).join("\n");
|
|
242
|
+
return { output: `${header}
|
|
243
|
+
|
|
244
|
+
${shown}`, strategy: "minitest:failures" };
|
|
245
|
+
}
|
|
246
|
+
function filterGenericTest(raw, level) {
|
|
247
|
+
const lines = raw.split("\n");
|
|
248
|
+
const failedMatch = raw.match(/(\d+)\s+(?:failed|failing|failure)/i);
|
|
249
|
+
const passedMatch = raw.match(/(\d+)\s+(?:passed|passing|success)/i);
|
|
250
|
+
if (failedMatch && parseInt(failedMatch[1]) === 0 && passedMatch) {
|
|
251
|
+
return { output: `PASSED: ${passedMatch[1]} tests`, strategy: "test:generic:allpass" };
|
|
252
|
+
}
|
|
253
|
+
const important = lines.filter(
|
|
254
|
+
(l) => /fail|error|assert|expect|panic/i.test(l) || /\d+\s+(passed|failed|tests)/i.test(l) || l.startsWith("FAIL") || l.startsWith("ERROR")
|
|
255
|
+
);
|
|
256
|
+
if (important.length > 0 && important.length < lines.length * 0.5) {
|
|
257
|
+
const maxLines = level === "ultra" ? 10 : level === "aggressive" ? 20 : 30;
|
|
258
|
+
return { output: important.slice(0, maxLines).join("\n"), strategy: "test:generic:filtered" };
|
|
259
|
+
}
|
|
260
|
+
return { output: raw, strategy: "test:generic:passthrough" };
|
|
261
|
+
}
|
|
262
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
263
|
+
0 && (module.exports = {
|
|
264
|
+
testFilter
|
|
265
|
+
});
|
|
266
|
+
//# sourceMappingURL=test.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/compression/filters/test.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Test runner output filters (jest, vitest, pytest, cargo test, go test, rspec, minitest)\n */\n\nimport type { CommandFilter, FilterResult, CompressorOptions } from '../types';\n\nexport const testFilter: CommandFilter = {\n name: 'test',\n\n matches(command: string): boolean {\n return /\\b(jest|vitest|pytest|cargo\\s+test|go\\s+test|rspec|rake\\s+test|mocha|ava|tap|npm\\s+test|yarn\\s+test|pnpm\\s+test|npx\\s+vitest|npx\\s+jest)\\b/.test(command);\n },\n\n filter(command: string, rawOutput: string, level: CompressorOptions['level']): FilterResult {\n // Detect which runner\n if (/vitest/i.test(command)) return filterVitest(rawOutput, level);\n if (/jest/i.test(command)) return filterJest(rawOutput, level);\n if (/pytest/i.test(command)) return filterPytest(rawOutput, level);\n if (/cargo\\s+test/i.test(command)) return filterCargoTest(rawOutput, level);\n if (/go\\s+test/i.test(command)) return filterGoTest(rawOutput, level);\n if (/rspec/i.test(command)) return filterRspec(rawOutput, level);\n if (/rake\\s+test/i.test(command)) return filterMinitest(rawOutput, level);\n\n // Generic test output\n return filterGenericTest(rawOutput, level);\n },\n};\n\nfunction filterVitest(raw: string, level: CompressorOptions['level']): FilterResult {\n return filterJsTestRunner(raw, level, 'vitest');\n}\n\nfunction filterJest(raw: string, level: CompressorOptions['level']): FilterResult {\n return filterJsTestRunner(raw, level, 'jest');\n}\n\nfunction filterJsTestRunner(raw: string, level: CompressorOptions['level'], runner: string): FilterResult {\n const lines = raw.split('\\n');\n\n // Check if all passed\n const summaryLine = lines.find(l => /Tests:\\s+\\d+/.test(l) || /\\d+\\s+passed/.test(l));\n const failedMatch = raw.match(/(\\d+)\\s+failed/);\n const passedMatch = raw.match(/(\\d+)\\s+passed/);\n const totalMatch = raw.match(/Tests:\\s+(\\d+)/);\n\n const failed = failedMatch ? parseInt(failedMatch[1]) : 0;\n const passed = passedMatch ? parseInt(passedMatch[1]) : 0;\n const total = totalMatch ? parseInt(totalMatch[1]) : (failed + passed);\n\n if (failed === 0) {\n if (level === 'ultra') {\n return { output: `\u2713 ${passed}/${total}`, strategy: `${runner}:allpass:ultra` };\n }\n return { output: `PASSED: ${passed}/${total} tests`, strategy: `${runner}:allpass` };\n }\n\n // Extract failure details\n const failures: string[] = [];\n let inFailure = false;\n let failureBlock: string[] = [];\n\n for (const line of lines) {\n if (line.includes('FAIL') && line.includes('\u25CF') || line.includes('\u2715') || line.includes('\u2717') || line.match(/FAIL\\s+/)) {\n if (failureBlock.length > 0) failures.push(failureBlock.join('\\n'));\n failureBlock = [line];\n inFailure = true;\n } else if (inFailure) {\n if (line.trim() === '' && failureBlock.length > 3) {\n failures.push(failureBlock.join('\\n'));\n failureBlock = [];\n inFailure = false;\n } else {\n failureBlock.push(line);\n }\n }\n }\n if (failureBlock.length > 0) failures.push(failureBlock.join('\\n'));\n\n const header = `FAILED: ${failed}/${total} tests`;\n if (level === 'ultra') {\n const shortFailures = failures.map(f => f.split('\\n')[0]).slice(0, 5);\n return { output: `${header}\\n${shortFailures.join('\\n')}`, strategy: `${runner}:failures:ultra` };\n }\n\n const maxFailures = level === 'aggressive' ? 3 : 5;\n const shown = failures.slice(0, maxFailures).join('\\n\\n');\n const extra = failures.length > maxFailures ? `\\n\u2026+${failures.length - maxFailures} more failures` : '';\n\n return { output: `${header}\\n\\n${shown}${extra}`, strategy: `${runner}:failures` };\n}\n\nfunction filterPytest(raw: string, level: CompressorOptions['level']): FilterResult {\n const lines = raw.split('\\n');\n\n // Summary line: \"X passed, Y failed\"\n const summaryLine = lines.find(l => /\\d+\\s+passed/.test(l) || /\\d+\\s+failed/.test(l));\n const failedMatch = raw.match(/(\\d+)\\s+failed/);\n const passedMatch = raw.match(/(\\d+)\\s+passed/);\n\n const failed = failedMatch ? parseInt(failedMatch[1]) : 0;\n const passed = passedMatch ? parseInt(passedMatch[1]) : 0;\n const total = failed + passed;\n\n if (failed === 0) {\n if (level === 'ultra') return { output: `\u2713 ${passed}/${total}`, strategy: 'pytest:allpass:ultra' };\n return { output: `PASSED: ${passed}/${total} tests`, strategy: 'pytest:allpass' };\n }\n\n // Extract FAILED sections\n const failures: string[] = [];\n let inFailure = false;\n let block: string[] = [];\n\n for (const line of lines) {\n if (line.startsWith('FAILED') || line.startsWith('___ ') || line.includes('FAILURES ___')) {\n if (block.length > 0) failures.push(block.join('\\n'));\n block = [line];\n inFailure = true;\n } else if (inFailure) {\n block.push(line);\n if (block.length > 20) {\n failures.push(block.join('\\n'));\n block = [];\n inFailure = false;\n }\n }\n }\n if (block.length > 0) failures.push(block.join('\\n'));\n\n const header = `FAILED: ${failed}/${total} tests`;\n const maxFailures = level === 'ultra' ? 2 : level === 'aggressive' ? 3 : 5;\n const shown = failures.slice(0, maxFailures).join('\\n\\n');\n const extra = failures.length > maxFailures ? `\\n\u2026+${failures.length - maxFailures} more` : '';\n\n return { output: `${header}\\n\\n${shown}${extra}`, strategy: 'pytest:failures' };\n}\n\nfunction filterCargoTest(raw: string, level: CompressorOptions['level']): FilterResult {\n const lines = raw.split('\\n');\n\n const resultLine = lines.find(l => l.startsWith('test result:'));\n const failedMatch = raw.match(/(\\d+)\\s+failed/);\n const passedMatch = raw.match(/(\\d+)\\s+passed/);\n\n const failed = failedMatch ? parseInt(failedMatch[1]) : 0;\n const passed = passedMatch ? parseInt(passedMatch[1]) : 0;\n const total = failed + passed;\n\n if (failed === 0) {\n if (level === 'ultra') return { output: `\u2713 ${passed}/${total}`, strategy: 'cargo-test:allpass:ultra' };\n return { output: `PASSED: ${passed}/${total} tests`, strategy: 'cargo-test:allpass' };\n }\n\n // Extract failures\n const failures: string[] = [];\n let inFailure = false;\n let block: string[] = [];\n\n for (const line of lines) {\n if (line.includes('FAILED') || line.includes(\"panicked at\") || line.includes('---- ') && line.includes(' ----')) {\n if (block.length > 0) failures.push(block.join('\\n'));\n block = [line];\n inFailure = true;\n } else if (inFailure) {\n if (line.startsWith('test ') && line.includes('...')) {\n failures.push(block.join('\\n'));\n block = [];\n inFailure = false;\n } else {\n block.push(line);\n }\n }\n }\n if (block.length > 0) failures.push(block.join('\\n'));\n\n const header = `FAILED: ${failed}/${total} tests`;\n const maxFailures = level === 'ultra' ? 2 : level === 'aggressive' ? 3 : 5;\n const shown = failures.slice(0, maxFailures).join('\\n\\n');\n const extra = failures.length > maxFailures ? `\\n\u2026+${failures.length - maxFailures} more` : '';\n\n return { output: `${header}\\n\\n${shown}${extra}`, strategy: 'cargo-test:failures' };\n}\n\nfunction filterGoTest(raw: string, level: CompressorOptions['level']): FilterResult {\n const lines = raw.split('\\n');\n\n const failLines = lines.filter(l => l.startsWith('--- FAIL'));\n const passLines = lines.filter(l => l.startsWith('--- PASS') || l.startsWith('ok'));\n\n if (failLines.length === 0) {\n const passed = passLines.length || lines.filter(l => l.startsWith('ok')).length;\n if (level === 'ultra') return { output: `\u2713 ${passed} passed`, strategy: 'go-test:allpass:ultra' };\n return { output: `PASSED: ${passed} test(s)`, strategy: 'go-test:allpass' };\n }\n\n // Extract failure blocks\n const failures: string[] = [];\n let inFailure = false;\n let block: string[] = [];\n\n for (const line of lines) {\n if (line.startsWith('--- FAIL')) {\n if (block.length > 0) failures.push(block.join('\\n'));\n block = [line];\n inFailure = true;\n } else if (inFailure) {\n if (line.startsWith('--- ') || line.startsWith('FAIL') || line.startsWith('ok')) {\n failures.push(block.join('\\n'));\n block = [];\n inFailure = false;\n } else {\n block.push(line);\n }\n }\n }\n if (block.length > 0) failures.push(block.join('\\n'));\n\n const header = `FAILED: ${failLines.length} test(s)`;\n const maxFailures = level === 'ultra' ? 2 : level === 'aggressive' ? 3 : 5;\n const shown = failures.slice(0, maxFailures).join('\\n\\n');\n const extra = failures.length > maxFailures ? `\\n\u2026+${failures.length - maxFailures} more` : '';\n\n return { output: `${header}\\n\\n${shown}${extra}`, strategy: 'go-test:failures' };\n}\n\nfunction filterRspec(raw: string, level: CompressorOptions['level']): FilterResult {\n const lines = raw.split('\\n');\n const summaryMatch = raw.match(/(\\d+)\\s+examples?,\\s+(\\d+)\\s+failures?/);\n\n if (!summaryMatch) return { output: raw, strategy: 'rspec:passthrough' };\n\n const total = parseInt(summaryMatch[1]);\n const failed = parseInt(summaryMatch[2]);\n\n if (failed === 0) {\n if (level === 'ultra') return { output: `\u2713 ${total}/${total}`, strategy: 'rspec:allpass:ultra' };\n return { output: `PASSED: ${total}/${total} examples`, strategy: 'rspec:allpass' };\n }\n\n // Extract failure messages\n const failures = lines.filter(l => l.includes('Failure/Error') || l.includes('expected') || l.includes('got:'));\n const header = `FAILED: ${failed}/${total} examples`;\n const maxLines = level === 'ultra' ? 5 : level === 'aggressive' ? 10 : 20;\n const shown = failures.slice(0, maxLines).join('\\n');\n\n return { output: `${header}\\n\\n${shown}`, strategy: 'rspec:failures' };\n}\n\nfunction filterMinitest(raw: string, level: CompressorOptions['level']): FilterResult {\n const lines = raw.split('\\n');\n const summaryMatch = raw.match(/(\\d+)\\s+runs?,\\s+\\d+\\s+assertions?,\\s+(\\d+)\\s+failures?/);\n\n if (!summaryMatch) return { output: raw, strategy: 'minitest:passthrough' };\n\n const total = parseInt(summaryMatch[1]);\n const failed = parseInt(summaryMatch[2]);\n\n if (failed === 0) {\n if (level === 'ultra') return { output: `\u2713 ${total}/${total}`, strategy: 'minitest:allpass:ultra' };\n return { output: `PASSED: ${total}/${total} tests`, strategy: 'minitest:allpass' };\n }\n\n const failures = lines.filter(l => l.includes('Failure:') || l.includes('Error:') || l.includes('Expected'));\n const header = `FAILED: ${failed}/${total} tests`;\n const maxLines = level === 'ultra' ? 5 : level === 'aggressive' ? 10 : 20;\n const shown = failures.slice(0, maxLines).join('\\n');\n\n return { output: `${header}\\n\\n${shown}`, strategy: 'minitest:failures' };\n}\n\nfunction filterGenericTest(raw: string, level: CompressorOptions['level']): FilterResult {\n const lines = raw.split('\\n');\n\n // Try to detect pass/fail from common patterns\n const failedMatch = raw.match(/(\\d+)\\s+(?:failed|failing|failure)/i);\n const passedMatch = raw.match(/(\\d+)\\s+(?:passed|passing|success)/i);\n\n if (failedMatch && parseInt(failedMatch[1]) === 0 && passedMatch) {\n return { output: `PASSED: ${passedMatch[1]} tests`, strategy: 'test:generic:allpass' };\n }\n\n // Keep only lines that look like failures or summaries\n const important = lines.filter(l =>\n /fail|error|assert|expect|panic/i.test(l) ||\n /\\d+\\s+(passed|failed|tests)/i.test(l) ||\n l.startsWith('FAIL') || l.startsWith('ERROR')\n );\n\n if (important.length > 0 && important.length < lines.length * 0.5) {\n const maxLines = level === 'ultra' ? 10 : level === 'aggressive' ? 20 : 30;\n return { output: important.slice(0, maxLines).join('\\n'), strategy: 'test:generic:filtered' };\n }\n\n return { output: raw, strategy: 'test:generic:passthrough' };\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAMO,MAAM,aAA4B;AAAA,EACvC,MAAM;AAAA,EAEN,QAAQ,SAA0B;AAChC,WAAO,6IAA6I,KAAK,OAAO;AAAA,EAClK;AAAA,EAEA,OAAO,SAAiB,WAAmB,OAAiD;AAE1F,QAAI,UAAU,KAAK,OAAO,EAAG,QAAO,aAAa,WAAW,KAAK;AACjE,QAAI,QAAQ,KAAK,OAAO,EAAG,QAAO,WAAW,WAAW,KAAK;AAC7D,QAAI,UAAU,KAAK,OAAO,EAAG,QAAO,aAAa,WAAW,KAAK;AACjE,QAAI,gBAAgB,KAAK,OAAO,EAAG,QAAO,gBAAgB,WAAW,KAAK;AAC1E,QAAI,aAAa,KAAK,OAAO,EAAG,QAAO,aAAa,WAAW,KAAK;AACpE,QAAI,SAAS,KAAK,OAAO,EAAG,QAAO,YAAY,WAAW,KAAK;AAC/D,QAAI,eAAe,KAAK,OAAO,EAAG,QAAO,eAAe,WAAW,KAAK;AAGxE,WAAO,kBAAkB,WAAW,KAAK;AAAA,EAC3C;AACF;AAEA,SAAS,aAAa,KAAa,OAAiD;AAClF,SAAO,mBAAmB,KAAK,OAAO,QAAQ;AAChD;AAEA,SAAS,WAAW,KAAa,OAAiD;AAChF,SAAO,mBAAmB,KAAK,OAAO,MAAM;AAC9C;AAEA,SAAS,mBAAmB,KAAa,OAAmC,QAA8B;AACxG,QAAM,QAAQ,IAAI,MAAM,IAAI;AAG5B,QAAM,cAAc,MAAM,KAAK,OAAK,eAAe,KAAK,CAAC,KAAK,eAAe,KAAK,CAAC,CAAC;AACpF,QAAM,cAAc,IAAI,MAAM,gBAAgB;AAC9C,QAAM,cAAc,IAAI,MAAM,gBAAgB;AAC9C,QAAM,aAAa,IAAI,MAAM,gBAAgB;AAE7C,QAAM,SAAS,cAAc,SAAS,YAAY,CAAC,CAAC,IAAI;AACxD,QAAM,SAAS,cAAc,SAAS,YAAY,CAAC,CAAC,IAAI;AACxD,QAAM,QAAQ,aAAa,SAAS,WAAW,CAAC,CAAC,IAAK,SAAS;AAE/D,MAAI,WAAW,GAAG;AAChB,QAAI,UAAU,SAAS;AACrB,aAAO,EAAE,QAAQ,UAAK,MAAM,IAAI,KAAK,IAAI,UAAU,GAAG,MAAM,iBAAiB;AAAA,IAC/E;AACA,WAAO,EAAE,QAAQ,WAAW,MAAM,IAAI,KAAK,UAAU,UAAU,GAAG,MAAM,WAAW;AAAA,EACrF;AAGA,QAAM,WAAqB,CAAC;AAC5B,MAAI,YAAY;AAChB,MAAI,eAAyB,CAAC;AAE9B,aAAW,QAAQ,OAAO;AACxB,QAAI,KAAK,SAAS,MAAM,KAAK,KAAK,SAAS,QAAG,KAAK,KAAK,SAAS,QAAG,KAAK,KAAK,SAAS,QAAG,KAAK,KAAK,MAAM,SAAS,GAAG;AACpH,UAAI,aAAa,SAAS,EAAG,UAAS,KAAK,aAAa,KAAK,IAAI,CAAC;AAClE,qBAAe,CAAC,IAAI;AACpB,kBAAY;AAAA,IACd,WAAW,WAAW;AACpB,UAAI,KAAK,KAAK,MAAM,MAAM,aAAa,SAAS,GAAG;AACjD,iBAAS,KAAK,aAAa,KAAK,IAAI,CAAC;AACrC,uBAAe,CAAC;AAChB,oBAAY;AAAA,MACd,OAAO;AACL,qBAAa,KAAK,IAAI;AAAA,MACxB;AAAA,IACF;AAAA,EACF;AACA,MAAI,aAAa,SAAS,EAAG,UAAS,KAAK,aAAa,KAAK,IAAI,CAAC;AAElE,QAAM,SAAS,WAAW,MAAM,IAAI,KAAK;AACzC,MAAI,UAAU,SAAS;AACrB,UAAM,gBAAgB,SAAS,IAAI,OAAK,EAAE,MAAM,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,GAAG,CAAC;AACpE,WAAO,EAAE,QAAQ,GAAG,MAAM;AAAA,EAAK,cAAc,KAAK,IAAI,CAAC,IAAI,UAAU,GAAG,MAAM,kBAAkB;AAAA,EAClG;AAEA,QAAM,cAAc,UAAU,eAAe,IAAI;AACjD,QAAM,QAAQ,SAAS,MAAM,GAAG,WAAW,EAAE,KAAK,MAAM;AACxD,QAAM,QAAQ,SAAS,SAAS,cAAc;AAAA,SAAO,SAAS,SAAS,WAAW,mBAAmB;AAErG,SAAO,EAAE,QAAQ,GAAG,MAAM;AAAA;AAAA,EAAO,KAAK,GAAG,KAAK,IAAI,UAAU,GAAG,MAAM,YAAY;AACnF;AAEA,SAAS,aAAa,KAAa,OAAiD;AAClF,QAAM,QAAQ,IAAI,MAAM,IAAI;AAG5B,QAAM,cAAc,MAAM,KAAK,OAAK,eAAe,KAAK,CAAC,KAAK,eAAe,KAAK,CAAC,CAAC;AACpF,QAAM,cAAc,IAAI,MAAM,gBAAgB;AAC9C,QAAM,cAAc,IAAI,MAAM,gBAAgB;AAE9C,QAAM,SAAS,cAAc,SAAS,YAAY,CAAC,CAAC,IAAI;AACxD,QAAM,SAAS,cAAc,SAAS,YAAY,CAAC,CAAC,IAAI;AACxD,QAAM,QAAQ,SAAS;AAEvB,MAAI,WAAW,GAAG;AAChB,QAAI,UAAU,QAAS,QAAO,EAAE,QAAQ,UAAK,MAAM,IAAI,KAAK,IAAI,UAAU,uBAAuB;AACjG,WAAO,EAAE,QAAQ,WAAW,MAAM,IAAI,KAAK,UAAU,UAAU,iBAAiB;AAAA,EAClF;AAGA,QAAM,WAAqB,CAAC;AAC5B,MAAI,YAAY;AAChB,MAAI,QAAkB,CAAC;AAEvB,aAAW,QAAQ,OAAO;AACxB,QAAI,KAAK,WAAW,QAAQ,KAAK,KAAK,WAAW,MAAM,KAAK,KAAK,SAAS,cAAc,GAAG;AACzF,UAAI,MAAM,SAAS,EAAG,UAAS,KAAK,MAAM,KAAK,IAAI,CAAC;AACpD,cAAQ,CAAC,IAAI;AACb,kBAAY;AAAA,IACd,WAAW,WAAW;AACpB,YAAM,KAAK,IAAI;AACf,UAAI,MAAM,SAAS,IAAI;AACrB,iBAAS,KAAK,MAAM,KAAK,IAAI,CAAC;AAC9B,gBAAQ,CAAC;AACT,oBAAY;AAAA,MACd;AAAA,IACF;AAAA,EACF;AACA,MAAI,MAAM,SAAS,EAAG,UAAS,KAAK,MAAM,KAAK,IAAI,CAAC;AAEpD,QAAM,SAAS,WAAW,MAAM,IAAI,KAAK;AACzC,QAAM,cAAc,UAAU,UAAU,IAAI,UAAU,eAAe,IAAI;AACzE,QAAM,QAAQ,SAAS,MAAM,GAAG,WAAW,EAAE,KAAK,MAAM;AACxD,QAAM,QAAQ,SAAS,SAAS,cAAc;AAAA,SAAO,SAAS,SAAS,WAAW,UAAU;AAE5F,SAAO,EAAE,QAAQ,GAAG,MAAM;AAAA;AAAA,EAAO,KAAK,GAAG,KAAK,IAAI,UAAU,kBAAkB;AAChF;AAEA,SAAS,gBAAgB,KAAa,OAAiD;AACrF,QAAM,QAAQ,IAAI,MAAM,IAAI;AAE5B,QAAM,aAAa,MAAM,KAAK,OAAK,EAAE,WAAW,cAAc,CAAC;AAC/D,QAAM,cAAc,IAAI,MAAM,gBAAgB;AAC9C,QAAM,cAAc,IAAI,MAAM,gBAAgB;AAE9C,QAAM,SAAS,cAAc,SAAS,YAAY,CAAC,CAAC,IAAI;AACxD,QAAM,SAAS,cAAc,SAAS,YAAY,CAAC,CAAC,IAAI;AACxD,QAAM,QAAQ,SAAS;AAEvB,MAAI,WAAW,GAAG;AAChB,QAAI,UAAU,QAAS,QAAO,EAAE,QAAQ,UAAK,MAAM,IAAI,KAAK,IAAI,UAAU,2BAA2B;AACrG,WAAO,EAAE,QAAQ,WAAW,MAAM,IAAI,KAAK,UAAU,UAAU,qBAAqB;AAAA,EACtF;AAGA,QAAM,WAAqB,CAAC;AAC5B,MAAI,YAAY;AAChB,MAAI,QAAkB,CAAC;AAEvB,aAAW,QAAQ,OAAO;AACxB,QAAI,KAAK,SAAS,QAAQ,KAAK,KAAK,SAAS,aAAa,KAAK,KAAK,SAAS,OAAO,KAAK,KAAK,SAAS,OAAO,GAAG;AAC/G,UAAI,MAAM,SAAS,EAAG,UAAS,KAAK,MAAM,KAAK,IAAI,CAAC;AACpD,cAAQ,CAAC,IAAI;AACb,kBAAY;AAAA,IACd,WAAW,WAAW;AACpB,UAAI,KAAK,WAAW,OAAO,KAAK,KAAK,SAAS,KAAK,GAAG;AACpD,iBAAS,KAAK,MAAM,KAAK,IAAI,CAAC;AAC9B,gBAAQ,CAAC;AACT,oBAAY;AAAA,MACd,OAAO;AACL,cAAM,KAAK,IAAI;AAAA,MACjB;AAAA,IACF;AAAA,EACF;AACA,MAAI,MAAM,SAAS,EAAG,UAAS,KAAK,MAAM,KAAK,IAAI,CAAC;AAEpD,QAAM,SAAS,WAAW,MAAM,IAAI,KAAK;AACzC,QAAM,cAAc,UAAU,UAAU,IAAI,UAAU,eAAe,IAAI;AACzE,QAAM,QAAQ,SAAS,MAAM,GAAG,WAAW,EAAE,KAAK,MAAM;AACxD,QAAM,QAAQ,SAAS,SAAS,cAAc;AAAA,SAAO,SAAS,SAAS,WAAW,UAAU;AAE5F,SAAO,EAAE,QAAQ,GAAG,MAAM;AAAA;AAAA,EAAO,KAAK,GAAG,KAAK,IAAI,UAAU,sBAAsB;AACpF;AAEA,SAAS,aAAa,KAAa,OAAiD;AAClF,QAAM,QAAQ,IAAI,MAAM,IAAI;AAE5B,QAAM,YAAY,MAAM,OAAO,OAAK,EAAE,WAAW,UAAU,CAAC;AAC5D,QAAM,YAAY,MAAM,OAAO,OAAK,EAAE,WAAW,UAAU,KAAK,EAAE,WAAW,IAAI,CAAC;AAElF,MAAI,UAAU,WAAW,GAAG;AAC1B,UAAM,SAAS,UAAU,UAAU,MAAM,OAAO,OAAK,EAAE,WAAW,IAAI,CAAC,EAAE;AACzE,QAAI,UAAU,QAAS,QAAO,EAAE,QAAQ,UAAK,MAAM,WAAW,UAAU,wBAAwB;AAChG,WAAO,EAAE,QAAQ,WAAW,MAAM,YAAY,UAAU,kBAAkB;AAAA,EAC5E;AAGA,QAAM,WAAqB,CAAC;AAC5B,MAAI,YAAY;AAChB,MAAI,QAAkB,CAAC;AAEvB,aAAW,QAAQ,OAAO;AACxB,QAAI,KAAK,WAAW,UAAU,GAAG;AAC/B,UAAI,MAAM,SAAS,EAAG,UAAS,KAAK,MAAM,KAAK,IAAI,CAAC;AACpD,cAAQ,CAAC,IAAI;AACb,kBAAY;AAAA,IACd,WAAW,WAAW;AACpB,UAAI,KAAK,WAAW,MAAM,KAAK,KAAK,WAAW,MAAM,KAAK,KAAK,WAAW,IAAI,GAAG;AAC/E,iBAAS,KAAK,MAAM,KAAK,IAAI,CAAC;AAC9B,gBAAQ,CAAC;AACT,oBAAY;AAAA,MACd,OAAO;AACL,cAAM,KAAK,IAAI;AAAA,MACjB;AAAA,IACF;AAAA,EACF;AACA,MAAI,MAAM,SAAS,EAAG,UAAS,KAAK,MAAM,KAAK,IAAI,CAAC;AAEpD,QAAM,SAAS,WAAW,UAAU,MAAM;AAC1C,QAAM,cAAc,UAAU,UAAU,IAAI,UAAU,eAAe,IAAI;AACzE,QAAM,QAAQ,SAAS,MAAM,GAAG,WAAW,EAAE,KAAK,MAAM;AACxD,QAAM,QAAQ,SAAS,SAAS,cAAc;AAAA,SAAO,SAAS,SAAS,WAAW,UAAU;AAE5F,SAAO,EAAE,QAAQ,GAAG,MAAM;AAAA;AAAA,EAAO,KAAK,GAAG,KAAK,IAAI,UAAU,mBAAmB;AACjF;AAEA,SAAS,YAAY,KAAa,OAAiD;AACjF,QAAM,QAAQ,IAAI,MAAM,IAAI;AAC5B,QAAM,eAAe,IAAI,MAAM,wCAAwC;AAEvE,MAAI,CAAC,aAAc,QAAO,EAAE,QAAQ,KAAK,UAAU,oBAAoB;AAEvE,QAAM,QAAQ,SAAS,aAAa,CAAC,CAAC;AACtC,QAAM,SAAS,SAAS,aAAa,CAAC,CAAC;AAEvC,MAAI,WAAW,GAAG;AAChB,QAAI,UAAU,QAAS,QAAO,EAAE,QAAQ,UAAK,KAAK,IAAI,KAAK,IAAI,UAAU,sBAAsB;AAC/F,WAAO,EAAE,QAAQ,WAAW,KAAK,IAAI,KAAK,aAAa,UAAU,gBAAgB;AAAA,EACnF;AAGA,QAAM,WAAW,MAAM,OAAO,OAAK,EAAE,SAAS,eAAe,KAAK,EAAE,SAAS,UAAU,KAAK,EAAE,SAAS,MAAM,CAAC;AAC9G,QAAM,SAAS,WAAW,MAAM,IAAI,KAAK;AACzC,QAAM,WAAW,UAAU,UAAU,IAAI,UAAU,eAAe,KAAK;AACvE,QAAM,QAAQ,SAAS,MAAM,GAAG,QAAQ,EAAE,KAAK,IAAI;AAEnD,SAAO,EAAE,QAAQ,GAAG,MAAM;AAAA;AAAA,EAAO,KAAK,IAAI,UAAU,iBAAiB;AACvE;AAEA,SAAS,eAAe,KAAa,OAAiD;AACpF,QAAM,QAAQ,IAAI,MAAM,IAAI;AAC5B,QAAM,eAAe,IAAI,MAAM,yDAAyD;AAExF,MAAI,CAAC,aAAc,QAAO,EAAE,QAAQ,KAAK,UAAU,uBAAuB;AAE1E,QAAM,QAAQ,SAAS,aAAa,CAAC,CAAC;AACtC,QAAM,SAAS,SAAS,aAAa,CAAC,CAAC;AAEvC,MAAI,WAAW,GAAG;AAChB,QAAI,UAAU,QAAS,QAAO,EAAE,QAAQ,UAAK,KAAK,IAAI,KAAK,IAAI,UAAU,yBAAyB;AAClG,WAAO,EAAE,QAAQ,WAAW,KAAK,IAAI,KAAK,UAAU,UAAU,mBAAmB;AAAA,EACnF;AAEA,QAAM,WAAW,MAAM,OAAO,OAAK,EAAE,SAAS,UAAU,KAAK,EAAE,SAAS,QAAQ,KAAK,EAAE,SAAS,UAAU,CAAC;AAC3G,QAAM,SAAS,WAAW,MAAM,IAAI,KAAK;AACzC,QAAM,WAAW,UAAU,UAAU,IAAI,UAAU,eAAe,KAAK;AACvE,QAAM,QAAQ,SAAS,MAAM,GAAG,QAAQ,EAAE,KAAK,IAAI;AAEnD,SAAO,EAAE,QAAQ,GAAG,MAAM;AAAA;AAAA,EAAO,KAAK,IAAI,UAAU,oBAAoB;AAC1E;AAEA,SAAS,kBAAkB,KAAa,OAAiD;AACvF,QAAM,QAAQ,IAAI,MAAM,IAAI;AAG5B,QAAM,cAAc,IAAI,MAAM,qCAAqC;AACnE,QAAM,cAAc,IAAI,MAAM,qCAAqC;AAEnE,MAAI,eAAe,SAAS,YAAY,CAAC,CAAC,MAAM,KAAK,aAAa;AAChE,WAAO,EAAE,QAAQ,WAAW,YAAY,CAAC,CAAC,UAAU,UAAU,uBAAuB;AAAA,EACvF;AAGA,QAAM,YAAY,MAAM;AAAA,IAAO,OAC7B,kCAAkC,KAAK,CAAC,KACxC,+BAA+B,KAAK,CAAC,KACrC,EAAE,WAAW,MAAM,KAAK,EAAE,WAAW,OAAO;AAAA,EAC9C;AAEA,MAAI,UAAU,SAAS,KAAK,UAAU,SAAS,MAAM,SAAS,KAAK;AACjE,UAAM,WAAW,UAAU,UAAU,KAAK,UAAU,eAAe,KAAK;AACxE,WAAO,EAAE,QAAQ,UAAU,MAAM,GAAG,QAAQ,EAAE,KAAK,IAAI,GAAG,UAAU,wBAAwB;AAAA,EAC9F;AAEA,SAAO,EAAE,QAAQ,KAAK,UAAU,2BAA2B;AAC7D;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var compression_exports = {};
|
|
20
|
+
__export(compression_exports, {
|
|
21
|
+
compress: () => compress,
|
|
22
|
+
detectCommandFamily: () => detectCommandFamily,
|
|
23
|
+
estimateTokens: () => estimateTokens
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(compression_exports);
|
|
26
|
+
var import_git = require("./filters/git");
|
|
27
|
+
var import_test = require("./filters/test");
|
|
28
|
+
var import_lint = require("./filters/lint");
|
|
29
|
+
var import_files = require("./filters/files");
|
|
30
|
+
var import_docker = require("./filters/docker");
|
|
31
|
+
var import_package = require("./filters/package");
|
|
32
|
+
var import_aws = require("./filters/aws");
|
|
33
|
+
var import_github = require("./filters/github");
|
|
34
|
+
var import_misc = require("./filters/misc");
|
|
35
|
+
var import_generic = require("./filters/generic");
|
|
36
|
+
const FILTERS = [
|
|
37
|
+
import_git.gitFilter,
|
|
38
|
+
import_test.testFilter,
|
|
39
|
+
import_lint.lintFilter,
|
|
40
|
+
import_misc.miscFilter,
|
|
41
|
+
// grep, diff, curl, wget, playwright, prisma
|
|
42
|
+
import_files.filesFilter,
|
|
43
|
+
import_docker.dockerFilter,
|
|
44
|
+
import_package.packageFilter,
|
|
45
|
+
import_aws.awsFilter,
|
|
46
|
+
import_github.githubFilter,
|
|
47
|
+
import_generic.genericFilter
|
|
48
|
+
// Always last — catches everything
|
|
49
|
+
];
|
|
50
|
+
function estimateTokens(text) {
|
|
51
|
+
if (!text) return 0;
|
|
52
|
+
return Math.ceil(text.length / 4);
|
|
53
|
+
}
|
|
54
|
+
const DEFAULT_OPTIONS = {
|
|
55
|
+
level: "normal",
|
|
56
|
+
preserveErrors: true
|
|
57
|
+
};
|
|
58
|
+
function compress(command, rawOutput, opts) {
|
|
59
|
+
const options = { ...DEFAULT_OPTIONS, ...opts };
|
|
60
|
+
if (!rawOutput || !rawOutput.trim()) {
|
|
61
|
+
return {
|
|
62
|
+
output: rawOutput || "",
|
|
63
|
+
originalTokens: 0,
|
|
64
|
+
compressedTokens: 0,
|
|
65
|
+
savings: 0,
|
|
66
|
+
strategy: "empty",
|
|
67
|
+
commandFamily: "none"
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
const originalTokens = estimateTokens(rawOutput);
|
|
71
|
+
const filter = FILTERS.find((f) => f.matches(command));
|
|
72
|
+
if (!filter) {
|
|
73
|
+
return {
|
|
74
|
+
output: rawOutput,
|
|
75
|
+
originalTokens,
|
|
76
|
+
compressedTokens: originalTokens,
|
|
77
|
+
savings: 0,
|
|
78
|
+
strategy: "none",
|
|
79
|
+
commandFamily: "unknown"
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
if (options.preserveErrors && isErrorOutput(rawOutput, command)) {
|
|
83
|
+
const result2 = filter.filter(command, rawOutput, "normal");
|
|
84
|
+
const compressedTokens2 = estimateTokens(result2.output);
|
|
85
|
+
return {
|
|
86
|
+
output: result2.output,
|
|
87
|
+
originalTokens,
|
|
88
|
+
compressedTokens: compressedTokens2,
|
|
89
|
+
savings: Math.round((originalTokens - compressedTokens2) / originalTokens * 100),
|
|
90
|
+
strategy: result2.strategy + ":error-preserved",
|
|
91
|
+
commandFamily: filter.name
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
const result = filter.filter(command, rawOutput, options.level);
|
|
95
|
+
let output = result.output;
|
|
96
|
+
if (options.maxOutputTokens && estimateTokens(output) > options.maxOutputTokens) {
|
|
97
|
+
const maxChars = options.maxOutputTokens * 4;
|
|
98
|
+
output = output.slice(0, maxChars) + "\n\u2026(truncated to token limit)";
|
|
99
|
+
}
|
|
100
|
+
const compressedTokens = estimateTokens(output);
|
|
101
|
+
const savings = originalTokens > 0 ? Math.round((originalTokens - compressedTokens) / originalTokens * 100) : 0;
|
|
102
|
+
return {
|
|
103
|
+
output,
|
|
104
|
+
originalTokens,
|
|
105
|
+
compressedTokens,
|
|
106
|
+
savings: Math.max(0, savings),
|
|
107
|
+
// Never negative
|
|
108
|
+
strategy: result.strategy,
|
|
109
|
+
commandFamily: filter.name
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
function detectCommandFamily(command) {
|
|
113
|
+
for (const filter of FILTERS) {
|
|
114
|
+
if (filter !== import_generic.genericFilter && filter.matches(command)) {
|
|
115
|
+
return filter.name;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return "other";
|
|
119
|
+
}
|
|
120
|
+
function isErrorOutput(output, _command) {
|
|
121
|
+
const errorIndicators = [
|
|
122
|
+
/^error/im,
|
|
123
|
+
/\bfailed\b/i,
|
|
124
|
+
/\bpanic\b/i,
|
|
125
|
+
/\bfatal\b/i,
|
|
126
|
+
/exit\s+code\s+[1-9]/i,
|
|
127
|
+
/\bException\b/,
|
|
128
|
+
/\bTraceback\b/,
|
|
129
|
+
/\bsegfault\b/i,
|
|
130
|
+
/\bSIGSEGV\b/,
|
|
131
|
+
/\bSIGABRT\b/
|
|
132
|
+
];
|
|
133
|
+
const head = output.slice(0, 500);
|
|
134
|
+
const tail = output.slice(-500);
|
|
135
|
+
const sample = head + tail;
|
|
136
|
+
return errorIndicators.some((re) => re.test(sample));
|
|
137
|
+
}
|
|
138
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
139
|
+
0 && (module.exports = {
|
|
140
|
+
compress,
|
|
141
|
+
detectCommandFamily,
|
|
142
|
+
estimateTokens
|
|
143
|
+
});
|
|
144
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/compression/index.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * KiroGraph Shell Compression Engine\n *\n * Filters and compresses command outputs to reduce token consumption.\n * Inspired by rtk (https://github.com/rtk-ai/rtk), implemented in pure TypeScript.\n */\n\nimport type { CompressionResult, CompressorOptions, CommandFilter } from './types';\nimport { gitFilter } from './filters/git';\nimport { testFilter } from './filters/test';\nimport { lintFilter } from './filters/lint';\nimport { filesFilter } from './filters/files';\nimport { dockerFilter } from './filters/docker';\nimport { packageFilter } from './filters/package';\nimport { awsFilter } from './filters/aws';\nimport { githubFilter } from './filters/github';\nimport { miscFilter } from './filters/misc';\nimport { genericFilter } from './filters/generic';\n\nexport type { CompressionResult, CompressorOptions, CommandFilter, TokenSavingsRecord } from './types';\n\n// \u2500\u2500 Filter registry (order matters \u2014 first match wins) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst FILTERS: CommandFilter[] = [\n gitFilter,\n testFilter,\n lintFilter,\n miscFilter, // grep, diff, curl, wget, playwright, prisma\n filesFilter,\n dockerFilter,\n packageFilter,\n awsFilter,\n githubFilter,\n genericFilter, // Always last \u2014 catches everything\n];\n\n// \u2500\u2500 Token estimation \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Rough token count estimation.\n * Uses the ~4 chars per token heuristic for English/code text.\n * Good enough for savings tracking without pulling in a tokenizer.\n */\nexport function estimateTokens(text: string): number {\n if (!text) return 0;\n // Approximate: 1 token \u2248 4 characters for code/English mix\n return Math.ceil(text.length / 4);\n}\n\n// \u2500\u2500 Main compress function \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst DEFAULT_OPTIONS: CompressorOptions = {\n level: 'normal',\n preserveErrors: true,\n};\n\n/**\n * Compress command output using the appropriate filter.\n *\n * @param command - The shell command that was executed\n * @param rawOutput - The raw stdout/stderr output\n * @param opts - Compression options\n * @returns Compression result with output, token counts, and strategy info\n */\nexport function compress(command: string, rawOutput: string, opts?: Partial<CompressorOptions>): CompressionResult {\n const options: CompressorOptions = { ...DEFAULT_OPTIONS, ...opts };\n\n // Empty output \u2014 nothing to compress\n if (!rawOutput || !rawOutput.trim()) {\n return {\n output: rawOutput || '',\n originalTokens: 0,\n compressedTokens: 0,\n savings: 0,\n strategy: 'empty',\n commandFamily: 'none',\n };\n }\n\n const originalTokens = estimateTokens(rawOutput);\n\n // Find matching filter\n const filter = FILTERS.find(f => f.matches(command));\n if (!filter) {\n // Should never happen since genericFilter always matches\n return {\n output: rawOutput,\n originalTokens,\n compressedTokens: originalTokens,\n savings: 0,\n strategy: 'none',\n commandFamily: 'unknown',\n };\n }\n\n // Check if output looks like an error and preserveErrors is on\n if (options.preserveErrors && isErrorOutput(rawOutput, command)) {\n // Still apply filter but with less aggressive truncation\n const result = filter.filter(command, rawOutput, 'normal');\n const compressedTokens = estimateTokens(result.output);\n return {\n output: result.output,\n originalTokens,\n compressedTokens,\n savings: Math.round(((originalTokens - compressedTokens) / originalTokens) * 100),\n strategy: result.strategy + ':error-preserved',\n commandFamily: filter.name,\n };\n }\n\n // Apply filter\n const result = filter.filter(command, rawOutput, options.level);\n let output = result.output;\n\n // Apply maxOutputTokens truncation if specified\n if (options.maxOutputTokens && estimateTokens(output) > options.maxOutputTokens) {\n const maxChars = options.maxOutputTokens * 4;\n output = output.slice(0, maxChars) + '\\n\u2026(truncated to token limit)';\n }\n\n const compressedTokens = estimateTokens(output);\n const savings = originalTokens > 0\n ? Math.round(((originalTokens - compressedTokens) / originalTokens) * 100)\n : 0;\n\n return {\n output,\n originalTokens,\n compressedTokens,\n savings: Math.max(0, savings), // Never negative\n strategy: result.strategy,\n commandFamily: filter.name,\n };\n}\n\n/**\n * Detect the command family without running the full filter.\n * Useful for analytics and reporting.\n */\nexport function detectCommandFamily(command: string): string {\n for (const filter of FILTERS) {\n if (filter !== genericFilter && filter.matches(command)) {\n return filter.name;\n }\n }\n return 'other';\n}\n\n// \u2500\u2500 Helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Heuristic: does this output look like a command failure?\n * If so, we want to preserve more detail.\n */\nfunction isErrorOutput(output: string, _command: string): boolean {\n const errorIndicators = [\n /^error/im,\n /\\bfailed\\b/i,\n /\\bpanic\\b/i,\n /\\bfatal\\b/i,\n /exit\\s+code\\s+[1-9]/i,\n /\\bException\\b/,\n /\\bTraceback\\b/,\n /\\bsegfault\\b/i,\n /\\bSIGSEGV\\b/,\n /\\bSIGABRT\\b/,\n ];\n\n // Only consider it an error if the indicators appear near the start or end\n const head = output.slice(0, 500);\n const tail = output.slice(-500);\n const sample = head + tail;\n\n return errorIndicators.some(re => re.test(sample));\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["result", "compressedTokens"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var naive_cost_exports = {};
|
|
20
|
+
__export(naive_cost_exports, {
|
|
21
|
+
estimateNaiveCost: () => estimateNaiveCost
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(naive_cost_exports);
|
|
24
|
+
const AVG_FILE_TOKENS = 1500;
|
|
25
|
+
const AVG_GREP_TOKENS = 800;
|
|
26
|
+
const AVG_FIND_TOKENS = 2e3;
|
|
27
|
+
function estimateNaiveCost(toolName, outputTokens, args) {
|
|
28
|
+
switch (toolName) {
|
|
29
|
+
case "kirograph_context": {
|
|
30
|
+
const maxNodes = args?.maxNodes || 20;
|
|
31
|
+
const filesEstimate = Math.min(Math.ceil(maxNodes / 2), 10);
|
|
32
|
+
return filesEstimate * AVG_FILE_TOKENS;
|
|
33
|
+
}
|
|
34
|
+
case "kirograph_search": {
|
|
35
|
+
const limit = args?.limit || 10;
|
|
36
|
+
return AVG_GREP_TOKENS + Math.min(limit, 5) * (AVG_FILE_TOKENS / 3);
|
|
37
|
+
}
|
|
38
|
+
case "kirograph_callers": {
|
|
39
|
+
const limit = args?.limit || 20;
|
|
40
|
+
const callersEstimate = Math.min(limit, 10);
|
|
41
|
+
return AVG_GREP_TOKENS + callersEstimate * (AVG_FILE_TOKENS / 2);
|
|
42
|
+
}
|
|
43
|
+
case "kirograph_callees": {
|
|
44
|
+
return AVG_FILE_TOKENS + AVG_GREP_TOKENS * 3;
|
|
45
|
+
}
|
|
46
|
+
case "kirograph_impact": {
|
|
47
|
+
const depth = args?.depth || 2;
|
|
48
|
+
return (AVG_GREP_TOKENS + AVG_FILE_TOKENS * 3) * depth;
|
|
49
|
+
}
|
|
50
|
+
case "kirograph_node": {
|
|
51
|
+
return AVG_FILE_TOKENS;
|
|
52
|
+
}
|
|
53
|
+
case "kirograph_files": {
|
|
54
|
+
return AVG_FIND_TOKENS;
|
|
55
|
+
}
|
|
56
|
+
case "kirograph_status": {
|
|
57
|
+
return 500;
|
|
58
|
+
}
|
|
59
|
+
case "kirograph_path": {
|
|
60
|
+
return AVG_GREP_TOKENS * 4 + AVG_FILE_TOKENS * 3;
|
|
61
|
+
}
|
|
62
|
+
case "kirograph_type_hierarchy": {
|
|
63
|
+
return AVG_GREP_TOKENS * 3 + AVG_FILE_TOKENS * 2;
|
|
64
|
+
}
|
|
65
|
+
case "kirograph_dead_code": {
|
|
66
|
+
return Math.max(outputTokens * 5, AVG_FILE_TOKENS * 10);
|
|
67
|
+
}
|
|
68
|
+
case "kirograph_circular_deps": {
|
|
69
|
+
return Math.max(outputTokens * 5, AVG_FILE_TOKENS * 8);
|
|
70
|
+
}
|
|
71
|
+
case "kirograph_hotspots": {
|
|
72
|
+
return Math.max(outputTokens * 5, AVG_FILE_TOKENS * 10);
|
|
73
|
+
}
|
|
74
|
+
case "kirograph_surprising": {
|
|
75
|
+
return Math.max(outputTokens * 5, AVG_FILE_TOKENS * 10);
|
|
76
|
+
}
|
|
77
|
+
case "kirograph_architecture":
|
|
78
|
+
case "kirograph_coupling":
|
|
79
|
+
case "kirograph_package": {
|
|
80
|
+
return Math.max(outputTokens * 4, AVG_FILE_TOKENS * 5);
|
|
81
|
+
}
|
|
82
|
+
case "kirograph_diff": {
|
|
83
|
+
return Math.max(outputTokens * 3, AVG_FILE_TOKENS * 5);
|
|
84
|
+
}
|
|
85
|
+
// kirograph_exec and kirograph_gain are tracked separately
|
|
86
|
+
default:
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
91
|
+
0 && (module.exports = {
|
|
92
|
+
estimateNaiveCost
|
|
93
|
+
});
|
|
94
|
+
//# sourceMappingURL=naive-cost.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/compression/naive-cost.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Naive cost estimator for KiroGraph MCP tools.\n *\n * Estimates how many tokens the agent would have consumed doing the same\n * work without KiroGraph (reading files, running grep, etc.).\n *\n * These are conservative estimates based on typical agent behavior:\n * - kirograph_context: agent would read 5-10 files fully to orient\n * - kirograph_search: agent would run grep/ripgrep across the project\n * - kirograph_callers/callees: agent would grep for the symbol name + read each file\n * - kirograph_impact: agent would trace callers recursively (multiple grep + read cycles)\n * - kirograph_node: agent would read the full file containing the symbol\n * - kirograph_files: agent would run find/ls -R\n * - kirograph_status: agent would check file counts, run wc, etc.\n * - kirograph_hotspots/surprising/dead_code: not feasible manually (infinite cost \u2192 cap at 5x)\n */\n\nimport { estimateTokens } from './index';\n\n/** Average tokens per file read (medium-sized source file ~200 lines) */\nconst AVG_FILE_TOKENS = 1500;\n\n/** Average tokens for a grep result across a medium project */\nconst AVG_GREP_TOKENS = 800;\n\n/** Average tokens for ls -R or find output on a medium project */\nconst AVG_FIND_TOKENS = 2000;\n\n/**\n * Estimate the naive token cost (what the agent would have spent without KiroGraph).\n *\n * @param toolName - The MCP tool that was called\n * @param outputTokens - Actual tokens in the tool's response\n * @param args - The tool arguments (for context-aware estimation)\n * @returns Estimated naive cost in tokens, or null if not estimable\n */\nexport function estimateNaiveCost(toolName: string, outputTokens: number, args?: Record<string, unknown>): number | null {\n switch (toolName) {\n case 'kirograph_context': {\n // Agent would read ~5-10 files to understand a task area\n const maxNodes = (args?.maxNodes as number) || 20;\n const filesEstimate = Math.min(Math.ceil(maxNodes / 2), 10);\n return filesEstimate * AVG_FILE_TOKENS;\n }\n\n case 'kirograph_search': {\n // Agent would run grep/ripgrep and read through results\n const limit = (args?.limit as number) || 10;\n // grep output + reading top matches\n return AVG_GREP_TOKENS + Math.min(limit, 5) * (AVG_FILE_TOKENS / 3);\n }\n\n case 'kirograph_callers': {\n // Agent would grep for the symbol, then read each calling file\n const limit = (args?.limit as number) || 20;\n const callersEstimate = Math.min(limit, 10);\n return AVG_GREP_TOKENS + callersEstimate * (AVG_FILE_TOKENS / 2);\n }\n\n case 'kirograph_callees': {\n // Agent would read the function body + grep for each called symbol\n return AVG_FILE_TOKENS + AVG_GREP_TOKENS * 3;\n }\n\n case 'kirograph_impact': {\n // Agent would need multiple rounds of grep + read (recursive)\n const depth = (args?.depth as number) || 2;\n return (AVG_GREP_TOKENS + AVG_FILE_TOKENS * 3) * depth;\n }\n\n case 'kirograph_node': {\n // Agent would read the full file to find the symbol\n return AVG_FILE_TOKENS;\n }\n\n case 'kirograph_files': {\n // Agent would run find or ls -R\n return AVG_FIND_TOKENS;\n }\n\n case 'kirograph_status': {\n // Agent would run multiple commands (wc -l, find, du, etc.)\n return 500;\n }\n\n case 'kirograph_path': {\n // Agent would need to manually trace connections \u2014 multiple grep + read cycles\n return AVG_GREP_TOKENS * 4 + AVG_FILE_TOKENS * 3;\n }\n\n case 'kirograph_type_hierarchy': {\n // Agent would grep for extends/implements, read each file\n return AVG_GREP_TOKENS * 3 + AVG_FILE_TOKENS * 2;\n }\n\n case 'kirograph_dead_code': {\n // Not feasible manually \u2014 would require reading every file and cross-referencing\n // Cap at 5x the output (conservative)\n return Math.max(outputTokens * 5, AVG_FILE_TOKENS * 10);\n }\n\n case 'kirograph_circular_deps': {\n // Not feasible manually \u2014 would require building a full import graph\n return Math.max(outputTokens * 5, AVG_FILE_TOKENS * 8);\n }\n\n case 'kirograph_hotspots': {\n // Not feasible manually \u2014 would require counting edges for every symbol\n return Math.max(outputTokens * 5, AVG_FILE_TOKENS * 10);\n }\n\n case 'kirograph_surprising': {\n // Not feasible manually\n return Math.max(outputTokens * 5, AVG_FILE_TOKENS * 10);\n }\n\n case 'kirograph_architecture':\n case 'kirograph_coupling':\n case 'kirograph_package': {\n // Architecture analysis is not feasible manually\n return Math.max(outputTokens * 4, AVG_FILE_TOKENS * 5);\n }\n\n case 'kirograph_diff': {\n // Agent would need to compare file lists and grep for symbols\n return Math.max(outputTokens * 3, AVG_FILE_TOKENS * 5);\n }\n\n // kirograph_exec and kirograph_gain are tracked separately\n default:\n return null;\n }\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAoBA,MAAM,kBAAkB;AAGxB,MAAM,kBAAkB;AAGxB,MAAM,kBAAkB;AAUjB,SAAS,kBAAkB,UAAkB,cAAsB,MAA+C;AACvH,UAAQ,UAAU;AAAA,IAChB,KAAK,qBAAqB;AAExB,YAAM,WAAY,MAAM,YAAuB;AAC/C,YAAM,gBAAgB,KAAK,IAAI,KAAK,KAAK,WAAW,CAAC,GAAG,EAAE;AAC1D,aAAO,gBAAgB;AAAA,IACzB;AAAA,IAEA,KAAK,oBAAoB;AAEvB,YAAM,QAAS,MAAM,SAAoB;AAEzC,aAAO,kBAAkB,KAAK,IAAI,OAAO,CAAC,KAAK,kBAAkB;AAAA,IACnE;AAAA,IAEA,KAAK,qBAAqB;AAExB,YAAM,QAAS,MAAM,SAAoB;AACzC,YAAM,kBAAkB,KAAK,IAAI,OAAO,EAAE;AAC1C,aAAO,kBAAkB,mBAAmB,kBAAkB;AAAA,IAChE;AAAA,IAEA,KAAK,qBAAqB;AAExB,aAAO,kBAAkB,kBAAkB;AAAA,IAC7C;AAAA,IAEA,KAAK,oBAAoB;AAEvB,YAAM,QAAS,MAAM,SAAoB;AACzC,cAAQ,kBAAkB,kBAAkB,KAAK;AAAA,IACnD;AAAA,IAEA,KAAK,kBAAkB;AAErB,aAAO;AAAA,IACT;AAAA,IAEA,KAAK,mBAAmB;AAEtB,aAAO;AAAA,IACT;AAAA,IAEA,KAAK,oBAAoB;AAEvB,aAAO;AAAA,IACT;AAAA,IAEA,KAAK,kBAAkB;AAErB,aAAO,kBAAkB,IAAI,kBAAkB;AAAA,IACjD;AAAA,IAEA,KAAK,4BAA4B;AAE/B,aAAO,kBAAkB,IAAI,kBAAkB;AAAA,IACjD;AAAA,IAEA,KAAK,uBAAuB;AAG1B,aAAO,KAAK,IAAI,eAAe,GAAG,kBAAkB,EAAE;AAAA,IACxD;AAAA,IAEA,KAAK,2BAA2B;AAE9B,aAAO,KAAK,IAAI,eAAe,GAAG,kBAAkB,CAAC;AAAA,IACvD;AAAA,IAEA,KAAK,sBAAsB;AAEzB,aAAO,KAAK,IAAI,eAAe,GAAG,kBAAkB,EAAE;AAAA,IACxD;AAAA,IAEA,KAAK,wBAAwB;AAE3B,aAAO,KAAK,IAAI,eAAe,GAAG,kBAAkB,EAAE;AAAA,IACxD;AAAA,IAEA,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK,qBAAqB;AAExB,aAAO,KAAK,IAAI,eAAe,GAAG,kBAAkB,CAAC;AAAA,IACvD;AAAA,IAEA,KAAK,kBAAkB;AAErB,aAAO,KAAK,IAAI,eAAe,GAAG,kBAAkB,CAAC;AAAA,IACvD;AAAA;AAAA,IAGA;AACE,aAAO;AAAA,EACX;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|