lean_ctx_patterns/
env_filter.rs1use std::collections::BTreeMap;
4
5pub fn compress(output: &str) -> Option<String> {
6 let trimmed = output.trim();
7 if trimmed.is_empty() {
8 return Some("(empty)".to_string());
9 }
10
11 let mut groups: BTreeMap<String, Vec<String>> = BTreeMap::new();
12 let mut ungrouped = Vec::new();
13
14 let sensitive_patterns = [
15 "KEY",
16 "SECRET",
17 "TOKEN",
18 "PASSWORD",
19 "PASSWD",
20 "CREDENTIALS",
21 "AUTH",
22 "API_KEY",
23 "PRIVATE",
24 "CERT",
25 ];
26
27 for line in trimmed.lines() {
28 let l = line.trim();
29 if l.is_empty() {
30 continue;
31 }
32
33 if let Some((key, value)) = l.split_once('=') {
34 let is_sensitive = sensitive_patterns
35 .iter()
36 .any(|p| key.to_uppercase().contains(p));
37 let display_value = if is_sensitive {
38 "***".to_string()
39 } else if value.len() > 80 {
40 let truncated: String = value.chars().take(40).collect();
41 format!("{truncated}...")
42 } else {
43 value.to_string()
44 };
45
46 let prefix = key.split('_').next().unwrap_or("OTHER").to_string();
47
48 groups
49 .entry(prefix)
50 .or_default()
51 .push(format!("{key}={display_value}"));
52 } else {
53 ungrouped.push(l.to_string());
54 }
55 }
56
57 let total: usize = groups.values().map(std::vec::Vec::len).sum();
58
59 let mut parts = Vec::new();
60 parts.push(format!("{total} variables:"));
61
62 for (prefix, vars) in &groups {
63 if vars.len() >= 3 {
64 parts.push(format!("[{prefix}_*] ({} vars)", vars.len()));
65 for v in vars.iter().take(3) {
66 parts.push(format!(" {v}"));
67 }
68 if vars.len() > 3 {
69 parts.push(format!(" ... +{} more", vars.len() - 3));
70 }
71 }
72 }
73
74 let small_groups: Vec<String> = groups
75 .iter()
76 .filter(|(_, v)| v.len() < 3)
77 .flat_map(|(_, v)| v.iter().cloned())
78 .collect();
79
80 if !small_groups.is_empty() {
81 parts.push(format!("[other] ({} vars)", small_groups.len()));
82 for v in small_groups.iter().take(5) {
83 parts.push(format!(" {v}"));
84 }
85 if small_groups.len() > 5 {
86 parts.push(format!(" ... +{} more", small_groups.len() - 5));
87 }
88 }
89
90 Some(parts.join("\n"))
91}