codebase-graph 1.1.5

Native codebaseGraph CLI and MCP server for local code knowledge graphs.
use super::{home_dir, NativeMcpDescriptor};
use std::{
    env,
    path::{Path, PathBuf},
};

pub(in crate::cli) fn default_client_config_path(
    client: &str,
    scope: &str,
    descriptor: &NativeMcpDescriptor,
) -> PathBuf {
    let home = home_dir();
    match adapter_id(client, scope) {
        "codex" => env::var_os("CODEX_HOME")
            .map(PathBuf::from)
            .unwrap_or_else(|| home.join(".codex"))
            .join("config.toml"),
        "claude" => {
            let mac_path =
                home.join("Library/Application Support/Claude/claude_desktop_config.json");
            if mac_path.parent().is_some_and(Path::exists) {
                mac_path
            } else {
                home.join(".config/claude/claude_desktop_config.json")
            }
        }
        "claude-project" => PathBuf::from(&descriptor.repo_root).join(".mcp.json"),
        "lmstudio" => home.join(".lmstudio/mcp.json"),
        "github-copilot" => PathBuf::from(&descriptor.repo_root).join(".vscode/mcp.json"),
        "hermes" => home.join(".hermes/config.yaml"),
        "openclaw" => env::var_os("OPENCLAW_HOME")
            .map(PathBuf::from)
            .unwrap_or_else(|| home.join(".openclaw"))
            .join("mcp.json5"),
        _ => home.join(".config/mcp/mcp.json"),
    }
}

pub(in crate::cli) fn supported_install_clients() -> Vec<&'static str> {
    vec![
        "claude",
        "claude-project",
        "codex",
        "copilot-studio",
        "generic",
        "github-copilot",
        "hermes",
        "lmstudio",
        "microsoft-copilot",
        "openclaw",
    ]
}

pub(in crate::cli) fn supported_install_clients_with_all() -> Vec<&'static str> {
    let mut clients = supported_install_clients();
    clients.push("all");
    clients
}

pub(in crate::cli) fn install_scope(client: &str, scope: &str) -> String {
    if client == "claude-project" {
        "project".to_string()
    } else {
        scope.to_string()
    }
}

pub(in crate::cli) fn adapter_id<'a>(client: &'a str, scope: &str) -> &'a str {
    if client == "claude" && scope == "project" {
        "claude-project"
    } else {
        client
    }
}

pub(in crate::cli) fn native_client_command(
    client: &str,
    descriptor: &NativeMcpDescriptor,
    scope: &str,
) -> Option<Vec<String>> {
    match client {
        "codex" => Some(vec![
            "codex".to_string(),
            "mcp".to_string(),
            "add".to_string(),
            descriptor.name.clone(),
            "--".to_string(),
            descriptor.command.clone(),
            descriptor.args[0].clone(),
            descriptor.args[1].clone(),
            descriptor.args[2].clone(),
            descriptor.args[3].clone(),
        ]),
        "claude" | "claude-project" => Some(vec![
            "claude".to_string(),
            "mcp".to_string(),
            "add".to_string(),
            "--transport".to_string(),
            "stdio".to_string(),
            "--scope".to_string(),
            install_scope(client, scope),
            descriptor.name.clone(),
            "--".to_string(),
            descriptor.command.clone(),
            descriptor.args[0].clone(),
            descriptor.args[1].clone(),
            descriptor.args[2].clone(),
            descriptor.args[3].clone(),
        ]),
        "openclaw" => Some(vec![
            "openclaw".to_string(),
            "mcp".to_string(),
            "set".to_string(),
            descriptor.name.clone(),
            serde_json::to_string(&descriptor.stdio_entry(true, false)).ok()?,
        ]),
        _ => None,
    }
}