vv-agent 0.6.0

VectorVein agent runtime, SDK, CLI, tools, and workspace backends
Documentation
use super::ShellInvocation;

pub(super) fn resolve_posix_shell(shell: Option<&str>) -> ShellInvocation {
    let selected = shell
        .map(str::trim)
        .filter(|value| !value.is_empty() && normalize_shell_name(value) != "auto")
        .unwrap_or("bash");
    resolve_named_shell(selected, false)
}

fn resolve_named_shell(shell: &str, windows: bool) -> ShellInvocation {
    let normalized = normalize_shell_name(shell);
    if windows && matches!(normalized.as_str(), "cmd" | "cmd.exe") {
        return ShellInvocation {
            kind: "cmd".to_string(),
            name: shell.to_string(),
            prefix: vec![shell.to_string(), "/C".to_string()],
        };
    }
    if matches!(normalized.as_str(), "powershell" | "powershell.exe") {
        return ShellInvocation {
            kind: "powershell".to_string(),
            name: shell.to_string(),
            prefix: vec![
                shell.to_string(),
                "-NoLogo".to_string(),
                "-NoProfile".to_string(),
                "-Command".to_string(),
            ],
        };
    }
    if matches!(normalized.as_str(), "pwsh" | "pwsh.exe") {
        return ShellInvocation {
            kind: "pwsh".to_string(),
            name: shell.to_string(),
            prefix: vec![
                shell.to_string(),
                "-NoLogo".to_string(),
                "-NoProfile".to_string(),
                "-Command".to_string(),
            ],
        };
    }
    if matches!(normalized.as_str(), "cmd" | "cmd.exe") {
        return ShellInvocation {
            kind: "cmd".to_string(),
            name: shell.to_string(),
            prefix: vec![shell.to_string(), "/c".to_string()],
        };
    }
    ShellInvocation {
        kind: infer_shell_kind(shell).to_string(),
        name: shell.to_string(),
        prefix: vec![shell.to_string(), "-lc".to_string()],
    }
}

pub(super) fn invocation_from_executable(kind: &str, executable: String) -> ShellInvocation {
    match kind {
        "cmd" => ShellInvocation {
            kind: "cmd".to_string(),
            name: executable.clone(),
            prefix: vec![executable, "/c".to_string()],
        },
        "powershell" => ShellInvocation {
            kind: "powershell".to_string(),
            name: executable.clone(),
            prefix: vec![
                executable,
                "-NoLogo".to_string(),
                "-NoProfile".to_string(),
                "-Command".to_string(),
            ],
        },
        "pwsh" => ShellInvocation {
            kind: "pwsh".to_string(),
            name: executable.clone(),
            prefix: vec![
                executable,
                "-NoLogo".to_string(),
                "-NoProfile".to_string(),
                "-Command".to_string(),
            ],
        },
        _ => ShellInvocation {
            kind: "bash".to_string(),
            name: executable.clone(),
            prefix: vec![executable, "-lc".to_string()],
        },
    }
}

pub(super) fn normalize_shell_name(value: &str) -> String {
    value.trim().to_ascii_lowercase().replace('_', "-")
}

pub(super) fn infer_shell_kind(executable_name: &str) -> &'static str {
    let lowered = executable_name
        .rsplit(['/', '\\'])
        .next()
        .unwrap_or(executable_name)
        .trim()
        .to_ascii_lowercase();
    if matches!(lowered.as_str(), "cmd" | "cmd.exe") {
        "cmd"
    } else if lowered.starts_with("pwsh") {
        "pwsh"
    } else if lowered.contains("powershell") {
        "powershell"
    } else {
        "bash"
    }
}