#![forbid(unsafe_code)]
pub mod cli;
pub mod config;
pub mod discovery;
pub mod error;
pub mod evidence;
pub mod git;
pub mod policy;
pub mod report;
pub mod rules;
pub mod source;
pub use config::{Config, OutputFormat};
pub use error::{Error, Result};
pub use report::Report;
pub use source::Workspace;
use tracing::info;
pub fn analyze(config: &Config) -> Result<Report> {
let (report, _workspace) = analyze_with_workspace(config)?;
Ok(report)
}
pub fn analyze_with_workspace(config: &Config) -> Result<(Report, Workspace)> {
info!(target = %config.target, "resolving repository");
let workspace = source::resolve(&config.target, config.commit_sample_limit)?;
info!(
path = %workspace.path.display(),
label = %workspace.label,
remote = workspace.is_remote(),
"discovering repository"
);
let ctx = discovery::discover(&workspace.path, config.commit_sample_limit)?;
info!(files = ctx.inventory.len(), "evaluating hygiene rules");
let findings = rules::evaluate_all(&ctx);
info!(count = findings.len(), "computing policy scores");
let policy = policy::evaluate(&findings);
let report = Report::build(&ctx, findings, policy, &workspace);
Ok((report, workspace))
}
pub fn analyze_and_write(config: &Config) -> Result<(Report, Vec<std::path::PathBuf>)> {
let (report, workspace) = analyze_with_workspace(config)?;
let cwd = std::env::current_dir()?;
let default_dir = config
.output
.as_ref()
.and_then(|p| {
if p.is_dir() {
Some(p.as_path())
} else {
p.parent()
}
})
.unwrap_or(if workspace.is_remote() {
cwd.as_path()
} else {
workspace.path.as_path()
});
let write_dir = if config.output.is_none() {
if workspace.is_remote() {
cwd.as_path()
} else {
workspace.path.as_path()
}
} else {
default_dir
};
let mut written = Vec::new();
if !config.prompt_only {
written.extend(report::write_report(
&report,
config.format,
config.output.as_deref(),
write_dir,
)?);
}
if config.llm_prompt {
let prompt_path = report::resolve_prompt_path(&report, config.output.as_deref(), write_dir);
report::write_llm_prompt(&report, &prompt_path)?;
written.push(prompt_path);
}
drop(workspace);
Ok((report, written))
}