1use clap::{Parser, Subcommand, ValueEnum};
2use std::path::PathBuf;
3
4#[derive(Parser, Debug)]
6#[command(name = "magick-mcp")]
7#[command(version = env!("CARGO_PKG_VERSION"))]
8pub struct Args {
9 #[command(subcommand)]
10 pub command: Commands,
11}
12
13#[derive(Subcommand, Debug)]
14pub enum Commands {
15 Check,
17 Mcp,
19 Install {
21 #[arg(long, value_enum, default_value = "both")]
23 r#type: ClientTypeArg,
24 },
25 Magick {
27 command: String,
29 },
30 Func {
32 #[command(subcommand)]
33 func_command: FuncCommands,
34 },
35}
36
37#[derive(Subcommand, Debug)]
38pub enum FuncCommands {
39 List,
41 Print {
43 name: String,
45 },
46 Execute {
48 name: String,
50 #[arg(long)]
52 input: Option<String>,
53 },
54 Save {
56 #[arg(long)]
58 file: PathBuf,
59 },
60}
61
62#[derive(Debug, Clone, Copy, ValueEnum)]
63pub enum ClientTypeArg {
64 Cursor,
65 Claude,
66 Both,
67}
68
69impl From<ClientTypeArg> for crate::ClientType {
70 fn from(arg: ClientTypeArg) -> Self {
71 match arg {
72 ClientTypeArg::Cursor => crate::ClientType::Cursor,
73 ClientTypeArg::Claude => crate::ClientType::Claude,
74 ClientTypeArg::Both => crate::ClientType::Both,
75 }
76 }
77}
78
79pub fn handle_command(command: Commands) {
81 match command {
82 Commands::Check => match crate::check() {
83 Ok(output) => {
84 println!("{output}");
85 std::process::exit(0);
86 }
87 Err(e) => {
88 eprintln!("Error: {e}");
89 std::process::exit(1);
90 }
91 },
92 Commands::Mcp => {
93 let rt = tokio::runtime::Runtime::new().expect("Failed to create tokio runtime");
94 if let Err(e) = rt.block_on(crate::mcp::run_server()) {
95 eprintln!("Error running MCP server: {e}");
96 std::process::exit(1);
97 }
98 }
99 Commands::Install { r#type } => {
100 let client_type: crate::ClientType = r#type.into();
101 let config_paths = match crate::ConfigPaths::from_home_dir() {
102 Ok(paths) => paths,
103 Err(e) => {
104 eprintln!("Error getting config paths: {e}");
105 std::process::exit(1);
106 }
107 };
108 match crate::install(client_type, config_paths) {
109 Ok(_) => {
110 println!("Successfully installed magick-mcp to MCP configuration");
111 std::process::exit(0);
112 }
113 Err(e) => {
114 eprintln!("Error installing magick-mcp: {e}");
115 std::process::exit(1);
116 }
117 }
118 }
119 Commands::Magick { command } => match crate::magick(&command, None) {
120 Ok(output) => {
121 println!("{output}");
122 std::process::exit(0);
123 }
124 Err(e) => {
125 eprintln!("Error executing magick command: {e}");
126 std::process::exit(1);
127 }
128 },
129 Commands::Func { func_command } => handle_func_command(func_command),
130 }
131}
132
133fn handle_func_command(func_command: FuncCommands) {
135 match func_command {
136 FuncCommands::List => match crate::list_functions() {
137 Ok(functions) => {
138 if functions.is_empty() {
139 println!("No functions found");
140 } else {
141 for name in functions {
142 println!("{name}");
143 }
144 }
145 std::process::exit(0);
146 }
147 Err(e) => {
148 eprintln!("Error listing functions: {e}");
149 std::process::exit(1);
150 }
151 },
152 FuncCommands::Print { name } => match crate::load_function(&name) {
153 Ok(function) => {
154 println!("Name: {}", function.name);
155 println!("Commands:");
156 for command in &function.commands {
157 println!(" - {command}");
158 }
159 std::process::exit(0);
160 }
161 Err(e) => {
162 eprintln!("Error loading function '{name}': {e}");
163 std::process::exit(1);
164 }
165 },
166 FuncCommands::Execute { name, input } => {
167 let function = match crate::load_function(&name) {
168 Ok(f) => f,
169 Err(e) => {
170 eprintln!("Error loading function '{name}': {e}");
171 std::process::exit(1);
172 }
173 };
174 let input_ref = input.as_deref();
175 match crate::run_function(&function, None, input_ref) {
176 Ok(outputs) => {
177 for output in outputs {
178 println!("{output}");
179 }
180 std::process::exit(0);
181 }
182 Err(e) => {
183 eprintln!("Error executing function '{name}': {e}");
184 std::process::exit(1);
185 }
186 }
187 }
188 FuncCommands::Save { file } => {
189 let contents = match std::fs::read_to_string(&file) {
190 Ok(c) => c,
191 Err(e) => {
192 eprintln!("Error reading file '{}': {e}", file.display());
193 std::process::exit(1);
194 }
195 };
196 let function: crate::Function = match serde_json::from_str(&contents) {
197 Ok(f) => f,
198 Err(e) => {
199 eprintln!("Error parsing JSON from '{}': {e}", file.display());
200 std::process::exit(1);
201 }
202 };
203 match crate::save_function(function) {
204 Ok(_) => {
205 println!("Function saved successfully");
206 std::process::exit(0);
207 }
208 Err(e) => {
209 eprintln!("Error saving function: {e}");
210 std::process::exit(1);
211 }
212 }
213 }
214 }
215}