use std::path::PathBuf;
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(),
}
}
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}");
}
}
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}");
}
}
}