lean_ctx/core/patterns/
helm.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("list") || cmd.contains("ls") {
8 return Some(compress_list(trimmed));
9 }
10 if cmd.contains("install") || cmd.contains("upgrade") {
11 return Some(compress_install(trimmed));
12 }
13 if cmd.contains("status") {
14 return Some(compress_status(trimmed));
15 }
16 if cmd.contains("template") || cmd.contains("dry-run") {
17 return Some(compress_template(trimmed));
18 }
19 if cmd.contains("repo") {
20 return Some(compress_repo(trimmed));
21 }
22
23 Some(compact_lines(trimmed, 15))
24}
25
26fn compress_list(output: &str) -> String {
27 let lines: Vec<&str> = output.lines().collect();
28 if lines.len() <= 1 {
29 return "no releases".to_string();
30 }
31
32 let header = lines[0];
33 let releases: Vec<&str> = lines[1..]
34 .iter()
35 .copied()
36 .filter(|l| !l.trim().is_empty())
37 .collect();
38 if releases.len() <= 15 {
39 return output.to_string();
40 }
41 format!(
42 "{header}\n{}\n... ({} more)",
43 releases[..10].join("\n"),
44 releases.len() - 10
45 )
46}
47
48fn compress_install(output: &str) -> String {
49 let mut name = String::new();
50 let mut status = String::new();
51 let mut notes_start = false;
52 let mut notes = Vec::new();
53
54 for line in output.lines() {
55 let trimmed = line.trim();
56 if trimmed.starts_with("NAME:") {
57 name = trimmed
58 .strip_prefix("NAME:")
59 .unwrap_or("")
60 .trim()
61 .to_string();
62 } else if trimmed.starts_with("STATUS:") {
63 status = trimmed
64 .strip_prefix("STATUS:")
65 .unwrap_or("")
66 .trim()
67 .to_string();
68 } else if trimmed == "NOTES:" {
69 notes_start = true;
70 } else if notes_start && !trimmed.is_empty() && notes.len() < 5 {
71 notes.push(trimmed.to_string());
72 }
73 }
74
75 let mut result = format!("{name}: {status}");
76 if !notes.is_empty() {
77 result.push_str(&format!("\nnotes: {}", notes.join(" | ")));
78 }
79 result
80}
81
82fn compress_status(output: &str) -> String {
83 let mut parts = Vec::new();
84 for line in output.lines() {
85 let trimmed = line.trim();
86 if trimmed.starts_with("NAME:")
87 || trimmed.starts_with("STATUS:")
88 || trimmed.starts_with("NAMESPACE:")
89 || trimmed.starts_with("REVISION:")
90 || trimmed.starts_with("LAST DEPLOYED:")
91 {
92 parts.push(trimmed.to_string());
93 }
94 }
95 if parts.is_empty() {
96 return compact_lines(output, 10);
97 }
98 parts.join("\n")
99}
100
101fn compress_template(output: &str) -> String {
102 let lines: Vec<&str> = output.lines().collect();
103 let yaml_docs: Vec<usize> = lines
104 .iter()
105 .enumerate()
106 .filter(|(_, l)| l.trim() == "---")
107 .map(|(i, _)| i)
108 .collect();
109
110 let mut kinds = Vec::new();
111 for line in &lines {
112 let trimmed = line.trim();
113 if trimmed.starts_with("kind:") {
114 kinds.push(
115 trimmed
116 .strip_prefix("kind:")
117 .unwrap_or("")
118 .trim()
119 .to_string(),
120 );
121 }
122 }
123
124 if kinds.is_empty() {
125 return format!("{} lines of YAML", lines.len());
126 }
127
128 let mut counts: std::collections::HashMap<&str, u32> = std::collections::HashMap::new();
129 for k in &kinds {
130 *counts.entry(k.as_str()).or_insert(0) += 1;
131 }
132 let summary: Vec<String> = counts.iter().map(|(k, v)| format!(" {k}: {v}")).collect();
133 format!(
134 "{} YAML docs ({} resources):\n{}",
135 yaml_docs.len().max(1),
136 kinds.len(),
137 summary.join("\n")
138 )
139}
140
141fn compress_repo(output: &str) -> String {
142 compact_lines(output, 10)
143}
144
145fn compact_lines(text: &str, max: usize) -> String {
146 let lines: Vec<&str> = text.lines().filter(|l| !l.trim().is_empty()).collect();
147 if lines.len() <= max {
148 return lines.join("\n");
149 }
150 format!(
151 "{}\n... ({} more lines)",
152 lines[..max].join("\n"),
153 lines.len() - max
154 )
155}