1use std::fs::{self, OpenOptions};
7use std::io::Write;
8use std::path::{Path, PathBuf};
9
10pub fn events_dir() -> PathBuf {
12 let home = std::env::var("HOME").unwrap_or_default();
13 PathBuf::from(home).join(".cove").join("events")
14}
15
16pub fn write_event(session_id: &str, cwd: &str, pane_id: &str, state: &str) -> Result<(), String> {
18 write_event_to(&events_dir(), session_id, cwd, pane_id, state)
19}
20
21pub fn write_event_to(
23 dir: &Path,
24 session_id: &str,
25 cwd: &str,
26 pane_id: &str,
27 state: &str,
28) -> Result<(), String> {
29 fs::create_dir_all(dir).map_err(|e| format!("create events dir: {e}"))?;
30
31 let path = dir.join(format!("{session_id}.jsonl"));
32 let mut file = OpenOptions::new()
33 .create(true)
34 .append(true)
35 .open(&path)
36 .map_err(|e| format!("open event file: {e}"))?;
37
38 let ts = std::time::SystemTime::now()
39 .duration_since(std::time::UNIX_EPOCH)
40 .unwrap_or_default()
41 .as_secs();
42
43 let line = format!(r#"{{"state":"{state}","cwd":"{cwd}","pane_id":"{pane_id}","ts":{ts}}}"#);
44 writeln!(file, "{line}").map_err(|e| format!("write event: {e}"))?;
45
46 Ok(())
47}
48
49pub fn find_session_id(pane_id: &str) -> Option<String> {
53 find_session_id_in(&events_dir(), pane_id)
54}
55
56pub fn find_session_id_in(dir: &Path, pane_id: &str) -> Option<String> {
58 let entries = fs::read_dir(dir).ok()?;
59
60 let mut best: Option<(String, u64)> = None;
61 for entry in entries.flatten() {
62 let path = entry.path();
63 if path.extension().and_then(|e| e.to_str()) != Some("jsonl") {
64 continue;
65 }
66 let content = fs::read_to_string(&path).unwrap_or_default();
67 let last_line = content.lines().rev().find(|l| !l.trim().is_empty());
68 if let Some(line) = last_line {
69 if let Ok(event) = serde_json::from_str::<serde_json::Value>(line) {
70 if event.get("pane_id").and_then(|v| v.as_str()) == Some(pane_id) {
71 let ts = event.get("ts").and_then(|v| v.as_u64()).unwrap_or(0);
72 if best.as_ref().is_none_or(|(_, prev_ts)| ts > *prev_ts) {
73 if let Some(sid) = path.file_stem().and_then(|s| s.to_str()) {
74 best = Some((sid.to_string(), ts));
75 }
76 }
77 }
78 }
79 }
80 }
81
82 best.map(|(sid, _)| sid)
83}