1use std::ffi::OsString;
2use std::process::ExitCode;
3
4use crate::cli::{print_help, Cli, Command};
5use crate::config::Config;
6use crate::error::ViaError;
7use crate::executor;
8use crate::providers::ProviderRegistry;
9
10pub fn run(args: impl IntoIterator<Item = OsString>) -> ExitCode {
11 crate::tls::install_crypto_provider();
12
13 match try_run(args) {
14 Ok(code) => code,
15 Err(ViaError::Clap(error)) => {
16 let exit_code = if error.use_stderr() { 2 } else { 0 };
17 if error.use_stderr() {
18 eprint!("{error}");
19 } else {
20 print!("{error}");
21 }
22 ExitCode::from(exit_code)
23 }
24 Err(error) => {
25 eprintln!("error: {error}");
26 ExitCode::from(error.exit_code())
27 }
28 }
29}
30
31fn try_run(args: impl IntoIterator<Item = OsString>) -> Result<ExitCode, ViaError> {
32 let cli = Cli::parse(args)?;
33
34 match cli.command {
35 Command::Help => {
36 print_help();
37 Ok(ExitCode::SUCCESS)
38 }
39 Command::Capabilities { json } => {
40 let config = Config::load(cli.config_path.as_deref())?;
41 crate::capabilities::print(&config, json)?;
42 Ok(ExitCode::SUCCESS)
43 }
44 Command::Config(command) => {
45 crate::config_command::run(cli.config_path.as_deref(), command)?;
46 Ok(ExitCode::SUCCESS)
47 }
48 Command::SkillPrint => {
49 let config = Config::load(cli.config_path.as_deref())?;
50 crate::skill::print(&config);
51 Ok(ExitCode::SUCCESS)
52 }
53 Command::Invoke {
54 service,
55 capability,
56 args,
57 } => {
58 let config = Config::load(cli.config_path.as_deref())?;
59 let providers = ProviderRegistry::from_config(&config)?;
60 executor::invoke(&config, &providers, &service, &capability, args)?;
61 Ok(ExitCode::SUCCESS)
62 }
63 }
64}
65
66#[cfg(test)]
67mod tests {
68 use super::*;
69
70 #[test]
71 fn capabilities_command_returns_success() {
72 let code = try_run([
73 OsString::from("via"),
74 OsString::from("--config"),
75 OsString::from("examples/github.toml"),
76 OsString::from("capabilities"),
77 ])
78 .unwrap();
79
80 assert_eq!(code, ExitCode::SUCCESS);
81 }
82}