Refactor verdict handling and editor state management
- Removed the Escalate variant from the Verdict enum and associated parsing logic. - Cleaned up the EditorState struct by removing unused fields and methods. - Simplified MCP connection functions by removing unnecessary disconnect and handle dismiss functions. - Added tick count to MiscState for managing UI updates during processing. - Updated chat and status views to display a spinner during AI processing using the tick count. - Created a README.md file to document the project, its features, architecture, usage, key bindings, agent modes, security measures, installation instructions, and configuration details.
This commit is contained in:
@@ -2,7 +2,6 @@
|
||||
pub enum Verdict {
|
||||
Allow,
|
||||
Block(String),
|
||||
Escalate,
|
||||
}
|
||||
|
||||
pub struct Harness;
|
||||
@@ -80,7 +79,6 @@ mod tests {
|
||||
"block" => Some(Verdict::Block(
|
||||
v.get("reason").and_then(|r| r.as_str()).unwrap_or("blocked").to_string()
|
||||
)),
|
||||
"escalate" => Some(Verdict::Escalate),
|
||||
_ => None,
|
||||
};
|
||||
}
|
||||
@@ -153,12 +151,6 @@ mod tests {
|
||||
assert_eq!(v, Some(Verdict::Block("dangerous operation".to_string())));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_verdict_json_escalate() {
|
||||
let v = parse_verdict(r#"{"verdict": "escalate"}"#);
|
||||
assert_eq!(v, Some(Verdict::Escalate));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parse_verdict_text_allow() {
|
||||
let v = parse_verdict("Verdict: Allow");
|
||||
|
||||
@@ -8,16 +8,6 @@ pub struct EditorState {
|
||||
pub undo_stack: Vec<Vec<String>>,
|
||||
pub cursor_line: usize,
|
||||
pub cursor_col: usize,
|
||||
pub scroll_offset: usize,
|
||||
pub active: bool,
|
||||
pub mode: EditorMode,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum EditorMode {
|
||||
Normal,
|
||||
Insert,
|
||||
Visual,
|
||||
}
|
||||
|
||||
impl Default for EditorState {
|
||||
@@ -28,9 +18,6 @@ impl Default for EditorState {
|
||||
undo_stack: Vec::new(),
|
||||
cursor_line: 0,
|
||||
cursor_col: 0,
|
||||
scroll_offset: 0,
|
||||
active: false,
|
||||
mode: EditorMode::Normal,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,7 +28,6 @@ impl EditorState {
|
||||
EditorState {
|
||||
path,
|
||||
content,
|
||||
active: true,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
@@ -160,29 +146,6 @@ impl EditorState {
|
||||
pub fn as_string(&self) -> String {
|
||||
self.content.join("\n")
|
||||
}
|
||||
|
||||
pub fn close(&mut self) {
|
||||
self.active = false;
|
||||
}
|
||||
|
||||
pub fn toggle_mode(&mut self) {
|
||||
self.mode = match self.mode {
|
||||
EditorMode::Normal => EditorMode::Insert,
|
||||
EditorMode::Insert => EditorMode::Normal,
|
||||
EditorMode::Visual => EditorMode::Normal,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct AppEditorState {
|
||||
pub editor: Option<EditorState>,
|
||||
}
|
||||
|
||||
impl AppEditorState {
|
||||
pub fn new() -> Self {
|
||||
AppEditorState { editor: None }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_editor_input(state: &mut AppStateRest, text: String) {
|
||||
|
||||
@@ -1,17 +1,6 @@
|
||||
use crate::app::state::rest::AppStateRest;
|
||||
use crate::app::state::types::Overlay;
|
||||
|
||||
pub fn connect_mcp(state: &mut AppStateRest, server_name: &str) {
|
||||
let _ = server_name;
|
||||
state.dirty = true;
|
||||
}
|
||||
|
||||
pub fn disconnect_mcp(state: &mut AppStateRest, server_name: &str) {
|
||||
let _ = server_name;
|
||||
state.dirty = true;
|
||||
}
|
||||
|
||||
pub fn handle_mcp_dismiss(state: &mut AppStateRest) {
|
||||
state.misc.overlay = Overlay::None;
|
||||
state.dirty = true;
|
||||
}
|
||||
|
||||
@@ -275,6 +275,7 @@ pub fn apply_action(state: &mut AppStateRest, action: Action) {
|
||||
state.dirty = true;
|
||||
}
|
||||
Action::Tick => {
|
||||
state.misc.tick_count = state.misc.tick_count.wrapping_add(1);
|
||||
let now_ms = chrono::Utc::now().timestamp_millis();
|
||||
state.misc.drain_expired_toasts(now_ms);
|
||||
crate::app::review::maybe_run_staleness_sweep(state);
|
||||
@@ -693,12 +694,6 @@ fn run_agent_turn(
|
||||
Err(e) => (e.to_string(), true, false),
|
||||
},
|
||||
Verdict::Block(reason) => (format!("Blocked: {}", reason), true, false),
|
||||
Verdict::Escalate => (
|
||||
"Tool requires approval. Provide explicit approval."
|
||||
.to_string(),
|
||||
true,
|
||||
false,
|
||||
),
|
||||
};
|
||||
|
||||
if is_edit {
|
||||
|
||||
@@ -236,6 +236,7 @@ pub struct MiscState {
|
||||
pub selected_index: usize,
|
||||
pub editor: Option<super::super::mode::editor::EditorState>,
|
||||
pub api_connected: bool,
|
||||
pub tick_count: u64,
|
||||
}
|
||||
|
||||
impl MiscState {
|
||||
@@ -252,6 +253,7 @@ impl MiscState {
|
||||
selected_index: 0,
|
||||
editor: None,
|
||||
api_connected: false,
|
||||
tick_count: 0,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-2
@@ -83,10 +83,12 @@ pub fn draw_chat(frame: &mut Frame, area: Rect, state: &crate::app::state::rest:
|
||||
display_lines.push(Line::from(Span::raw("")));
|
||||
}
|
||||
|
||||
if state.misc.thinking {
|
||||
if state.turn_in_flight() {
|
||||
let spinner_frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
||||
let frame = spinner_frames[(state.misc.tick_count as usize / 2) % spinner_frames.len()];
|
||||
display_lines.push(Line::from(vec![
|
||||
Span::styled(" AI ", Style::default().fg(Theme::BG).bg(Theme::ROLE_ASSISTANT).add_modifier(Modifier::BOLD)),
|
||||
Span::styled(" Thinking...", Style::default().fg(Theme::DIM)),
|
||||
Span::styled(format!(" {} Generating...", frame), Style::default().fg(Theme::DIM)),
|
||||
]));
|
||||
display_lines.push(Line::from(Span::raw("")));
|
||||
}
|
||||
|
||||
+5
-3
@@ -10,12 +10,14 @@ pub fn draw_status_bar(frame: &mut Frame, area: Rect, state: &crate::app::state:
|
||||
// PROG → turn is in flight
|
||||
// READY → connected and ready
|
||||
// NOAPI → disconnected
|
||||
let spinner_frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
||||
let (agent_status, conn_color) = if state.turn_in_flight() {
|
||||
("PROG", Theme::MODE_YOLO)
|
||||
let frame = spinner_frames[(state.misc.tick_count as usize / 2) % spinner_frames.len()];
|
||||
(format!("{} PROG", frame), Theme::MODE_YOLO)
|
||||
} else if state.misc.api_connected {
|
||||
("READY", Theme::MODE_AUTO)
|
||||
("READY".to_string(), Theme::MODE_AUTO)
|
||||
} else {
|
||||
("NOAPI", Theme::DIM)
|
||||
("NOAPI".to_string(), Theme::DIM)
|
||||
};
|
||||
let status = Span::styled(
|
||||
format!(" {} ", agent_status),
|
||||
|
||||
Reference in New Issue
Block a user