1use super::snapshot::WrapSnapshot;
4use std::path::Path;
5
6pub fn run_unwrap(args: &[String]) {
7 if args.iter().any(|a| a == "--help" || a == "-h") {
8 println!("Usage: lean-ctx unwrap <agent>");
9 println!();
10 println!("Restore the agent's configuration to its pre-wrap state.");
11 println!("Removes lean-ctx MCP registration, hooks, and shell integration");
12 println!("that were installed by `lean-ctx wrap <agent>`.");
13 return;
14 }
15
16 let agent_key = match args.first() {
17 Some(a) if !a.starts_with('-') => a.as_str(),
18 _ => {
19 eprintln!("Usage: lean-ctx unwrap <agent>");
20 eprintln!("Example: lean-ctx unwrap cursor");
21 std::process::exit(1);
22 }
23 };
24
25 let snap = match WrapSnapshot::load(agent_key) {
26 Ok(s) => s,
27 Err(e) => {
28 eprintln!("{e}");
29 std::process::exit(1);
30 }
31 };
32
33 eprintln!(
34 "Restoring {agent_key} to pre-wrap state (snapshot from {})...",
35 snap.timestamp
36 );
37
38 let mut restored = 0u32;
39 let mut errors = 0u32;
40
41 for (path_str, record) in &snap.files {
42 let path = Path::new(path_str);
43
44 if !record.existed {
45 if path.exists() {
46 match std::fs::remove_file(path) {
47 Ok(()) => {
48 eprintln!(" Removed: {path_str}");
49 restored += 1;
50 }
51 Err(e) => {
52 eprintln!(" Error removing {path_str}: {e}");
53 errors += 1;
54 }
55 }
56 }
57 continue;
58 }
59
60 if record.backup_path.is_empty() {
61 eprintln!(" Skipped: {path_str} (no backup available)");
62 continue;
63 }
64
65 let backup = Path::new(&record.backup_path);
66 if !backup.exists() {
67 eprintln!(" Skipped: {path_str} (backup file missing)");
68 continue;
69 }
70
71 match std::fs::copy(backup, path) {
72 Ok(_) => {
73 eprintln!(" Restored: {path_str}");
74 restored += 1;
75 }
76 Err(e) => {
77 eprintln!(" Error restoring {path_str}: {e}");
78 errors += 1;
79 }
80 }
81 }
82
83 eprintln!(" Removing MCP registration...");
85 if let Some(home) = dirs::home_dir() {
86 let targets = crate::core::editor_registry::build_targets(&home);
87 for target in targets.iter().filter(|t| t.agent_key == agent_key) {
88 let _ = crate::core::editor_registry::remove_lean_ctx_mcp_server(
89 &target.config_path,
90 crate::core::editor_registry::WriteOptions {
91 overwrite_invalid: true,
92 },
93 );
94 }
95 }
96
97 if let Ok(state) = crate::core::paths::state_dir() {
99 let snap_dir = state.join("snapshots").join(agent_key);
100 let _ = std::fs::remove_dir_all(&snap_dir);
101 }
102
103 eprintln!();
104 if errors == 0 {
105 eprintln!(
106 "\x1b[1;32mlean-ctx unwrapped {agent_key} successfully.\x1b[0m ({restored} files restored)"
107 );
108 } else {
109 eprintln!(
110 "\x1b[1;33mlean-ctx unwrap completed with {errors} error(s).\x1b[0m ({restored} files restored)"
111 );
112 }
113 eprintln!();
114 eprintln!(" Restart {agent_key} to complete the removal.");
115}