pub mod accounts;
pub mod approve;
pub mod auth;
pub mod backup;
pub mod doctor;
pub mod init;
pub mod mcp;
pub mod restore;
pub mod run;
pub mod settings;
pub mod stats;
pub mod test;
pub mod tick;
pub mod uninstall;
pub mod update;
pub mod upgrade;
use clap::Args;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OutputFormat {
Text,
Json,
}
impl OutputFormat {
pub fn from_str(s: &str) -> Self {
match s {
"json" => Self::Json,
_ => Self::Text,
}
}
pub fn is_json(self) -> bool {
self == Self::Json
}
}
#[derive(Debug, Args)]
pub struct InitArgs {
#[arg(long)]
pub force: bool,
#[arg(long)]
pub non_interactive: bool,
#[arg(long)]
pub advanced: bool,
}
#[derive(Debug, Args)]
pub struct RunArgs {
#[arg(long, default_value = "0")]
pub status_interval: u64,
}
#[derive(Debug, Args)]
pub struct AuthArgs {
#[arg(long, value_parser = ["manual", "local_callback"])]
pub mode: Option<String>,
}
#[derive(Debug, Args)]
pub struct TestArgs;
#[derive(Debug, Args)]
pub struct DoctorArgs;
#[derive(Debug, Args)]
pub struct DiscoverArgs {
#[arg(long)]
pub dry_run: bool,
#[arg(long, default_value = "50")]
pub limit: u32,
}
#[derive(Debug, Args)]
pub struct MentionsArgs {
#[arg(long)]
pub dry_run: bool,
#[arg(long, default_value = "20")]
pub limit: u32,
}
#[derive(Debug, Args)]
pub struct PostArgs {
#[arg(long)]
pub dry_run: bool,
#[arg(long)]
pub topic: Option<String>,
}
#[derive(Debug, Args)]
pub struct ThreadArgs {
#[arg(long)]
pub dry_run: bool,
#[arg(long)]
pub topic: Option<String>,
#[arg(long)]
pub count: Option<u32>,
}
#[derive(Debug, Args)]
pub struct ScoreArgs {
pub tweet_id: String,
}
#[derive(Debug, Args)]
pub struct StatsArgs;
#[derive(Debug, Args)]
pub struct ApproveArgs {
#[arg(long)]
pub list: bool,
#[arg(long)]
pub approve: Option<i64>,
#[arg(long)]
pub reject: Option<i64>,
#[arg(long)]
pub approve_all: bool,
}
#[derive(Debug, Args)]
pub struct SettingsArgs {
#[arg(long)]
pub show: bool,
#[arg(long)]
pub set: Option<String>,
#[arg(value_name = "CATEGORY")]
pub category: Option<String>,
}
#[derive(Debug, Args)]
pub struct UpdateArgs {
#[arg(long)]
pub non_interactive: bool,
#[arg(long)]
pub check: bool,
#[arg(long)]
pub config_only: bool,
}
#[derive(Debug, Args)]
pub struct UpgradeArgs {
#[arg(long)]
pub non_interactive: bool,
}
#[derive(Debug, Args)]
pub struct TickArgs {
#[arg(long)]
pub dry_run: bool,
#[arg(long)]
pub ignore_schedule: bool,
#[arg(long, value_delimiter = ',')]
pub loops: Option<Vec<String>>,
#[arg(long)]
pub require_approval: bool,
}
#[derive(Debug, Args)]
pub struct BackupArgs {
#[arg(long)]
pub output_dir: Option<String>,
#[arg(long)]
pub list: bool,
#[arg(long)]
pub prune: Option<usize>,
}
#[derive(Debug, Args)]
pub struct RestoreArgs {
pub backup_path: String,
#[arg(long)]
pub force: bool,
#[arg(long)]
pub validate_only: bool,
}
#[derive(Debug, Args)]
pub struct UninstallArgs {
#[arg(long)]
pub force: bool,
#[arg(long)]
pub data_only: bool,
}
#[derive(Debug, Args)]
pub struct AccountsArgs {
#[command(subcommand)]
pub command: accounts::AccountsSubcommand,
}
#[derive(Debug, Args)]
pub struct McpArgs {
#[command(subcommand)]
pub command: McpSubcommand,
}
#[derive(Debug, clap::Subcommand)]
pub enum McpSubcommand {
Serve {
#[arg(long, default_value = "write")]
profile: String,
},
Manifest {
#[arg(long, default_value = "write")]
profile: String,
},
Setup,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn output_format_from_str_json() {
assert_eq!(OutputFormat::from_str("json"), OutputFormat::Json);
}
#[test]
fn output_format_from_str_text() {
assert_eq!(OutputFormat::from_str("text"), OutputFormat::Text);
}
#[test]
fn output_format_from_str_unknown_defaults_to_text() {
assert_eq!(OutputFormat::from_str("xml"), OutputFormat::Text);
assert_eq!(OutputFormat::from_str(""), OutputFormat::Text);
assert_eq!(OutputFormat::from_str("JSON"), OutputFormat::Text); }
#[test]
fn output_format_is_json() {
assert!(OutputFormat::Json.is_json());
assert!(!OutputFormat::Text.is_json());
}
#[test]
fn output_format_debug_impl() {
assert_eq!(format!("{:?}", OutputFormat::Json), "Json");
assert_eq!(format!("{:?}", OutputFormat::Text), "Text");
}
#[test]
fn output_format_clone_and_copy() {
let a = OutputFormat::Json;
let b = a; let c = a.clone(); assert_eq!(a, b);
assert_eq!(a, c);
}
#[test]
fn output_format_eq() {
assert_eq!(OutputFormat::Json, OutputFormat::Json);
assert_eq!(OutputFormat::Text, OutputFormat::Text);
assert_ne!(OutputFormat::Json, OutputFormat::Text);
}
#[test]
fn init_args_debug() {
let args = InitArgs {
force: true,
non_interactive: false,
advanced: true,
};
let debug = format!("{:?}", args);
assert!(debug.contains("force: true"));
assert!(debug.contains("advanced: true"));
}
#[test]
fn approve_args_debug() {
let args = ApproveArgs {
list: true,
approve: Some(42),
reject: None,
approve_all: false,
};
let debug = format!("{:?}", args);
assert!(debug.contains("list: true"));
assert!(debug.contains("42"));
}
#[test]
fn settings_args_debug() {
let args = SettingsArgs {
show: true,
set: Some("key=value".to_string()),
category: None,
};
let debug = format!("{:?}", args);
assert!(debug.contains("show: true"));
assert!(debug.contains("key=value"));
}
#[test]
fn backup_args_debug() {
let args = BackupArgs {
output_dir: Some("/tmp".to_string()),
list: false,
prune: Some(5),
};
let debug = format!("{:?}", args);
assert!(debug.contains("/tmp"));
assert!(debug.contains("5"));
}
#[test]
fn tick_args_debug() {
let args = TickArgs {
dry_run: true,
ignore_schedule: false,
loops: Some(vec!["discovery".to_string(), "content".to_string()]),
require_approval: false,
};
let debug = format!("{:?}", args);
assert!(debug.contains("dry_run: true"));
assert!(debug.contains("discovery"));
}
#[test]
fn update_args_debug() {
let args = UpdateArgs {
non_interactive: true,
check: false,
config_only: true,
};
let debug = format!("{:?}", args);
assert!(debug.contains("non_interactive: true"));
assert!(debug.contains("config_only: true"));
}
#[test]
fn upgrade_args_debug() {
let args = UpgradeArgs {
non_interactive: true,
};
let debug = format!("{:?}", args);
assert!(debug.contains("non_interactive: true"));
}
#[test]
fn restore_args_debug() {
let args = RestoreArgs {
backup_path: "/tmp/backup.db".to_string(),
force: true,
validate_only: false,
};
let debug = format!("{:?}", args);
assert!(debug.contains("/tmp/backup.db"));
assert!(debug.contains("force: true"));
}
#[test]
fn uninstall_args_debug() {
let args = UninstallArgs {
force: false,
data_only: true,
};
let debug = format!("{:?}", args);
assert!(debug.contains("data_only: true"));
}
}