kai-tool 0.1.6

CLI helpers for AI coding, Codex credentials, and git worktree management.
use std::env;
use std::path::{Path, PathBuf};

use anyhow::{Context, Result, bail};

#[derive(Debug, Clone)]
pub struct RuntimePaths {
    pub credentials_home: PathBuf,
    pub codex_home: PathBuf,
}

impl RuntimePaths {
    pub fn from_env() -> Result<Self> {
        let home = capulus::paths::home_dir()
            .context("could not determine the current user's home directory")?;
        Self::new(
            env_path("KAI_CREDENTIALS_HOME")
                .unwrap_or_else(|| home.join(".kai").join("credentials")),
            env_path("CODEX_HOME").unwrap_or_else(|| home.join(".codex")),
        )
    }

    pub fn new(credentials_home: PathBuf, codex_home: PathBuf) -> Result<Self> {
        Ok(Self {
            credentials_home: absolute(&credentials_home)
                .context("could not resolve KAI_CREDENTIALS_HOME")?,
            codex_home: absolute(&codex_home).context("could not resolve CODEX_HOME")?,
        })
    }

    pub fn active_auth(&self) -> PathBuf {
        self.codex_home.join("auth.json")
    }

    pub fn codex_config(&self) -> PathBuf {
        self.codex_home.join("config.toml")
    }

    pub fn profiles_dir(&self) -> PathBuf {
        self.credentials_home.join("profiles")
    }

    pub fn state_file(&self) -> PathBuf {
        self.credentials_home.join("state.json")
    }
}

fn env_path(name: &str) -> Option<PathBuf> {
    env::var_os(name)
        .filter(|value| !value.is_empty())
        .map(PathBuf::from)
}

fn absolute(path: &Path) -> Result<PathBuf> {
    if path.as_os_str().is_empty() {
        bail!("path cannot be empty");
    }
    std::path::absolute(path).map_err(Into::into)
}