Skip to main content

lean_ctx/cli/
tee_cmd.rs

1pub fn cmd_tee(args: &[String]) {
2    let tee_dir = if let Some(h) = dirs::home_dir() {
3        h.join(".lean-ctx").join("tee")
4    } else {
5        eprintln!("Cannot determine home directory");
6        std::process::exit(1);
7    };
8
9    let action = args.first().map_or("list", std::string::String::as_str);
10    match action {
11        "list" | "ls" => {
12            if !tee_dir.exists() {
13                println!("No tee logs found (~/.lean-ctx/tee/ does not exist)");
14                return;
15            }
16            let mut entries: Vec<_> = std::fs::read_dir(&tee_dir)
17                .unwrap_or_else(|e| {
18                    eprintln!("Error: {e}");
19                    std::process::exit(1);
20                })
21                .filter_map(std::result::Result::ok)
22                .filter(|e| e.path().extension().and_then(|x| x.to_str()) == Some("log"))
23                .collect();
24            entries.sort_by_key(std::fs::DirEntry::file_name);
25
26            if entries.is_empty() {
27                println!("No tee logs found.");
28                return;
29            }
30
31            println!("Tee logs ({}):\n", entries.len());
32            for entry in &entries {
33                let size = entry.metadata().map_or(0, |m| m.len());
34                let name = entry.file_name();
35                let size_str = if size > 1024 {
36                    format!("{}K", size / 1024)
37                } else {
38                    format!("{size}B")
39                };
40                println!("  {:<60} {}", name.to_string_lossy(), size_str);
41            }
42            println!("\nUse 'lean-ctx tee clear' to delete all logs.");
43        }
44        "clear" | "purge" => {
45            if !tee_dir.exists() {
46                println!("No tee logs to clear.");
47                return;
48            }
49            let mut count = 0u32;
50            if let Ok(entries) = std::fs::read_dir(&tee_dir) {
51                for entry in entries.flatten() {
52                    if entry.path().extension().and_then(|x| x.to_str()) == Some("log")
53                        && std::fs::remove_file(entry.path()).is_ok()
54                    {
55                        count += 1;
56                    }
57                }
58            }
59            println!("Cleared {count} tee log(s) from {}", tee_dir.display());
60        }
61        "show" => {
62            let Some(filename) = args.get(1) else {
63                eprintln!("Usage: lean-ctx tee show <filename>");
64                std::process::exit(1);
65            };
66            let fname = filename.as_str();
67            let basename = std::path::Path::new(fname).file_name().unwrap_or_default();
68            if basename.is_empty()
69                || basename != fname
70                || fname == "."
71                || fname == ".."
72                || fname.contains(std::path::MAIN_SEPARATOR)
73            {
74                eprintln!("Error: filename must be a plain basename (no path separators or '..')");
75                std::process::exit(1);
76            }
77            let path = tee_dir.join(basename);
78            match crate::tools::ctx_read::read_file_lossy(&path.to_string_lossy()) {
79                Ok(content) => print!("{content}"),
80                Err(e) => {
81                    eprintln!("Error reading {}: {e}", path.display());
82                    std::process::exit(1);
83                }
84            }
85        }
86        "last" => {
87            if !tee_dir.exists() {
88                println!("No tee logs found.");
89                return;
90            }
91            let mut entries: Vec<_> = std::fs::read_dir(&tee_dir)
92                .ok()
93                .into_iter()
94                .flat_map(|d| d.filter_map(std::result::Result::ok))
95                .filter(|e| e.path().extension().and_then(|x| x.to_str()) == Some("log"))
96                .collect();
97            entries.sort_by_key(|e| {
98                e.metadata()
99                    .and_then(|m| m.modified())
100                    .unwrap_or(std::time::SystemTime::UNIX_EPOCH)
101            });
102            match entries.last() {
103                Some(entry) => {
104                    let path = entry.path();
105                    println!(
106                        "--- {} ---\n",
107                        path.file_name().unwrap_or_default().to_string_lossy()
108                    );
109                    match crate::tools::ctx_read::read_file_lossy(&path.to_string_lossy()) {
110                        Ok(content) => print!("{content}"),
111                        Err(e) => eprintln!("Error: {e}"),
112                    }
113                }
114                None => println!("No tee logs found."),
115            }
116        }
117        _ => {
118            eprintln!("Usage: lean-ctx tee [list|clear|show <file>|last]");
119            std::process::exit(1);
120        }
121    }
122}
123
124pub fn cmd_filter(args: &[String]) {
125    let action = args.first().map_or("list", std::string::String::as_str);
126    match action {
127        "list" | "ls" => {
128            if let Some(engine) = crate::core::filters::FilterEngine::load() {
129                let rules = engine.list_rules();
130                println!("Loaded {} filter rule(s):\n", rules.len());
131                for rule in &rules {
132                    println!("{rule}");
133                }
134            } else {
135                println!("No custom filters found.");
136                println!("Create one: lean-ctx filter init");
137            }
138        }
139        "validate" => {
140            let Some(path) = args.get(1) else {
141                eprintln!("Usage: lean-ctx filter validate <file.toml>");
142                std::process::exit(1);
143            };
144            match crate::core::filters::validate_filter_file(path) {
145                Ok(count) => println!("Valid: {count} rule(s) parsed successfully."),
146                Err(e) => {
147                    eprintln!("Validation failed: {e}");
148                    std::process::exit(1);
149                }
150            }
151        }
152        "init" => match crate::core::filters::create_example_filter() {
153            Ok(path) => {
154                println!("Created example filter: {path}");
155                println!("Edit it to add your custom compression rules.");
156            }
157            Err(e) => {
158                eprintln!("{e}");
159                std::process::exit(1);
160            }
161        },
162        _ => {
163            eprintln!("Usage: lean-ctx filter [list|validate <file>|init]");
164            std::process::exit(1);
165        }
166    }
167}
168
169pub fn cmd_slow_log(args: &[String]) {
170    use crate::core::slow_log;
171
172    let action = args.first().map_or("list", std::string::String::as_str);
173    match action {
174        "list" | "ls" | "" => println!("{}", slow_log::list()),
175        "clear" | "purge" => println!("{}", slow_log::clear()),
176        _ => {
177            eprintln!("Usage: lean-ctx slow-log [list|clear]");
178            std::process::exit(1);
179        }
180    }
181}