1use std::fmt;
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq)]
4pub enum SafetyLevel {
5 Verbatim,
6 Minimal,
7 Standard,
8 Aggressive,
9}
10
11impl fmt::Display for SafetyLevel {
12 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
13 match self {
14 SafetyLevel::Verbatim => write!(f, "verbatim"),
15 SafetyLevel::Minimal => write!(f, "minimal"),
16 SafetyLevel::Standard => write!(f, "standard"),
17 SafetyLevel::Aggressive => write!(f, "aggressive"),
18 }
19 }
20}
21
22pub struct CommandSafety {
23 pub command: &'static str,
24 pub level: SafetyLevel,
25 pub description: &'static str,
26}
27
28pub const COMMAND_SAFETY_TABLE: &[CommandSafety] = &[
29 CommandSafety {
31 command: "df",
32 level: SafetyLevel::Verbatim,
33 description: "Disk usage — root filesystem must never be hidden",
34 },
35 CommandSafety {
36 command: "git status",
37 level: SafetyLevel::Verbatim,
38 description: "DETACHED HEAD, staged/unstaged lists preserved verbatim",
39 },
40 CommandSafety {
41 command: "git stash",
42 level: SafetyLevel::Verbatim,
43 description: "Stash save/pop/list output preserved verbatim",
44 },
45 CommandSafety {
46 command: "ls",
47 level: SafetyLevel::Verbatim,
48 description: "All files shown including .env, dotfiles",
49 },
50 CommandSafety {
51 command: "find",
52 level: SafetyLevel::Verbatim,
53 description: "Full absolute paths preserved",
54 },
55 CommandSafety {
56 command: "wc",
57 level: SafetyLevel::Verbatim,
58 description: "Pipe/stdin input handled correctly",
59 },
60 CommandSafety {
61 command: "env/printenv",
62 level: SafetyLevel::Verbatim,
63 description: "Environment variables preserved (values filtered)",
64 },
65 CommandSafety {
67 command: "git diff",
68 level: SafetyLevel::Minimal,
69 description: "All +/- lines preserved, only index headers and excess context trimmed",
70 },
71 CommandSafety {
72 command: "git log",
73 level: SafetyLevel::Minimal,
74 description: "Up to 50 entries, respects --max-count/-n, shows truncation notice",
75 },
76 CommandSafety {
77 command: "git blame",
78 level: SafetyLevel::Minimal,
79 description: "Verbatim up to 100 lines, then author/line-range summary",
80 },
81 CommandSafety {
82 command: "docker ps",
83 level: SafetyLevel::Minimal,
84 description: "Header-parsed columns; (unhealthy), Exited status always preserved",
85 },
86 CommandSafety {
87 command: "grep/rg",
88 level: SafetyLevel::Minimal,
89 description: "Verbatim up to 100 lines, then grouped by file with line numbers",
90 },
91 CommandSafety {
92 command: "ruff check",
93 level: SafetyLevel::Minimal,
94 description: "Verbatim up to 30 issues (file:line:col preserved), then summary",
95 },
96 CommandSafety {
97 command: "npm audit",
98 level: SafetyLevel::Minimal,
99 description: "CVE IDs, severity, package names, fix recommendations preserved",
100 },
101 CommandSafety {
102 command: "pip list",
103 level: SafetyLevel::Minimal,
104 description: "All packages shown (no truncation)",
105 },
106 CommandSafety {
107 command: "pip uninstall",
108 level: SafetyLevel::Minimal,
109 description: "All removed package names listed",
110 },
111 CommandSafety {
112 command: "pytest",
113 level: SafetyLevel::Minimal,
114 description: "passed/failed/skipped/xfailed/xpassed/warnings all counted",
115 },
116 CommandSafety {
117 command: "docker logs",
118 level: SafetyLevel::Minimal,
119 description: "Dedup + safety-needle scan preserves FATAL/ERROR/CRITICAL lines",
120 },
121 CommandSafety {
122 command: "cat (logs)",
123 level: SafetyLevel::Minimal,
124 description: "Log dedup preserves all severity levels including CRITICAL",
125 },
126 CommandSafety {
128 command: "cargo build/test",
129 level: SafetyLevel::Standard,
130 description: "Errors and warnings preserved, progress lines removed",
131 },
132 CommandSafety {
133 command: "npm install",
134 level: SafetyLevel::Standard,
135 description: "Package count, vulnerability summary preserved",
136 },
137 CommandSafety {
138 command: "docker build",
139 level: SafetyLevel::Standard,
140 description: "Step count, errors preserved, intermediate output removed",
141 },
142 CommandSafety {
143 command: "git commit",
144 level: SafetyLevel::Standard,
145 description: "Branch, hash, change stats preserved; hook output kept",
146 },
147 CommandSafety {
148 command: "git push/pull",
149 level: SafetyLevel::Standard,
150 description: "Remote, branch, conflict info preserved",
151 },
152 CommandSafety {
153 command: "eslint/biome",
154 level: SafetyLevel::Standard,
155 description: "Error/warning counts, file references preserved",
156 },
157 CommandSafety {
158 command: "tsc",
159 level: SafetyLevel::Standard,
160 description: "Type errors with file:line preserved",
161 },
162 CommandSafety {
163 command: "curl (JSON)",
164 level: SafetyLevel::Standard,
165 description: "Schema extraction; sensitive keys (token/password/secret) REDACTED",
166 },
167 CommandSafety {
169 command: "kubectl describe",
170 level: SafetyLevel::Aggressive,
171 description: "Key fields extracted, verbose event history trimmed",
172 },
173 CommandSafety {
174 command: "aws CLI",
175 level: SafetyLevel::Aggressive,
176 description: "JSON schema extraction for large API responses",
177 },
178 CommandSafety {
179 command: "terraform plan",
180 level: SafetyLevel::Aggressive,
181 description: "Resource changes summarized, full plan truncated",
182 },
183 CommandSafety {
184 command: "docker images",
185 level: SafetyLevel::Aggressive,
186 description: "Compressed to name:tag (size) list",
187 },
188];
189
190pub fn format_safety_table() -> String {
191 let mut out = String::new();
192 out.push_str("Command Compression Safety Levels\n");
193 out.push_str(&"=".repeat(72));
194 out.push('\n');
195 out.push('\n');
196
197 for level in &[
198 SafetyLevel::Verbatim,
199 SafetyLevel::Minimal,
200 SafetyLevel::Standard,
201 SafetyLevel::Aggressive,
202 ] {
203 let label = match level {
204 SafetyLevel::Verbatim => "VERBATIM — output passes through unchanged",
205 SafetyLevel::Minimal => {
206 "MINIMAL — light formatting, all safety-critical data preserved"
207 }
208 SafetyLevel::Standard => "STANDARD — structured compression, key info preserved",
209 SafetyLevel::Aggressive => "AGGRESSIVE — heavy compression for verbose output",
210 };
211 out.push_str(&format!("[{label}]\n"));
212
213 for entry in COMMAND_SAFETY_TABLE.iter().filter(|e| e.level == *level) {
214 out.push_str(&format!(" {:<20} {}\n", entry.command, entry.description));
215 }
216 out.push('\n');
217 }
218
219 out.push_str("Safety features active on ALL commands:\n");
220 out.push_str(" • Safety-needle scan: CRITICAL/FATAL/panic/ERROR/CVE lines preserved\n");
221 out.push_str(" • Safeguard ratio: >95% compression on >100 tokens triggers fallback\n");
222 out.push_str(" • Auth flow detection: login/OAuth prompts never compressed\n");
223 out.push_str(" • Minimum token threshold: outputs <50 tokens pass through unchanged\n");
224 out.push('\n');
225 out.push_str("Use `lean-ctx bypass \"command\"` to run any command with zero compression.\n");
226
227 out
228}
229
230#[cfg(test)]
231mod tests {
232 use super::*;
233
234 #[test]
235 fn safety_table_has_entries() {
236 assert!(COMMAND_SAFETY_TABLE.len() > 20);
237 }
238
239 #[test]
240 fn format_table_contains_all_levels() {
241 let table = format_safety_table();
242 assert!(table.contains("VERBATIM"));
243 assert!(table.contains("MINIMAL"));
244 assert!(table.contains("STANDARD"));
245 assert!(table.contains("AGGRESSIVE"));
246 }
247
248 #[test]
249 fn df_is_verbatim() {
250 let df = COMMAND_SAFETY_TABLE
251 .iter()
252 .find(|e| e.command == "df")
253 .unwrap();
254 assert_eq!(df.level, SafetyLevel::Verbatim);
255 }
256
257 #[test]
258 fn git_diff_is_minimal() {
259 let diff = COMMAND_SAFETY_TABLE
260 .iter()
261 .find(|e| e.command == "git diff")
262 .unwrap();
263 assert_eq!(diff.level, SafetyLevel::Minimal);
264 }
265}