pub mod commands;
pub mod debug_agent;
pub mod discord;
pub mod docs;
pub mod echo;
pub mod gcal;
pub mod help_agent;
pub mod lifecycle;
pub mod man;
pub mod onepass;
pub mod permissions;
pub mod service;
pub mod service_discord;
pub mod service_gcal;
pub mod service_list;
pub mod service_onepass;
pub mod service_slack;
pub mod service_spotify;
pub mod service_status;
pub mod service_telegram;
pub mod service_ymusic;
pub mod signing;
pub mod slack;
pub mod spotify;
pub mod telegram;
pub mod ymusic;
use clap::{Parser, Subcommand};
use zad::error::Result;
pub(crate) trait DialoguerExt<T> {
fn into_zad(self) -> Result<T>;
}
impl<T> DialoguerExt<T> for std::result::Result<T, dialoguer::Error> {
fn into_zad(self) -> Result<T> {
self.map_err(|e| zad::ZadError::Prompt(e.to_string()))
}
}
#[derive(Debug, Parser)]
#[command(
name = "zad",
version,
about = "Connect AI agents to external services via scoped service configs.",
disable_help_subcommand = true,
propagate_version = true
)]
pub struct Cli {
#[arg(long, global = true)]
pub debug: bool,
#[arg(long, global = true)]
pub help_agent: bool,
#[arg(long, global = true)]
pub debug_agent: bool,
#[arg(long, global = true)]
pub wait: bool,
#[command(subcommand)]
pub command: Option<Command>,
}
#[derive(Debug, Subcommand)]
pub enum Command {
Service(service::ServiceArgs),
#[command(name = "1pass")]
OnePass(onepass::OnePassArgs),
Discord(discord::DiscordArgs),
Gcal(gcal::GcalArgs),
Slack(slack::SlackArgs),
Spotify(spotify::SpotifyArgs),
Telegram(telegram::TelegramArgs),
Ymusic(ymusic::YmusicArgs),
Signing(signing::SigningArgs),
Commands(commands::CommandsArgs),
Docs(docs::DocsArgs),
Man(man::ManArgs),
}
fn rate_limit_service_for(cmd: &Command) -> Option<&'static str> {
match cmd {
Command::Discord(_) => Some("discord"),
Command::Gcal(_) => Some("gcal"),
Command::Slack(_) => Some("slack"),
Command::Spotify(_) => Some("spotify"),
Command::Telegram(_) => Some("telegram"),
Command::Ymusic(_) => Some("ymusic"),
Command::OnePass(_)
| Command::Service(_)
| Command::Signing(_)
| Command::Commands(_)
| Command::Docs(_)
| Command::Man(_) => None,
}
}
pub async fn run() -> Result<()> {
let cli = Cli::parse();
zad::logging::init(cli.debug);
if cli.help_agent {
print!("{}", help_agent::render());
return Ok(());
}
if cli.debug_agent {
print!("{}", debug_agent::render());
return Ok(());
}
if let Some(cmd) = cli.command.as_ref()
&& let Some(svc) = rate_limit_service_for(cmd)
{
zad::rate_limit::precall_check(svc, cli.wait).await?;
}
match cli.command {
Some(Command::Service(args)) => service::run(args).await,
Some(Command::OnePass(args)) => onepass::run(args).await,
Some(Command::Discord(args)) => discord::run(args).await,
Some(Command::Gcal(args)) => gcal::run(args).await,
Some(Command::Slack(args)) => slack::run(args).await,
Some(Command::Spotify(args)) => spotify::run(args).await,
Some(Command::Telegram(args)) => telegram::run(args).await,
Some(Command::Ymusic(args)) => ymusic::run(args).await,
Some(Command::Signing(args)) => signing::run(args),
Some(Command::Commands(args)) => commands::run(args),
Some(Command::Docs(args)) => docs::run(args),
Some(Command::Man(args)) => man::run(args),
None => {
println!("zad {}", zad::version());
println!("Run `zad --help` for usage.");
Ok(())
}
}
}