oy-cli 0.12.0

OpenCode launcher and deterministic MCP helpers for repository audit and review workflows
Documentation
use anyhow::{Context, Result, anyhow};
use serde_json::Value;
use std::ffi::OsString;
use std::path::Path;
use std::sync::LazyLock;
use std::time::Duration;

use super::super::ToolContext;
use super::super::args::{ExcludeArg, SlocArgs};
use super::super::external::{ExternalCommand, discover};
use super::output::SlocOutput;
use super::paths::resolve_existing_paths;

const SLOC_TIMEOUT: Duration = Duration::from_secs(120);
const SLOC_OUTPUT_LIMIT: usize = 8 * 1024 * 1024;

static TOKEI: LazyLock<std::result::Result<ExternalCommand, String>> =
    LazyLock::new(|| discover_tokei().map_err(|err| format!("{err:#}")));

pub(crate) fn tool_sloc(ctx: &ToolContext, args: SlocArgs) -> Result<Value> {
    let targets = resolve_existing_paths(ctx, &args.path)?;
    let exclude = args
        .exclude
        .as_ref()
        .map(ExcludeArg::patterns)
        .unwrap_or_default();
    let output = run_tokei(ctx.root(), &targets, &exclude)?;

    Ok(serde_json::to_value(SlocOutput {
        path: args.path,
        format: "tokei-json",
        output,
        exclude: (!exclude.is_empty()).then_some(exclude),
    })?)
}

pub(crate) fn has_tokei() -> bool {
    tokei_command().is_ok()
}

fn run_tokei(root: &Path, targets: &[std::path::PathBuf], exclude: &[String]) -> Result<Value> {
    let command = tokei_command()?;
    let mut args = vec![
        OsString::from("--output"),
        OsString::from("json"),
        OsString::from("--sort"),
        OsString::from("code"),
    ];
    for pattern in exclude {
        args.push(OsString::from("--exclude"));
        args.push(OsString::from(pattern));
    }
    for target in targets {
        args.push(target.as_os_str().to_os_string());
    }

    let output = command.run(root, args, SLOC_TIMEOUT, SLOC_OUTPUT_LIMIT)?;
    output.require_success(command)?;
    serde_json::from_slice(&output.stdout).context("tokei output was not valid JSON")
}

fn tokei_command() -> Result<&'static ExternalCommand> {
    TOKEI.as_ref().map_err(|err| anyhow!(err.clone()))
}

fn discover_tokei() -> Result<ExternalCommand> {
    discover("tokei", "OY_TOKEI", &["tokei"], |command| {
        let output = command.probe(&["--version"])?;
        output.require_success(command)?;
        if !String::from_utf8_lossy(&output.stdout)
            .to_ascii_lowercase()
            .contains("tokei")
        {
            anyhow::bail!("version output does not identify tokei");
        }
        Ok(())
    })
}