pub mod affected;
pub mod authoring;
pub mod board;
pub mod check;
pub mod compile;
pub mod daemon;
pub mod db;
pub mod doctor;
pub mod git;
pub mod hook;
pub mod init;
pub mod instructions;
pub mod policy;
pub mod report;
pub mod stats;
pub mod waive;
use anyhow::{Context, Result};
use pushkin_core::envelope::CheckResult;
use pushkin_core::manifest::Manifest;
use std::path::PathBuf;
pub const MANIFEST_FILE: &str = "pushkin.toml";
pub const EVENTS_DB: &str = ".pushkin/events.db";
pub const CONSENT_FILE: &str = ".pushkin/consent.json";
pub const CLAUDE_SETTINGS: &str = ".claude/settings.json";
pub const CONSENT_VERSION: u32 = 2;
pub const PUSHKIN_MARKER: &str = "pushkin-v1";
pub fn load_manifest() -> Result<Manifest> {
let text = std::fs::read_to_string(MANIFEST_FILE)
.with_context(|| format!("cannot read {MANIFEST_FILE} in the current directory"))?;
Manifest::parse(&text).context("manifest rejected")
}
pub fn events_db_path() -> Result<PathBuf> {
let path = PathBuf::from(EVENTS_DB);
if let Some(parent) = path.parent() {
std::fs::create_dir_all(parent).context("cannot create .pushkin/")?;
}
Ok(path)
}
#[must_use]
pub fn gate_read_only(manifest: &Manifest, mut result: CheckResult, path: &str) -> CheckResult {
if manifest.is_read_only(path) && committed_in_head(path) {
result
.violations
.push(pushkin_core::pipeline::read_only_violation(path));
result.decision = pushkin_core::envelope::Decision::Block;
}
result
}
pub(crate) fn committed_in_head(path: &str) -> bool {
std::process::Command::new("git")
.args(["cat-file", "-e", &format!("HEAD:{path}")])
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null())
.status()
.is_ok_and(|status| status.success())
}
#[must_use]
pub fn apply_waivers(result: pushkin_core::envelope::CheckResult) -> CheckResult {
match pushkin_core::waivers::WaiverSet::load(std::path::Path::new(waive::WAIVERS_FILE)) {
Ok(set) => set.apply_now(result),
Err(_) => result,
}
}