diff --git a/crates/tui/src/tools/fim.rs b/crates/tui/src/tools/fim.rs index 0510a2c3b..f59dc53ba 100644 --- a/crates/tui/src/tools/fim.rs +++ b/crates/tui/src/tools/fim.rs @@ -94,8 +94,10 @@ impl ToolSpec for FimEditTool { } fn capabilities(&self) -> Vec { + // Writes the target file atomically (see execute step 7), so ReadOnly + // would be false; repo_law::WRITE_TOOLS also relies on this tool being + // recognized as write-capable. vec![ - ToolCapability::ReadOnly, ToolCapability::WritesFiles, ToolCapability::RequiresApproval, ] @@ -180,3 +182,24 @@ impl ToolSpec for FimEditTool { ToolResult::json(&result).map_err(|e| ToolError::execution_failed(e.to_string())) } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn fim_edit_declares_write_capability_without_read_only() { + let tool = FimEditTool::new(None, "fim-model".to_string()); + let capabilities = tool.capabilities(); + + assert!( + capabilities.contains(&ToolCapability::WritesFiles), + "fim_edit writes the target file atomically" + ); + assert!( + !capabilities.contains(&ToolCapability::ReadOnly), + "a file-writing tool must not claim ReadOnly" + ); + assert!(!tool.is_read_only()); + } +} diff --git a/crates/tui/src/tools/plan.rs b/crates/tui/src/tools/plan.rs index b1f1ca12f..68e1ce3c1 100644 --- a/crates/tui/src/tools/plan.rs +++ b/crates/tui/src/tools/plan.rs @@ -570,7 +570,8 @@ impl ToolSpec for UpdatePlanTool { } fn capabilities(&self) -> Vec { - vec![ToolCapability::WritesFiles] + // Mutates only in-memory session plan state; no filesystem writes. + vec![] } fn approval_requirement(&self) -> ApprovalRequirement { @@ -664,9 +665,24 @@ fn string_vec_field(input: &serde_json::Value, field: &str) -> Vec { #[cfg(test)] mod tests { use super::*; - use crate::tools::spec::{ToolContext, ToolSpec}; + use crate::tools::spec::{ToolCapability, ToolContext, ToolSpec}; use serde_json::json; + #[test] + fn update_plan_declares_no_filesystem_write_capability() { + let tool = UpdatePlanTool::new(new_shared_plan_state()); + let capabilities = tool.capabilities(); + + assert!( + !capabilities.contains(&ToolCapability::WritesFiles), + "update_plan mutates only in-memory session plan state" + ); + assert!( + !tool.is_read_only(), + "update_plan still mutates session state" + ); + } + #[test] fn update_plan_description_keeps_work_update_as_primary_progress() { let tool = UpdatePlanTool::new(new_shared_plan_state());