cersei_tools/
plan_mode.rs1use super::*;
4use std::sync::atomic::{AtomicBool, Ordering};
5
6static PLAN_MODE: AtomicBool = AtomicBool::new(false);
8
9pub fn is_plan_mode() -> bool {
11 PLAN_MODE.load(Ordering::Relaxed)
12}
13
14pub fn set_plan_mode(active: bool) {
16 PLAN_MODE.store(active, Ordering::Relaxed);
17}
18
19pub struct EnterPlanModeTool;
20
21#[async_trait]
22impl Tool for EnterPlanModeTool {
23 fn name(&self) -> &str {
24 "EnterPlanMode"
25 }
26 fn description(&self) -> &str {
27 "Enter plan mode: restricts to read-only tools for safe exploration and planning."
28 }
29 fn permission_level(&self) -> PermissionLevel {
30 PermissionLevel::None
31 }
32
33 fn input_schema(&self) -> Value {
34 serde_json::json!({
35 "type": "object",
36 "properties": {},
37 "required": []
38 })
39 }
40
41 async fn execute(&self, _input: Value, _ctx: &ToolContext) -> ToolResult {
42 PLAN_MODE.store(true, Ordering::Relaxed);
43 ToolResult::success("Plan mode activated. Only read-only tools are available.")
44 }
45}
46
47pub struct ExitPlanModeTool;
48
49#[async_trait]
50impl Tool for ExitPlanModeTool {
51 fn name(&self) -> &str {
52 "ExitPlanMode"
53 }
54 fn description(&self) -> &str {
55 "Exit plan mode and return to full tool access."
56 }
57 fn permission_level(&self) -> PermissionLevel {
58 PermissionLevel::None
59 }
60
61 fn input_schema(&self) -> Value {
62 serde_json::json!({
63 "type": "object",
64 "properties": {},
65 "required": []
66 })
67 }
68
69 async fn execute(&self, _input: Value, _ctx: &ToolContext) -> ToolResult {
70 PLAN_MODE.store(false, Ordering::Relaxed);
71 ToolResult::success("Plan mode deactivated. Full tool access restored.")
72 }
73}
74
75#[cfg(test)]
76mod tests {
77 use super::*;
78 use crate::permissions::AllowAll;
79 use std::sync::Arc;
80
81 fn test_ctx() -> ToolContext {
82 ToolContext {
83 working_dir: std::env::temp_dir(),
84 session_id: "test".into(),
85 permissions: Arc::new(AllowAll),
86 cost_tracker: Arc::new(CostTracker::new()),
87 mcp_manager: None,
88 extensions: Extensions::default(),
89 }
90 }
91
92 #[tokio::test]
93 async fn test_plan_mode_toggle() {
94 set_plan_mode(false);
95 assert!(!is_plan_mode());
96
97 let enter = EnterPlanModeTool;
98 enter.execute(serde_json::json!({}), &test_ctx()).await;
99 assert!(is_plan_mode());
100
101 let exit = ExitPlanModeTool;
102 exit.execute(serde_json::json!({}), &test_ctx()).await;
103 assert!(!is_plan_mode());
104 }
105}