use crate::core::session::Session;
use anyhow::{Context, Result};
use serde::Deserialize;
use serde_json::json;
#[derive(Debug, Deserialize)]
struct SessionStart {
#[serde(default)]
session_id: Option<String>,
#[serde(default)]
source: Option<String>,
}
const TRACKER_RESETTING_SOURCES: &[&str] = &["compact", "clear", "resume"];
pub fn handle(stdin_payload: &str) -> Result<String> {
if std::env::var_os("DRIP_DISABLE").is_some() {
return Ok(empty());
}
let mut compaction_notice: Option<String> = None;
if let Err(e) = drop_baselines_if_needed(stdin_payload, &mut compaction_notice) {
eprintln!("drip: SessionStart handler failed: {e:#}");
}
Ok(match compaction_notice {
Some(msg) => json!({
"hookSpecificOutput": {
"hookEventName": "SessionStart",
"additionalContext": msg,
}
})
.to_string(),
None => empty(),
})
}
fn drop_baselines_if_needed(
stdin_payload: &str,
compaction_notice: &mut Option<String>,
) -> Result<()> {
let p: SessionStart =
serde_json::from_str(stdin_payload).context("SessionStart payload malformed")?;
let source = p.source.as_deref().unwrap_or("").to_string();
if !TRACKER_RESETTING_SOURCES.contains(&source.as_str()) {
return Ok(());
}
let session_id = match p.session_id.filter(|s| !s.is_empty()) {
Some(id) => id,
None => return Ok(()),
};
let session = Session::open_with_id(session_id)?;
session.reset_for_compaction()?;
let count = session
.compaction_state()
.ok()
.flatten()
.map(|c| c.count)
.unwrap_or(0);
let count_str = if count > 0 {
format!(" (#{count})")
} else {
String::new()
};
*compaction_notice = Some(format!(
"DRIP: ↺ context was {source}ed{count_str} — per-session baselines have been reset. \
The next read of each file will return full content (or a semantically-compressed view); \
subsequent re-reads use the normal unchanged/delta path."
));
Ok(())
}
fn empty() -> String {
json!({}).to_string()
}