magi-code 0.96.1

Repository-aware CLI coding agent for terminal work
Documentation
use super::{MissionControlApp, state};
use crate::auth::ProviderCredential;

impl MissionControlApp {
    /// Called after terminal restoration and worker cleanup, while still owning
    /// the writer. Materialize an empty session with a lifecycle diagnostic
    /// so --resume can reopen its exact ID.
    pub(crate) fn finish_update_handoff(
        &mut self,
    ) -> anyhow::Result<Option<crate::updates::RestartContext>> {
        if self.update_restart.is_some()
            && let Some(session) = &self.state.current_session
            && !session.path().try_exists()?
        {
            session.append_with_outcome(&crate::sessions::SessionEvent::new_kind(
                crate::sessions::SessionEventKind::Diagnostic,
                session.id().to_owned(),
                self.state.cwd.clone(),
                serde_json::json!({"lifecycle": "created"}),
            ))?;
        }
        Ok(self.update_restart.take())
    }

    pub(super) fn request_update(
        &mut self,
        argument: Option<&str>,
        ui_state: &mut state::MissionControlState,
    ) -> bool {
        if argument.is_some() {
            ui_state.status = "usage: /update (no arguments)".into();
            return false;
        }
        if self.active_run
            || self.worker.is_some()
            || self.side.is_pending()
            || self.pending_session_switch.is_some()
            || self.pending_rewind.is_some()
            || self.pending_export.is_some()
            || self.pending_model_selection.is_some()
            || self.pending_theme_save.is_some()
            || self.settings_persistence.is_pending()
            || self.fast_mode_persistence.is_pending()
            || self.session_maintenance.is_pruning()
            || self.pending_startup_prompt.is_some()
        {
            ui_state.status = "Wait for the current work to finish before /update.".into();
            return false;
        }
        let mut command = std::process::Command::new("magi-code");
        command
            .current_dir(&self.state.cwd)
            .env("MC_HOME", &self.config.paths.root);
        if let Some(session_id) = self.state.active_session_id() {
            command.arg("--resume").arg(session_id);
        } else {
            command.arg("--no-session");
        }
        command.arg("--update-restart");
        if let Some(provider) = &self.config.provider {
            command.arg("--provider").arg(provider);
        }
        if let Some(model) = &self.config.model {
            command.arg("--model").arg(model);
        }
        if self.theme_cli_override {
            command.arg("--theme").arg(&self.appearance.theme.id);
        }
        // Credentials are never placed in argv or a restart file. OAuth remains
        // provider-keyed in its normal store; API keys use the provider's own env.
        if let Some(ProviderCredential::ApiKey { key }) = &self.config.auth {
            let provider = self.config.provider.as_deref().unwrap_or_default();
            let variable = if provider == crate::providers::ANTHROPIC_PROVIDER {
                Some("ANTHROPIC_API_KEY")
            } else {
                self.config
                    .custom_providers
                    .get(provider)
                    .and_then(|provider| provider.api_key_env_var.as_deref())
            };
            let Some(variable) = variable else {
                ui_state.status =
                    "Cannot safely preserve this credential; use --update outside Mission Control."
                        .into();
                return false;
            };
            command.env(variable, key);
        }
        let session = self
            .state
            .active_session_id()
            .map(|id| (self.config.paths.sessions.clone(), id.to_owned()));
        self.update_restart = Some(crate::updates::RestartContext { command, session });
        true
    }
}