Skip to main content

tracevault_cli/commands/
hook.rs

1use std::fs::{self, OpenOptions};
2use std::io::{self, Read, Write};
3use std::path::Path;
4use tracevault_core::hooks::{parse_hook_event, HookResponse};
5
6pub fn handle_hook_from_stdin(project_root: &Path) -> Result<(), io::Error> {
7    let mut input = String::new();
8    io::stdin().read_to_string(&mut input)?;
9    handle_hook_event(&input, project_root)?;
10
11    // Output JSON response to stdout
12    let response = HookResponse::allow();
13    println!("{}", serde_json::to_string(&response).unwrap());
14    Ok(())
15}
16
17pub fn handle_hook_event(json_input: &str, project_root: &Path) -> Result<(), io::Error> {
18    let event =
19        parse_hook_event(json_input).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
20
21    // Create session directory
22    let session_dir = project_root
23        .join(".tracevault")
24        .join("sessions")
25        .join(&event.session_id);
26    fs::create_dir_all(&session_dir)?;
27
28    // Append event to events.jsonl
29    let events_path = session_dir.join("events.jsonl");
30    let mut file = OpenOptions::new()
31        .create(true)
32        .append(true)
33        .open(&events_path)?;
34
35    let event_json = serde_json::to_string(&event).map_err(io::Error::other)?;
36    writeln!(file, "{event_json}")?;
37
38    // Write session metadata if it doesn't exist
39    let meta_path = session_dir.join("metadata.json");
40    if !meta_path.exists() {
41        let metadata = serde_json::json!({
42            "session_id": event.session_id,
43            "transcript_path": event.transcript_path,
44            "cwd": event.cwd,
45            "started_at": chrono::Utc::now().to_rfc3339(),
46        });
47        fs::write(&meta_path, serde_json::to_string_pretty(&metadata).unwrap())?;
48    }
49
50    Ok(())
51}