ai-agent 0.88.0

Idiomatic agent sdk inspired by the claude code source leak
Documentation
use std::collections::HashMap;
use std::sync::Mutex;

static REPO_CACHE: std::sync::LazyLock<Mutex<HashMap<String, Option<ParsedRepository>>>> =
    std::sync::LazyLock::new(|| Mutex::new(HashMap::new()));

#[derive(Clone, Debug)]
pub struct ParsedRepository {
    pub host: String,
    pub owner: String,
    pub name: String,
}

pub fn clear_repository_caches() {
    REPO_CACHE.lock().unwrap().clear();
}

pub fn parse_git_remote(input: &str) -> Option<ParsedRepository> {
    let trimmed = input.trim();

    if let Some(ssh_match) = regex_lite::Regex::new(r"^git@([^:]+):([^/]+)/([^/]+?)(?:\.git)?$")
        .ok()
        .and_then(|re| re.captures(trimmed))
    {
        let host = ssh_match.get(1)?.as_str();
        if !looks_like_real_hostname(host) {
            return None;
        }
        return Some(ParsedRepository {
            host: host.to_string(),
            owner: ssh_match.get(2)?.as_str().to_string(),
            name: ssh_match.get(3)?.as_str().to_string(),
        });
    }

    if let Some(url_match) = regex_lite::Regex::new(
        r"^(https?|ssh|git)://(?:[^@]+@)?([^/:]+(?::\d+)?)/([^/]+)/([^/]+?)(?:\.git)?$",
    )
    .ok()
    .and_then(|re| re.captures(trimmed))
    {
        let protocol = url_match.get(1)?.as_str();
        let host_with_port = url_match.get(2)?.as_str();
        let host = if protocol == "https" || protocol == "http" {
            host_with_port.to_string()
        } else {
            host_with_port.split(':').next().unwrap_or("").to_string()
        };

        if !looks_like_real_hostname(&host) {
            return None;
        }

        return Some(ParsedRepository {
            host,
            owner: url_match.get(3)?.as_str().to_string(),
            name: url_match.get(4)?.as_str().to_string(),
        });
    }

    None
}

fn looks_like_real_hostname(host: &str) -> bool {
    if !host.contains('.') {
        return false;
    }
    let last_segment = host.split('.').last()?;
    last_segment.chars().all(|c| c.is_alphabetic())
}

pub fn parse_github_repository(input: &str) -> Option<String> {
    let trimmed = input.trim();

    if let Some(parsed) = parse_git_remote(trimmed) {
        if parsed.host != "github.com" {
            return None;
        }
        return Some(format!("{}/{}", parsed.owner, parsed.name));
    }

    if !trimmed.contains("://") && !trimmed.contains('@') && trimmed.contains('/') {
        let parts: Vec<&str> = trimmed.split('/').collect();
        if parts.len() == 2 {
            let repo = parts[1].trim_end_matches(".git");
            return Some(format!("{}/{}", parts[0], repo));
        }
    }

    None
}