use serde::Deserialize;
use serde_json::Value;
use crate::hook::error::HookError;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum HookType {
SessionStart,
PostToolUse,
PostToolUseFailure,
UserPromptSubmit,
SubagentStop,
Stop,
PreCompact,
}
impl HookType {
pub fn parse(s: &str) -> Result<Self, HookError> {
Ok(match s {
"session-start" => HookType::SessionStart,
"post-tool-use" => HookType::PostToolUse,
"post-tool-use-failure" => HookType::PostToolUseFailure,
"user-prompt-submit" => HookType::UserPromptSubmit,
"subagent-stop" => HookType::SubagentStop,
"stop" => HookType::Stop,
"pre-compact" => HookType::PreCompact,
other => return Err(HookError::UnknownHookType(other.to_string())),
})
}
pub fn as_str(self) -> &'static str {
match self {
HookType::SessionStart => "session-start",
HookType::PostToolUse => "post-tool-use",
HookType::PostToolUseFailure => "post-tool-use-failure",
HookType::UserPromptSubmit => "user-prompt-submit",
HookType::SubagentStop => "subagent-stop",
HookType::Stop => "stop",
HookType::PreCompact => "pre-compact",
}
}
pub fn log_label(self) -> &'static str {
match self {
HookType::SessionStart => "SessionStart",
HookType::PostToolUse => "PostToolUse",
HookType::PostToolUseFailure => "PostToolUseFailure",
HookType::UserPromptSubmit => "UserPromptSubmit",
HookType::SubagentStop => "SubagentStop",
HookType::Stop => "Stop",
HookType::PreCompact => "PreCompact",
}
}
}
#[derive(Debug, Clone, Default, Deserialize)]
#[serde(default)]
pub struct HookInput {
pub session_id: Option<String>,
pub cwd: String,
pub tool_name: Option<String>,
pub tool_input: Option<Value>,
pub tool_result: Option<Value>,
pub tool_error: Option<String>,
pub error: Option<String>,
pub content: Option<String>,
pub prompt: Option<String>,
pub agent_type: Option<String>,
pub output: Option<String>,
pub task: Option<String>,
pub stop_reason: Option<String>,
pub reason: Option<String>,
pub summary: Option<String>,
}
impl HookInput {
pub fn session_id_or_unknown(&self) -> String {
match self.session_id.as_deref() {
Some(s) if !s.is_empty() => s.to_string(),
_ => "unknown".to_string(),
}
}
pub fn cwd_or_process(&self) -> String {
if self.cwd.is_empty() {
std::env::current_dir()
.map(|p| p.to_string_lossy().into_owned())
.unwrap_or_default()
} else {
self.cwd.clone()
}
}
}