use std::collections::BTreeSet;
use std::path::Path;
use anyhow::Result;
use serde_json::{json, Value};
use super::{armed_path, read_json_object, str_field, write_atomic};
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub(crate) struct ArmedMarker {
pub(crate) slots_seen: BTreeSet<u32>,
pub(crate) last_event: Option<String>,
pub(crate) last_ts_utc: Option<String>,
pub(crate) hook_session: Option<String>,
pub(crate) claude_code_version: Option<String>,
}
impl ArmedMarker {
pub(crate) fn to_json(&self) -> Value {
json!({
"slots_seen": self.slots_seen.iter().copied().collect::<Vec<u32>>(),
"last_event": self.last_event,
"last_ts_utc": self.last_ts_utc,
"hook_session": self.hook_session,
"claude_code_version": self.claude_code_version,
})
}
pub(crate) fn from_json(v: &Value) -> Self {
let slots_seen = v
.get("slots_seen")
.and_then(Value::as_array)
.map(|a| {
a.iter()
.filter_map(Value::as_u64)
.filter_map(|n| u32::try_from(n).ok())
.collect()
})
.unwrap_or_default();
ArmedMarker {
slots_seen,
last_event: str_field(v, "last_event"),
last_ts_utc: str_field(v, "last_ts_utc"),
hook_session: str_field(v, "hook_session"),
claude_code_version: str_field(v, "claude_code_version"),
}
}
}
pub(crate) fn read_armed(root: &Path, lane: &str) -> Result<Option<ArmedMarker>> {
let path = armed_path(root, lane)?;
Ok(read_json_object(&path).map(|v| ArmedMarker::from_json(&v)))
}
pub(crate) fn refresh_armed(
root: &Path,
lane: &str,
slot: u32,
event: &str,
ts_utc: &str,
hook_session: Option<&str>,
claude_code_version: Option<&str>,
) -> Result<ArmedMarker> {
let path = armed_path(root, lane)?;
let mut marker =
read_json_object(&path).map_or_else(ArmedMarker::default, |v| ArmedMarker::from_json(&v));
marker.slots_seen.insert(slot);
marker.last_event = Some(event.to_string());
marker.last_ts_utc = Some(ts_utc.to_string());
if let Some(session) = hook_session {
marker.hook_session = Some(session.to_string());
}
if let Some(version) = claude_code_version {
marker.claude_code_version = Some(version.to_string());
}
write_atomic(&path, &serde_json::to_string(&marker.to_json())?)?;
Ok(marker)
}