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 path = tee_dir.join(filename);
67 match crate::tools::ctx_read::read_file_lossy(&path.to_string_lossy()) {
68 Ok(content) => print!("{content}"),
69 Err(e) => {
70 eprintln!("Error reading {}: {e}", path.display());
71 std::process::exit(1);
72 }
73 }
74 }
75 "last" => {
76 if !tee_dir.exists() {
77 println!("No tee logs found.");
78 return;
79 }
80 let mut entries: Vec<_> = std::fs::read_dir(&tee_dir)
81 .ok()
82 .into_iter()
83 .flat_map(|d| d.filter_map(std::result::Result::ok))
84 .filter(|e| e.path().extension().and_then(|x| x.to_str()) == Some("log"))
85 .collect();
86 entries.sort_by_key(|e| {
87 e.metadata()
88 .and_then(|m| m.modified())
89 .unwrap_or(std::time::SystemTime::UNIX_EPOCH)
90 });
91 match entries.last() {
92 Some(entry) => {
93 let path = entry.path();
94 println!(
95 "--- {} ---\n",
96 path.file_name().unwrap_or_default().to_string_lossy()
97 );
98 match crate::tools::ctx_read::read_file_lossy(&path.to_string_lossy()) {
99 Ok(content) => print!("{content}"),
100 Err(e) => eprintln!("Error: {e}"),
101 }
102 }
103 None => println!("No tee logs found."),
104 }
105 }
106 _ => {
107 eprintln!("Usage: lean-ctx tee [list|clear|show <file>|last]");
108 std::process::exit(1);
109 }
110 }
111}
112
113pub fn cmd_filter(args: &[String]) {
114 let action = args.first().map_or("list", std::string::String::as_str);
115 match action {
116 "list" | "ls" => {
117 if let Some(engine) = crate::core::filters::FilterEngine::load() {
118 let rules = engine.list_rules();
119 println!("Loaded {} filter rule(s):\n", rules.len());
120 for rule in &rules {
121 println!("{rule}");
122 }
123 } else {
124 println!("No custom filters found.");
125 println!("Create one: lean-ctx filter init");
126 }
127 }
128 "validate" => {
129 let Some(path) = args.get(1) else {
130 eprintln!("Usage: lean-ctx filter validate <file.toml>");
131 std::process::exit(1);
132 };
133 match crate::core::filters::validate_filter_file(path) {
134 Ok(count) => println!("Valid: {count} rule(s) parsed successfully."),
135 Err(e) => {
136 eprintln!("Validation failed: {e}");
137 std::process::exit(1);
138 }
139 }
140 }
141 "init" => match crate::core::filters::create_example_filter() {
142 Ok(path) => {
143 println!("Created example filter: {path}");
144 println!("Edit it to add your custom compression rules.");
145 }
146 Err(e) => {
147 eprintln!("{e}");
148 std::process::exit(1);
149 }
150 },
151 _ => {
152 eprintln!("Usage: lean-ctx filter [list|validate <file>|init]");
153 std::process::exit(1);
154 }
155 }
156}
157
158pub fn cmd_slow_log(args: &[String]) {
159 use crate::core::slow_log;
160
161 let action = args.first().map_or("list", std::string::String::as_str);
162 match action {
163 "list" | "ls" | "" => println!("{}", slow_log::list()),
164 "clear" | "purge" => println!("{}", slow_log::clear()),
165 _ => {
166 eprintln!("Usage: lean-ctx slow-log [list|clear]");
167 std::process::exit(1);
168 }
169 }
170}