use clap::{Parser, Subcommand, ValueEnum};
use std::str::FromStr;
use crate::commit_reference::CommitReference;
#[derive(Copy, Clone, PartialEq, Eq, ValueEnum, Debug)]
pub enum VcsOverride {
Git,
Jj,
}
#[derive(Parser)]
#[command(name = "lumen")]
#[command(about = "AI-powered CLI tool for git commit summaries", long_about = None)]
#[command(version)]
pub struct Cli {
#[arg(long)]
pub config: Option<String>,
#[arg(value_enum, short = 'p', long = "provider")]
pub provider: Option<ProviderType>,
#[arg(short = 'k', long = "api-key")]
pub api_key: Option<String>,
#[arg(short = 'm', long = "model")]
pub model: Option<String>,
#[arg(value_enum, long = "vcs")]
pub vcs: Option<VcsOverride>,
#[command(subcommand)]
pub command: Commands,
}
#[derive(Copy, Clone, PartialEq, Eq, ValueEnum, Debug)]
pub enum ProviderType {
Openai,
Groq,
Claude,
Ollama,
OpencodeZen,
Openrouter,
Deepseek,
Gemini,
Xai,
Vercel,
}
impl FromStr for ProviderType {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_lowercase().as_str() {
"openai" => Ok(ProviderType::Openai),
"groq" => Ok(ProviderType::Groq),
"claude" => Ok(ProviderType::Claude),
"ollama" => Ok(ProviderType::Ollama),
"opencode-zen" => Ok(ProviderType::OpencodeZen),
"openrouter" => Ok(ProviderType::Openrouter),
"deepseek" => Ok(ProviderType::Deepseek),
"gemini" => Ok(ProviderType::Gemini),
"xai" => Ok(ProviderType::Xai),
"vercel" => Ok(ProviderType::Vercel),
_ => Err(format!("Unknown provider: {}", s)),
}
}
}
#[derive(Subcommand)]
pub enum Commands {
Explain {
#[arg(value_parser = clap::value_parser!(CommitReference))]
reference: Option<CommitReference>,
#[arg(long)]
staged: bool,
#[arg(short, long)]
query: Option<String>,
#[arg(long)]
list: bool,
},
List,
Draft {
#[arg(short, long)]
context: Option<String>,
},
Operate {
#[arg()]
query: String,
},
Diff {
#[arg(value_parser = clap::value_parser!(CommitReference))]
reference: Option<CommitReference>,
#[arg(long)]
pr: Option<String>,
#[arg(short, long)]
file: Option<Vec<String>>,
#[arg(short, long)]
watch: bool,
#[arg(short, long)]
theme: Option<String>,
#[arg(long)]
stacked: bool,
#[arg(long)]
focus: Option<String>,
},
Configure,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_vcs_git_parses() {
let cli = Cli::try_parse_from(["lumen", "--vcs", "git", "diff"]).unwrap();
assert_eq!(cli.vcs, Some(VcsOverride::Git));
}
#[test]
fn test_vcs_jj_parses() {
let cli = Cli::try_parse_from(["lumen", "--vcs", "jj", "diff"]).unwrap();
assert_eq!(cli.vcs, Some(VcsOverride::Jj));
}
#[test]
fn test_vcs_not_specified() {
let cli = Cli::try_parse_from(["lumen", "diff"]).unwrap();
assert_eq!(cli.vcs, None);
}
}