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 CronListTool { config: Arc, } impl CronListTool { pub fn new(config: Arc) -> Self { Self { config } } } #[async_trait] impl Tool for CronListTool { fn name(&self) -> &str { "cron_list" } fn description(&self) -> &str { "List all scheduled cron jobs" } fn parameters_schema(&self) -> serde_json::Value { json!({ "type": "object", "properties": {}, "additionalProperties": false }) } 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()), }); } match cron::list_jobs(&self.config) { Ok(jobs) => Ok(ToolResult { success: true, output: serde_json::to_string_pretty(&jobs)?, 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; async fn test_config(tmp: &TempDir) -> Arc { let config = Config { workspace_dir: tmp.path().join("workspace"), config_path: tmp.path().join("config.toml"), ..Config::default() }; tokio::fs::create_dir_all(&config.workspace_dir) .await .unwrap(); Arc::new(config) } #[tokio::test] async fn returns_empty_list_when_no_jobs() { let tmp = TempDir::new().unwrap(); let cfg = test_config(&tmp).await; let tool = CronListTool::new(cfg); let result = tool.execute(json!({})).await.unwrap(); assert!(result.success); assert_eq!(result.output.trim(), "[]"); } #[tokio::test] async fn errors_when_cron_disabled() { let tmp = TempDir::new().unwrap(); let mut cfg = (*test_config(&tmp).await).clone(); cfg.cron.enabled = false; let tool = CronListTool::new(Arc::new(cfg)); let result = tool.execute(json!({})).await.unwrap(); assert!(!result.success); assert!(result .error .unwrap_or_default() .contains("cron is disabled")); } }