a8e-acp 0.3.0

Articulate (a8e): The sovereign AI operator for your terminal.
use a8e_acp::server_factory::{AcpServer, AcpServerFactoryConfig};
use a8e_core::config::paths::Paths;
use anyhow::Result;
use clap::Parser;
use std::net::SocketAddr;
use std::sync::Arc;
use tracing::info;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter};

#[derive(Parser)]
#[command(name = "a8e-acp-server")]
#[command(about = "ACP server for a8e over HTTP and WebSocket")]
struct Cli {
    #[arg(long, default_value = "127.0.0.1")]
    host: String,

    #[arg(long, default_value = "3284")]
    port: u16,

    #[arg(long = "builtin", action = clap::ArgAction::Append)]
    builtins: Vec<String>,
}

#[tokio::main]
async fn main() -> Result<()> {
    let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info"));
    tracing_subscriber::registry()
        .with(filter)
        .with(tracing_subscriber::fmt::layer().with_target(true))
        .init();

    let cli = Cli::parse();

    let builtins = if cli.builtins.is_empty() {
        vec!["developer".to_string()]
    } else {
        cli.builtins
    };

    let server = Arc::new(AcpServer::new(AcpServerFactoryConfig {
        builtins,
        data_dir: Paths::data_dir(),
        config_dir: Paths::config_dir(),
    }));
    let router = a8e_acp::transport::create_router(server);

    let addr: SocketAddr = format!("{}:{}", cli.host, cli.port).parse()?;
    info!("Starting a8e-acp-server on {}", addr);

    let listener = tokio::net::TcpListener::bind(addr).await?;
    axum::serve(listener, router).await?;

    Ok(())
}