magi-code 0.63.4

Repository-aware CLI coding agent for terminal work
Documentation
use crate::commands::{BuiltInCommand, CommandRegistry, ParsedSlashCommand, parse_slash_command};

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(in crate::tui) enum SubmitDecision {
    Accept,
    IgnoreEmpty,
    QueueSteering,
}

#[derive(Debug, PartialEq, Eq)]
pub(in crate::tui) enum TuiSubmitCommand<'a> {
    Compact(Option<&'a str>),
    Changes,
    Rewind(Option<&'a str>),
    Help,
    Login(Option<&'a str>),
    Logout(Option<&'a str>),
    Model(Option<&'a str>),
    Models(Option<&'a str>),
    Usage(Option<&'a str>),
    Mcp(Option<&'a str>),
    Tools(Option<&'a str>),
    Subagents(Option<&'a str>),
    Skills,
    Sessions(Option<&'a str>),
    SystemPrompt,
    New,
    PruneSessions(Option<&'a str>),
    Quit,
    Unsupported(&'a str),
    None,
}

impl TuiSubmitCommand<'_> {
    pub(in crate::tui) fn requires_idle(&self) -> bool {
        matches!(
            self,
            Self::Compact(_)
                | Self::Rewind(_)
                | Self::Login(_)
                | Self::Logout(_)
                | Self::Model(_)
                | Self::Models(_)
                | Self::Usage(_)
                | Self::Mcp(_)
                | Self::Tools(_)
                | Self::Subagents(_)
                | Self::Skills
                | Self::Sessions(_)
                | Self::PruneSessions(_)
                | Self::New
        )
    }

    pub(in crate::tui) fn active_run_error(&self) -> Option<&'static str> {
        match self {
            Self::Compact(_) => Some("cannot compact while a prompt is running"),
            Self::Rewind(_) => Some("cannot rewind while a prompt is running"),
            Self::Login(_) => Some("cannot start login while a prompt is running"),
            Self::Logout(_) => Some("cannot logout while a prompt is running"),
            Self::Model(_) => Some("cannot change model while a prompt is running"),
            Self::Models(_) => Some("cannot manage models while a prompt is running"),
            Self::Usage(_) => Some("wait for the active run to finish before opening usage"),
            Self::Mcp(_) => Some("cannot manage MCP servers while a prompt is running"),
            Self::Tools(_) => Some("cannot manage tools while a prompt is running"),
            Self::Subagents(_) => Some("cannot manage subagents while a prompt is running"),
            Self::Skills => Some("cannot manage skills while a prompt is running"),
            Self::Sessions(_) => Some("cannot switch sessions while a prompt is running"),
            Self::PruneSessions(_) => Some("cannot prune sessions while a prompt is running"),
            Self::New => Some("cannot start a new session while a prompt is running"),
            Self::SystemPrompt
            | Self::Changes
            | Self::Help
            | Self::Quit
            | Self::Unsupported(_)
            | Self::None => None,
        }
    }
}

pub(in crate::tui) fn tui_submit_command<'a>(
    prompt: &'a str,
    commands: &CommandRegistry,
) -> TuiSubmitCommand<'a> {
    match parse_slash_command(prompt, commands) {
        ParsedSlashCommand::Empty | ParsedSlashCommand::Prompt(_) => TuiSubmitCommand::None,
        ParsedSlashCommand::Unknown { token } => TuiSubmitCommand::Unsupported(token),
        ParsedSlashCommand::BuiltIn { command, arg } => match command {
            BuiltInCommand::Help => TuiSubmitCommand::Help,
            BuiltInCommand::Login => TuiSubmitCommand::Login(arg),
            BuiltInCommand::Logout => TuiSubmitCommand::Logout(arg),
            BuiltInCommand::Compact => TuiSubmitCommand::Compact(arg),
            BuiltInCommand::Changes => TuiSubmitCommand::Changes,
            BuiltInCommand::Rewind => TuiSubmitCommand::Rewind(arg),
            BuiltInCommand::New => TuiSubmitCommand::New,
            BuiltInCommand::Model => TuiSubmitCommand::Model(arg),
            BuiltInCommand::Models => TuiSubmitCommand::Models(arg),
            BuiltInCommand::Usage => TuiSubmitCommand::Usage(arg),
            BuiltInCommand::Mcp => TuiSubmitCommand::Mcp(arg),
            BuiltInCommand::Tools => TuiSubmitCommand::Tools(arg),
            BuiltInCommand::Subagents => TuiSubmitCommand::Subagents(arg),
            BuiltInCommand::SystemPrompt => TuiSubmitCommand::SystemPrompt,
            BuiltInCommand::Skills => TuiSubmitCommand::Skills,
            BuiltInCommand::Sessions => TuiSubmitCommand::Sessions(arg),
            BuiltInCommand::PruneSessions => TuiSubmitCommand::PruneSessions(arg),
            BuiltInCommand::Quit => TuiSubmitCommand::Quit,
        },
    }
}

pub(in crate::tui) fn submit_decision(active_run: bool, prompt: &str) -> SubmitDecision {
    if prompt.trim().is_empty() {
        SubmitDecision::IgnoreEmpty
    } else if active_run {
        SubmitDecision::QueueSteering
    } else {
        SubmitDecision::Accept
    }
}

#[cfg(test)]
pub(in crate::tui) fn slash_command_token(prompt: &str) -> Option<&str> {
    match parse_slash_command(prompt, &CommandRegistry::mvp()) {
        ParsedSlashCommand::BuiltIn { command, .. } => Some(match command {
            BuiltInCommand::Help => "/help",
            BuiltInCommand::Login => "/login",
            BuiltInCommand::Logout => "/logout",
            BuiltInCommand::Compact => "/compact",
            BuiltInCommand::Changes => "/changes",
            BuiltInCommand::Rewind => "/rewind",
            BuiltInCommand::New => "/new",
            BuiltInCommand::Model => "/setmodel",
            BuiltInCommand::Models => "/models",
            BuiltInCommand::Usage => "/usage",
            BuiltInCommand::Mcp => "/mcp",
            BuiltInCommand::Tools => "/tools",
            BuiltInCommand::Subagents => "/subagents",
            BuiltInCommand::SystemPrompt => "/system-prompt",
            BuiltInCommand::Skills => "/skills",
            BuiltInCommand::Sessions => "/sessions",
            BuiltInCommand::PruneSessions => "/prune-sessions",
            BuiltInCommand::Quit => "/quit",
        }),
        ParsedSlashCommand::Unknown { token } => Some(token),
        ParsedSlashCommand::Empty | ParsedSlashCommand::Prompt(_) => None,
    }
}

#[cfg(test)]
pub(in crate::tui) fn is_new_session_command(prompt: &str) -> bool {
    matches!(
        tui_submit_command(prompt, &CommandRegistry::mvp()),
        TuiSubmitCommand::New
    )
}

#[cfg(test)]
pub(in crate::tui) fn is_quit_command(prompt: &str) -> bool {
    matches!(
        tui_submit_command(prompt, &CommandRegistry::mvp()),
        TuiSubmitCommand::Quit
    )
}

#[cfg(test)]
pub(in crate::tui) fn unsupported_slash_command(prompt: &str) -> Option<&str> {
    match tui_submit_command(prompt, &CommandRegistry::mvp()) {
        TuiSubmitCommand::Unsupported(command) => Some(command),
        _ => None,
    }
}