collet 0.1.1

Relentless agentic coding orchestrator with zero-drop agent loops
Documentation
use std::path::PathBuf;

/// Task journaling: writes `STATUS.md` to project data dir for crash recovery.
pub struct Journal {
    status_path: PathBuf,
    session_id: String,
}

impl Journal {
    pub fn new(working_dir: &str) -> Self {
        let dir = crate::config::project_data_dir(working_dir);
        let _ = std::fs::create_dir_all(&dir);
        Self {
            status_path: dir.join("STATUS.md"),
            session_id: uuid::Uuid::new_v4().to_string(),
        }
    }

    /// Write current agent status to disk.
    pub async fn write_status(
        &self,
        iteration: u32,
        phase: &str,
        user_task: &str,
        tool_calls: &[(&str, &str)],
        last_response: &str,
    ) {
        let tools_md = if tool_calls.is_empty() {
            "  (none)\n".to_string()
        } else {
            tool_calls
                .iter()
                .map(|(name, args)| {
                    let preview: String = args.chars().take(80).collect();
                    format!("  - `{name}`: `{preview}`\n")
                })
                .collect()
        };

        let response_preview: String = last_response.chars().take(500).collect();
        let now = chrono::Utc::now().to_rfc3339();

        let content = format!(
            "# Agent Status\n\
             \n\
             | Field | Value |\n\
             |-------|-------|\n\
             | Session | `{}` |\n\
             | Iteration | {} |\n\
             | Phase | `{}` |\n\
             | Updated | {} |\n\
             \n\
             ## Current Task\n\
             \n\
             {}\n\
             \n\
             ## Last Tool Calls\n\
             \n\
             {}\n\
             ## Last Response\n\
             \n\
             {}\n",
            self.session_id, iteration, phase, now, user_task, tools_md, response_preview,
        );

        if let Err(e) = tokio::fs::write(&self.status_path, content).await {
            tracing::warn!("Failed to write journal: {e}");
        }
    }

    /// Mark the task as completed.
    pub async fn write_completion(&self) {
        let now = chrono::Utc::now().to_rfc3339();
        let content = format!(
            "# Agent Status\n\
             \n\
             | Field | Value |\n\
             |-------|-------|\n\
             | Session | `{}` |\n\
             | Phase | `completed` |\n\
             | Completed | {} |\n",
            self.session_id, now,
        );

        if let Err(e) = tokio::fs::write(&self.status_path, content).await {
            tracing::warn!("Failed to write journal completion: {e}");
        }
    }
}