use anyhow::{Context, Result};
use colored::Colorize;
use std::process::Command;
const MARKETPLACE_ID: &str = "lightonai-plaid";
const PLUGIN_NAME: &str = "plaid";
const MIN_CLAUDE_VERSION: &str = "2.0.36";
pub fn install_claude_code() -> Result<()> {
let shell = get_shell();
println!("Adding plaid to Claude Code marketplace...");
let marketplace_add = Command::new(&shell)
.args([
"-c",
&format!("claude plugin marketplace add {}", MARKETPLACE_ID),
])
.output()
.context("Failed to execute claude CLI")?;
if !marketplace_add.status.success() {
let stderr = String::from_utf8_lossy(&marketplace_add.stderr);
eprintln!(
"{} Failed to add plugin to marketplace: {}",
"Error:".red(),
stderr
);
eprintln!(
"{}",
format!(
"Do you have Claude Code version {} or higher installed?",
MIN_CLAUDE_VERSION
)
.yellow()
);
anyhow::bail!("Failed to add plugin to marketplace");
}
println!("{} Added plaid plugin to the marketplace", "✓".green());
println!("Installing plaid plugin...");
let plugin_install = Command::new(&shell)
.args(["-c", &format!("claude plugin install {}", PLUGIN_NAME)])
.output()
.context("Failed to execute claude CLI")?;
if !plugin_install.status.success() {
let stderr = String::from_utf8_lossy(&plugin_install.stderr);
eprintln!("{} Failed to install plugin: {}", "Error:".red(), stderr);
eprintln!(
"{}",
format!(
"Do you have Claude Code version {} or higher installed?",
MIN_CLAUDE_VERSION
)
.yellow()
);
anyhow::bail!("Failed to install plugin");
}
println!("{} Installed plaid plugin", "✓".green());
print_install_success();
Ok(())
}
pub fn uninstall_claude_code() -> Result<()> {
let shell = get_shell();
println!("Uninstalling plaid plugin...");
let plugin_uninstall = Command::new(&shell)
.args(["-c", &format!("claude plugin uninstall {}", PLUGIN_NAME)])
.output()
.context("Failed to execute claude CLI")?;
if !plugin_uninstall.status.success() {
let stderr = String::from_utf8_lossy(&plugin_uninstall.stderr);
eprintln!("{} Failed to uninstall plugin: {}", "Error:".red(), stderr);
eprintln!(
"{}",
format!(
"Do you have Claude Code version {} or higher installed?",
MIN_CLAUDE_VERSION
)
.yellow()
);
} else {
println!("{} Uninstalled plaid plugin", "✓".green());
}
println!("Removing plaid from marketplace...");
let marketplace_remove = Command::new(&shell)
.args([
"-c",
&format!("claude plugin marketplace remove {}", MARKETPLACE_ID),
])
.output()
.context("Failed to execute claude CLI")?;
if !marketplace_remove.status.success() {
let stderr = String::from_utf8_lossy(&marketplace_remove.stderr);
eprintln!(
"{} Failed to remove plugin from marketplace: {}",
"Error:".red(),
stderr
);
eprintln!(
"{}",
format!(
"Do you have Claude Code version {} or higher installed?",
MIN_CLAUDE_VERSION
)
.yellow()
);
anyhow::bail!("Failed to remove plugin from marketplace");
}
println!("{} Removed plaid from marketplace", "✓".green());
println!();
println!("{}", "Plaid has been uninstalled from Claude Code.".green());
Ok(())
}
fn get_shell() -> String {
if cfg!(target_os = "windows") {
std::env::var("COMSPEC").unwrap_or_else(|_| "cmd.exe".to_string())
} else {
std::env::var("SHELL").unwrap_or_else(|_| "/bin/sh".to_string())
}
}
fn print_install_success() {
let border = "═".repeat(70);
println!();
println!("{}", border.yellow());
println!();
println!(
" {} {}",
"✓".green().bold(),
"PLAID INSTALLED FOR CLAUDE CODE".green().bold()
);
println!();
println!(" Plaid is now available as a semantic search tool in Claude Code.");
println!(" Claude will automatically use plaid for code searches.");
println!();
println!(" {}", "What happens:".cyan().bold());
println!(" • Plaid indexes your project on first search");
println!(" • Subsequent searches use the cached index");
println!(" • Index updates automatically when files change");
println!();
println!(" {}", "To uninstall:".cyan().bold());
println!(" {}", "plaid uninstall-claude-code".green());
println!();
println!("{}", border.yellow());
println!();
}