#[derive(Debug)]
pub struct CommitLogSession {
run_dir: PathBuf,
attempt_counter: usize,
}
impl CommitLogSession {
pub fn new(base_log_dir: &str, workspace: &dyn Workspace) -> std::io::Result<Self> {
let timestamp = Local::now().format("%Y%m%d_%H%M%S");
let run_dir = PathBuf::from(base_log_dir).join(format!("run_{timestamp}"));
workspace.create_dir_all(&run_dir)?;
Ok(Self {
run_dir,
attempt_counter: 0,
})
}
#[must_use]
pub fn noop() -> Self {
Self {
run_dir: PathBuf::from("/dev/null/ralph-noop-session"),
attempt_counter: 0,
}
}
#[must_use]
pub fn is_noop(&self) -> bool {
self.run_dir.starts_with("/dev/null")
}
#[must_use]
pub fn run_dir(&self) -> &Path {
&self.run_dir
}
pub fn next_attempt_number(&mut self) -> usize {
self.attempt_counter = self.attempt_counter.saturating_add(1);
self.attempt_counter
}
pub fn new_attempt(&mut self, agent: &str, strategy: &str) -> CommitAttemptLog {
let attempt_number = self.next_attempt_number();
CommitAttemptLog::new(attempt_number, agent, strategy)
}
pub fn write_summary(
&self,
total_attempts: usize,
final_outcome: &str,
workspace: &dyn Workspace,
) -> std::io::Result<()> {
if self.is_noop() {
return Ok(());
}
let summary_path = self.run_dir.join("SUMMARY.txt");
let content = format!(
"COMMIT GENERATION SESSION SUMMARY\n\
=================================\n\
\n\
Run directory: {}\n\
Total attempts: {}\n\
Final outcome: {}\n\
\n\
Individual attempt logs are in this directory.\n",
self.run_dir.display(),
total_attempts,
final_outcome
);
workspace.write(&summary_path, &content)?;
Ok(())
}
}