pi-rtk-optimizer 0.3.3 → 0.4.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/CHANGELOG.md +83 -67
- package/README.md +292 -290
- package/config/config.example.json +36 -35
- package/package.json +60 -60
- package/src/additional-coverage-test.ts +197 -0
- package/src/boolean-format.ts +3 -0
- package/src/command-rewriter-test.ts +160 -120
- package/src/command-rewriter.ts +594 -585
- package/src/config-modal-test.ts +168 -0
- package/src/config-modal.ts +613 -600
- package/src/config-store.ts +224 -217
- package/src/index-test.ts +54 -0
- package/src/index.ts +320 -289
- package/src/output-compactor-test.ts +334 -158
- package/src/output-compactor.ts +418 -349
- package/src/record-utils.ts +6 -0
- package/src/rewrite-bypass.ts +332 -173
- package/src/rewrite-pipeline-safety.ts +154 -0
- package/src/rewrite-rules.ts +255 -255
- package/src/runtime-guard-test.ts +42 -50
- package/src/runtime-guard.ts +14 -14
- package/src/techniques/build.ts +155 -155
- package/src/techniques/git.ts +229 -229
- package/src/techniques/index.ts +8 -16
- package/src/techniques/linter.ts +151 -161
- package/src/techniques/path-utils.ts +67 -0
- package/src/techniques/search.ts +67 -76
- package/src/techniques/source.ts +253 -253
- package/src/techniques/test-output.ts +172 -172
- package/src/test-helpers.ts +10 -0
- package/src/types-shims.d.ts +189 -183
- package/src/types.ts +103 -114
- package/src/zellij-modal.ts +1001 -1001
- package/src/compat-commands.ts +0 -207
|
@@ -1,158 +1,334 @@
|
|
|
1
|
-
import assert from "node:assert/strict";
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
);
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
);
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
);
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
|
|
5
|
+
import { compactToolResult } from "./output-compactor.ts";
|
|
6
|
+
import { cloneDefaultConfig, runTest } from "./test-helpers.ts";
|
|
7
|
+
|
|
8
|
+
function buildReadContent(lineCount: number): string {
|
|
9
|
+
const lines: string[] = [];
|
|
10
|
+
for (let index = 0; index < lineCount; index += 1) {
|
|
11
|
+
if (index % 2 === 0) {
|
|
12
|
+
lines.push(`// comment ${index}`);
|
|
13
|
+
} else {
|
|
14
|
+
lines.push(`const value${index} = ${index};`);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return `${lines.join("\n")}\n`;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function firstTextBlock(content: unknown[] | undefined): string {
|
|
21
|
+
if (!Array.isArray(content) || content.length === 0) {
|
|
22
|
+
return "";
|
|
23
|
+
}
|
|
24
|
+
const first = content[0] as { type?: string; text?: string };
|
|
25
|
+
if (first?.type !== "text" || typeof first.text !== "string") {
|
|
26
|
+
return "";
|
|
27
|
+
}
|
|
28
|
+
return first.text;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const OUTPUT_EMOJI_MARKERS = ["✓", "✔", "❌", "⚠️", "⚠", "📋", "📄", "🔍", "✅", "⏭️", "📌", "📝", "❓", "•"];
|
|
32
|
+
|
|
33
|
+
function compactBashOutput(command: string, text: string): string {
|
|
34
|
+
const result = compactToolResult(
|
|
35
|
+
{
|
|
36
|
+
toolName: "bash",
|
|
37
|
+
input: { command },
|
|
38
|
+
content: [{ type: "text", text }],
|
|
39
|
+
},
|
|
40
|
+
cloneDefaultConfig(),
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
assert.equal(result.changed, true);
|
|
44
|
+
return firstTextBlock(result.content);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function compactGrepOutput(text: string): string {
|
|
48
|
+
const result = compactToolResult(
|
|
49
|
+
{
|
|
50
|
+
toolName: "grep",
|
|
51
|
+
input: { pattern: "match" },
|
|
52
|
+
content: [{ type: "text", text }],
|
|
53
|
+
},
|
|
54
|
+
cloneDefaultConfig(),
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
assert.equal(result.changed, true);
|
|
58
|
+
return firstTextBlock(result.content);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function assertNoOutputEmoji(text: string): void {
|
|
62
|
+
for (const marker of OUTPUT_EMOJI_MARKERS) {
|
|
63
|
+
assert.equal(text.includes(marker), false, `Unexpected output emoji marker: ${marker}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
runTest("precision read with offset keeps exact output (no source/smart/hard truncation)", () => {
|
|
68
|
+
const config = cloneDefaultConfig();
|
|
69
|
+
config.outputCompaction.truncate.enabled = true;
|
|
70
|
+
config.outputCompaction.truncate.maxChars = 500;
|
|
71
|
+
config.outputCompaction.smartTruncate.enabled = true;
|
|
72
|
+
config.outputCompaction.smartTruncate.maxLines = 40;
|
|
73
|
+
|
|
74
|
+
const content = buildReadContent(220);
|
|
75
|
+
const result = compactToolResult(
|
|
76
|
+
{
|
|
77
|
+
toolName: "read",
|
|
78
|
+
input: { path: "sample.ts", offset: 1 },
|
|
79
|
+
content: [{ type: "text", text: content }],
|
|
80
|
+
},
|
|
81
|
+
config,
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
assert.equal(result.changed, false);
|
|
85
|
+
assert.deepEqual(result.techniques, []);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
runTest("precision read with limit keeps exact output", () => {
|
|
89
|
+
const config = cloneDefaultConfig();
|
|
90
|
+
config.outputCompaction.truncate.enabled = true;
|
|
91
|
+
config.outputCompaction.truncate.maxChars = 500;
|
|
92
|
+
config.outputCompaction.smartTruncate.enabled = true;
|
|
93
|
+
config.outputCompaction.smartTruncate.maxLines = 40;
|
|
94
|
+
|
|
95
|
+
const content = buildReadContent(220);
|
|
96
|
+
const result = compactToolResult(
|
|
97
|
+
{
|
|
98
|
+
toolName: "read",
|
|
99
|
+
input: { path: "sample.ts", limit: 200 },
|
|
100
|
+
content: [{ type: "text", text: content }],
|
|
101
|
+
},
|
|
102
|
+
config,
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
assert.equal(result.changed, false);
|
|
106
|
+
assert.deepEqual(result.techniques, []);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
runTest("normal read compacts and adds banner", () => {
|
|
110
|
+
const config = cloneDefaultConfig();
|
|
111
|
+
config.outputCompaction.smartTruncate.enabled = true;
|
|
112
|
+
config.outputCompaction.smartTruncate.maxLines = 40;
|
|
113
|
+
|
|
114
|
+
const content = buildReadContent(220);
|
|
115
|
+
const result = compactToolResult(
|
|
116
|
+
{
|
|
117
|
+
toolName: "read",
|
|
118
|
+
input: { path: "sample.ts" },
|
|
119
|
+
content: [{ type: "text", text: content }],
|
|
120
|
+
},
|
|
121
|
+
config,
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
assert.equal(result.changed, true);
|
|
125
|
+
assert.ok(result.techniques.includes("source:minimal"));
|
|
126
|
+
|
|
127
|
+
const compacted = firstTextBlock(result.content);
|
|
128
|
+
assert.ok(compacted.startsWith("[RTK compacted output:"));
|
|
129
|
+
assert.ok(compacted.includes("source:minimal"));
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
runTest("short read output stays exact below threshold", () => {
|
|
133
|
+
const config = cloneDefaultConfig();
|
|
134
|
+
const content = buildReadContent(40);
|
|
135
|
+
|
|
136
|
+
const result = compactToolResult(
|
|
137
|
+
{
|
|
138
|
+
toolName: "read",
|
|
139
|
+
input: { path: "sample.ts" },
|
|
140
|
+
content: [{ type: "text", text: content }],
|
|
141
|
+
},
|
|
142
|
+
config,
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
assert.equal(result.changed, false);
|
|
146
|
+
assert.deepEqual(result.techniques, []);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
runTest("read output stays exact at the 80-line boundary with trailing newline", () => {
|
|
150
|
+
const config = cloneDefaultConfig();
|
|
151
|
+
config.outputCompaction.smartTruncate.enabled = true;
|
|
152
|
+
config.outputCompaction.smartTruncate.maxLines = 40;
|
|
153
|
+
|
|
154
|
+
const content = buildReadContent(80);
|
|
155
|
+
const result = compactToolResult(
|
|
156
|
+
{
|
|
157
|
+
toolName: "read",
|
|
158
|
+
input: { path: "sample.ts" },
|
|
159
|
+
content: [{ type: "text", text: content }],
|
|
160
|
+
},
|
|
161
|
+
config,
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
assert.equal(result.changed, false);
|
|
165
|
+
assert.deepEqual(result.techniques, []);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
runTest("read output compacts once the content exceeds the 80-line exactness threshold", () => {
|
|
169
|
+
const config = cloneDefaultConfig();
|
|
170
|
+
config.outputCompaction.smartTruncate.enabled = true;
|
|
171
|
+
config.outputCompaction.smartTruncate.maxLines = 40;
|
|
172
|
+
|
|
173
|
+
const content = buildReadContent(81);
|
|
174
|
+
const result = compactToolResult(
|
|
175
|
+
{
|
|
176
|
+
toolName: "read",
|
|
177
|
+
input: { path: "sample.ts" },
|
|
178
|
+
content: [{ type: "text", text: content }],
|
|
179
|
+
},
|
|
180
|
+
config,
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
assert.equal(result.changed, true);
|
|
184
|
+
assert.ok(result.techniques.includes("source:minimal") || result.techniques.includes("smart-truncate"));
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
runTest("source file reads skip lossy source filtering when truncation safeguards are not needed", () => {
|
|
188
|
+
const config = cloneDefaultConfig();
|
|
189
|
+
config.outputCompaction.smartTruncate.enabled = false;
|
|
190
|
+
config.outputCompaction.truncate.enabled = false;
|
|
191
|
+
|
|
192
|
+
const content = buildReadContent(120);
|
|
193
|
+
const result = compactToolResult(
|
|
194
|
+
{
|
|
195
|
+
toolName: "read",
|
|
196
|
+
input: { path: "sample.ts" },
|
|
197
|
+
content: [{ type: "text", text: content }],
|
|
198
|
+
},
|
|
199
|
+
config,
|
|
200
|
+
);
|
|
201
|
+
|
|
202
|
+
assert.equal(result.changed, false);
|
|
203
|
+
assert.deepEqual(result.techniques, []);
|
|
204
|
+
assert.equal(firstTextBlock(result.content), "");
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
runTest("skill reads stay exact when preserveExactSkillReads is enabled for user skills", () => {
|
|
208
|
+
const config = cloneDefaultConfig();
|
|
209
|
+
config.outputCompaction.preserveExactSkillReads = true;
|
|
210
|
+
config.outputCompaction.truncate.enabled = true;
|
|
211
|
+
config.outputCompaction.truncate.maxChars = 500;
|
|
212
|
+
config.outputCompaction.smartTruncate.enabled = true;
|
|
213
|
+
config.outputCompaction.smartTruncate.maxLines = 40;
|
|
214
|
+
|
|
215
|
+
const content = buildReadContent(220);
|
|
216
|
+
const result = compactToolResult(
|
|
217
|
+
{
|
|
218
|
+
toolName: "read",
|
|
219
|
+
input: { path: join(homedir(), ".pi", "agent", "skills", "example", "SKILL.md") },
|
|
220
|
+
content: [{ type: "text", text: content }],
|
|
221
|
+
},
|
|
222
|
+
config,
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
assert.equal(result.changed, false);
|
|
226
|
+
assert.deepEqual(result.techniques, []);
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
runTest("project .pi skill reads stay exact when preserveExactSkillReads is enabled", () => {
|
|
230
|
+
const config = cloneDefaultConfig();
|
|
231
|
+
config.outputCompaction.preserveExactSkillReads = true;
|
|
232
|
+
config.outputCompaction.truncate.enabled = true;
|
|
233
|
+
config.outputCompaction.truncate.maxChars = 500;
|
|
234
|
+
config.outputCompaction.smartTruncate.enabled = true;
|
|
235
|
+
config.outputCompaction.smartTruncate.maxLines = 40;
|
|
236
|
+
|
|
237
|
+
const content = buildReadContent(220);
|
|
238
|
+
const result = compactToolResult(
|
|
239
|
+
{
|
|
240
|
+
toolName: "read",
|
|
241
|
+
input: { path: ".pi/skills/example/SKILL.md" },
|
|
242
|
+
content: [{ type: "text", text: content }],
|
|
243
|
+
},
|
|
244
|
+
config,
|
|
245
|
+
);
|
|
246
|
+
|
|
247
|
+
assert.equal(result.changed, false);
|
|
248
|
+
assert.deepEqual(result.techniques, []);
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
runTest("ancestor .agents skill reads stay exact when preserveExactSkillReads is enabled", () => {
|
|
252
|
+
const config = cloneDefaultConfig();
|
|
253
|
+
config.outputCompaction.preserveExactSkillReads = true;
|
|
254
|
+
config.outputCompaction.truncate.enabled = true;
|
|
255
|
+
config.outputCompaction.truncate.maxChars = 500;
|
|
256
|
+
config.outputCompaction.smartTruncate.enabled = true;
|
|
257
|
+
config.outputCompaction.smartTruncate.maxLines = 40;
|
|
258
|
+
|
|
259
|
+
const content = buildReadContent(220);
|
|
260
|
+
const result = compactToolResult(
|
|
261
|
+
{
|
|
262
|
+
toolName: "read",
|
|
263
|
+
input: { path: "../.agents/skills/example/SKILL.md" },
|
|
264
|
+
content: [{ type: "text", text: content }],
|
|
265
|
+
},
|
|
266
|
+
config,
|
|
267
|
+
);
|
|
268
|
+
|
|
269
|
+
assert.equal(result.changed, false);
|
|
270
|
+
assert.deepEqual(result.techniques, []);
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
runTest("build output uses plain-text status markers", () => {
|
|
274
|
+
const compacted = compactBashOutput("npm run build", "Compiling app v0.1.0\n");
|
|
275
|
+
|
|
276
|
+
assert.equal(compacted, "[OK] Build successful (1 units compiled)");
|
|
277
|
+
assertNoOutputEmoji(compacted);
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
runTest("git status output uses plain-text labels", () => {
|
|
281
|
+
const compacted = compactBashOutput(
|
|
282
|
+
"git status --short --branch",
|
|
283
|
+
"## main...origin/main\nM staged.ts\n M modified.ts\n?? new.ts\nUU conflict.ts\n",
|
|
284
|
+
);
|
|
285
|
+
|
|
286
|
+
assert.ok(compacted.startsWith("Branch: main\n"));
|
|
287
|
+
assert.ok(compacted.includes("Staged: 1 files\n staged.ts\n"));
|
|
288
|
+
assert.ok(compacted.includes("Modified: 1 files\n modified.ts\n"));
|
|
289
|
+
assert.ok(compacted.includes("Untracked: 1 files\n new.ts\n"));
|
|
290
|
+
assert.ok(compacted.includes("Conflicts: 1 files"));
|
|
291
|
+
assertNoOutputEmoji(compacted);
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
runTest("git diff output uses plain-text file markers", () => {
|
|
295
|
+
const compacted = compactBashOutput(
|
|
296
|
+
"git diff",
|
|
297
|
+
"diff --git a/src/example.ts b/src/example.ts\n@@ -1 +1 @@\n-oldValue\n+newValue\n",
|
|
298
|
+
);
|
|
299
|
+
|
|
300
|
+
assert.ok(compacted.includes("\n> src/example.ts\n"));
|
|
301
|
+
assertNoOutputEmoji(compacted);
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
runTest("linter success output uses plain-text status markers", () => {
|
|
305
|
+
const compacted = compactBashOutput("npx eslint .", "");
|
|
306
|
+
|
|
307
|
+
assert.equal(compacted, "[OK] ESLint: No issues found");
|
|
308
|
+
assertNoOutputEmoji(compacted);
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
runTest("test output uses plain-text labels and bullets", () => {
|
|
312
|
+
const compacted = compactBashOutput(
|
|
313
|
+
"bun test",
|
|
314
|
+
"3 passed, 1 failed, 2 skipped\nFAIL src/example.test.ts\n Expected: true\n Received: false\n\n\n",
|
|
315
|
+
);
|
|
316
|
+
|
|
317
|
+
assert.ok(compacted.includes("Test Results:"));
|
|
318
|
+
assert.ok(compacted.includes("PASS: 3 passed"));
|
|
319
|
+
assert.ok(compacted.includes("FAIL: 1 failed"));
|
|
320
|
+
assert.ok(compacted.includes("SKIP: 2 skipped"));
|
|
321
|
+
assert.ok(compacted.includes(" - FAIL src/example.test.ts"));
|
|
322
|
+
assertNoOutputEmoji(compacted);
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
runTest("search output uses plain-text summary and file markers", () => {
|
|
326
|
+
const compacted = compactGrepOutput("src/a.ts:1:const match = true;\nsrc/b.ts:2:return match;\n");
|
|
327
|
+
|
|
328
|
+
assert.ok(compacted.startsWith("2 matches in 2 files:\n\n"));
|
|
329
|
+
assert.ok(compacted.includes("> src/a.ts (1 matches):\n"));
|
|
330
|
+
assert.ok(compacted.includes("> src/b.ts (1 matches):\n"));
|
|
331
|
+
assertNoOutputEmoji(compacted);
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
console.log("All output-compactor tests passed.");
|