use clap::{Parser, Subcommand};
use envconfig::Envconfig;
use crate::api;
use crate::agents;
use crate::swarms;
use crate::functions;
use crate::viewer;
use crate::schemas;
use crate::laboratories;
use crate::logs;
use crate::plugins;
use crate::vector;
use crate::instructions;
use crate::error;
#[derive(Envconfig)]
struct EnvConfigBuilder {
#[envconfig(from = "CONFIG_SET_FORBIDDEN")]
config_set_forbidden: Option<String>,
#[envconfig(from = "CONFIG_BASE_DIR")]
config_base_dir: Option<String>,
#[envconfig(from = "COMMIT_AUTHOR_NAME")]
commit_author_name: Option<String>,
#[envconfig(from = "COMMIT_AUTHOR_EMAIL")]
commit_author_email: Option<String>,
#[envconfig(from = "GITHUB_AUTHORIZATION")]
github_authorization: Option<String>,
}
impl EnvConfigBuilder {
pub fn build(self) -> ConfigBuilder {
fn parse_bool(s: &str) -> bool {
let v = s.trim();
!v.is_empty() && v != "0" && !v.eq_ignore_ascii_case("false")
}
ConfigBuilder {
config_set_forbidden: self.config_set_forbidden.map(|s| parse_bool(&s)),
config_base_dir: self.config_base_dir,
commit_author_name: self.commit_author_name,
commit_author_email: self.commit_author_email,
github_authorization: self.github_authorization,
}
}
}
#[derive(Default)]
pub struct ConfigBuilder {
pub config_set_forbidden: Option<bool>,
pub config_base_dir: Option<String>,
pub commit_author_name: Option<String>,
pub commit_author_email: Option<String>,
pub github_authorization: Option<String>,
}
impl Envconfig for ConfigBuilder {
#[allow(deprecated)]
fn init() -> Result<Self, envconfig::Error> {
EnvConfigBuilder::init().map(|e| e.build())
}
fn init_from_env() -> Result<Self, envconfig::Error> {
EnvConfigBuilder::init_from_env().map(|e| e.build())
}
fn init_from_hashmap(hashmap: &std::collections::HashMap<String, String>) -> Result<Self, envconfig::Error> {
EnvConfigBuilder::init_from_hashmap(hashmap).map(|e| e.build())
}
}
impl ConfigBuilder {
pub fn build(self) -> Config {
Config {
config_set_forbidden: self.config_set_forbidden.unwrap_or(false),
config_base_dir: self.config_base_dir,
commit_author_name: self.commit_author_name,
commit_author_email: self.commit_author_email,
github_authorization: self.github_authorization,
}
}
}
#[derive(Debug, Clone)]
pub struct Config {
pub config_set_forbidden: bool,
pub config_base_dir: Option<String>,
pub commit_author_name: Option<String>,
pub commit_author_email: Option<String>,
pub github_authorization: Option<String>,
}
#[derive(Parser)]
#[command(name = "objectiveai")]
#[command(about = "ObjectiveAI CLI")]
#[command(after_help = "\
JSON schemas for every public type are available via `objectiveai schemas`. \
Run `objectiveai schemas --help` to browse them, or pipe a specific schema \
into your tool of choice to drive structured-output generation.")]
struct Cli {
#[command(subcommand)]
command: Commands,
}
#[derive(Subcommand)]
enum Commands {
Api {
#[command(subcommand)]
command: api::Commands,
},
Agents {
#[command(subcommand)]
command: agents::Commands,
},
Swarms {
#[command(subcommand)]
command: swarms::Commands,
},
Functions {
#[command(subcommand)]
command: functions::Commands,
},
Viewer {
#[command(subcommand)]
command: viewer::Commands,
},
Schemas {
#[command(subcommand)]
command: schemas::Commands,
},
Laboratories {
#[command(subcommand)]
command: laboratories::Commands,
},
Vector {
#[command(subcommand)]
command: vector::Commands,
},
Logs {
#[command(subcommand)]
command: logs::Commands,
},
Instructions {
#[command(subcommand)]
command: instructions::Commands,
},
Plugins {
#[command(subcommand)]
command: plugins::Commands,
},
#[command(external_subcommand)]
External(Vec<String>),
}
impl Commands {
pub async fn handle(
self,
cli_config: &Config,
handle: &objectiveai_cli_sdk::output::Handle,
) -> Result<(), error::Error> {
match self {
Commands::Api { command } => command.handle(cli_config, handle).await,
Commands::Agents { command } => command.handle(cli_config, handle).await,
Commands::Swarms { command } => command.handle(cli_config, handle).await,
Commands::Functions { command } => command.handle(cli_config, handle).await,
Commands::Viewer { command } => command.handle(cli_config, handle).await,
Commands::Schemas { command } => command.handle(handle).await,
Commands::Laboratories { command } => command.handle(cli_config, handle).await,
Commands::Vector { command } => command.handle(cli_config, handle).await,
Commands::Logs { command } => command.handle(cli_config, handle).await,
Commands::Instructions { command } => command.handle(cli_config, handle).await,
Commands::Plugins { command } => command.handle(cli_config, handle).await,
Commands::External(args) => crate::plugins::dispatch_external(args, cli_config, handle).await,
}
}
}
pub fn load_config() -> Config {
ConfigBuilder::init_from_env().unwrap_or_default().build()
}
pub async fn run<I, T>(
args: I,
cli_config: &Config,
handle: objectiveai_cli_sdk::output::Handle,
) -> i32
where
I: IntoIterator<Item = T>,
T: Into<std::ffi::OsString> + Clone,
{
use objectiveai_cli_sdk::output::{Error as OutputError, Level, Output};
Output::<serde_json::Value>::Begin.emit(&handle).await;
let code = match Cli::try_parse_from(args) {
Ok(cli) => match cli.command.handle(cli_config, &handle).await {
Ok(()) => 0,
Err(e) => {
let err = e.to_output(Level::Error, true);
Output::<serde_json::Value>::Error(err).emit(&handle).await;
1
}
},
Err(e) => {
let err = OutputError {
level: Level::Error,
fatal: true,
message: e.to_string().into(),
};
Output::<serde_json::Value>::Error(err).emit(&handle).await;
1
}
};
Output::<serde_json::Value>::End.emit(&handle).await;
code
}