use std::path::PathBuf;
use anyhow::Result;
use clap::{Args, Parser, Subcommand};
use tracing::Level;
use tracing_subscriber::FmtSubscriber;
mod commands;
mod progress;
#[derive(Parser, Debug)]
#[command(name = "codeprysm")]
#[command(author, version, about, long_about = None)]
#[command(propagate_version = true)]
struct Cli {
#[command(subcommand)]
command: Commands,
#[command(flatten)]
global: GlobalOptions,
}
#[derive(Args, Debug, Clone)]
struct GlobalOptions {
#[arg(long, short = 'w', global = true, env = "CODEPRYSM_WORKSPACE")]
workspace: Option<String>,
#[arg(long, short = 'c', global = true, env = "CODEPRYSM_CONFIG")]
config: Option<PathBuf>,
#[arg(long, short = 'v', global = true)]
verbose: bool,
#[arg(long, short = 'q', global = true)]
quiet: bool,
#[arg(
long,
global = true,
env = "CODEPRYSM_QDRANT_URL",
default_value = "http://localhost:6334"
)]
qdrant_url: String,
#[arg(long, global = true, env = "CODEPRYSM_EMBEDDING_PROVIDER", value_parser = parse_embedding_provider)]
embedding_provider: Option<codeprysm_config::EmbeddingProviderType>,
}
fn parse_embedding_provider(s: &str) -> Result<codeprysm_config::EmbeddingProviderType, String> {
s.parse()
.map_err(|e: codeprysm_config::ConfigError| e.to_string())
}
impl GlobalOptions {
pub fn to_config_overrides(&self) -> codeprysm_config::ConfigOverrides {
codeprysm_config::ConfigOverrides {
qdrant_url: Some(self.qdrant_url.clone()),
embedding_provider: self.embedding_provider,
..Default::default()
}
}
}
#[derive(Subcommand, Debug)]
enum Commands {
Init(commands::init::InitArgs),
Update(commands::update::UpdateArgs),
Search(commands::search::SearchArgs),
Graph(commands::graph::GraphArgs),
#[command(subcommand)]
Components(commands::components::ComponentsCommand),
#[command(subcommand)]
Workspace(commands::workspace::WorkspaceCommand),
Status(commands::status::StatusArgs),
Doctor(commands::doctor::DoctorArgs),
Clean(commands::clean::CleanArgs),
#[command(subcommand)]
Backend(commands::backend::BackendCommand),
#[command(subcommand)]
Config(commands::config::ConfigCommand),
Mcp(commands::mcp::McpArgs),
}
#[tokio::main]
async fn main() -> Result<()> {
let cli = Cli::parse();
let log_level = if cli.global.quiet {
Level::ERROR
} else if cli.global.verbose {
Level::DEBUG
} else {
Level::INFO
};
let subscriber = FmtSubscriber::builder()
.with_max_level(log_level)
.with_writer(std::io::stderr)
.with_ansi(true)
.finish();
tracing::subscriber::set_global_default(subscriber)?;
match cli.command {
Commands::Init(args) => commands::init::execute(args, cli.global).await,
Commands::Update(args) => commands::update::execute(args, cli.global).await,
Commands::Search(args) => commands::search::execute(args, cli.global).await,
Commands::Graph(args) => commands::graph::execute(args, cli.global).await,
Commands::Components(cmd) => commands::components::execute(cmd, cli.global).await,
Commands::Workspace(cmd) => commands::workspace::execute(cmd, cli.global).await,
Commands::Status(args) => commands::status::execute(args, cli.global).await,
Commands::Doctor(args) => commands::doctor::execute(args, cli.global).await,
Commands::Clean(args) => commands::clean::execute(args, cli.global).await,
Commands::Backend(cmd) => commands::backend::execute(cmd, cli.global).await,
Commands::Config(cmd) => commands::config::execute(cmd, cli.global).await,
Commands::Mcp(args) => commands::mcp::execute(args, cli.global).await,
}
}