use std::path::Path;
use super::event::EventContext;
#[derive(Debug, Clone, Default)]
pub struct GitContext {
pub branch: Option<String>,
pub worktree: Option<String>,
pub commit: Option<String>,
}
pub fn resolve_context(ito_path: &Path) -> EventContext {
let session_id = resolve_session_id(ito_path);
let harness_session_id = resolve_harness_session_id();
let git = resolve_git_context();
EventContext {
session_id,
harness_session_id,
branch: git.branch,
worktree: git.worktree,
commit: git.commit,
}
}
pub fn resolve_session_id(ito_path: &Path) -> String {
let session_dir = ito_path.join(".state").join("audit");
let session_file = session_dir.join(".session");
if let Ok(contents) = std::fs::read_to_string(&session_file) {
let contents = contents.trim().to_string();
if !contents.is_empty() {
return contents;
}
}
let id = uuid::Uuid::new_v4().to_string();
let _ = std::fs::create_dir_all(&session_dir);
let _ = std::fs::write(&session_file, &id);
id
}
pub fn resolve_harness_session_id() -> Option<String> {
ito_common::harness::resolve_harness_session_id()
}
pub fn resolve_git_context() -> GitContext {
let branch = run_git_command(&["symbolic-ref", "--short", "HEAD"]);
let commit = run_git_command(&["rev-parse", "--short=8", "HEAD"]);
let worktree = detect_worktree_name();
GitContext {
branch,
worktree,
commit,
}
}
pub fn resolve_user_identity() -> String {
let name = run_git_command(&["config", "user.name"])
.or_else(|| std::env::var("USER").ok())
.unwrap_or_else(|| "unknown".to_string());
format!("@{}", name.to_lowercase().replace(' ', "-"))
}
fn run_git_command(args: &[&str]) -> Option<String> {
let output = std::process::Command::new("git").args(args).output().ok()?;
if !output.status.success() {
return None;
}
let s = String::from_utf8_lossy(&output.stdout).trim().to_string();
if s.is_empty() { None } else { Some(s) }
}
fn detect_worktree_name() -> Option<String> {
let git_dir = run_git_command(&["rev-parse", "--git-dir"])?;
let common_dir = run_git_command(&["rev-parse", "--git-common-dir"])?;
let git_dir_path = std::path::Path::new(&git_dir);
let common_dir_path = std::path::Path::new(&common_dir);
if git_dir_path.canonicalize().ok()? != common_dir_path.canonicalize().ok()? {
let toplevel = run_git_command(&["rev-parse", "--show-toplevel"])?;
let path = std::path::Path::new(&toplevel);
Some(path.file_name()?.to_string_lossy().to_string())
} else {
None
}
}
#[cfg(test)]
#[path = "context_tests.rs"]
mod context_tests;