fundaia 0.53.0

Command line for the Fundaia deployment platform: projects, services, variables, deployments, logs and metrics
use anyhow::Result;
use owo_colors::OwoColorize;

use crate::output::{self, Format};
use crate::render::markdown;
use crate::render::theme;

pub const GUIDE: &str = include_str!("../../AGENT.md");

pub fn run(format: Format) -> Result<()> {
    if format.is_json() {
        output::emit(&serde_json::json!({
            "version": env!("CARGO_PKG_VERSION"),
            "markdown": GUIDE,
        }));
        return Ok(());
    }

    println!();
    println!("{}", markdown::body(GUIDE));
    println!();
    println!(
        "  {}",
        "`fundaia schema --json` es la superficie entera, comando por comando."
            .style(theme::muted()),
    );
    println!();
    Ok(())
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn it_should_warn_that_creating_a_service_deploys_it() {
        assert!(GUIDE.contains("Creating a service deploys it."));
    }

    #[test]
    fn it_should_say_what_the_exit_codes_mean() {
        assert!(GUIDE.contains("The exit code says which kind of failure it was"));
    }

    #[test]
    fn it_should_send_a_caller_that_speaks_mcp_to_the_instance_instead() {
        assert!(GUIDE.contains("/api/infra/mcp"));
    }

    #[test]
    fn it_should_say_that_nothing_ever_prompts() {
        assert!(GUIDE.contains("Nothing ever prompts."));
    }

    #[test]
    fn it_should_say_that_a_confirmation_is_the_name_and_not_a_yes() {
        assert!(GUIDE.contains("the name of the\n  thing, not a `yes`"));
    }

    #[test]
    fn it_should_close_every_delimiter_on_the_line_that_opened_it() {
        let wrapped: Vec<&str> = GUIDE
            .lines()
            .filter(|line| line.matches('`').count() % 2 != 0 || unbalanced_bold(line))
            .collect();

        assert_eq!(wrapped, Vec::<&str>::new());
    }

    fn unbalanced_bold(line: &str) -> bool {
        line.matches("**").count() % 2 != 0
    }

    #[test]
    fn it_should_name_no_command_the_parser_does_not_accept() {
        let parser = crate::built();
        let invented: Vec<&str> = commands_named_in(GUIDE)
            .into_iter()
            .filter(|named| {
                !parser
                    .get_subcommands()
                    .any(|command| command.get_name() == *named)
            })
            .collect();

        assert_eq!(invented, Vec::<&str>::new());
    }

    fn commands_named_in(text: &str) -> Vec<&str> {
        text.split("fundaia ")
            .skip(1)
            .filter_map(|after| after.split([' ', '`', '\n', ',', '.']).next())
            .filter(|word| !word.is_empty() && !word.starts_with('<'))
            .collect()
    }
}