Skip to main content

aster/tools/
three_files_tool.rs

1use async_trait::async_trait;
2use serde::{Deserialize, Serialize};
3use std::fs;
4use std::path::Path;
5
6use crate::tools::{Tool, ToolContext, ToolError, ToolResult};
7
8/// 三阶段工作流工具 - 基于 planning-with-files 的核心机制
9///
10/// 核心理念:文件系统作为持久化记忆 (Context Window = RAM, Filesystem = Disk)
11/// 三阶段工作流:Pre-Action → Action → Post-Action
12///
13/// 功能:
14/// 1. 自动化上下文工程 - 防止目标漂移和上下文丢失
15/// 2. 错误学习机制 - 3次错误协议,永不重复失败
16/// 3. 2-Action 规则 - 每2次视觉操作后立即保存发现
17/// 4. 阶段完成验证 - 确保工作流完整性
18#[derive(Debug, Clone, Serialize, Deserialize)]
19pub struct ThreeStageWorkflowTool {
20    name: String,
21    description: String,
22}
23
24impl Default for ThreeStageWorkflowTool {
25    fn default() -> Self {
26        Self {
27            name: "three_stage_workflow".to_string(),
28            description: "Implements three-stage workflow pattern for complex tasks. Manages task_plan.md, findings.md, and progress.md with automated context engineering and error learning.".to_string(),
29        }
30    }
31}
32
33#[derive(Debug, Clone, Serialize, Deserialize)]
34pub struct WorkflowParams {
35    pub action: String,
36    pub project_name: Option<String>,
37    pub phase_update: Option<PhaseUpdate>,
38    pub finding: Option<String>,
39    pub progress_entry: Option<String>,
40    pub error_info: Option<ErrorInfo>,
41    pub decision: Option<DecisionInfo>,
42}
43
44#[derive(Debug, Clone, Serialize, Deserialize)]
45pub struct PhaseUpdate {
46    pub phase_number: u32,
47    pub status: String, // "pending", "in_progress", "complete"
48    pub notes: Option<String>,
49}
50
51#[derive(Debug, Clone, Serialize, Deserialize)]
52pub struct ErrorInfo {
53    pub error_description: String,
54    pub attempt_number: u32,
55    pub resolution: Option<String>,
56}
57
58#[derive(Debug, Clone, Serialize, Deserialize)]
59pub struct DecisionInfo {
60    pub decision: String,
61    pub rationale: String,
62}
63
64#[async_trait]
65impl Tool for ThreeStageWorkflowTool {
66    fn name(&self) -> &str {
67        &self.name
68    }
69
70    fn description(&self) -> &str {
71        &self.description
72    }
73
74    fn input_schema(&self) -> serde_json::Value {
75        serde_json::json!({
76            "type": "object",
77            "properties": {
78                "action": {
79                    "type": "string",
80                    "enum": [
81                        "init_workflow",
82                        "pre_action_check",
83                        "post_action_update",
84                        "update_phase",
85                        "add_finding",
86                        "add_progress",
87                        "log_error",
88                        "log_decision",
89                        "check_completion",
90                        "apply_2action_rule"
91                    ],
92                    "description": "Workflow action: init_workflow (create files), pre_action_check (read plan before action), post_action_update (update after action), update_phase (change phase status), add_finding (save discovery), add_progress (log action), log_error (track error), log_decision (record decision), check_completion (verify all phases complete), apply_2action_rule (save findings after 2 visual operations)"
93                },
94                "project_name": {
95                    "type": "string",
96                    "description": "Name of the project (used for init_workflow action)"
97                },
98                "phase_update": {
99                    "type": "object",
100                    "properties": {
101                        "phase_number": {
102                            "type": "integer",
103                            "description": "Phase number to update (1-5)"
104                        },
105                        "status": {
106                            "type": "string",
107                            "enum": ["pending", "in_progress", "complete"],
108                            "description": "New status for the phase"
109                        },
110                        "notes": {
111                            "type": "string",
112                            "description": "Optional notes about the phase update"
113                        }
114                    },
115                    "required": ["phase_number", "status"]
116                },
117                "finding": {
118                    "type": "string",
119                    "description": "Finding or discovery to add to findings.md (use after visual operations)"
120                },
121                "progress_entry": {
122                    "type": "string",
123                    "description": "Progress entry to add to progress.md"
124                },
125                "error_info": {
126                    "type": "object",
127                    "properties": {
128                        "error_description": {
129                            "type": "string",
130                            "description": "Description of the error encountered"
131                        },
132                        "attempt_number": {
133                            "type": "integer",
134                            "description": "Which attempt this was (1, 2, 3)"
135                        },
136                        "resolution": {
137                            "type": "string",
138                            "description": "How the error was resolved (if resolved)"
139                        }
140                    },
141                    "required": ["error_description", "attempt_number"]
142                },
143                "decision": {
144                    "type": "object",
145                    "properties": {
146                        "decision": {
147                            "type": "string",
148                            "description": "The decision made"
149                        },
150                        "rationale": {
151                            "type": "string",
152                            "description": "The reasoning behind the decision"
153                        }
154                    },
155                    "required": ["decision", "rationale"]
156                }
157            },
158            "required": ["action"]
159        })
160    }
161
162    async fn execute(
163        &self,
164        params: serde_json::Value,
165        _context: &ToolContext,
166    ) -> Result<ToolResult, ToolError> {
167        let params: WorkflowParams =
168            serde_json::from_value(params).map_err(|e| ToolError::invalid_params(e.to_string()))?;
169
170        match params.action.as_str() {
171            "init_workflow" => self.init_workflow(params.project_name.as_deref()),
172            "pre_action_check" => self.pre_action_check(),
173            "post_action_update" => self.post_action_update(),
174            "update_phase" => {
175                if let Some(phase_update) = params.phase_update {
176                    self.update_phase(phase_update)
177                } else {
178                    Err(ToolError::invalid_params(
179                        "phase_update required for update_phase action",
180                    ))
181                }
182            }
183            "add_finding" => {
184                if let Some(finding) = params.finding {
185                    self.add_finding(&finding)
186                } else {
187                    Err(ToolError::invalid_params(
188                        "finding required for add_finding action",
189                    ))
190                }
191            }
192            "add_progress" => {
193                if let Some(progress_entry) = params.progress_entry {
194                    self.add_progress(&progress_entry)
195                } else {
196                    Err(ToolError::invalid_params(
197                        "progress_entry required for add_progress action",
198                    ))
199                }
200            }
201            "log_error" => {
202                if let Some(error_info) = params.error_info {
203                    self.log_error(error_info)
204                } else {
205                    Err(ToolError::invalid_params(
206                        "error_info required for log_error action",
207                    ))
208                }
209            }
210            "log_decision" => {
211                if let Some(decision) = params.decision {
212                    self.log_decision(decision)
213                } else {
214                    Err(ToolError::invalid_params(
215                        "decision required for log_decision action",
216                    ))
217                }
218            }
219            "check_completion" => self.check_completion(),
220            "apply_2action_rule" => {
221                if let Some(finding) = params.finding {
222                    self.apply_2action_rule(&finding)
223                } else {
224                    Err(ToolError::invalid_params(
225                        "finding required for apply_2action_rule action",
226                    ))
227                }
228            }
229            _ => Err(ToolError::invalid_params(format!(
230                "Unknown action: {}",
231                params.action
232            ))),
233        }
234    }
235}
236
237impl ThreeStageWorkflowTool {
238    /// 初始化三阶段工作流文件
239    fn init_workflow(&self, project_name: Option<&str>) -> Result<ToolResult, ToolError> {
240        let project_name = project_name.unwrap_or("project");
241        let date = chrono::Utc::now().format("%Y-%m-%d").to_string();
242
243        // 创建 task_plan.md - 核心规划文件
244        let task_plan_content = format!(
245            r#"# Task Plan: {}
246
247## Goal
248[One sentence describing the end state]
249
250## Current Phase
251Phase 1
252
253## Phases
254
255### Phase 1: Requirements & Discovery
256- [ ] Understand user intent and requirements
257- [ ] Identify constraints and dependencies
258- [ ] Document findings in findings.md
259- **Status:** in_progress
260
261### Phase 2: Planning & Structure
262- [ ] Define technical approach and architecture
263- [ ] Create project structure if needed
264- [ ] Document key decisions with rationale
265- **Status:** pending
266
267### Phase 3: Implementation
268- [ ] Execute the plan step by step
269- [ ] Write code to files before executing
270- [ ] Test incrementally and document results
271- **Status:** pending
272
273### Phase 4: Testing & Verification
274- [ ] Verify all requirements are met
275- [ ] Document test results in progress.md
276- [ ] Fix any issues found and log resolutions
277- **Status:** pending
278
279### Phase 5: Delivery & Completion
280- [ ] Review all output files and deliverables
281- [ ] Ensure completeness and quality
282- [ ] Deliver final results to user
283- **Status:** pending
284
285## Key Questions
2861. [Important question to answer during the task]
2872. [Another key question that guides decisions]
288
289## Decisions Made
290| Decision | Rationale |
291|----------|-----------|
292|          |           |
293
294## Errors Encountered
295| Error | Attempt | Resolution |
296|-------|---------|------------|
297|       | 1       |            |
298
299## Notes
300- **CRITICAL**: Re-read this plan before major decisions (attention manipulation)
301- **2-Action Rule**: Save findings after every 2 view/browser operations
302- **3-Strike Protocol**: Never repeat the same failed action 3 times
303- Update phase status: pending → in_progress → complete
304"#,
305            project_name
306        );
307
308        // 创建 findings.md - 研究发现存储
309        let findings_content = r#"# Findings & Research
310
311## Requirements Analysis
312-
313
314## Research Findings
315-
316
317## Technical Decisions
318| Decision | Rationale | Impact |
319|----------|-----------|--------|
320
321## Issues & Solutions
322| Issue | Root Cause | Resolution |
323|-------|------------|------------|
324
325## Resources & References
326-
327
328## Key Insights
329-
330"#;
331
332        // 创建 progress.md - 会话日志
333        let progress_content = format!(
334            r#"# Progress Log
335
336## Session: {}
337
338### Current Status
339- **Phase:** 1 - Requirements & Discovery
340- **Started:** {}
341- **Visual Operations Count:** 0
342
343### Actions Taken
344-
345
346### Test Results
347| Test | Expected | Actual | Status |
348|------|----------|--------|--------|
349
350### Error Log
351| Time | Error | Attempt | Resolution |
352|------|-------|---------|------------|
353
354### Context Refreshes
355| Time | Reason | Action |
356|------|--------|--------|
357"#,
358            date, date
359        );
360
361        // 写入文件
362        fs::write("task_plan.md", task_plan_content)?;
363        fs::write("findings.md", findings_content)?;
364        fs::write("progress.md", progress_content)?;
365
366        Ok(ToolResult::success("✅ Three-stage workflow initialized! Created task_plan.md, findings.md, progress.md with automated context engineering.")
367            .with_metadata("files_created", serde_json::json!(["task_plan.md", "findings.md", "progress.md"]))
368            .with_metadata("project_name", serde_json::json!(project_name))
369            .with_metadata("workflow_stage", serde_json::json!("initialized")))
370    }
371
372    /// Pre-Action 阶段:在执行重要操作前刷新上下文
373    fn pre_action_check(&self) -> Result<ToolResult, ToolError> {
374        if !Path::new("task_plan.md").exists() {
375            return Err(ToolError::execution_failed(
376                "task_plan.md not found. Run init_workflow first.",
377            ));
378        }
379
380        let content = fs::read_to_string("task_plan.md")?;
381
382        // 提取关键信息
383        let goal = self.extract_goal(&content);
384        let current_phase = self.extract_current_phase(&content);
385        let pending_tasks = self.extract_pending_tasks(&content);
386
387        // 记录上下文刷新
388        let _ = self.log_context_refresh("Pre-action context refresh");
389
390        Ok(ToolResult::success(format!(
391            "🔄 Pre-Action Context Refresh:\n\n**Goal:** {}\n**Current Phase:** {}\n**Pending Tasks:**\n{}\n\n⚠️ Keep these goals in mind for the next action!",
392            goal,
393            current_phase,
394            pending_tasks.join("\n")
395        ))
396        .with_metadata("goal", serde_json::json!(goal))
397        .with_metadata("current_phase", serde_json::json!(current_phase))
398        .with_metadata("pending_tasks", serde_json::json!(pending_tasks))
399        .with_metadata("workflow_stage", serde_json::json!("pre_action")))
400    }
401
402    /// Post-Action 阶段:提醒更新状态
403    fn post_action_update(&self) -> Result<ToolResult, ToolError> {
404        Ok(ToolResult::success("📝 Post-Action Reminder:\n\n1. Did this action complete a phase? Update task_plan.md status\n2. Any new findings? Add to findings.md\n3. Any errors encountered? Log them for learning\n4. Update progress.md with what was accomplished")
405            .with_metadata("workflow_stage", serde_json::json!("post_action"))
406            .with_metadata("reminder_type", serde_json::json!("status_update")))
407    }
408
409    /// 应用 2-Action 规则:每2次视觉操作后保存发现
410    fn apply_2action_rule(&self, finding: &str) -> Result<ToolResult, ToolError> {
411        // 更新视觉操作计数
412        let _ = self.increment_visual_operations();
413
414        // 添加发现到 findings.md
415        self.add_finding(finding)?;
416
417        Ok(ToolResult::success(format!(
418            "🎯 2-Action Rule Applied: Saved finding after visual operations\n\nFinding: {}",
419            finding
420        ))
421        .with_metadata("rule_applied", serde_json::json!("2_action_rule"))
422        .with_metadata("finding", serde_json::json!(finding)))
423    }
424
425    /// 记录错误信息(3次错误协议)
426    fn log_error(&self, error_info: ErrorInfo) -> Result<ToolResult, ToolError> {
427        if !Path::new("task_plan.md").exists() {
428            return Err(ToolError::execution_failed(
429                "task_plan.md not found. Run init_workflow first.",
430            ));
431        }
432
433        let mut content = fs::read_to_string("task_plan.md")?;
434
435        // 添加错误到错误表格
436        let resolution = error_info.resolution.as_deref().unwrap_or("In progress");
437        let error_entry = format!(
438            "| {} | {} | {} |",
439            error_info.error_description, error_info.attempt_number, resolution
440        );
441
442        if let Some(pos) = content.find("## Errors Encountered\n| Error | Attempt | Resolution |\n|-------|---------|------------|") {
443            let insert_pos = pos + "## Errors Encountered\n| Error | Attempt | Resolution |\n|-------|---------|------------|\n".len();
444            content.insert_str(insert_pos, &format!("{}\n", error_entry));
445        }
446
447        fs::write("task_plan.md", content)?;
448
449        // 同时记录到 progress.md
450        let _ = self.log_error_to_progress(&error_info);
451
452        let warning = if error_info.attempt_number >= 3 {
453            "\n⚠️ WARNING: 3rd attempt! Consider escalating to user or changing approach completely."
454        } else {
455            ""
456        };
457
458        Ok(ToolResult::success(format!(
459            "🚨 Error Logged (Attempt {}): {}{}",
460            error_info.attempt_number, error_info.error_description, warning
461        ))
462        .with_metadata("error_logged", serde_json::json!(true))
463        .with_metadata(
464            "attempt_number",
465            serde_json::json!(error_info.attempt_number),
466        )
467        .with_metadata(
468            "needs_escalation",
469            serde_json::json!(error_info.attempt_number >= 3),
470        ))
471    }
472
473    /// 记录决策信息
474    fn log_decision(&self, decision_info: DecisionInfo) -> Result<ToolResult, ToolError> {
475        if !Path::new("task_plan.md").exists() {
476            return Err(ToolError::execution_failed(
477                "task_plan.md not found. Run init_workflow first.",
478            ));
479        }
480
481        let mut content = fs::read_to_string("task_plan.md")?;
482
483        // 添加决策到决策表格
484        let decision_entry = format!(
485            "| {} | {} |",
486            decision_info.decision, decision_info.rationale
487        );
488
489        if let Some(pos) =
490            content.find("## Decisions Made\n| Decision | Rationale |\n|----------|-----------|")
491        {
492            let insert_pos = pos
493                + "## Decisions Made\n| Decision | Rationale |\n|----------|-----------|\n".len();
494            content.insert_str(insert_pos, &format!("{}\n", decision_entry));
495        }
496
497        fs::write("task_plan.md", content)?;
498
499        Ok(ToolResult::success(format!(
500            "📋 Decision Logged: {} (Rationale: {})",
501            decision_info.decision, decision_info.rationale
502        ))
503        .with_metadata("decision", serde_json::json!(decision_info.decision))
504        .with_metadata("rationale", serde_json::json!(decision_info.rationale)))
505    }
506
507    /// 检查任务完成状态
508    fn check_completion(&self) -> Result<ToolResult, ToolError> {
509        if !Path::new("task_plan.md").exists() {
510            return Err(ToolError::execution_failed(
511                "task_plan.md not found. Run init_workflow first.",
512            ));
513        }
514
515        let content = fs::read_to_string("task_plan.md")?;
516
517        // 统计阶段状态
518        let total_phases = content.matches("### Phase").count();
519        let complete_phases = content.matches("**Status:** complete").count();
520        let in_progress_phases = content.matches("**Status:** in_progress").count();
521        let pending_phases = content.matches("**Status:** pending").count();
522
523        let is_complete = complete_phases == total_phases && total_phases > 0;
524        let completion_percentage = if total_phases > 0 {
525            (complete_phases as f64 / total_phases as f64 * 100.0) as u32
526        } else {
527            0
528        };
529
530        let status_message = if is_complete {
531            "🎉 ALL PHASES COMPLETE! Task ready for delivery."
532        } else {
533            "⏳ Task in progress. Do not stop until all phases are complete."
534        };
535
536        Ok(ToolResult::success(format!(
537            "� Task Completion Status:\n\n{}\n\n📈 Progress: {}% ({}/{} phases complete)\n📋 Breakdown: {} complete, {} in progress, {} pending",
538            status_message,
539            completion_percentage,
540            complete_phases,
541            total_phases,
542            complete_phases,
543            in_progress_phases,
544            pending_phases
545        ))
546        .with_metadata("total_phases", serde_json::json!(total_phases))
547        .with_metadata("complete_phases", serde_json::json!(complete_phases))
548        .with_metadata("in_progress_phases", serde_json::json!(in_progress_phases))
549        .with_metadata("pending_phases", serde_json::json!(pending_phases))
550        .with_metadata("is_complete", serde_json::json!(is_complete))
551        .with_metadata("completion_percentage", serde_json::json!(completion_percentage)))
552    }
553
554    // 辅助方法实现
555    fn update_phase(&self, phase_update: PhaseUpdate) -> Result<ToolResult, ToolError> {
556        if !Path::new("task_plan.md").exists() {
557            return Err(ToolError::execution_failed(
558                "task_plan.md not found. Run init_workflow first.",
559            ));
560        }
561
562        let content = fs::read_to_string("task_plan.md")?;
563
564        // 更新阶段状态 - 使用字符串替换方式
565        let phase_pattern = format!("### Phase {}", phase_update.phase_number);
566        let mut updated_content = content.clone();
567
568        // 找到目标阶段并更新状态
569        if let Some(phase_start) = updated_content.find(&phase_pattern) {
570            // 找到下一个阶段或文件结尾
571            let search_start = phase_start + phase_pattern.len();
572            let next_phase_pos = updated_content
573                .get(search_start..)
574                .and_then(|s| s.find("### Phase"))
575                .map(|pos| search_start + pos)
576                .unwrap_or(updated_content.len());
577
578            let phase_section = updated_content
579                .get(phase_start..next_phase_pos)
580                .unwrap_or("");
581
582            // 替换状态行
583            let old_status_pattern = "**Status:**";
584            if let Some(status_pos) = phase_section.find(old_status_pattern) {
585                let status_line_start = phase_start + status_pos;
586                let status_line_end = updated_content
587                    .get(status_line_start..)
588                    .and_then(|s| s.find('\n'))
589                    .map(|pos| status_line_start + pos)
590                    .unwrap_or(updated_content.len());
591
592                let new_status_line = format!("- **Status:** {}", phase_update.status);
593                updated_content.replace_range(status_line_start..status_line_end, &new_status_line);
594            }
595        }
596        fs::write("task_plan.md", updated_content)?;
597
598        // 更新当前阶段指示器
599        if phase_update.status == "in_progress" {
600            let _ = self.update_current_phase(phase_update.phase_number);
601        }
602
603        Ok(ToolResult::success(format!(
604            "✅ Phase {} status updated to: {}",
605            phase_update.phase_number, phase_update.status
606        ))
607        .with_metadata("phase", serde_json::json!(phase_update.phase_number))
608        .with_metadata("status", serde_json::json!(phase_update.status)))
609    }
610
611    fn add_finding(&self, finding: &str) -> Result<ToolResult, ToolError> {
612        if !Path::new("findings.md").exists() {
613            return Err(ToolError::execution_failed(
614                "findings.md not found. Run init_workflow first.",
615            ));
616        }
617
618        let mut content = fs::read_to_string("findings.md")?;
619
620        let timestamp = chrono::Utc::now().format("%H:%M").to_string();
621        let finding_entry = format!("- [{}] {}", timestamp, finding);
622
623        if let Some(pos) = content.find("## Research Findings\n-") {
624            let insert_pos = pos + "## Research Findings\n".len();
625            content.insert_str(insert_pos, &format!("{}\n", finding_entry));
626        } else {
627            content.push_str(&format!("\n{}\n", finding_entry));
628        }
629
630        fs::write("findings.md", content)?;
631
632        Ok(
633            ToolResult::success(format!("💡 Finding saved: {}", finding))
634                .with_metadata("timestamp", serde_json::json!(timestamp))
635                .with_metadata("finding", serde_json::json!(finding)),
636        )
637    }
638
639    fn add_progress(&self, progress_entry: &str) -> Result<ToolResult, ToolError> {
640        if !Path::new("progress.md").exists() {
641            return Err(ToolError::execution_failed(
642                "progress.md not found. Run init_workflow first.",
643            ));
644        }
645
646        let mut content = fs::read_to_string("progress.md")?;
647
648        let timestamp = chrono::Utc::now().format("%H:%M").to_string();
649        let progress_line = format!("- [{}] {}", timestamp, progress_entry);
650
651        if let Some(pos) = content.find("### Actions Taken\n-") {
652            let insert_pos = pos + "### Actions Taken\n".len();
653            content.insert_str(insert_pos, &format!("{}\n", progress_line));
654        } else {
655            content.push_str(&format!("\n{}\n", progress_line));
656        }
657
658        fs::write("progress.md", content)?;
659
660        Ok(
661            ToolResult::success(format!("📝 Progress logged: {}", progress_entry))
662                .with_metadata("timestamp", serde_json::json!(timestamp))
663                .with_metadata("progress", serde_json::json!(progress_entry)),
664        )
665    }
666
667    // 私有辅助方法
668    fn extract_goal(&self, content: &str) -> String {
669        content
670            .lines()
671            .skip_while(|line| !line.starts_with("## Goal"))
672            .nth(1)
673            .unwrap_or("[Goal not found]")
674            .trim()
675            .to_string()
676    }
677
678    fn extract_current_phase(&self, content: &str) -> String {
679        content
680            .lines()
681            .skip_while(|line| !line.starts_with("## Current Phase"))
682            .nth(1)
683            .unwrap_or("Phase 1")
684            .trim()
685            .to_string()
686    }
687
688    fn extract_pending_tasks(&self, content: &str) -> Vec<String> {
689        content
690            .lines()
691            .filter(|line| line.contains("- [ ]"))
692            .map(|line| line.trim().to_string())
693            .collect()
694    }
695
696    fn log_context_refresh(&self, reason: &str) -> Result<(), std::io::Error> {
697        if !Path::new("progress.md").exists() {
698            return Ok(());
699        }
700
701        let mut content = fs::read_to_string("progress.md")?;
702        let timestamp = chrono::Utc::now().format("%H:%M").to_string();
703        let refresh_entry = format!("| {} | {} | Context refreshed |", timestamp, reason);
704
705        if let Some(pos) = content.find("### Context Refreshes\n| Time | Reason | Action |") {
706            let insert_pos = pos + "### Context Refreshes\n| Time | Reason | Action |\n|------|--------|---------|\n".len();
707            content.insert_str(insert_pos, &format!("{}\n", refresh_entry));
708            fs::write("progress.md", content)?;
709        }
710
711        Ok(())
712    }
713
714    fn increment_visual_operations(&self) -> Result<(), std::io::Error> {
715        if !Path::new("progress.md").exists() {
716            return Ok(());
717        }
718
719        let content = fs::read_to_string("progress.md")?;
720
721        // 简单实现:在进度文件中记录视觉操作
722        let timestamp = chrono::Utc::now().format("%H:%M").to_string();
723        let updated_content = content.replace(
724            "### Actions Taken\n-",
725            &format!(
726                "### Actions Taken\n- [{}] Visual operation recorded (2-Action Rule tracking)\n-",
727                timestamp
728            ),
729        );
730
731        fs::write("progress.md", updated_content)?;
732        Ok(())
733    }
734
735    fn log_error_to_progress(&self, error_info: &ErrorInfo) -> Result<(), std::io::Error> {
736        if !Path::new("progress.md").exists() {
737            return Ok(());
738        }
739
740        let mut content = fs::read_to_string("progress.md")?;
741        let timestamp = chrono::Utc::now().format("%H:%M").to_string();
742        let error_entry = format!(
743            "| {} | {} | {} | {} |",
744            timestamp,
745            error_info.error_description,
746            error_info.attempt_number,
747            error_info.resolution.as_deref().unwrap_or("In progress")
748        );
749
750        if let Some(pos) = content.find("### Error Log\n| Time | Error | Attempt | Resolution |") {
751            let insert_pos = pos + "### Error Log\n| Time | Error | Attempt | Resolution |\n|------|-------|---------|------------|\n".len();
752            content.insert_str(insert_pos, &format!("{}\n", error_entry));
753            fs::write("progress.md", content)?;
754        }
755
756        Ok(())
757    }
758
759    fn update_current_phase(&self, phase_number: u32) -> Result<(), std::io::Error> {
760        if !Path::new("task_plan.md").exists() {
761            return Ok(());
762        }
763
764        let content = fs::read_to_string("task_plan.md")?;
765        let updated_content = content.replace(
766            "## Current Phase\nPhase",
767            &format!("## Current Phase\nPhase {}", phase_number),
768        );
769
770        fs::write("task_plan.md", updated_content)?;
771        Ok(())
772    }
773}