pub mod run;
pub mod store;
mod types;
use std::time::{SystemTime, UNIX_EPOCH};
use tracing::warn;
use crate::multiplexer::{AgentStatus, Multiplexer};
pub use store::StateStore;
pub use types::{AgentState, LastDoneCycleState, PaneKey, RuntimeState};
pub fn persist_agent_update(
mux: &dyn Multiplexer,
pane_id: &str,
status: Option<AgentStatus>,
title_override: Option<String>,
) {
let pane_key = PaneKey {
backend: mux.name().to_string(),
instance: mux.instance_id(),
pane_id: pane_id.to_string(),
};
let live_info = match mux.get_live_pane_info(pane_id) {
Ok(Some(info)) => info,
Ok(None) => {
warn!(%pane_id, "pane not found, skipping state persist");
return;
}
Err(e) => {
warn!(error = %e, "failed to get live pane info, skipping state persist");
return;
}
};
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.map(|d| d.as_secs())
.unwrap_or(0);
let existing = StateStore::new()
.ok()
.and_then(|store| store.get_agent(&pane_key).ok().flatten());
let final_status = status.or(existing.as_ref().and_then(|e| e.status));
let status_ts = if final_status == existing.as_ref().and_then(|e| e.status) {
existing.as_ref().and_then(|e| e.status_ts).unwrap_or(now)
} else {
now
};
let pane_title = title_override
.or(existing.and_then(|e| e.pane_title))
.or(live_info.title);
let boot_id = mux.server_boot_id().unwrap_or(None);
let state = AgentState {
pane_key,
workdir: live_info.working_dir,
status: final_status,
status_ts: Some(status_ts),
pane_title,
pane_pid: live_info.pid.unwrap_or(0),
command: live_info.current_command.unwrap_or_default(),
updated_ts: now,
window_name: live_info.window,
session_name: live_info.session,
boot_id,
};
if let Ok(store) = StateStore::new()
&& let Err(e) = store.upsert_agent(&state)
{
warn!(error = %e, "failed to persist agent state");
}
}