Refactor scrolling methods in ScrollState to accept an amount parameter

- Updated `scroll_up` and `scroll_down` methods to take an `amount` parameter for more flexible scrolling.
- Removed the `AgentMode` enum and related methods from the types module to simplify state management.
- Modified `AppStateRest` to remove the `mode` field and adjusted related logic.
- Enhanced `run_subagent` to build tool definitions and handle API key resolution from configuration.
- Updated command parsing to reflect changes in login handling.
- Removed onboarding overlays and related logic from input handling and rendering.
- Improved status bar to reflect connection status and agent readiness.
- Adjusted workflow panel rendering to simplify phase status display.
- Refactored edit log initialization to load from disk if available.
- Updated settings structure to use a HashMap for API keys.
- Enhanced error handling in LlmClient for authentication issues.
This commit is contained in:
asepharyana
2026-07-12 03:14:52 +07:00
parent 71d3494372
commit 36573e7e3b
28 changed files with 435 additions and 482 deletions
+19 -54
View File
@@ -109,11 +109,7 @@ pub fn handle_key(key: KeyEvent, state: &mut AppStateRest) -> Vec<Action> {
} else if state.misc.overlay == Overlay::Effort {
mode::effort::cycle_effort(state);
Vec::new()
} else if state.misc.overlay == Overlay::OnboardProvider {
let n = mode::onboard_provider::PROVIDERS.len();
state.misc.selected_index = if state.misc.selected_index == 0 { n - 1 } else { state.misc.selected_index - 1 };
state.dirty = true;
Vec::new()
} else if state.misc.overlay == Overlay::Rewind {
let n = mode::rewind::rewind_count(state);
state.misc.selected_index = if state.misc.selected_index == 0 { n.saturating_sub(1) } else { state.misc.selected_index - 1 };
@@ -124,11 +120,7 @@ pub fn handle_key(key: KeyEvent, state: &mut AppStateRest) -> Vec<Action> {
state.misc.selected_index = if state.misc.selected_index == 0 { n.saturating_sub(1) } else { state.misc.selected_index - 1 };
state.dirty = true;
Vec::new()
} else if state.misc.overlay == Overlay::LoginPicker {
let n = crate::app::mode::onboard_provider::PROVIDERS.len();
state.misc.selected_index = if state.misc.selected_index == 0 { n.saturating_sub(1) } else { state.misc.selected_index - 1 };
state.dirty = true;
Vec::new()
} else {
vec![Action::ScrollUp]
}
@@ -143,11 +135,7 @@ pub fn handle_key(key: KeyEvent, state: &mut AppStateRest) -> Vec<Action> {
} else if state.misc.overlay == Overlay::Effort {
mode::effort::cycle_effort(state);
Vec::new()
} else if state.misc.overlay == Overlay::OnboardProvider {
let n = mode::onboard_provider::PROVIDERS.len();
state.misc.selected_index = (state.misc.selected_index + 1) % n;
state.dirty = true;
Vec::new()
} else if state.misc.overlay == Overlay::Rewind {
let n = mode::rewind::rewind_count(state);
state.misc.selected_index = if n == 0 { 0 } else { (state.misc.selected_index + 1) % n };
@@ -158,11 +146,7 @@ pub fn handle_key(key: KeyEvent, state: &mut AppStateRest) -> Vec<Action> {
state.misc.selected_index = if n == 0 { 0 } else { (state.misc.selected_index + 1) % n };
state.dirty = true;
Vec::new()
} else if state.misc.overlay == Overlay::LoginPicker {
let n = crate::app::mode::onboard_provider::PROVIDERS.len();
state.misc.selected_index = (state.misc.selected_index + 1) % n;
state.dirty = true;
Vec::new()
} else {
vec![Action::ScrollDown]
}
@@ -174,7 +158,9 @@ pub fn handle_key(key: KeyEvent, state: &mut AppStateRest) -> Vec<Action> {
vec![Action::ScrollDown]
}
KeyCode::Esc => {
if state.input.autocomplete_visible {
if state.turn_in_flight() {
vec![Action::AbortTurn]
} else if state.input.autocomplete_visible {
state.input.close_autocomplete();
state.dirty = true;
Vec::new()
@@ -232,7 +218,11 @@ fn handle_overlay_enter(state: &mut AppStateRest) -> Vec<Action> {
Overlay::KeyInput => {
let text = state.input.buffer.clone();
mode::key_input::handle_key_text(state, text.clone());
state.settings.api_key = if text.is_empty() { None } else { Some(text) };
if text.is_empty() {
state.settings.api_keys.remove(&state.settings.provider);
} else {
state.settings.api_keys.insert(state.settings.provider.clone(), text.clone());
}
let _ = state.settings.save();
state.input.buffer.clear();
state.input.cursor = 0;
@@ -244,26 +234,7 @@ fn handle_overlay_enter(state: &mut AppStateRest) -> Vec<Action> {
state.dirty = true;
Vec::new()
}
Overlay::Onboard => {
state.misc.overlay = Overlay::OnboardProvider;
state.misc.selected_index = 0;
state.dirty = true;
Vec::new()
}
Overlay::OnboardProvider => {
let idx = state.misc.selected_index.min(mode::onboard_provider::PROVIDERS.len() - 1);
let provider = mode::onboard_provider::PROVIDERS[idx];
mode::onboard_provider::set_provider(&mut state.settings, provider);
state.push_toast(crate::app::state::types::Toast::new(
crate::app::state::types::ToastKind::Info,
format!("Provider set to {}", provider),
));
state.misc.overlay = Overlay::KeyInput;
state.input.buffer.clear();
state.input.cursor = 0;
state.dirty = true;
Vec::new()
}
Overlay::Mcp => {
mode::mcp::connect_mcp(state, "");
Vec::new()
@@ -280,13 +251,11 @@ fn handle_overlay_enter(state: &mut AppStateRest) -> Vec<Action> {
let model = cfg.default_model.clone().unwrap_or_else(|| "claude-opus-4-8".to_string());
state.settings.provider = provider.clone();
state.settings.model = model.clone();
// Use the selected provider's default API key
state.settings.api_key = if let Some(ref key) = cfg.default_api_key {
Some(key.clone())
} else {
state.settings.api_key.clone().or_else(|| cfg.api_key_env.as_ref()
.and_then(|env| std::env::var(env).ok()))
};
if let Some(ref key) = cfg.default_api_key {
state.settings.api_keys.insert(provider.clone(), key.clone());
} else if let Some(env_key) = cfg.api_key_env.as_ref().and_then(|env| std::env::var(env).ok()) {
state.settings.api_keys.insert(provider.clone(), env_key);
}
let _ = state.settings.save();
state.push_toast(crate::app::state::types::Toast::new(
crate::app::state::types::ToastKind::Success,
@@ -307,11 +276,7 @@ fn handle_overlay_enter(state: &mut AppStateRest) -> Vec<Action> {
state.dirty = true;
Vec::new()
}
Overlay::LoginPicker => {
state.misc.overlay = Overlay::OnboardProvider;
state.dirty = true;
Vec::new()
}
_ => Vec::new(),
}
}