git-slop 0.16.1

A deterministic repository token-defragmenter for humans and AI agents.
Documentation
fn print_text(value: &str) {
    if value.is_empty() {
        return;
    }
    print!("{value}");
    if !value.ends_with('\n') {
        println!();
    }
}

fn safe_terminal(value: &str) -> String {
    crate::text::visible_controls(value)
}

fn relative_display(path: &Path, root: &Path) -> String {
    path.strip_prefix(root)
        .unwrap_or(path)
        .to_string_lossy()
        .replace('\\', "/")
}

fn durable_report_path(repo_root: &Path) -> PathBuf {
    config::latest_dir(repo_root).join("report.json")
}

fn ephemeral_report_path(repo_root: &Path) -> Option<PathBuf> {
    config::git_runtime_dir(repo_root)
        .ok()
        .map(|path| path.join("ephemeral/latest/report.json"))
}

fn default_report_path(repo_root: &Path) -> PathBuf {
    let durable = durable_report_path(repo_root);
    if durable.exists() {
        return durable;
    }
    ephemeral_report_path(repo_root)
        .filter(|path| path.exists())
        .unwrap_or(durable)
}

fn default_report_locations(repo_root: &Path) -> Vec<PathBuf> {
    let mut locations = vec![durable_report_path(repo_root)];
    if let Some(path) = ephemeral_report_path(repo_root) {
        locations.push(path);
    }
    locations
}

fn resolve_repo_path(repo_root: &Path, path: &Path) -> PathBuf {
    if path.is_absolute() || repo_root.as_os_str().is_empty() {
        path.to_path_buf()
    } else {
        repo_root.join(path)
    }
}

fn load_report_at(path: &Path) -> Result<Option<Value>> {
    if !path.exists() {
        return Ok(None);
    }
    report::load_report(path).map(Some)
}

fn load_default_report(
    repo_root: &Path,
    explicit_report: Option<&Path>,
) -> Result<Option<(Value, PathBuf)>> {
    let path = explicit_report
        .map(|path| resolve_repo_path(repo_root, path))
        .unwrap_or_else(|| default_report_path(repo_root));
    Ok(load_report_at(&path)?.map(|report| (report, path)))
}

fn report_or_missing(repo_root: &Path, explicit_report: Option<&Path>) -> Result<(Value, PathBuf)> {
    let fallback = explicit_report
        .map(|path| resolve_repo_path(repo_root, path))
        .unwrap_or_else(|| default_report_path(repo_root));
    let loaded = load_default_report(repo_root, explicit_report).map_err(|error| {
        ClassifiedError::new(ErrorKind::Contract, "report_invalid", format!("{error:#}"))
            .at("/report")
            .with_details(json!({"path": fallback}))
    })?;
    let loaded = loaded.ok_or_else(|| -> anyhow::Error {
        let searched = explicit_report.map_or_else(
            || default_report_locations(repo_root),
            |path| vec![resolve_repo_path(repo_root, path)],
        );
        let searched_display = searched
            .iter()
            .map(|path| path.display().to_string())
            .collect::<Vec<_>>()
            .join(", ");
        ClassifiedError::new(
            ErrorKind::Contract,
            "report_not_found",
            format!(
                "Report not found. Searched: {searched_display}\nRun `git slop find` to generate a Git-private first-run report, or `git slop init` first for durable reports."
            ),
        )
        .at("/report")
        .with_details(json!({"path": fallback, "searched": searched}))
        .into()
    })?;
    if explicit_report.is_none() && !repo_root.as_os_str().is_empty() {
        match crate::freshness::evaluate(repo_root, &loaded.0) {
            Ok(freshness) if !freshness.current => eprintln!(
                "git-slop: warning: values below are from a stale report snapshot ({}), not the current worktree; run `git slop find`.",
                freshness.reason_codes()
            ),
            Err(error) => eprintln!(
                "git-slop: warning: latest report currentness could not be checked: {error:#}"
            ),
            Ok(_) => {}
        }
    }
    Ok(loaded)
}

fn report_or_missing_with_currentness(
    repo_root: &Path,
    explicit_report: Option<&Path>,
    require_current: bool,
) -> Result<(Value, PathBuf)> {
    let loaded = report_or_missing(repo_root, explicit_report)?;
    if require_current {
        require_current_report(repo_root, &loaded.0)?;
    }
    Ok(loaded)
}