pi-rtk-optimizer 0.3.3 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/CHANGELOG.md +102 -67
  2. package/README.md +292 -290
  3. package/config/config.example.json +36 -35
  4. package/package.json +4 -4
  5. package/src/additional-coverage-test.ts +278 -0
  6. package/src/boolean-format.ts +3 -0
  7. package/src/command-rewriter-test.ts +160 -120
  8. package/src/command-rewriter.ts +594 -585
  9. package/src/config-modal-test.ts +168 -0
  10. package/src/config-modal.ts +613 -600
  11. package/src/config-store.ts +224 -217
  12. package/src/index-test.ts +54 -0
  13. package/src/index.ts +410 -289
  14. package/src/output-compactor-test.ts +500 -158
  15. package/src/output-compactor.ts +432 -349
  16. package/src/record-utils.ts +6 -0
  17. package/src/rewrite-bypass.ts +332 -173
  18. package/src/rewrite-pipeline-safety.ts +154 -0
  19. package/src/rewrite-rules.ts +255 -255
  20. package/src/rtk-command-environment.ts +64 -0
  21. package/src/runtime-guard-test.ts +42 -50
  22. package/src/runtime-guard.ts +14 -14
  23. package/src/techniques/build.ts +155 -155
  24. package/src/techniques/emoji.ts +91 -0
  25. package/src/techniques/git.ts +231 -229
  26. package/src/techniques/index.ts +10 -16
  27. package/src/techniques/linter.ts +151 -161
  28. package/src/techniques/path-utils.ts +67 -0
  29. package/src/techniques/rtk.ts +136 -0
  30. package/src/techniques/search.ts +67 -76
  31. package/src/techniques/source.ts +253 -253
  32. package/src/techniques/test-output.ts +172 -172
  33. package/src/test-helpers.ts +10 -0
  34. package/src/tool-execution-sanitizer.ts +69 -0
  35. package/src/types-shims.d.ts +192 -183
  36. package/src/types.ts +103 -114
  37. package/src/zellij-modal.ts +1001 -1001
  38. package/src/compat-commands.ts +0 -207
