use crate::Claude;
use crate::command::ClaudeCommand;
use crate::error::Result;
use crate::exec::{self, CommandOutput};
#[derive(Debug, Clone, Default)]
pub struct AuthStatusCommand {
json: bool,
}
impl AuthStatusCommand {
#[must_use]
pub fn new() -> Self {
Self { json: true }
}
#[must_use]
pub fn text(mut self) -> Self {
self.json = false;
self
}
#[cfg(feature = "json")]
pub async fn execute_json(&self, claude: &Claude) -> Result<crate::types::AuthStatus> {
let mut cmd = self.clone();
cmd.json = true;
let output = exec::run_claude(claude, cmd.args()).await?;
serde_json::from_str(&output.stdout).map_err(|e| crate::error::Error::Json {
message: format!("failed to parse auth status: {e}"),
source: e,
})
}
}
impl ClaudeCommand for AuthStatusCommand {
type Output = CommandOutput;
fn args(&self) -> Vec<String> {
let mut args = vec!["auth".to_string(), "status".to_string()];
if self.json {
args.push("--json".to_string());
} else {
args.push("--text".to_string());
}
args
}
async fn execute(&self, claude: &Claude) -> Result<CommandOutput> {
exec::run_claude(claude, self.args()).await
}
}
#[derive(Debug, Clone, Default)]
pub struct AuthLoginCommand {
email: Option<String>,
sso: Option<String>,
}
impl AuthLoginCommand {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn email(mut self, email: impl Into<String>) -> Self {
self.email = Some(email.into());
self
}
#[must_use]
pub fn sso(mut self, provider: impl Into<String>) -> Self {
self.sso = Some(provider.into());
self
}
}
impl ClaudeCommand for AuthLoginCommand {
type Output = CommandOutput;
fn args(&self) -> Vec<String> {
let mut args = vec!["auth".to_string(), "login".to_string()];
if let Some(ref email) = self.email {
args.push("--email".to_string());
args.push(email.clone());
}
if let Some(ref sso) = self.sso {
args.push("--sso".to_string());
args.push(sso.clone());
}
args
}
async fn execute(&self, claude: &Claude) -> Result<CommandOutput> {
exec::run_claude(claude, self.args()).await
}
}
#[derive(Debug, Clone, Default)]
pub struct AuthLogoutCommand;
impl AuthLogoutCommand {
#[must_use]
pub fn new() -> Self {
Self
}
}
impl ClaudeCommand for AuthLogoutCommand {
type Output = CommandOutput;
fn args(&self) -> Vec<String> {
vec!["auth".to_string(), "logout".to_string()]
}
async fn execute(&self, claude: &Claude) -> Result<CommandOutput> {
exec::run_claude(claude, self.args()).await
}
}
#[derive(Debug, Clone, Default)]
pub struct SetupTokenCommand;
impl SetupTokenCommand {
#[must_use]
pub fn new() -> Self {
Self
}
}
impl ClaudeCommand for SetupTokenCommand {
type Output = CommandOutput;
fn args(&self) -> Vec<String> {
vec!["setup-token".to_string()]
}
async fn execute(&self, claude: &Claude) -> Result<CommandOutput> {
exec::run_claude(claude, self.args()).await
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_auth_status_args() {
let cmd = AuthStatusCommand::new();
assert_eq!(cmd.args(), vec!["auth", "status", "--json"]);
}
#[test]
fn test_auth_status_text() {
let cmd = AuthStatusCommand::new().text();
assert_eq!(cmd.args(), vec!["auth", "status", "--text"]);
}
#[test]
fn test_auth_login_default() {
let cmd = AuthLoginCommand::new();
assert_eq!(cmd.args(), vec!["auth", "login"]);
}
#[test]
fn test_auth_login_with_email() {
let cmd = AuthLoginCommand::new().email("user@example.com");
assert_eq!(
cmd.args(),
vec!["auth", "login", "--email", "user@example.com"]
);
}
#[test]
fn test_auth_login_with_sso() {
let cmd = AuthLoginCommand::new().sso("okta");
assert_eq!(cmd.args(), vec!["auth", "login", "--sso", "okta"]);
}
#[test]
fn test_auth_logout() {
let cmd = AuthLogoutCommand::new();
assert_eq!(cmd.args(), vec!["auth", "logout"]);
}
#[test]
fn test_setup_token() {
let cmd = SetupTokenCommand::new();
assert_eq!(cmd.args(), vec!["setup-token"]);
}
}