use crate::{
instructions::InstructionFile,
sessions::{
MAX_METADATA_VISIT_BYTES, MAX_METADATA_VISIT_LINES, Session, SessionEventKind,
report_session_diagnostic,
},
};
use std::{collections::HashSet, path::PathBuf};
#[derive(Debug, Default)]
pub(crate) struct SubdirInstructionState {
claimed: HashSet<PathBuf>,
}
impl SubdirInstructionState {
pub(crate) fn new(initial_instructions: &[InstructionFile], session: Option<&Session>) -> Self {
let mut state = Self::default();
state.seed_initial(initial_instructions);
if let Some(session) = session {
state.seed_from_full_session_log(session);
}
state
}
pub(crate) fn claimed_mut(&mut self) -> &mut HashSet<PathBuf> {
&mut self.claimed
}
pub(crate) fn seed_initial(&mut self, instructions: &[InstructionFile]) {
for instruction in instructions {
let canonical = instruction
.path
.canonicalize()
.unwrap_or_else(|_| instruction.path.clone());
self.claimed.insert(canonical);
}
}
pub(crate) fn seed_from_full_session_log(&mut self, session: &Session) {
let events = match session
.read_events_tolerant_bounded(MAX_METADATA_VISIT_LINES, MAX_METADATA_VISIT_BYTES)
{
Ok(events) => events,
Err(error) => {
report_session_diagnostic(
crate::sessions::SessionDiagnosticOperation::Replay,
session.path(),
&error,
);
return;
}
};
for event in events.events {
match event.kind() {
Some(SessionEventKind::SubdirInstructionLoad) => {
if event
.payload
.get("source")
.and_then(serde_json::Value::as_str)
== Some("subdir_agents")
&& event
.payload
.get("status")
.and_then(serde_json::Value::as_str)
== Some("success")
&& let Some(path) = event
.payload
.get("path")
.and_then(serde_json::Value::as_str)
{
self.claimed.insert(PathBuf::from(path));
}
}
Some(SessionEventKind::ProviderContextItem) => {
if event
.payload
.get("source")
.and_then(serde_json::Value::as_str)
== Some("subdir_agents")
&& let Some(path) = event
.payload
.get("path")
.and_then(serde_json::Value::as_str)
{
self.claimed.insert(PathBuf::from(path));
}
}
_ => {}
}
}
}
}