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.
- package/CHANGELOG.md +102 -67
- package/README.md +292 -290
- package/config/config.example.json +36 -35
- package/package.json +4 -4
- package/src/additional-coverage-test.ts +278 -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 +410 -289
- package/src/output-compactor-test.ts +500 -158
- package/src/output-compactor.ts +432 -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/rtk-command-environment.ts +64 -0
- 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/emoji.ts +91 -0
- package/src/techniques/git.ts +231 -229
- package/src/techniques/index.ts +10 -16
- package/src/techniques/linter.ts +151 -161
- package/src/techniques/path-utils.ts +67 -0
- package/src/techniques/rtk.ts +136 -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/tool-execution-sanitizer.ts +69 -0
- package/src/types-shims.d.ts +192 -183
- package/src/types.ts +103 -114
- package/src/zellij-modal.ts +1001 -1001
- package/src/compat-commands.ts +0 -207
|
@@ -1,50 +1,42 @@
|
|
|
1
|
-
import assert from "node:assert/strict";
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
shouldRequireRtkAvailabilityForCommandHandling,
|
|
5
|
-
shouldSkipCommandHandlingWhenRtkMissing,
|
|
6
|
-
} from "./runtime-guard.ts";
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
config
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
assert.equal(
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
config
|
|
35
|
-
config.
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
assert.equal(
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
config.mode = "rewrite";
|
|
44
|
-
config.guardWhenRtkMissing = false;
|
|
45
|
-
|
|
46
|
-
assert.equal(shouldRequireRtkAvailabilityForCommandHandling(config), false);
|
|
47
|
-
assert.equal(shouldSkipCommandHandlingWhenRtkMissing(config, runtimeStatus(false)), false);
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
console.log("All runtime-guard tests passed.");
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
shouldRequireRtkAvailabilityForCommandHandling,
|
|
5
|
+
shouldSkipCommandHandlingWhenRtkMissing,
|
|
6
|
+
} from "./runtime-guard.ts";
|
|
7
|
+
import { cloneDefaultConfig, runTest } from "./test-helpers.ts";
|
|
8
|
+
import type { RuntimeStatus } from "./types.ts";
|
|
9
|
+
|
|
10
|
+
function runtimeStatus(rtkAvailable: boolean): RuntimeStatus {
|
|
11
|
+
return { rtkAvailable };
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
runTest("rewrite mode still requires RTK availability when guard is enabled", () => {
|
|
15
|
+
const config = cloneDefaultConfig();
|
|
16
|
+
config.mode = "rewrite";
|
|
17
|
+
config.guardWhenRtkMissing = true;
|
|
18
|
+
|
|
19
|
+
assert.equal(shouldRequireRtkAvailabilityForCommandHandling(config), true);
|
|
20
|
+
assert.equal(shouldSkipCommandHandlingWhenRtkMissing(config, runtimeStatus(false)), true);
|
|
21
|
+
assert.equal(shouldSkipCommandHandlingWhenRtkMissing(config, runtimeStatus(true)), false);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
runTest("suggest mode does not suppress suggestions when RTK is missing", () => {
|
|
25
|
+
const config = cloneDefaultConfig();
|
|
26
|
+
config.mode = "suggest";
|
|
27
|
+
config.guardWhenRtkMissing = true;
|
|
28
|
+
|
|
29
|
+
assert.equal(shouldRequireRtkAvailabilityForCommandHandling(config), false);
|
|
30
|
+
assert.equal(shouldSkipCommandHandlingWhenRtkMissing(config, runtimeStatus(false)), false);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
runTest("guard disabled never blocks command handling", () => {
|
|
34
|
+
const config = cloneDefaultConfig();
|
|
35
|
+
config.mode = "rewrite";
|
|
36
|
+
config.guardWhenRtkMissing = false;
|
|
37
|
+
|
|
38
|
+
assert.equal(shouldRequireRtkAvailabilityForCommandHandling(config), false);
|
|
39
|
+
assert.equal(shouldSkipCommandHandlingWhenRtkMissing(config, runtimeStatus(false)), false);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
console.log("All runtime-guard tests passed.");
|
package/src/runtime-guard.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import type { RtkIntegrationConfig, RuntimeStatus } from "./types.js";
|
|
2
|
-
|
|
3
|
-
export function shouldRequireRtkAvailabilityForCommandHandling(
|
|
4
|
-
config: Pick<RtkIntegrationConfig, "mode" | "guardWhenRtkMissing">,
|
|
5
|
-
): boolean {
|
|
6
|
-
return config.mode === "rewrite" && config.guardWhenRtkMissing;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export function shouldSkipCommandHandlingWhenRtkMissing(
|
|
10
|
-
config: Pick<RtkIntegrationConfig, "mode" | "guardWhenRtkMissing">,
|
|
11
|
-
runtimeStatus: Pick<RuntimeStatus, "rtkAvailable">,
|
|
12
|
-
): boolean {
|
|
13
|
-
return shouldRequireRtkAvailabilityForCommandHandling(config) && !runtimeStatus.rtkAvailable;
|
|
14
|
-
}
|
|
1
|
+
import type { RtkIntegrationConfig, RuntimeStatus } from "./types.js";
|
|
2
|
+
|
|
3
|
+
export function shouldRequireRtkAvailabilityForCommandHandling(
|
|
4
|
+
config: Pick<RtkIntegrationConfig, "mode" | "guardWhenRtkMissing">,
|
|
5
|
+
): boolean {
|
|
6
|
+
return config.mode === "rewrite" && config.guardWhenRtkMissing;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function shouldSkipCommandHandlingWhenRtkMissing(
|
|
10
|
+
config: Pick<RtkIntegrationConfig, "mode" | "guardWhenRtkMissing">,
|
|
11
|
+
runtimeStatus: Pick<RuntimeStatus, "rtkAvailable">,
|
|
12
|
+
): boolean {
|
|
13
|
+
return shouldRequireRtkAvailabilityForCommandHandling(config) && !runtimeStatus.rtkAvailable;
|
|
14
|
+
}
|
package/src/techniques/build.ts
CHANGED
|
@@ -1,155 +1,155 @@
|
|
|
1
|
-
import { matchesCommandPatterns } from "./command-detection.js";
|
|
2
|
-
|
|
3
|
-
interface BuildStats {
|
|
4
|
-
compiled: number;
|
|
5
|
-
errors: string[][];
|
|
6
|
-
warnings: string[];
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
const BUILD_COMMAND_PATTERNS = [
|
|
10
|
-
/^cargo\s+(build|check)\b/,
|
|
11
|
-
/^bun\s+build\b/,
|
|
12
|
-
/^npm\s+run\s+build\b/,
|
|
13
|
-
/^yarn\s+build\b/,
|
|
14
|
-
/^pnpm\s+build\b/,
|
|
15
|
-
/^(?:npx\s+)?tsc\b/,
|
|
16
|
-
/^make\b/,
|
|
17
|
-
/^cmake\b/,
|
|
18
|
-
/^gradle\b/,
|
|
19
|
-
/^mvn\b/,
|
|
20
|
-
/^go\s+(build|install)\b/,
|
|
21
|
-
/^python\s+setup\.py\s+build\b/,
|
|
22
|
-
/^pip\s+install\b/,
|
|
23
|
-
] as const;
|
|
24
|
-
|
|
25
|
-
const SKIP_PATTERNS = [
|
|
26
|
-
/^\s*Compiling\s+/,
|
|
27
|
-
/^\s*Checking\s+/,
|
|
28
|
-
/^\s*Downloading\s+/,
|
|
29
|
-
/^\s*Downloaded\s+/,
|
|
30
|
-
/^\s*Fetching\s+/,
|
|
31
|
-
/^\s*Fetched\s+/,
|
|
32
|
-
/^\s*Updating\s+/,
|
|
33
|
-
/^\s*Updated\s+/,
|
|
34
|
-
/^\s*Building\s+/,
|
|
35
|
-
/^\s*Generated\s+/,
|
|
36
|
-
/^\s*Creating\s+/,
|
|
37
|
-
/^\s*Running\s+/,
|
|
38
|
-
];
|
|
39
|
-
|
|
40
|
-
const ERROR_START_PATTERNS = [/^error\[/, /^error:/, /^\[ERROR\]/, /^FAIL/];
|
|
41
|
-
const WARNING_PATTERNS = [/^warning:/, /^\[WARNING\]/, /^warn:/];
|
|
42
|
-
|
|
43
|
-
function isSkipLine(line: string): boolean {
|
|
44
|
-
return SKIP_PATTERNS.some((pattern) => pattern.test(line));
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
function isErrorStart(line: string): boolean {
|
|
48
|
-
return ERROR_START_PATTERNS.some((pattern) => pattern.test(line));
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
function isWarning(line: string): boolean {
|
|
52
|
-
return WARNING_PATTERNS.some((pattern) => pattern.test(line));
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export function isBuildCommand(command: string | undefined | null): boolean {
|
|
56
|
-
return matchesCommandPatterns(command, BUILD_COMMAND_PATTERNS);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export function filterBuildOutput(output: string, command: string | undefined | null): string | null {
|
|
60
|
-
if (!isBuildCommand(command)) {
|
|
61
|
-
return null;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const lines = output.split("\n");
|
|
65
|
-
const stats: BuildStats = {
|
|
66
|
-
compiled: 0,
|
|
67
|
-
errors: [],
|
|
68
|
-
warnings: [],
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
let inErrorBlock = false;
|
|
72
|
-
let currentError: string[] = [];
|
|
73
|
-
let blankCount = 0;
|
|
74
|
-
|
|
75
|
-
for (const line of lines) {
|
|
76
|
-
if (line.match(/^\s*(Compiling|Checking|Building)\s+/)) {
|
|
77
|
-
stats.compiled++;
|
|
78
|
-
continue;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (isSkipLine(line)) {
|
|
82
|
-
continue;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
if (isErrorStart(line)) {
|
|
86
|
-
if (inErrorBlock && currentError.length > 0) {
|
|
87
|
-
stats.errors.push([...currentError]);
|
|
88
|
-
}
|
|
89
|
-
inErrorBlock = true;
|
|
90
|
-
currentError = [line];
|
|
91
|
-
blankCount = 0;
|
|
92
|
-
continue;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
if (isWarning(line)) {
|
|
96
|
-
stats.warnings.push(line);
|
|
97
|
-
continue;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
if (!inErrorBlock) {
|
|
101
|
-
continue;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
if (line.trim() === "") {
|
|
105
|
-
blankCount++;
|
|
106
|
-
if (blankCount >= 2 && currentError.length > 3) {
|
|
107
|
-
stats.errors.push([...currentError]);
|
|
108
|
-
inErrorBlock = false;
|
|
109
|
-
currentError = [];
|
|
110
|
-
} else {
|
|
111
|
-
currentError.push(line);
|
|
112
|
-
}
|
|
113
|
-
continue;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
if (line.match(/^\s/) || line.match(/^-->/)) {
|
|
117
|
-
currentError.push(line);
|
|
118
|
-
blankCount = 0;
|
|
119
|
-
continue;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
stats.errors.push([...currentError]);
|
|
123
|
-
inErrorBlock = false;
|
|
124
|
-
currentError = [];
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
if (inErrorBlock && currentError.length > 0) {
|
|
128
|
-
stats.errors.push(currentError);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
if (stats.errors.length === 0 && stats.warnings.length === 0) {
|
|
132
|
-
return
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
const result: string[] = [];
|
|
136
|
-
|
|
137
|
-
if (stats.errors.length > 0) {
|
|
138
|
-
result.push(
|
|
139
|
-
for (const error of stats.errors.slice(0, 5)) {
|
|
140
|
-
result.push(...error.slice(0, 10));
|
|
141
|
-
if (error.length > 10) {
|
|
142
|
-
result.push(" ...");
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
if (stats.errors.length > 5) {
|
|
146
|
-
result.push(`... and ${stats.errors.length - 5} more errors`);
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
if (stats.warnings.length > 0) {
|
|
151
|
-
result.push(`\n
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
return result.join("\n");
|
|
155
|
-
}
|
|
1
|
+
import { matchesCommandPatterns } from "./command-detection.js";
|
|
2
|
+
|
|
3
|
+
interface BuildStats {
|
|
4
|
+
compiled: number;
|
|
5
|
+
errors: string[][];
|
|
6
|
+
warnings: string[];
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const BUILD_COMMAND_PATTERNS = [
|
|
10
|
+
/^cargo\s+(build|check)\b/,
|
|
11
|
+
/^bun\s+build\b/,
|
|
12
|
+
/^npm\s+run\s+build\b/,
|
|
13
|
+
/^yarn\s+build\b/,
|
|
14
|
+
/^pnpm\s+build\b/,
|
|
15
|
+
/^(?:npx\s+)?tsc\b/,
|
|
16
|
+
/^make\b/,
|
|
17
|
+
/^cmake\b/,
|
|
18
|
+
/^gradle\b/,
|
|
19
|
+
/^mvn\b/,
|
|
20
|
+
/^go\s+(build|install)\b/,
|
|
21
|
+
/^python\s+setup\.py\s+build\b/,
|
|
22
|
+
/^pip\s+install\b/,
|
|
23
|
+
] as const;
|
|
24
|
+
|
|
25
|
+
const SKIP_PATTERNS = [
|
|
26
|
+
/^\s*Compiling\s+/,
|
|
27
|
+
/^\s*Checking\s+/,
|
|
28
|
+
/^\s*Downloading\s+/,
|
|
29
|
+
/^\s*Downloaded\s+/,
|
|
30
|
+
/^\s*Fetching\s+/,
|
|
31
|
+
/^\s*Fetched\s+/,
|
|
32
|
+
/^\s*Updating\s+/,
|
|
33
|
+
/^\s*Updated\s+/,
|
|
34
|
+
/^\s*Building\s+/,
|
|
35
|
+
/^\s*Generated\s+/,
|
|
36
|
+
/^\s*Creating\s+/,
|
|
37
|
+
/^\s*Running\s+/,
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
const ERROR_START_PATTERNS = [/^error\[/, /^error:/, /^\[ERROR\]/, /^FAIL/];
|
|
41
|
+
const WARNING_PATTERNS = [/^warning:/, /^\[WARNING\]/, /^warn:/];
|
|
42
|
+
|
|
43
|
+
function isSkipLine(line: string): boolean {
|
|
44
|
+
return SKIP_PATTERNS.some((pattern) => pattern.test(line));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function isErrorStart(line: string): boolean {
|
|
48
|
+
return ERROR_START_PATTERNS.some((pattern) => pattern.test(line));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function isWarning(line: string): boolean {
|
|
52
|
+
return WARNING_PATTERNS.some((pattern) => pattern.test(line));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function isBuildCommand(command: string | undefined | null): boolean {
|
|
56
|
+
return matchesCommandPatterns(command, BUILD_COMMAND_PATTERNS);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function filterBuildOutput(output: string, command: string | undefined | null): string | null {
|
|
60
|
+
if (!isBuildCommand(command)) {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const lines = output.split("\n");
|
|
65
|
+
const stats: BuildStats = {
|
|
66
|
+
compiled: 0,
|
|
67
|
+
errors: [],
|
|
68
|
+
warnings: [],
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
let inErrorBlock = false;
|
|
72
|
+
let currentError: string[] = [];
|
|
73
|
+
let blankCount = 0;
|
|
74
|
+
|
|
75
|
+
for (const line of lines) {
|
|
76
|
+
if (line.match(/^\s*(Compiling|Checking|Building)\s+/)) {
|
|
77
|
+
stats.compiled++;
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (isSkipLine(line)) {
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (isErrorStart(line)) {
|
|
86
|
+
if (inErrorBlock && currentError.length > 0) {
|
|
87
|
+
stats.errors.push([...currentError]);
|
|
88
|
+
}
|
|
89
|
+
inErrorBlock = true;
|
|
90
|
+
currentError = [line];
|
|
91
|
+
blankCount = 0;
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (isWarning(line)) {
|
|
96
|
+
stats.warnings.push(line);
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (!inErrorBlock) {
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (line.trim() === "") {
|
|
105
|
+
blankCount++;
|
|
106
|
+
if (blankCount >= 2 && currentError.length > 3) {
|
|
107
|
+
stats.errors.push([...currentError]);
|
|
108
|
+
inErrorBlock = false;
|
|
109
|
+
currentError = [];
|
|
110
|
+
} else {
|
|
111
|
+
currentError.push(line);
|
|
112
|
+
}
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (line.match(/^\s/) || line.match(/^-->/)) {
|
|
117
|
+
currentError.push(line);
|
|
118
|
+
blankCount = 0;
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
stats.errors.push([...currentError]);
|
|
123
|
+
inErrorBlock = false;
|
|
124
|
+
currentError = [];
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (inErrorBlock && currentError.length > 0) {
|
|
128
|
+
stats.errors.push(currentError);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (stats.errors.length === 0 && stats.warnings.length === 0) {
|
|
132
|
+
return `[OK] Build successful (${stats.compiled} units compiled)`;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const result: string[] = [];
|
|
136
|
+
|
|
137
|
+
if (stats.errors.length > 0) {
|
|
138
|
+
result.push(`[ERROR] ${stats.errors.length} error(s):`);
|
|
139
|
+
for (const error of stats.errors.slice(0, 5)) {
|
|
140
|
+
result.push(...error.slice(0, 10));
|
|
141
|
+
if (error.length > 10) {
|
|
142
|
+
result.push(" ...");
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
if (stats.errors.length > 5) {
|
|
146
|
+
result.push(`... and ${stats.errors.length - 5} more errors`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (stats.warnings.length > 0) {
|
|
151
|
+
result.push(`\n[WARN] ${stats.warnings.length} warning(s)`);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return result.join("\n");
|
|
155
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
const RTK_COMMAND_PATTERN = /^\s*rtk(?:\.exe)?(?:\s|$)/;
|
|
2
|
+
const RTK_OUTPUT_SIGNATURE_PATTERNS = [
|
|
3
|
+
/^π PATH Variables:/m,
|
|
4
|
+
/^π§ Language\/Runtime:/m,
|
|
5
|
+
/^βοΈ?\s+Cloud\/Services:/m,
|
|
6
|
+
/^π οΈ?\s+Tools:/m,
|
|
7
|
+
/^π Other:/m,
|
|
8
|
+
/^π Total:/m,
|
|
9
|
+
/^π\s+.+\s+β\s+.+/m,
|
|
10
|
+
/^π\s+/m,
|
|
11
|
+
/^β
Files are identical$/m,
|
|
12
|
+
/^β
Staged:/m,
|
|
13
|
+
/^π Modified:/m,
|
|
14
|
+
/^β Untracked:/m,
|
|
15
|
+
/^β οΈ?\s+Conflicts:/m,
|
|
16
|
+
/^π CI Checks Summary:/m,
|
|
17
|
+
/^π\s+\d+\s+in\s+\d+F:/m,
|
|
18
|
+
/^--- Changes ---$/m,
|
|
19
|
+
/^π\s+.+$/m,
|
|
20
|
+
/^π\s+\d+F\s+\d+D:/m,
|
|
21
|
+
/^βΈοΈ?\s+\d+\s+pods:/m,
|
|
22
|
+
/^π¦\s+/m,
|
|
23
|
+
] as const;
|
|
24
|
+
|
|
25
|
+
const LINE_PREFIX_REPLACEMENTS: Array<{ pattern: RegExp; replacement: string }> = [
|
|
26
|
+
{ pattern: /^π\s+/gm, replacement: "" },
|
|
27
|
+
{ pattern: /^π\s+/gm, replacement: "> " },
|
|
28
|
+
{ pattern: /^π\s+/gm, replacement: "" },
|
|
29
|
+
{ pattern: /^π§\s+/gm, replacement: "" },
|
|
30
|
+
{ pattern: /^βοΈ?\s+/gm, replacement: "" },
|
|
31
|
+
{ pattern: /^π οΈ?\s+/gm, replacement: "" },
|
|
32
|
+
{ pattern: /^π\s+/gm, replacement: "" },
|
|
33
|
+
{ pattern: /^π\s+/gm, replacement: "" },
|
|
34
|
+
{ pattern: /^π\s+/gm, replacement: "Branch: " },
|
|
35
|
+
{ pattern: /^π\s+/gm, replacement: "" },
|
|
36
|
+
{ pattern: /^π¦\s+/gm, replacement: "" },
|
|
37
|
+
{ pattern: /^π\s+/gm, replacement: "" },
|
|
38
|
+
{ pattern: /^βΈοΈ?\s+/gm, replacement: "" },
|
|
39
|
+
] as const;
|
|
40
|
+
|
|
41
|
+
const INLINE_REPLACEMENTS: Array<{ pattern: RegExp; replacement: string }> = [
|
|
42
|
+
{ pattern: /β
|β|β/g, replacement: "[OK]" },
|
|
43
|
+
{ pattern: /β|β|β/g, replacement: "[ERROR]" },
|
|
44
|
+
{ pattern: /β οΈ|β /g, replacement: "[WARN]" },
|
|
45
|
+
{ pattern: /β/g, replacement: "[INFO]" },
|
|
46
|
+
{ pattern: /βοΈ|β/g, replacement: "[SKIP]" },
|
|
47
|
+
{ pattern: /β³/g, replacement: "Pending" },
|
|
48
|
+
{ pattern: /β¬οΈ|β¬/g, replacement: "up" },
|
|
49
|
+
{ pattern: /β/g, replacement: "->" },
|
|
50
|
+
{ pattern: /β’/g, replacement: "-" },
|
|
51
|
+
] as const;
|
|
52
|
+
|
|
53
|
+
const REMAINING_EMOJI_PATTERN = /\p{Extended_Pictographic}/gu;
|
|
54
|
+
const EMOJI_VARIATION_SELECTOR_PATTERN = /\uFE0F/g;
|
|
55
|
+
const INLINE_LABEL_SPACING_PATTERN = /(\[[A-Z]+\])(\S)/g;
|
|
56
|
+
|
|
57
|
+
function isRtkCommand(command: string | undefined | null): boolean {
|
|
58
|
+
return typeof command === "string" && RTK_COMMAND_PATTERN.test(command);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function looksLikeRtkStyledOutput(output: string): boolean {
|
|
62
|
+
return RTK_OUTPUT_SIGNATURE_PATTERNS.some((pattern) => pattern.test(output));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* RTK emits emoji-heavy presentation in several command outputs. Pi should
|
|
67
|
+
* present tool results as plain text, so normalize RTK output markers before
|
|
68
|
+
* the agent consumes them. We apply this to explicit `rtk ...` commands and to
|
|
69
|
+
* recognizable RTK-shaped output that may have been prefixed by another layer.
|
|
70
|
+
*/
|
|
71
|
+
export function sanitizeRtkEmojiOutput(output: string, command: string | undefined | null): string | null {
|
|
72
|
+
if (!isRtkCommand(command) && !looksLikeRtkStyledOutput(output)) {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
let nextText = output;
|
|
77
|
+
|
|
78
|
+
for (const { pattern, replacement } of LINE_PREFIX_REPLACEMENTS) {
|
|
79
|
+
nextText = nextText.replace(pattern, replacement);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
for (const { pattern, replacement } of INLINE_REPLACEMENTS) {
|
|
83
|
+
nextText = nextText.replace(pattern, replacement);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
nextText = nextText.replace(REMAINING_EMOJI_PATTERN, "");
|
|
87
|
+
nextText = nextText.replace(EMOJI_VARIATION_SELECTOR_PATTERN, "");
|
|
88
|
+
nextText = nextText.replace(INLINE_LABEL_SPACING_PATTERN, "$1 $2");
|
|
89
|
+
|
|
90
|
+
return nextText === output ? null : nextText;
|
|
91
|
+
}
|