use crate::HookResult; use crate::state::HookState; use notcore::{HookPhase, HookSpec}; use std::path::PathBuf; use std::process::Command; pub struct HookRunner { state_dir: PathBuf, force: bool, } impl HookRunner { pub fn new(state_dir: PathBuf) -> Self { Self { state_dir, force: false, } } pub fn with_force(state_dir: PathBuf) -> Self { Self { state_dir, force: true, } } pub fn run_hook(&self, spec: &HookSpec) -> HookResult { let mut state = HookState::load(&self.state_dir).unwrap_or_default(); if spec.phase == HookPhase::Setup && !self.force && state.is_done(&spec.name) { return HookResult::Skipped; } // TODO: support other shells let result = Command::new("nu").arg(&spec.script).status(); match result { Ok(status) if status.success() => { if spec.phase == HookPhase::Setup { state.mark_done(&spec.name); let _ = state.save(&self.state_dir); } HookResult::Ok } Ok(status) => HookResult::Failed(format!("exit code {}", status.code().unwrap_or(-1))), Err(e) => HookResult::Failed(e.to_string()), } } }