systemprompt-cli 0.1.18

systemprompt.io OS - CLI for agent orchestration, AI operations, and system management
Documentation
use crate::CliConfig;
use anyhow::{Result, anyhow};
use dialoguer::theme::ColorfulTheme;
use dialoguer::{Confirm, Select};

pub fn require_confirmation(
    message: &str,
    skip_confirmation: bool,
    config: &CliConfig,
) -> Result<()> {
    if skip_confirmation {
        return Ok(());
    }

    if !config.is_interactive() {
        return Err(anyhow!("--yes is required in non-interactive mode"));
    }

    let confirmed = Confirm::with_theme(&ColorfulTheme::default())
        .with_prompt(message)
        .default(false)
        .interact()?;

    if confirmed {
        Ok(())
    } else {
        Err(anyhow!("Operation cancelled"))
    }
}

pub fn require_confirmation_default_yes(
    message: &str,
    skip_confirmation: bool,
    config: &CliConfig,
) -> Result<()> {
    if skip_confirmation {
        return Ok(());
    }

    if !config.is_interactive() {
        return Err(anyhow!("--yes is required in non-interactive mode"));
    }

    let confirmed = Confirm::with_theme(&ColorfulTheme::default())
        .with_prompt(message)
        .default(true)
        .interact()?;

    if confirmed {
        Ok(())
    } else {
        Err(anyhow!("Operation cancelled"))
    }
}

pub fn resolve_required<T, F>(
    value: Option<T>,
    flag_name: &str,
    config: &CliConfig,
    prompt_fn: F,
) -> Result<T>
where
    F: FnOnce() -> Result<T>,
{
    match value {
        Some(v) => Ok(v),
        None if config.is_interactive() => prompt_fn(),
        None => Err(anyhow!(
            "--{} is required in non-interactive mode",
            flag_name
        )),
    }
}

pub fn select_from_list<T: ToString + Clone>(
    prompt: &str,
    items: &[T],
    flag_name: &str,
    config: &CliConfig,
) -> Result<T> {
    if items.is_empty() {
        return Err(anyhow!("No items available for selection"));
    }

    if !config.is_interactive() {
        return Err(anyhow!(
            "--{} is required in non-interactive mode",
            flag_name
        ));
    }

    let display: Vec<String> = items.iter().map(ToString::to_string).collect();

    let idx = Select::with_theme(&ColorfulTheme::default())
        .with_prompt(prompt)
        .items(&display)
        .default(0)
        .interact()?;

    Ok(items[idx].clone())
}

pub fn select_index(prompt: &str, items: &[&str], config: &CliConfig) -> Result<Option<usize>> {
    if !config.is_interactive() {
        return Ok(None);
    }

    let idx = Select::with_theme(&ColorfulTheme::default())
        .with_prompt(prompt)
        .items(items)
        .default(0)
        .interact()?;

    Ok(Some(idx))
}

pub fn prompt_input(prompt: &str, flag_name: &str, config: &CliConfig) -> Result<String> {
    if !config.is_interactive() {
        return Err(anyhow!(
            "--{} is required in non-interactive mode",
            flag_name
        ));
    }

    let input = dialoguer::Input::<String>::with_theme(&ColorfulTheme::default())
        .with_prompt(prompt)
        .interact_text()?;

    Ok(input)
}

pub fn prompt_input_with_default(
    prompt: &str,
    default: &str,
    config: &CliConfig,
) -> Result<String> {
    if !config.is_interactive() {
        return Ok(default.to_string());
    }

    let input = dialoguer::Input::<String>::with_theme(&ColorfulTheme::default())
        .with_prompt(prompt)
        .default(default.to_string())
        .interact_text()?;

    Ok(input)
}

pub fn confirm_optional(message: &str, default: bool, config: &CliConfig) -> Result<bool> {
    if !config.is_interactive() {
        return Ok(default);
    }

    let confirmed = Confirm::with_theme(&ColorfulTheme::default())
        .with_prompt(message)
        .default(default)
        .interact()?;

    Ok(confirmed)
}