use super::storage::{ExecutionPlan, PlanStatus, PlanStorage, PlanTask, TaskData, TaskStatus};
use anyhow::{anyhow, Result};
use chrono::Utc;
pub struct MemoryPlanStorage {
plan: Option<ExecutionPlan>,
}
impl MemoryPlanStorage {
pub fn new() -> Self {
Self { plan: None }
}
}
impl Default for MemoryPlanStorage {
fn default() -> Self {
Self::new()
}
}
impl PlanStorage for MemoryPlanStorage {
fn create_plan(&mut self, title: String, tasks: Vec<TaskData>) -> Result<()> {
if tasks.is_empty() {
return Err(anyhow!("Cannot create plan with empty task list"));
}
let plan_tasks: Vec<PlanTask> = tasks
.into_iter()
.map(|task_data| PlanTask {
title: task_data.title,
description: task_data.description,
details: String::new(),
summary: None,
status: TaskStatus::InProgress, completed_at: None,
message_range: None, phase: task_data.phase, })
.collect();
self.plan = Some(ExecutionPlan {
title,
tasks: plan_tasks,
current_task_index: 0,
created_at: Utc::now(),
status: PlanStatus::Active,
phase_compressions: Vec::new(),
project_compression: None,
});
Ok(())
}
fn add_step_details(&mut self, content: String) -> Result<()> {
let plan = self
.plan
.as_mut()
.ok_or_else(|| anyhow!("No active plan"))?;
if plan.current_task_index >= plan.tasks.len() {
return Err(anyhow!("No current task to update"));
}
let current_task = &mut plan.tasks[plan.current_task_index];
if !current_task.details.is_empty() {
current_task.details.push_str("\n\n");
}
current_task.details.push_str(&content);
Ok(())
}
fn get_current_step_details(&self) -> Result<String> {
let plan = self
.plan
.as_ref()
.ok_or_else(|| anyhow!("No active plan"))?;
if plan.current_task_index >= plan.tasks.len() {
return Err(anyhow!("No current task"));
}
Ok(plan.tasks[plan.current_task_index].details.clone())
}
fn complete_current_task(&mut self, summary: String) -> Result<()> {
let plan = self
.plan
.as_mut()
.ok_or_else(|| anyhow!("No active plan"))?;
if plan.current_task_index >= plan.tasks.len() {
return Err(anyhow!("No current task to complete"));
}
let current_task = &mut plan.tasks[plan.current_task_index];
current_task.summary = Some(summary);
current_task.status = TaskStatus::Completed;
current_task.completed_at = Some(Utc::now());
plan.current_task_index += 1;
Ok(())
}
fn has_more_tasks(&self) -> Result<bool> {
let plan = self
.plan
.as_ref()
.ok_or_else(|| anyhow!("No active plan"))?;
Ok(plan.current_task_index < plan.tasks.len())
}
fn get_task_list(&self) -> Result<Vec<(String, String, TaskStatus)>> {
let plan = self
.plan
.as_ref()
.ok_or_else(|| anyhow!("No active plan"))?;
let mut tasks = Vec::new();
for (i, task) in plan.tasks.iter().enumerate() {
let status = if i < plan.current_task_index {
TaskStatus::Completed
} else {
TaskStatus::InProgress };
tasks.push((task.title.clone(), task.description.clone(), status));
}
Ok(tasks)
}
fn get_current_task_info(&self) -> Result<(usize, usize, String, String)> {
let plan = self
.plan
.as_ref()
.ok_or_else(|| anyhow!("No active plan"))?;
if plan.current_task_index >= plan.tasks.len() {
return Err(anyhow!("All tasks completed"));
}
let current_task = &plan.tasks[plan.current_task_index];
Ok((
plan.current_task_index + 1, plan.tasks.len(),
current_task.title.clone(),
current_task.description.clone(),
))
}
fn complete_plan(&mut self, _summary: String) -> Result<()> {
let plan = self
.plan
.as_mut()
.ok_or_else(|| anyhow!("No active plan"))?;
plan.status = PlanStatus::Completed;
Ok(())
}
fn clear_plan(&mut self) -> Result<()> {
self.plan = None;
Ok(())
}
fn has_active_plan(&self) -> Result<bool> {
Ok(self.plan.is_some() && matches!(self.plan.as_ref().unwrap().status, PlanStatus::Active))
}
fn get_plan_title(&self) -> Result<String> {
let plan = self
.plan
.as_ref()
.ok_or_else(|| anyhow!("No active plan"))?;
Ok(plan.title.clone())
}
fn set_current_task_message_range(
&mut self,
start_index: usize,
end_index: usize,
) -> Result<()> {
let plan = self
.plan
.as_mut()
.ok_or_else(|| anyhow!("No active plan"))?;
if plan.current_task_index == 0 {
return Err(anyhow!("No completed task to set message range for"));
}
let completed_task_index = plan.current_task_index - 1;
if completed_task_index >= plan.tasks.len() {
return Err(anyhow!("Invalid task index"));
}
plan.tasks[completed_task_index].message_range = Some(super::storage::MessageRange {
start_index,
end_index,
});
Ok(())
}
fn get_last_completed_task(&self) -> Result<Option<PlanTask>> {
let plan = self
.plan
.as_ref()
.ok_or_else(|| anyhow!("No active plan"))?;
if plan.current_task_index == 0 {
return Ok(None); }
let completed_task_index = plan.current_task_index - 1;
if completed_task_index >= plan.tasks.len() {
return Ok(None);
}
Ok(Some(plan.tasks[completed_task_index].clone()))
}
fn get_completed_task_count(&self) -> Result<usize> {
let plan = self
.plan
.as_ref()
.ok_or_else(|| anyhow!("No active plan"))?;
Ok(plan.current_task_index)
}
fn get_current_task_index(&self) -> Result<usize> {
let plan = self
.plan
.as_ref()
.ok_or_else(|| anyhow!("No active plan"))?;
Ok(plan.current_task_index)
}
fn get_total_task_count(&self) -> Result<usize> {
let plan = self
.plan
.as_ref()
.ok_or_else(|| anyhow!("No active plan"))?;
Ok(plan.tasks.len())
}
fn get_phase_count(&self) -> Result<usize> {
let plan = self
.plan
.as_ref()
.ok_or_else(|| anyhow!("No active plan"))?;
Ok(plan.phase_compressions.len())
}
fn get_plan(&self) -> Result<&ExecutionPlan> {
self.plan.as_ref().ok_or_else(|| anyhow!("No active plan"))
}
}