arcature-cli 2026.2.0

Developer lifecycle CLI for Arcature applications.
Documentation
//! `arc services` — list application services and their typed dependencies
//! (side-effect-free).
//!
//! Loads the metadata artifact (no application boot) and prints services with
//! their dependencies or JSON. Mirrors the `arc services` output contract
//! from PROGRAM.md §"arc services": service name, then one line per
//! dependency prefixed with `<-`. Supports `--json`.

use crate::cli::OutputFormat;
use crate::error::CommandError;
use crate::metadata::{ServiceEntry, Uag};
use crate::project;
use serde::Serialize;

pub(crate) fn execute(format: OutputFormat) -> Result<(), CommandError> {
    let project = project::discover()?;
    let artifact = crate::metadata::load(&project).map_err(CommandError::Metadata)?;
    let services: Vec<&ServiceEntry> = artifact.services.iter().collect();
    match format {
        OutputFormat::Human => print_human(&services),
        OutputFormat::Json => print_json(&artifact)?,
    }
    Ok(())
}

fn print_human(services: &[&ServiceEntry]) {
    if services.is_empty() {
        println!("no services registered");
        return;
    }
    for service in services {
        println!("{}", service.name);
        if service.deps.is_empty() {
            println!("  (no dependencies)");
        } else {
            for dep in &service.deps {
                println!("  <- {dep}");
            }
        }
    }
}

fn print_json(artifact: &Uag) -> Result<(), CommandError> {
    #[derive(Serialize)]
    struct Out<'a> {
        services: &'a [ServiceEntry],
    }
    println!(
        "{}",
        serde_json::to_string_pretty(&Out {
            services: &artifact.services
        })?
    );
    Ok(())
}