use std::path::{Path, PathBuf};
use anyhow::{Context, Result};
use crate::constants::paths::SESSION_FILENAME;
use crate::contracts::SessionState;
use crate::fsutil;
use crate::runutil::{ManagedCommand, TimeoutClass, execute_checked_command};
pub fn session_path(cache_dir: &Path) -> PathBuf {
cache_dir.join(SESSION_FILENAME)
}
pub fn session_exists(cache_dir: &Path) -> bool {
session_path(cache_dir).exists()
}
pub fn save_session(cache_dir: &Path, session: &SessionState) -> Result<()> {
let path = session_path(cache_dir);
let json = serde_json::to_string_pretty(session).context("serialize session state")?;
fsutil::write_atomic(&path, json.as_bytes()).context("write session file")?;
log::debug!("Session saved: task_id={}", session.task_id);
Ok(())
}
pub fn load_session(cache_dir: &Path) -> Result<Option<SessionState>> {
let path = session_path(cache_dir);
if !path.exists() {
return Ok(None);
}
let content = std::fs::read_to_string(&path).context("read session file")?;
let session: SessionState = serde_json::from_str(&content).context("parse session file")?;
if session.version > crate::contracts::SESSION_STATE_VERSION {
log::warn!(
"Session file version {} is newer than supported version {}. Attempting to load anyway.",
session.version,
crate::contracts::SESSION_STATE_VERSION
);
}
Ok(Some(session))
}
pub fn clear_session(cache_dir: &Path) -> Result<()> {
let path = session_path(cache_dir);
if path.exists() {
std::fs::remove_file(&path).context("remove session file")?;
log::debug!("Session cleared");
}
Ok(())
}
pub fn get_git_head_commit(repo_root: &Path) -> Option<String> {
let mut command = std::process::Command::new("git");
command
.arg("-c")
.arg("core.fsmonitor=false")
.arg("-C")
.arg(repo_root)
.arg("rev-parse")
.arg("HEAD");
execute_checked_command(ManagedCommand::new(
command,
format!("git rev-parse HEAD in {}", repo_root.display()),
TimeoutClass::MetadataProbe,
))
.ok()
.map(|output| output.stdout_lossy())
}