use crate::agent::Session;
use crate::declarations::{self, Declaration};
use crate::git;
use crate::report;
use crate::runner;
use crate::trailer::Verdict;
fn reaches(declaration: &Declaration) -> Result<bool, String> {
Ok(!git::tracked(&declaration.paths)?.is_empty())
}
fn sweep(
declaration: &Declaration,
agent: &crate::agent::Agent,
ceiling: std::time::Duration,
) -> Result<(Vec<Verdict>, String), String> {
let system = crate::brief::system(declaration, crate::brief::Reach::Whole)?;
let session = Session::opened();
report::reviewing(
&declaration.gate,
session.id(),
crate::agent::transcript_path(session.id()).as_deref(),
);
let answer = agent.run(
crate::agent::Role::Review,
&system,
&crate::brief::sweeping(),
&session,
declaration.model.as_deref(),
ceiling,
)?;
let verdicts = runner::verdicts(&answer, declaration.brief.simple)?;
Ok((verdicts, runner::findings(&answer.text)))
}
pub fn run(ceiling: std::time::Duration) -> Result<bool, String> {
let hook = declarations::read()?;
let agent = runner::configured()?;
report::auditing(&hook.path);
let mut blocked = false;
let mut reviewed = 0;
let mut failed: Vec<String> = Vec::new();
for declaration in &hook.gates {
if !reaches(declaration)? {
report::skipped(&declaration.gate, &declaration.paths);
continue;
}
match sweep(declaration, &agent, ceiling) {
Ok((verdicts, findings)) => {
blocked |= verdicts.iter().any(Verdict::blocks);
reviewed += 1;
report::audited(&declaration.gate, &verdicts, &findings);
}
Err(said) => {
report::gate_failed(&declaration.gate, &said);
failed.push(declaration.gate.clone());
}
}
}
if reviewed == 0 && failed.is_empty() {
return Err(format!("{} declared no gate this tree reaches", hook.path));
}
report::audit_done(reviewed, blocked, &failed);
if !failed.is_empty() {
return Err(format!(
"no verdict from {}: the audit is incomplete",
failed.join(", ")
));
}
Ok(!blocked)
}