use super::super::*;
use super::{
MissionControlApp, PendingSessionSwitch,
actions::{ActionContext, AppControlFlow, TuiAction},
};
impl MissionControlApp {
fn start_session_switch_worker(
&mut self,
session_id: String,
ui_state: &mut state::MissionControlState,
) {
if self.pending_session_switch.is_some() {
ui_state.status = "session switch already loading".to_string();
return;
}
if self.active_run || self.worker.is_some() {
ui_state.status = "cannot switch sessions while a prompt is running".to_string();
return;
}
if self.state.active_session_id() == Some(session_id.as_str()) {
ui_state.close_session_picker();
ui_state.status = format!("session unchanged: {}", short_session_id(&session_id));
return;
}
self.next_session_switch_request_id = self.next_session_switch_request_id.saturating_add(1);
let request_id = self.next_session_switch_request_id;
self.pending_session_switch = Some(PendingSessionSwitch {
request_id,
session_id: session_id.clone(),
generation: self.session_generation,
});
ui_state.status = "loading session…".to_string();
let manager = self.state.session_manager.clone();
let config = self.state.config.clone();
let sender = self.events.clone();
thread::spawn(move || {
let result = start_session_switch_load(&manager, config.as_ref(), &session_id);
let _ = send_tui_event(
&sender,
TuiEvent::SessionSwitchLoaded {
request_id,
session_id,
result: Box::new(result),
},
);
});
}
pub(super) fn apply_input_action(
&mut self,
action: TuiAction,
ui_state: &mut state::MissionControlState,
context: &mut ActionContext<'_>,
) -> AppControlFlow {
let TuiAction::Input(action) = action;
match action {
input::InputAction::Submit(prompt) => {
self.submit(prompt, ui_state, context.receiver, context.last_area);
}
input::InputAction::SelectModel(model_id) => {
self.select_model(&model_id, ui_state);
}
input::InputAction::SelectSession(session_id) => {
self.start_session_switch_worker(session_id, ui_state);
}
input::InputAction::SetSkillEnabled { name, enabled } => {
self.set_skill_enabled(&name, enabled, ui_state);
refresh_skill_autocomplete_candidates(
context.autocomplete_candidates,
&self.skills,
);
}
input::InputAction::ToggleSkillsSettingsScope => {
self.toggle_skills_settings_scope(ui_state, context.last_area);
}
input::InputAction::SetMcpServerEnabled { name, enabled } => {
self.set_mcp_server_enabled(&name, enabled, ui_state);
}
input::InputAction::SetToolEnabled { name, enabled } => {
self.set_tool_enabled(&name, enabled, ui_state);
}
input::InputAction::ToggleToolsSettingsScope => {
self.toggle_tools_settings_scope(ui_state, context.last_area);
}
input::InputAction::SetSubagentProfileEnabled { id, enabled } => {
self.set_subagent_profile_enabled(&id, enabled, ui_state);
}
input::InputAction::ToggleSubagentsSettingsScope => {
self.toggle_subagents_settings_scope(ui_state, context.last_area);
}
input::InputAction::SetModelEnabled { id, enabled } => {
self.set_model_enabled(&id, enabled, ui_state);
}
input::InputAction::ToggleModelsSettingsScope => {
self.toggle_models_settings_scope(ui_state, context.last_area);
}
input::InputAction::PrimaryAgentSelectionChanged(selected_id) => {
self.persist_primary_agent_selection(selected_id.as_deref(), ui_state);
}
input::InputAction::ThinkingLevelSelectionChanged(level) => {
self.persist_thinking_level(level, ui_state);
}
input::InputAction::SelectLoginProvider(provider_id) => {
self.start_login(&provider_id, ui_state);
}
input::InputAction::SelectLogoutProvider(provider_id) => {
self.logout_provider(&provider_id, ui_state);
}
input::InputAction::SubmitLoginFallback(input) => {
self.submit_login_fallback(input, ui_state);
}
input::InputAction::SubmitCustomProviderSetupStep => {
self.submit_custom_provider_setup_step(ui_state);
}
input::InputAction::CopyLoginUrl => {
if let Some(url) = ui_state
.modals
.active_login
.as_ref()
.map(|login| login.url.clone())
{
apply_copy_request(&url, ui_state, context.clipboard, Instant::now());
}
}
input::InputAction::OpenLoginUrl => {
ui_state.status = match ui_state
.modals
.active_login
.as_ref()
.map(|login| login.url.as_str())
{
Some(url) if !url.is_empty() => match open_url_in_browser(url) {
Ok(()) => "opened OAuth URL in browser".to_string(),
Err(error) => {
format!("could not open browser: {error}; press [Ctrl-Y] to copy URL")
}
},
_ => "OAuth URL is not ready yet".to_string(),
};
}
input::InputAction::CancelLogin => {
if ui_state.modals.custom_provider_setup.is_some() {
ui_state.clear_custom_provider_setup();
ui_state.status =
"custom provider setup cancelled; settings unchanged".to_string();
} else if let Some(status) = self.cancel_active_worker(ui_state) {
ui_state.status = status;
ui_state.clear_active_login();
} else {
ui_state.status =
"OpenAI Codex login cancelled; credentials unchanged".to_string();
ui_state.clear_active_login();
}
}
input::InputAction::ConfirmLogout(provider_id) => {
self.remove_logout_provider(&provider_id, ui_state);
}
input::InputAction::CancelLogout => {
ui_state.status = "logout cancelled; credentials unchanged".to_string();
}
input::InputAction::ConfirmCustomProviderReplacement => {
self.confirm_custom_provider_replacement(ui_state);
}
input::InputAction::CancelCustomProviderReplacement => {
ui_state.clear_custom_provider_setup();
ui_state.status =
"custom provider replacement cancelled; existing provider unchanged"
.to_string();
}
input::InputAction::ConfirmRewind => {
if let Some(plan) = ui_state.take_rewind_plan() {
let store = crate::checkpoints::CheckpointStore::from_paths(&self.config.paths);
let execution = store.execute_plan(&plan, &self.state.cwd);
let _ = record_session_event(
self.state.current_session.as_ref(),
&self.state.cwd,
SessionEventKind::Rewind,
crate::checkpoints::rewind_event_payload(&plan, &execution),
);
ui_state.status =
format!("rewind complete: {} operation(s)", execution.results.len());
ui_state.open_rewind_modal(
crate::shell::format_rewind_execution_for_tui(&execution),
None,
true,
);
}
}
input::InputAction::CancelRewind => {
ui_state.status = "rewind cancelled".to_string();
}
input::InputAction::CancelRunningPrompt => {
self.cancel_running_prompt(ui_state);
}
input::InputAction::OpenSetModel => {
if self.active_run || self.worker.is_some() {
ui_state.status = "cannot change model while a prompt is running".to_string();
} else {
self.open_model_picker(ui_state, context.last_area);
}
}
input::InputAction::Exit => {
if let Some(status) = self.cancel_active_worker(ui_state) {
ui_state.status = status;
}
self.join_worker_with_timeout(ui_state, WORKER_EXIT_JOIN_TIMEOUT);
return AppControlFlow::Exit;
}
input::InputAction::None => {}
}
AppControlFlow::Continue
}
}