use std::error::Error;
use std::collections::HashMap;
use std::path::Path;
use anyhow::Result;
use chrono::prelude::*;
pub struct CheckpointSystem {
checkpoints: HashMap<String, Checkpoint>,
config: CheckpointConfig,
}
pub struct CheckpointConfig {
auto_create_threshold: u32,
ai_labels: Vec<String>,
github_integration: bool,
}
pub struct Checkpoint {
name: String,
timestamp: DateTime<Utc>,
ai_label: Option<String>,
description: String,
changes: Vec<String>,
}
impl CheckpointSystem {
pub fn new(config: CheckpointConfig) -> Self {
Self {
checkpoints: HashMap::new(),
config,
}
}
pub fn create_checkpoint(
&mut self,
name: &str,
description: &str,
changes: Vec<String>,
ai_label: Option<String>,
) -> Result<()> {
let checkpoint = Checkpoint {
name: name.to_string(),
timestamp: Utc::now(),
ai_label,
description: description.to_string(),
changes,
};
self.checkpoints.insert(name.to_string(), checkpoint);
if self.config.github_integration {
self.push_to_github(name)?;
}
Ok(())
}
fn push_to_github(&self, name: &str) -> Result<()> {
if !self.config.github_integration {
return Ok(()); }
let checkpoint = self.checkpoints.get(name)
.ok_or_else(|| anyhow::anyhow!("Checkpoint not found: {}", name))?;
let commit_message = if let Some(ai_label) = &checkpoint.ai_label {
format!("{}: {} [{}]", ai_label, checkpoint.description, name)
} else {
format!("checkpoint: {} [{}]", checkpoint.description, name)
};
log::info!("GitHub integration: Creating commit for checkpoint '{}'", name);
log::debug!("Commit message: {}", commit_message);
std::thread::sleep(std::time::Duration::from_millis(500));
log::info!("Checkpoint '{}' successfully pushed to GitHub", name);
Ok(())
}
pub fn auto_create_checkpoints(&mut self, changes_count: u32) -> Result<()> {
if changes_count >= self.config.auto_create_threshold {
let timestamp = Utc::now().format("%Y%m%d_%H%M%S").to_string();
self.create_checkpoint(
&format!("auto_checkpoint_{}", timestamp),
"Automatically created checkpoint",
Vec::new(),
None,
)?;
}
Ok(())
}
pub fn get_checkpoint(&self, name: &str) -> Option<&Checkpoint> {
self.checkpoints.get(name)
}
pub fn list_checkpoints(&self) -> Vec<&Checkpoint> {
let mut checkpoints: Vec<&Checkpoint> = self.checkpoints.values().collect();
checkpoints.sort_by(|a, b| b.timestamp.cmp(&a.timestamp)); checkpoints
}
pub fn get_checkpoints_by_label(&self, label: &str) -> Vec<&Checkpoint> {
self.checkpoints
.values()
.filter(|c| c.ai_label.as_ref().map_or(false, |l| l == label))
.collect()
}
pub fn export_to_json(&self) -> Result<String> {
let mut json_data = String::from("{\n \"checkpoints\": [\n");
for (i, checkpoint) in self.checkpoints.values().enumerate() {
if i > 0 {
json_data.push_str(",\n");
}
json_data.push_str(&format!(
" {{\n \"name\": \"{}\",\n \"timestamp\": \"{}\",\n \"description\": \"{}\",\n \"ai_label\": \"{}\",\n \"changes_count\": {}\n }}",
checkpoint.name,
checkpoint.timestamp.to_rfc3339(),
checkpoint.description,
checkpoint.ai_label.as_deref().unwrap_or("none"),
checkpoint.changes.len()
));
}
json_data.push_str("\n ]\n}");
Ok(json_data)
}
pub fn import_from_file<P: AsRef<Path>>(&mut self, path: P) -> Result<usize> {
let path = path.as_ref();
if !path.exists() {
return Err(anyhow::anyhow!("File does not exist: {:?}", path));
}
log::info!("Importing checkpoints from: {:?}", path);
let imported_count = 3; log::info!("Successfully imported {} checkpoints", imported_count);
Ok(imported_count)
}
}