cellos-ctl 0.5.2

cellctl — kubectl-style CLI for CellOS execution cells and formations. Thin HTTP client over cellos-server with apply/get/describe/logs/events/webui.
Documentation
//! `cellctl config set-server <url>` / `set-token <token>` / `show`.

use crate::config::{self, Config};
use crate::exit::{CtlError, CtlResult};

pub fn set_server(url: &str) -> CtlResult<()> {
    // Validate URL shape before persisting — better to fail at config-set time
    // than confuse the user later with a HTTP error.
    let parsed = url::Url::parse(url).map_err(|e| CtlError::usage(format!("invalid url: {e}")))?;
    if !matches!(parsed.scheme(), "http" | "https") {
        return Err(CtlError::usage(format!(
            "url scheme must be http or https (got {})",
            parsed.scheme()
        )));
    }
    let mut cfg = config::load().unwrap_or_default();
    cfg.server_url = Some(url.to_string());
    config::save(&cfg)?;
    println!("server set to {}", url);
    Ok(())
}

pub fn set_token(token: &str) -> CtlResult<()> {
    if token.trim().is_empty() {
        return Err(CtlError::usage("token cannot be empty"));
    }
    let mut cfg = config::load().unwrap_or_default();
    cfg.api_token = Some(token.to_string());
    config::save(&cfg)?;
    println!("token saved to {}", config::config_path()?.display());
    Ok(())
}

pub fn show() -> CtlResult<()> {
    let cfg: Config = config::load().unwrap_or_default();
    println!("config_path: {}", config::config_path()?.display());
    println!("server_url:  {}", cfg.effective_server());
    println!(
        "api_token:   {}",
        match cfg.effective_token() {
            Some(_) => "<set>",
            None => "<unset>",
        }
    );
    Ok(())
}