vv-agent 0.6.0

VectorVein agent runtime, SDK, CLI, tools, and workspace backends
Documentation
use std::path::PathBuf;

use super::discovery::WindowsShellDiscovery;

const WINDOWS_GIT_BASH_RELATIVE_PATHS: [&[&str]; 2] = [
    &["Git", "bin", "bash.exe"],
    &["Git", "usr", "bin", "bash.exe"],
];
const WINDOWS_POWERSHELL_RELATIVE_PATH: [&str; 4] =
    ["System32", "WindowsPowerShell", "v1.0", "powershell.exe"];

pub(super) fn resolve_windows_powershell(discovery: &impl WindowsShellDiscovery) -> Option<String> {
    for executable in ["powershell.exe", "powershell"] {
        if let Some(resolved) = discovery.which(executable) {
            return Some(resolved);
        }
    }

    let system_root = discovery.env_var("SYSTEMROOT")?;
    let mut candidate = PathBuf::from(system_root);
    for component in WINDOWS_POWERSHELL_RELATIVE_PATH {
        candidate.push(component);
    }
    discovery
        .is_file(&candidate)
        .then(|| candidate.to_string_lossy().to_string())
}

pub(super) fn resolve_windows_git_bash(discovery: &impl WindowsShellDiscovery) -> Option<String> {
    let mut candidates = Vec::<PathBuf>::new();
    for root in windows_program_roots(discovery) {
        for relative_path in WINDOWS_GIT_BASH_RELATIVE_PATHS {
            let mut candidate = PathBuf::from(&root);
            for component in relative_path {
                candidate.push(component);
            }
            if !candidates.iter().any(|seen| seen == &candidate) {
                candidates.push(candidate);
            }
        }
    }

    for candidate in candidates {
        if discovery.is_file(&candidate) {
            return Some(candidate.to_string_lossy().to_string());
        }
    }

    discovery
        .which("bash.exe")
        .or_else(|| discovery.which("bash"))
}

fn windows_program_roots(discovery: &impl WindowsShellDiscovery) -> Vec<String> {
    let mut roots = Vec::new();
    for key in [
        "ProgramW6432",
        "ProgramFiles",
        "ProgramFiles(x86)",
        "LocalAppData",
    ] {
        let Some(root) = discovery.env_var(key) else {
            continue;
        };
        if !roots.iter().any(|seen| seen == &root) {
            roots.push(root);
        }
    }
    roots
}