use std::collections::BTreeSet;
use std::path::{Path, PathBuf};
use super::fold::fold;
use super::{
EventKind, LedgerAppender, LedgerError, LedgerEvent, Origin, WorktreeLedger, ledger_key,
};
use crate::session_manager::worktree_ownership::is_harness_agent_worktree;
use crate::session_manager::worktree_registry::list_registered_worktrees;
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct BackfillReport {
pub created: usize,
pub observed: usize,
pub already_recorded: usize,
pub unanswered: Vec<PathBuf>,
}
pub fn backfill_checkouts(
ledger: &WorktreeLedger,
checkouts: &[PathBuf],
) -> Result<BackfillReport, LedgerError> {
let mut known: BTreeSet<PathBuf> = fold(&ledger.read()?.events).live.into_keys().collect();
let mut report = BackfillReport::default();
let mut appender: Option<LedgerAppender> = None;
for checkout in checkouts {
let Some(listed) = list_registered_worktrees(checkout) else {
report.unanswered.push(checkout.clone());
continue;
};
let repo = listed
.iter()
.find(|w| w.is_main)
.map_or_else(|| ledger_key(checkout), |w| ledger_key(&w.path));
for wt in listed {
if wt.bare || wt.is_main || wt.prunable {
continue;
}
let key = ledger_key(&wt.path);
if !known.insert(key.clone()) {
report.already_recorded += 1;
continue;
}
let kind = if is_harness_agent_worktree(&key) {
report.observed += 1;
EventKind::Observed {
repo: repo.clone(),
branch: wt.branch,
origin: Origin::AgentIsolation,
}
} else {
report.created += 1;
EventKind::Created {
repo: repo.clone(),
branch: wt.branch,
origin: Origin::Backfill,
session: None,
}
};
if appender.is_none() {
appender = Some(ledger.open_appender()?);
}
if let Some(out) = appender.as_mut() {
out.append(&LedgerEvent::now(key, kind))?;
}
}
}
Ok(report)
}
pub async fn registered_checkouts(
registry_dir: &Path,
) -> Result<Vec<PathBuf>, crate::project::ProjectStoreError> {
let projects = crate::project::ProjectRegistry::load(registry_dir)
.await?
.list()
.await?;
let set: BTreeSet<PathBuf> = projects
.iter()
.filter_map(crate::project::resolver::local_checkout_for)
.filter(|p| p.is_dir())
.collect();
Ok(set.into_iter().collect())
}