skiff-cli 0.1.2

Progressive MCP / OpenAPI / GraphQL CLI for agents — fast warm discovery, sessions, spool
Documentation
//! Cache and config directory resolution (Python-compatible layout).
//!
//! - Cache: `$SKIFF_CACHE_DIR` or `~/.cache/skiff` (tool lists, GraphQL/OpenAPI,
//!   OAuth, sessions, usage)
//! - Config: `$SKIFF_CONFIG_DIR` or `~/.config/skiff` (`baked.json`)
//!
//! Tests may override via [`set_cache_dir_override`] / [`set_config_dir_override`]
//! under [`TEST_PATHS_LOCK`].

use std::path::PathBuf;
use std::sync::{LazyLock, RwLock};

static CACHE_DIR_OVERRIDE: LazyLock<RwLock<Option<PathBuf>>> = LazyLock::new(|| RwLock::new(None));
static CONFIG_DIR_OVERRIDE: LazyLock<RwLock<Option<PathBuf>>> = LazyLock::new(|| RwLock::new(None));

/// Override cache dir (for tests). `None` clears the override.
pub fn set_cache_dir_override(path: Option<PathBuf>) {
    *CACHE_DIR_OVERRIDE.write().expect("cache override lock") = path;
}

/// Override config dir (for tests). `None` clears the override.
pub fn set_config_dir_override(path: Option<PathBuf>) {
    *CONFIG_DIR_OVERRIDE.write().expect("config override lock") = path;
}

pub fn cache_dir() -> PathBuf {
    if let Some(p) = CACHE_DIR_OVERRIDE
        .read()
        .expect("cache override lock")
        .clone()
    {
        return p;
    }
    if let Ok(p) = std::env::var("SKIFF_CACHE_DIR") {
        return PathBuf::from(p);
    }
    home_dir()
        .map(|h| h.join(".cache").join("skiff"))
        .unwrap_or_else(|| PathBuf::from(".cache/skiff"))
}

pub fn config_dir() -> PathBuf {
    if let Some(p) = CONFIG_DIR_OVERRIDE
        .read()
        .expect("config override lock")
        .clone()
    {
        return p;
    }
    if let Ok(p) = std::env::var("SKIFF_CONFIG_DIR") {
        return PathBuf::from(p);
    }
    home_dir()
        .map(|h| h.join(".config").join("skiff"))
        .unwrap_or_else(|| PathBuf::from(".config/skiff"))
}

pub fn usage_file() -> PathBuf {
    cache_dir().join("usage.json")
}

pub fn baked_file() -> PathBuf {
    config_dir().join("baked.json")
}

fn home_dir() -> Option<PathBuf> {
    std::env::var_os("HOME")
        .or_else(|| std::env::var_os("USERPROFILE"))
        .map(PathBuf::from)
}

pub const DEFAULT_CACHE_TTL: u64 = 3600;

/// Shared lock so tests that override cache/config dirs don't race.
#[cfg(test)]
pub static TEST_PATHS_LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());