use super::traits::{Tool, ToolResult}; use crate::config::Config; use crate::cron; use async_trait::async_trait; use serde_json::json; use std::sync::Arc; pub struct CronRemoveTool { config: Arc, } impl CronRemoveTool { pub fn new(config: Arc) -> Self { Self { config } } } #[async_trait] impl Tool for CronRemoveTool { fn name(&self) -> &str { "cron_remove" } fn description(&self) -> &str { "Remove a cron job by id" } fn parameters_schema(&self) -> serde_json::Value { json!({ "type": "object", "properties": { "job_id": { "type": "string" } }, "required": ["job_id"] }) } async fn execute(&self, args: serde_json::Value) -> anyhow::Result { if !self.config.cron.enabled { return Ok(ToolResult { success: false, output: String::new(), error: Some("cron is disabled by config (cron.enabled=false)".to_string()), }); } let job_id = match args.get("job_id").and_then(serde_json::Value::as_str) { Some(v) if !v.trim().is_empty() => v, _ => { return Ok(ToolResult { success: false, output: String::new(), error: Some("Missing 'job_id' parameter".to_string()), }); } }; match cron::remove_job(&self.config, job_id) { Ok(()) => Ok(ToolResult { success: true, output: format!("Removed cron job {job_id}"), error: None, }), Err(e) => Ok(ToolResult { success: false, output: String::new(), error: Some(e.to_string()), }), } } } #[cfg(test)] mod tests { use super::*; use crate::config::Config; use tempfile::TempDir; fn test_config(tmp: &TempDir) -> Arc { let config = Config { workspace_dir: tmp.path().join("workspace"), config_path: tmp.path().join("config.toml"), ..Config::default() }; std::fs::create_dir_all(&config.workspace_dir).unwrap(); Arc::new(config) } #[tokio::test] async fn removes_existing_job() { let tmp = TempDir::new().unwrap(); let cfg = test_config(&tmp); let job = cron::add_job(&cfg, "*/5 * * * *", "echo ok").unwrap(); let tool = CronRemoveTool::new(cfg.clone()); let result = tool.execute(json!({"job_id": job.id})).await.unwrap(); assert!(result.success); assert!(cron::list_jobs(&cfg).unwrap().is_empty()); } #[tokio::test] async fn errors_when_job_id_missing() { let tmp = TempDir::new().unwrap(); let cfg = test_config(&tmp); let tool = CronRemoveTool::new(cfg); let result = tool.execute(json!({})).await.unwrap(); assert!(!result.success); assert!(result .error .unwrap_or_default() .contains("Missing 'job_id'")); } }