ralph_workflow/interrupt/
runtime.rs1use std::path::Path;
8use std::sync::{Mutex, OnceLock};
9
10use super::checkpoint::InterruptContext;
11
12pub(crate) static INTERRUPT_CONTEXT: OnceLock<Mutex<Option<InterruptContext>>> = OnceLock::new();
17
18fn interrupt_context_slot() -> &'static Mutex<Option<InterruptContext>> {
19 INTERRUPT_CONTEXT.get_or_init(|| Mutex::new(None))
20}
21
22fn lock_slot<'a>(
23 slot: &'a Mutex<Option<InterruptContext>>,
24) -> std::sync::MutexGuard<'a, Option<InterruptContext>> {
25 slot.lock().unwrap_or_else(|poisoned| poisoned.into_inner())
26}
27
28pub fn set_interrupt_context(context: InterruptContext) {
30 let mut guard = lock_slot(interrupt_context_slot());
31 *guard = Some(context);
32}
33
34pub fn clear_interrupt_context() {
36 if let Some(slot) = INTERRUPT_CONTEXT.get() {
37 let mut guard = lock_slot(slot);
38 *guard = None;
39 }
40}
41
42pub fn get_interrupt_context() -> Option<InterruptContext> {
44 INTERRUPT_CONTEXT.get().and_then(|slot| {
45 let guard = lock_slot(slot);
46 guard.clone()
47 })
48}
49
50#[expect(
54 clippy::exit,
55 reason = "Signal handler requires immediate process termination"
56)]
57pub fn exit_sigint() -> ! {
58 std::process::exit(130)
59}
60
61#[cfg(unix)]
66pub fn restore_prompt_md_writable(path: &Path) -> bool {
67 use std::os::unix::fs::PermissionsExt;
68
69 fn make_writable(path: &Path) -> bool {
70 let Ok(metadata) = std::fs::metadata(path) else {
71 return false;
72 };
73
74 let mut perms = metadata.permissions();
75 perms.set_mode(perms.mode() | 0o200);
76 std::fs::set_permissions(path, perms).is_ok()
77 }
78
79 make_writable(path)
80}
81
82#[cfg(unix)]
83pub fn restore_prompt_md_writable_in_repo(repo_root: &Path) -> bool {
84 use std::os::unix::fs::PermissionsExt;
85
86 fn make_writable(path: &Path) -> bool {
87 let Ok(metadata) = std::fs::metadata(path) else {
88 return false;
89 };
90
91 let mut perms = metadata.permissions();
92 perms.set_mode(perms.mode() | 0o200);
93 std::fs::set_permissions(path, perms).is_ok()
94 }
95
96 let prompt_path = repo_root.join("PROMPT.md");
97 make_writable(&prompt_path)
98}
99
100#[cfg(not(unix))]
101pub fn restore_prompt_md_writable(_path: &Path) -> bool {
102 false
103}
104
105#[cfg(not(unix))]
106pub fn restore_prompt_md_writable_in_repo(_repo_root: &Path) -> bool {
107 false
108}
109
110pub fn remove_ralph_dir(repo_root: &Path) {
112 let _ = std::fs::remove_dir_all(repo_root.join(".git/ralph"));
113}