@@ -1,229 +1,231 @@
1
- import { matchesCommandPatterns, normalizeCommandForDetection } from "./command-detection.js";
2
-
3
- const GIT_COMMAND_PATTERNS = [/^git\s+(diff|status|log|show|stash)\b/] as const;
4
-
5
- export function isGitCommand(command: string | undefined | null): boolean {
6
- return matchesCommandPatterns(command, GIT_COMMAND_PATTERNS);
7
- }
8
-
9
- export function compactDiff(output: string, maxLines = 50): string {
10
- const lines = output.split("\n");
11
- const result: string[] = [];
12
- let currentFile = "";
13
- let added = 0;
14
- let removed = 0;
15
- let inHunk = false;
16
- let hunkLines = 0;
17
- const maxHunkLines = 10;
18
-
19
- for (const line of lines) {
20
- if (result.length >= maxLines) {
21
- result.push("\n... (more changes truncated)");
22
- break;
23
- }
24
-
25
- if (line.startsWith("diff --git")) {
26
- if (currentFile && (added > 0 || removed > 0)) {
27
- result.push(` +${added} -${removed}`);
28
- }
29
-
30
- const match = line.match(/diff --git a\/(.+) b\/(.+)/);
31
- currentFile = match?.[2] ?? "unknown";
32
- result.push(`\nšŸ“„ ${currentFile}`);
33
- added = 0;
34
- removed = 0;
35
- inHunk = false;
36
- continue;
37
- }
38
-
39
- if (line.startsWith("@@")) {
40
- inHunk = true;
41
- hunkLines = 0;
42
- const hunkInfo = line.match(/@@ .+ @@/)?.[0] ?? "@@";
43
- result.push(` ${hunkInfo}`);
44
- continue;
45
- }
46
-
47
- if (!inHunk) {
48
- continue;
49
- }
50
-
51
- if (line.startsWith("+") && !line.startsWith("+++")) {
52
- added++;
53
- if (hunkLines < maxHunkLines) {
54
- result.push(` ${line}`);
55
- hunkLines++;
56
- }
57
- } else if (line.startsWith("-") && !line.startsWith("---")) {
58
- removed++;
59
- if (hunkLines < maxHunkLines) {
60
- result.push(` ${line}`);
61
- hunkLines++;
62
- }
63
- } else if (hunkLines < maxHunkLines && !line.startsWith("\\")) {
64
- if (hunkLines > 0) {
65
- result.push(` ${line}`);
66
- hunkLines++;
67
- }
68
- }
69
-
70
- if (hunkLines === maxHunkLines) {
71
- result.push(" ... (truncated)");
72
- hunkLines++;
73
- }
74
- }
75
-
76
- if (currentFile && (added > 0 || removed > 0)) {
77
- result.push(` +${added} -${removed}`);
78
- }
79
-
80
- return result.join("\n");
81
- }
82
-
83
- interface StatusStats {
84
- staged: number;
85
- modified: number;
86
- untracked: number;
87
- conflicts: number;
88
- stagedFiles: string[];
89
- modifiedFiles: string[];
90
- untrackedFiles: string[];
91
- }
92
-
93
- export function compactStatus(output: string): string {
94
- const lines = output.split("\n");
95
-
96
- if (lines.length === 0 || (lines.length === 1 && lines[0]?.trim() === "")) {
97
- return "Clean working tree";
98
- }
99
-
100
- const stats: StatusStats = {
101
- staged: 0,
102
- modified: 0,
103
- untracked: 0,
104
- conflicts: 0,
105
- stagedFiles: [],
106
- modifiedFiles: [],
107
- untrackedFiles: [],
108
- };
109
-
110
- let branchName = "";
111
-
112
- for (const line of lines) {
113
- if (line.startsWith("##")) {
114
- const match = line.match(/## (.+)/);
115
- if (match?.[1]) {
116
- branchName = match[1].split("...")[0] ?? match[1];
117
- }
118
- continue;
119
- }
120
-
121
- if (line.length < 3) {
122
- continue;
123
- }
124
-
125
- const status = line.slice(0, 2);
126
- const filename = line.slice(3);
127
- const indexStatus = status[0];
128
- const worktreeStatus = status[1];
129
-
130
- if (["M", "A", "D", "R", "C"].includes(indexStatus)) {
131
- stats.staged++;
132
- stats.stagedFiles.push(filename);
133
- }
134
-
135
- if (indexStatus === "U") {
136
- stats.conflicts++;
137
- }
138
-
139
- if (["M", "D"].includes(worktreeStatus)) {
140
- stats.modified++;
141
- stats.modifiedFiles.push(filename);
142
- }
143
-
144
- if (status === "??") {
145
- stats.untracked++;
146
- stats.untrackedFiles.push(filename);
147
- }
148
- }
149
-
150
- let result = `šŸ“Œ ${branchName}\n`;
151
-
152
- if (stats.staged > 0) {
153
- result += `āœ… Staged: ${stats.staged} files\n`;
154
- for (const file of stats.stagedFiles.slice(0, 5)) {
155
- result += ` ${file}\n`;
156
- }
157
- if (stats.staged > 5) {
158
- result += ` ... +${stats.staged - 5} more\n`;
159
- }
160
- }
161
-
162
- if (stats.modified > 0) {
163
- result += `šŸ“ Modified: ${stats.modified} files\n`;
164
- for (const file of stats.modifiedFiles.slice(0, 5)) {
165
- result += ` ${file}\n`;
166
- }
167
- if (stats.modified > 5) {
168
- result += ` ... +${stats.modified - 5} more\n`;
169
- }
170
- }
171
-
172
- if (stats.untracked > 0) {
173
- result += `ā“ Untracked: ${stats.untracked} files\n`;
174
- for (const file of stats.untrackedFiles.slice(0, 3)) {
175
- result += ` ${file}\n`;
176
- }
177
- if (stats.untracked > 3) {
178
- result += ` ... +${stats.untracked - 3} more\n`;
179
- }
180
- }
181
-
182
- if (stats.conflicts > 0) {
183
- result += `āš ļø Conflicts: ${stats.conflicts} files\n`;
184
- }
185
-
186
- return result.trim();
187
- }
188
-
189
- export function compactLog(output: string, limit = 20): string {
190
- const lines = output.split("\n");
191
- const result: string[] = [];
192
-
193
- for (const line of lines.slice(0, limit)) {
194
- if (line.length > 80) {
195
- result.push(`${line.slice(0, 77)}...`);
196
- } else {
197
- result.push(line);
198
- }
199
- }
200
-
201
- if (lines.length > limit) {
202
- result.push(`... and ${lines.length - limit} more commits`);
203
- }
204
-
205
- return result.join("\n");
206
- }
207
-
208
- export function compactGitOutput(output: string, command: string | undefined | null): string | null {
209
- if (!isGitCommand(command)) {
210
- return null;
211
- }
212
-
213
- const normalized = normalizeCommandForDetection(command);
214
- if (!normalized) {
215
- return null;
216
- }
217
-
218
- if (normalized.startsWith("git diff")) {
219
- return compactDiff(output);
220
- }
221
- if (normalized.startsWith("git status")) {
222
- return compactStatus(output);
223
- }
224
- if (normalized.startsWith("git log")) {
225
- return compactLog(output);
226
- }
227
-
228
- return null;
229
- }
1
+ import { matchesCommandPatterns, normalizeCommandForDetection } from "./command-detection.js";
2
+
3
+ const GIT_COMMAND_PATTERNS = [/^git\s+(diff|status|log|show|stash)\b/] as const;
4
+ const RAW_GIT_DIFF_PATTERN = /^diff --git /m;
5
+ const RAW_GIT_STATUS_PATTERN = /^(?:## |(?:M|A|D|R|C|U|\?| )\S)/m;
6
+
7
+ export function isGitCommand(command: string | undefined | null): boolean {
8
+ return matchesCommandPatterns(command, GIT_COMMAND_PATTERNS);
9
+ }
10
+
11
+ export function compactDiff(output: string, maxLines = 50): string {
12
+ const lines = output.split("\n");
13
+ const result: string[] = [];
14
+ let currentFile = "";
15
+ let added = 0;
16
+ let removed = 0;
17
+ let inHunk = false;
18
+ let hunkLines = 0;
19
+ const maxHunkLines = 10;
20
+
21
+ for (const line of lines) {
22
+ if (result.length >= maxLines) {
23
+ result.push("\n... (more changes truncated)");
24
+ break;
25
+ }
26
+
27
+ if (line.startsWith("diff --git")) {
28
+ if (currentFile && (added > 0 || removed > 0)) {
29
+ result.push(` +${added} -${removed}`);
30
+ }
31
+
32
+ const match = line.match(/diff --git a\/(.+) b\/(.+)/);
33
+ currentFile = match?.[2] ?? "unknown";
34
+ result.push(`\n> ${currentFile}`);
35
+ added = 0;
36
+ removed = 0;
37
+ inHunk = false;
38
+ continue;
39
+ }
40
+
41
+ if (line.startsWith("@@")) {
42
+ inHunk = true;
43
+ hunkLines = 0;
44
+ const hunkInfo = line.match(/@@ .+ @@/)?.[0] ?? "@@";
45
+ result.push(` ${hunkInfo}`);
46
+ continue;
47
+ }
48
+
49
+ if (!inHunk) {
50
+ continue;
51
+ }
52
+
53
+ if (line.startsWith("+") && !line.startsWith("+++")) {
54
+ added++;
55
+ if (hunkLines < maxHunkLines) {
56
+ result.push(` ${line}`);
57
+ hunkLines++;
58
+ }
59
+ } else if (line.startsWith("-") && !line.startsWith("---")) {
60
+ removed++;
61
+ if (hunkLines < maxHunkLines) {
62
+ result.push(` ${line}`);
63
+ hunkLines++;
64
+ }
65
+ } else if (hunkLines < maxHunkLines && !line.startsWith("\\")) {
66
+ if (hunkLines > 0) {
67
+ result.push(` ${line}`);
68
+ hunkLines++;
69
+ }
70
+ }
71
+
72
+ if (hunkLines === maxHunkLines) {
73
+ result.push(" ... (truncated)");
74
+ hunkLines++;
75
+ }
76
+ }
77
+
78
+ if (currentFile && (added > 0 || removed > 0)) {
79
+ result.push(` +${added} -${removed}`);
80
+ }
81
+
82
+ return result.join("\n");
83
+ }
84
+
85
+ interface StatusStats {
86
+ staged: number;
87
+ modified: number;
88
+ untracked: number;
89
+ conflicts: number;
90
+ stagedFiles: string[];
91
+ modifiedFiles: string[];
92
+ untrackedFiles: string[];
93
+ }
94
+
95
+ export function compactStatus(output: string): string {
96
+ const lines = output.split("\n");
97
+
98
+ if (lines.length === 0 || (lines.length === 1 && lines[0]?.trim() === "")) {
99
+ return "Clean working tree";
100
+ }
101
+
102
+ const stats: StatusStats = {
103
+ staged: 0,
104
+ modified: 0,
105
+ untracked: 0,
106
+ conflicts: 0,
107
+ stagedFiles: [],
108
+ modifiedFiles: [],
109
+ untrackedFiles: [],
110
+ };
111
+
112
+ let branchName = "";
113
+
114
+ for (const line of lines) {
115
+ if (line.startsWith("##")) {
116
+ const match = line.match(/## (.+)/);
117
+ if (match?.[1]) {
118
+ branchName = match[1].split("...")[0] ?? match[1];
119
+ }
120
+ continue;
121
+ }
122
+
123
+ if (line.length < 3) {
124
+ continue;
125
+ }
126
+
127
+ const status = line.slice(0, 2);
128
+ const filename = line.slice(3);
129
+ const indexStatus = status[0];
130
+ const worktreeStatus = status[1];
131
+
132
+ if (["M", "A", "D", "R", "C"].includes(indexStatus)) {
133
+ stats.staged++;
134
+ stats.stagedFiles.push(filename);
135
+ }
136
+
137
+ if (indexStatus === "U") {
138
+ stats.conflicts++;
139
+ }
140
+
141
+ if (["M", "D"].includes(worktreeStatus)) {
142
+ stats.modified++;
143
+ stats.modifiedFiles.push(filename);
144
+ }
145
+
146
+ if (status === "??") {
147
+ stats.untracked++;
148
+ stats.untrackedFiles.push(filename);
149
+ }
150
+ }
151
+
152
+ let result = `Branch: ${branchName}\n`;
153
+
154
+ if (stats.staged > 0) {
155
+ result += `Staged: ${stats.staged} files\n`;
156
+ for (const file of stats.stagedFiles.slice(0, 5)) {
157
+ result += ` ${file}\n`;
158
+ }
159
+ if (stats.staged > 5) {
160
+ result += ` ... +${stats.staged - 5} more\n`;
161
+ }
162
+ }
163
+
164
+ if (stats.modified > 0) {
165
+ result += `Modified: ${stats.modified} files\n`;
166
+ for (const file of stats.modifiedFiles.slice(0, 5)) {
167
+ result += ` ${file}\n`;
168
+ }
169
+ if (stats.modified > 5) {
170
+ result += ` ... +${stats.modified - 5} more\n`;
171
+ }
172
+ }
173
+
174
+ if (stats.untracked > 0) {
175
+ result += `Untracked: ${stats.untracked} files\n`;
176
+ for (const file of stats.untrackedFiles.slice(0, 3)) {
177
+ result += ` ${file}\n`;
178
+ }
179
+ if (stats.untracked > 3) {
180
+ result += ` ... +${stats.untracked - 3} more\n`;
181
+ }
182
+ }
183
+
184
+ if (stats.conflicts > 0) {
185
+ result += `Conflicts: ${stats.conflicts} files\n`;
186
+ }
187
+
188
+ return result.trim();
189
+ }
190
+
191
+ export function compactLog(output: string, limit = 20): string {
192
+ const lines = output.split("\n");
193
+ const result: string[] = [];
194
+
195
+ for (const line of lines.slice(0, limit)) {
196
+ if (line.length > 80) {
197
+ result.push(`${line.slice(0, 77)}...`);
198
+ } else {
199
+ result.push(line);
200
+ }
201
+ }
202
+
203
+ if (lines.length > limit) {
204
+ result.push(`... and ${lines.length - limit} more commits`);
205
+ }
206
+
207
+ return result.join("\n");
208
+ }
209
+
210
+ export function compactGitOutput(output: string, command: string | undefined | null): string | null {
211
+ if (!isGitCommand(command)) {
212
+ return null;
213
+ }
214
+
215
+ const normalized = normalizeCommandForDetection(command);
216
+ if (!normalized) {
217
+ return null;
218
+ }
219
+
220
+ if (normalized.startsWith("git diff")) {
221
+ return RAW_GIT_DIFF_PATTERN.test(output) ? compactDiff(output) : null;
222
+ }
223
+ if (normalized.startsWith("git status")) {
224
+ return RAW_GIT_STATUS_PATTERN.test(output) ? compactStatus(output) : null;
225
+ }
226
+ if (normalized.startsWith("git log")) {
227
+ return compactLog(output);
228
+ }
229
+
230
+ return null;
231
+ }
@@ -1,16 +1,10 @@
1
- export { stripAnsi, stripAnsiFast } from "./ansi.js";
2
- export { truncate } from "./truncate.js";
3
- export { filterBuildOutput, isBuildCommand } from "./build.js";
4
- export { aggregateTestOutput, isTestCommand } from "./test-output.js";
5
- export { aggregateLinterOutput, isLinterCommand } from "./linter.js";
6
- export {
7
- detectLanguage,
8
- filterMinimal,
9
- filterAggressive,
10
- smartTruncate,
11
- filterSourceCode,
12
- type Language,
13
- } from "./source.js";
14
- export { compactDiff, compactStatus, compactLog, compactGitOutput, isGitCommand } from "./git.js";
15
- export { groupSearchResults } from "./search.js";
16
- export { normalizeCommandForDetection, matchesCommandPatterns } from "./command-detection.js";
1
+ export { stripAnsiFast } from "./ansi.js";
2
+ export { truncate } from "./truncate.js";
3
+ export { sanitizeRtkEmojiOutput } from "./emoji.js";
4
+ export { filterBuildOutput } from "./build.js";
5
+ export { aggregateTestOutput } from "./test-output.js";
6
+ export { aggregateLinterOutput } from "./linter.js";
7
+ export { detectLanguage, smartTruncate, filterSourceCode } from "./source.js";
8
+ export { compactGitOutput } from "./git.js";
9
+ export { groupSearchResults } from "./search.js";
10
+ export { stripRtkHookWarnings } from "./rtk.js";