magi-code 0.96.1

Repository-aware CLI coding agent for terminal work
Documentation
//! Shared launch discovery and execution policy; no terminal or wire dependencies.
use crate::{
    cancellation::AgentCancellation,
    config::{AppearanceSettings, CliConfigOverrides, EffectiveConfig, McPaths, Settings},
    instructions::{InstructionFile, discover_agents_with_additional_markdown},
    primary_agents::{PrimaryAgentProfileDiscovery, resolve_persisted_primary_agent_selection},
    skills::{SkillDiscovery, SkillRoots, discover_skills, filter_enabled_skills},
};
use std::{
    collections::HashSet,
    path::PathBuf,
    sync::{Arc, Mutex},
};

pub(crate) struct LaunchContext {
    pub(crate) cwd: PathBuf,
    pub(crate) config: EffectiveConfig,
    pub(crate) settings: Settings,
    pub(crate) appearance_settings: AppearanceSettings,
    pub(crate) retention_days: u64,
    pub(crate) instructions: Vec<InstructionFile>,
    pub(crate) discovered_skills: SkillDiscovery,
    pub(crate) skills: SkillDiscovery,
}

impl LaunchContext {
    pub(crate) fn load(
        cwd: PathBuf,
        paths: McPaths,
        overrides: CliConfigOverrides,
    ) -> anyhow::Result<Self> {
        paths.ensure_runtime_dirs()?;
        let (config, settings, appearance_settings, session_settings) =
            crate::config::load_startup_config_with_settings(paths.clone(), overrides)?;
        let instructions = discover_agents_with_additional_markdown(
            &paths.user_agents,
            &cwd,
            &settings.instructions.additional_markdown_paths,
        )?;
        let mut roots = SkillRoots::from_paths(&paths.root, &cwd);
        roots.additional_paths = settings.skills.additional_paths.clone();
        let discovered_skills = discover_skills(&roots);
        let skills = filter_enabled_skills(
            &discovered_skills,
            &crate::config::disabled_skill_names_from_settings(&settings),
        );
        Ok(Self {
            cwd,
            config,
            settings,
            appearance_settings,
            retention_days: session_settings.retention_days,
            instructions,
            discovered_skills,
            skills,
        })
    }
}

#[derive(Debug, Clone)]
pub(crate) struct StartupPolicy {
    pub(crate) disabled_tools: HashSet<String>,
    pub(crate) disabled_subagent_profiles: HashSet<String>,
    pub(crate) skills: SkillDiscovery,
    pub(crate) subagent_profile_discovery: crate::subagents::profiles::SubagentProfileDiscovery,
    pub(crate) primary_agent_discovery: PrimaryAgentProfileDiscovery,
    pub(crate) selected_primary_agent: Option<String>,
    pub(crate) mcp: Option<Arc<Mutex<crate::mcp::manager::McpManager>>>,
}

#[derive(Debug)]
pub(crate) struct StartupFailure {
    #[cfg_attr(
        not(unix),
        expect(
            dead_code,
            reason = "structured startup codes belong to Unix local-agent protocol"
        )
    )]
    pub(crate) code: &'static str,
    pub(crate) detail: String,
}

impl std::fmt::Display for StartupFailure {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.write_str(&self.detail)
    }
}
impl std::error::Error for StartupFailure {}

pub(crate) fn bounded_startup_diagnostic(message: impl std::fmt::Display) -> String {
    const MAX_CHARS: usize = 512;
    let sanitized = crate::output::sanitize_display_text(&message.to_string());
    let normalized = sanitized.split_whitespace().collect::<Vec<_>>().join(" ");
    let mut bounded = normalized.chars().take(MAX_CHARS).collect::<String>();
    if normalized.chars().count() > MAX_CHARS {
        bounded.pop();
        bounded.push('…');
    }
    bounded
}

pub(crate) fn enabled_subagent_diagnostic(
    diagnostic: &crate::subagents::profiles::SubagentProfileDiagnostic,
    disabled: &HashSet<String>,
) -> bool {
    diagnostic.id.as_deref().is_some_and(|id| {
        crate::subagents::profiles::validate_subagent_identity_id(id).is_ok()
            && !disabled.contains(id)
    })
}

impl StartupPolicy {
    pub(crate) fn load(
        settings: &Settings,
        discovered_skills: &SkillDiscovery,
        paths: &McPaths,
        cancellation: &AgentCancellation,
    ) -> Result<Self, StartupFailure> {
        let failure = |code, detail| StartupFailure {
            code,
            detail: bounded_startup_diagnostic(detail),
        };
        cancellation
            .check()
            .map_err(|error| failure("startup_cancelled", error.to_string()))?;
        let disabled_tools = crate::config::disabled_tool_names_from_settings(settings)
            .into_iter()
            .collect();
        let disabled_subagent_profiles =
            crate::config::disabled_subagent_profile_names_from_settings(settings)
                .into_iter()
                .collect();
        let skills = filter_enabled_skills(
            discovered_skills,
            &crate::config::disabled_skill_names_from_settings(settings),
        );
        let subagent_profile_discovery =
            crate::subagents::profiles::discover_subagent_profiles(&paths.subagents);
        if let Some(diagnostic) = subagent_profile_discovery
            .diagnostics
            .iter()
            .find(|diagnostic| enabled_subagent_diagnostic(diagnostic, &disabled_subagent_profiles))
        {
            return Err(failure(
                "profile_invalid",
                format!(
                    "enabled subagent profile '{}' failed discovery: {}",
                    bounded_startup_diagnostic(diagnostic.id.as_deref().unwrap_or("<unknown>")),
                    diagnostic.message
                ),
            ));
        }
        let primary_agent_discovery =
            crate::primary_agents::discover_primary_agent_profiles(&paths.primary_agents);
        let selection = resolve_persisted_primary_agent_selection(
            settings.selected_primary_agent.as_deref(),
            &primary_agent_discovery.profiles,
        );
        if settings.selected_primary_agent.is_some() && selection.selected_id.is_none() {
            return Err(failure(
                "profile_invalid",
                format!(
                    "stored primary agent selection is unavailable: {}",
                    selection
                        .diagnostics
                        .first()
                        .map(|item| item.message.as_str())
                        .unwrap_or("stored primary agent selection is unavailable")
                ),
            ));
        }
        cancellation
            .check()
            .map_err(|error| failure("startup_cancelled", error.to_string()))?;
        let mcp = (!settings.mcp_servers.is_empty())
            .then(|| {
                crate::mcp::manager::McpManager::from_settings_strict_cancellable(
                    &settings.mcp_servers,
                    Some(&paths.root),
                    cancellation,
                )
                .map(|manager| Arc::new(Mutex::new(manager)))
            })
            .transpose()
            .map_err(|error| failure("mcp_unavailable", error.to_string()))?;
        Ok(Self {
            disabled_tools,
            disabled_subagent_profiles,
            skills,
            subagent_profile_discovery,
            primary_agent_discovery,
            selected_primary_agent: selection.selected_id,
            mcp,
        })
    }
}