systemprompt-cli 0.1.22

systemprompt.io OS - CLI for agent orchestration, AI operations, and system management
Documentation
use anyhow::{Context, Result, anyhow};
use clap::Args;

use super::types::{AgentDetailOutput, AgentListOutput, AgentSummary};
use crate::CliConfig;
use crate::shared::CommandResult;
use systemprompt_loader::ConfigLoader;

#[derive(Debug, Clone, Args)]
pub struct ListArgs {
    #[arg(help = "Agent name to show details (optional)")]
    pub name: Option<String>,

    #[arg(long, help = "Show only enabled agents")]
    pub enabled: bool,

    #[arg(long, help = "Show only disabled agents", conflicts_with = "enabled")]
    pub disabled: bool,
}

#[derive(Debug, serde::Serialize)]
#[serde(untagged)]
pub enum ListOrDetail {
    List(AgentListOutput),
    Detail(AgentDetailOutput),
}

pub fn execute(args: ListArgs, _config: &CliConfig) -> Result<CommandResult<ListOrDetail>> {
    let services_config = ConfigLoader::load().context("Failed to load services configuration")?;

    if let Some(name) = args.name {
        let agent = services_config
            .agents
            .get(&name)
            .ok_or_else(|| anyhow!("Agent '{}' not found", name))?;

        let output = AgentDetailOutput {
            name: agent.name.clone(),
            display_name: agent.card.display_name.clone(),
            description: agent.card.description.clone(),
            port: agent.port,
            endpoint: agent.endpoint.clone(),
            enabled: agent.enabled,
            provider: agent
                .metadata
                .provider
                .clone()
                .unwrap_or_else(|| "-".to_string()),
            model: agent
                .metadata
                .model
                .clone()
                .unwrap_or_else(|| "-".to_string()),
            mcp_servers: agent.metadata.mcp_servers.clone(),
            skills_count: agent.metadata.skills.len(),
        };

        return Ok(CommandResult::card(ListOrDetail::Detail(output))
            .with_title(format!("Agent: {}", name)));
    }

    let mut agents: Vec<AgentSummary> = services_config
        .agents
        .iter()
        .filter(|(_, agent)| {
            if args.enabled {
                agent.enabled
            } else if args.disabled {
                !agent.enabled
            } else {
                true
            }
        })
        .map(|(name, agent)| AgentSummary {
            name: name.clone(),
            display_name: agent.card.display_name.clone(),
            port: agent.port,
            enabled: agent.enabled,
            is_primary: agent.is_primary,
            is_default: agent.default,
        })
        .collect();

    agents.sort_by(|a, b| a.name.cmp(&b.name));

    let output = AgentListOutput { agents };

    Ok(CommandResult::table(ListOrDetail::List(output))
        .with_title("Agents")
        .with_columns(vec![
            "name".to_string(),
            "display_name".to_string(),
            "port".to_string(),
            "enabled".to_string(),
            "is_primary".to_string(),
            "is_default".to_string(),
        ]))
}