use std::path::Path;
use std::sync::{Mutex, OnceLock};
use super::checkpoint::InterruptContext;
pub(crate) static INTERRUPT_CONTEXT: OnceLock<Mutex<Option<InterruptContext>>> = OnceLock::new();
fn interrupt_context_slot() -> &'static Mutex<Option<InterruptContext>> {
INTERRUPT_CONTEXT.get_or_init(|| Mutex::new(None))
}
fn lock_slot<'a>(
slot: &'a Mutex<Option<InterruptContext>>,
) -> std::sync::MutexGuard<'a, Option<InterruptContext>> {
slot.lock().unwrap_or_else(|poisoned| poisoned.into_inner())
}
pub fn set_interrupt_context(context: InterruptContext) {
let mut guard = lock_slot(interrupt_context_slot());
*guard = Some(context);
}
pub fn clear_interrupt_context() {
if let Some(slot) = INTERRUPT_CONTEXT.get() {
let mut guard = lock_slot(slot);
*guard = None;
}
}
pub fn get_interrupt_context() -> Option<InterruptContext> {
INTERRUPT_CONTEXT.get().and_then(|slot| {
let guard = lock_slot(slot);
guard.clone()
})
}
#[expect(
clippy::exit,
reason = "Signal handler requires immediate process termination"
)]
pub fn exit_sigint() -> ! {
std::process::exit(130)
}
#[cfg(unix)]
pub fn restore_prompt_md_writable(path: &Path) -> bool {
use std::os::unix::fs::PermissionsExt;
fn make_writable(path: &Path) -> bool {
let Ok(metadata) = std::fs::metadata(path) else {
return false;
};
let mut perms = metadata.permissions();
perms.set_mode(perms.mode() | 0o200);
std::fs::set_permissions(path, perms).is_ok()
}
make_writable(path)
}
#[cfg(unix)]
pub fn restore_prompt_md_writable_in_repo(repo_root: &Path) -> bool {
use std::os::unix::fs::PermissionsExt;
fn make_writable(path: &Path) -> bool {
let Ok(metadata) = std::fs::metadata(path) else {
return false;
};
let mut perms = metadata.permissions();
perms.set_mode(perms.mode() | 0o200);
std::fs::set_permissions(path, perms).is_ok()
}
let prompt_path = repo_root.join("PROMPT.md");
make_writable(&prompt_path)
}
#[cfg(not(unix))]
pub fn restore_prompt_md_writable(_path: &Path) -> bool {
false
}
#[cfg(not(unix))]
pub fn restore_prompt_md_writable_in_repo(_repo_root: &Path) -> bool {
false
}
pub fn remove_ralph_dir(repo_root: &Path) {
let _ = std::fs::remove_dir_all(repo_root.join(".git/ralph"));
}