lean_ctx/core/patterns/
bun.rs1pub fn compress(cmd: &str, output: &str) -> Option<String> {
2 let trimmed = output.trim();
3 if trimmed.is_empty() {
4 return Some("ok".to_string());
5 }
6
7 if cmd.contains("test") {
8 return Some(compress_test(trimmed));
9 }
10 if cmd.contains("install") || cmd.contains("add") || cmd.contains("remove") {
11 return Some(compress_install(trimmed));
12 }
13 if cmd.contains("build") || cmd.contains("run") {
14 return Some(compress_build(trimmed));
15 }
16
17 Some(compact_lines(trimmed, 15))
18}
19
20fn compress_test(output: &str) -> String {
21 let mut passed = 0u32;
22 let mut failed = 0u32;
23 let mut skipped = 0u32;
24 let mut failures = Vec::new();
25 let mut time = String::new();
26
27 for line in output.lines() {
28 let trimmed = line.trim();
29 let plain = strip_ansi(trimmed);
30 if plain.contains("pass") && (plain.contains("tests") || plain.contains("test")) {
31 for word in plain.split_whitespace() {
32 if let Ok(n) = word.parse::<u32>() {
33 passed = n;
34 break;
35 }
36 }
37 }
38 if plain.contains("fail") && !plain.starts_with("FAIL") {
39 for word in plain.split_whitespace() {
40 if let Ok(n) = word.parse::<u32>() {
41 failed = n;
42 break;
43 }
44 }
45 }
46 if plain.contains("skip") {
47 for word in plain.split_whitespace() {
48 if let Ok(n) = word.parse::<u32>() {
49 skipped = n;
50 break;
51 }
52 }
53 }
54 if plain.starts_with("FAIL") || plain.starts_with("✗") || plain.starts_with("×") {
55 failures.push(plain.clone());
56 }
57 if (plain.contains("Ran") || plain.contains("Done"))
58 && (plain.contains("ms") || plain.contains("s"))
59 {
60 time = plain.clone();
61 }
62 }
63
64 if passed == 0 && failed == 0 {
65 return compact_lines(output, 10);
66 }
67
68 let mut result = format!("bun test: {passed} passed");
69 if failed > 0 {
70 result.push_str(&format!(", {failed} failed"));
71 }
72 if skipped > 0 {
73 result.push_str(&format!(", {skipped} skipped"));
74 }
75 if !time.is_empty() {
76 result.push_str(&format!(" ({time})"));
77 }
78 for f in failures.iter().take(5) {
79 result.push_str(&format!("\n {f}"));
80 }
81 result
82}
83
84fn compress_install(output: &str) -> String {
85 let mut installed = 0u32;
86 let mut removed = 0u32;
87 let mut time = String::new();
88
89 for line in output.lines() {
90 let plain = strip_ansi(line.trim());
91 if plain.contains("installed") || plain.starts_with('+') {
92 installed += 1;
93 }
94 if plain.contains("removed") || plain.starts_with('-') {
95 removed += 1;
96 }
97 if plain.contains("done") && (plain.contains("ms") || plain.contains("s")) {
98 time = plain.clone();
99 }
100 }
101
102 let mut parts = Vec::new();
103 if installed > 0 {
104 parts.push(format!("{installed} installed"));
105 }
106 if removed > 0 {
107 parts.push(format!("{removed} removed"));
108 }
109 if !time.is_empty() {
110 parts.push(time);
111 }
112
113 if parts.is_empty() {
114 return compact_lines(output, 5);
115 }
116 format!("bun: {}", parts.join(", "))
117}
118
119fn compress_build(output: &str) -> String {
120 let lines: Vec<&str> = output.lines().collect();
121 let errors: Vec<&&str> = lines
122 .iter()
123 .filter(|l| l.contains("error") || l.contains("Error"))
124 .collect();
125 if !errors.is_empty() {
126 let mut result = format!("{} errors:", errors.len());
127 for e in errors.iter().take(10) {
128 result.push_str(&format!("\n {}", e.trim()));
129 }
130 return result;
131 }
132 compact_lines(output, 10)
133}
134
135fn strip_ansi(s: &str) -> String {
136 let mut result = String::with_capacity(s.len());
137 let mut in_escape = false;
138 for c in s.chars() {
139 if c == '\x1b' {
140 in_escape = true;
141 } else if in_escape {
142 if c.is_ascii_alphabetic() {
143 in_escape = false;
144 }
145 } else {
146 result.push(c);
147 }
148 }
149 result
150}
151
152fn compact_lines(text: &str, max: usize) -> String {
153 let lines: Vec<&str> = text.lines().filter(|l| !l.trim().is_empty()).collect();
154 if lines.len() <= max {
155 return lines.join("\n");
156 }
157 format!(
158 "{}\n... ({} more lines)",
159 lines[..max].join("\n"),
160 lines.len() - max
161 )
162}