magi-code 0.61.0

Repository-aware CLI coding agent for terminal work
Documentation
use super::{AppError, AppResult, CliArgs};
use std::io::{self, IsTerminal};

fn usage_error(message: impl Into<String>) -> AppError {
    AppError::usage(anyhow::anyhow!(message.into()))
}

pub(super) fn validate_subcommand_launch(args: &CliArgs) -> AppResult<()> {
    if args.print {
        return Err(usage_error(
            "subcommands cannot be combined with --print; use one mode per invocation",
        ));
    }
    if args.tui || args.tui_experimental {
        return Err(usage_error(
            "subcommands cannot be combined with --tui or --tui-experimental; use one mode per invocation",
        ));
    }
    if args.dump_prompt {
        return Err(usage_error(
            "subcommands cannot be combined with --dump-prompt; use one mode per invocation",
        ));
    }
    if args.continue_session {
        return Err(usage_error(
            "subcommands cannot be combined with --continue; diagnostics do not attach to sessions",
        ));
    }
    if args.resume.is_some() {
        return Err(usage_error(
            "subcommands cannot be combined with --resume; diagnostics do not attach to sessions",
        ));
    }
    if args.no_session {
        return Err(usage_error(
            "subcommands cannot be combined with --no-session; diagnostics never create sessions",
        ));
    }
    if args.provider.is_some() {
        return Err(usage_error(
            "subcommands cannot be combined with --provider; diagnostics do not use provider auth",
        ));
    }
    if args.model.is_some() {
        return Err(usage_error(
            "subcommands cannot be combined with --model; diagnostics do not use provider models",
        ));
    }
    if args.api_key.is_some() {
        return Err(usage_error(
            "subcommands cannot be combined with --api-key; diagnostics do not authenticate",
        ));
    }
    if !args.prompt.is_empty() {
        return Err(usage_error(
            "subcommands do not accept trailing PROMPT arguments",
        ));
    }
    Ok(())
}

pub(super) fn validate_session_launch(args: &CliArgs) -> AppResult<()> {
    if args.no_session && (args.continue_session || args.resume.is_some()) {
        return Err(usage_error(
            "--no-session cannot be combined with --continue or --resume",
        ));
    }
    if args.continue_session && args.resume.is_some() {
        return Err(usage_error(
            "--continue cannot be combined with --resume; choose one session target",
        ));
    }
    Ok(())
}

pub(super) fn validate_dump_prompt_launch(args: &CliArgs) -> AppResult<()> {
    if !args.dump_prompt {
        return Ok(());
    }
    if args.provider.is_none() {
        return Err(usage_error(
            "--dump-prompt requires --provider with one of: anthropic, openai, openai-compatible, openai-codex, claude-code",
        ));
    }
    if args.print {
        return Err(usage_error(
            "--dump-prompt cannot be combined with --print; use one mode per invocation",
        ));
    }
    if args.tui || args.tui_experimental {
        return Err(usage_error(
            "--dump-prompt cannot be combined with --tui or --tui-experimental; use one mode per invocation",
        ));
    }
    if args.continue_session {
        return Err(usage_error(
            "--dump-prompt cannot be combined with --continue; dump mode never attaches to sessions",
        ));
    }
    if args.resume.is_some() {
        return Err(usage_error(
            "--dump-prompt cannot be combined with --resume; dump mode never attaches to sessions",
        ));
    }
    if args.no_session {
        return Err(usage_error(
            "--dump-prompt cannot be combined with --no-session; dump mode never creates sessions",
        ));
    }
    if args.model.is_some() {
        return Err(usage_error(
            "--dump-prompt cannot be combined with --model; provider schema target is selected by --provider",
        ));
    }
    if args.api_key.is_some() {
        return Err(usage_error(
            "--dump-prompt cannot be combined with --api-key; dump mode does not authenticate",
        ));
    }
    if !args.prompt.is_empty() {
        return Err(usage_error(
            "--dump-prompt does not accept trailing PROMPT arguments",
        ));
    }
    Ok(())
}

pub(super) fn validate_tui_launch(args: &CliArgs) -> AppResult<()> {
    if !args.tui && !args.tui_experimental {
        return Ok(());
    }
    if args.tui && args.tui_experimental {
        return Err(usage_error(
            "--tui and --tui-experimental cannot be combined; use one TUI mode per invocation",
        ));
    }
    let mode = if args.tui_experimental {
        "--tui-experimental"
    } else {
        "--tui"
    };
    if args.print {
        return Err(usage_error(format!(
            "{mode} cannot be combined with --print; use one mode per invocation"
        )));
    }
    if !args.prompt.is_empty() {
        return Err(usage_error(format!(
            "{mode} does not support trailing PROMPT arguments in the Phase 4 MVP; launch {mode} and type the prompt in Mission Control"
        )));
    }
    if args.tui_experimental {
        for (present, flag) in [
            (args.provider.is_some(), "--provider"),
            (args.model.is_some(), "--model"),
            (args.api_key.is_some(), "--api-key"),
            (args.continue_session, "--continue"),
            (args.resume.is_some(), "--resume"),
            (args.no_session, "--no-session"),
        ] {
            if present {
                return Err(usage_error(format!(
                    "{flag} is not supported with --tui-experimental; use --tui for agent execution"
                )));
            }
        }
    }
    let stdin_is_tty = io::stdin().is_terminal();
    let stdout_is_tty = io::stdout().is_terminal();
    if !stdin_is_tty || !stdout_is_tty {
        return Err(usage_error(format!(
            "{mode} requires both stdin and stdout to be TTYs; use classic mode or --print for pipes/non-interactive use"
        )));
    }
    Ok(())
}