lean-ctx-engine 3.12.3

LeanCTX | OSS library: the open-source runtime for the Context Gateway for AI agents behind the lean-ctx CLI, MCP server and proxy integrations.
Documentation
#[derive(Clone)]
pub struct GitLabConfig {
    pub host: String,
    pub token: String,
    pub project_path: Option<String>,
}

impl std::fmt::Debug for GitLabConfig {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("GitLabConfig")
            .field("host", &self.host)
            .field("token", &"[REDACTED]")
            .field("project_path", &self.project_path)
            .finish()
    }
}

impl GitLabConfig {
    pub fn from_session() -> Result<Self, String> {
        super::selected_gitlab::config().map_or_else(Self::from_env, Ok)
    }

    pub fn from_env() -> Result<Self, String> {
        let token = super::credentials::var("LEAN_CTX_GITLAB_TOKEN")
            .or_else(|_| super::credentials::var("GITLAB_TOKEN"))
            .or_else(|_| super::credentials::var("CI_JOB_TOKEN"))
            .map_err(|_| {
                "No GitLab token found. Set GITLAB_TOKEN or LEAN_CTX_GITLAB_TOKEN.".to_string()
            })?;

        let host = super::credentials::var("GITLAB_HOST")
            .or_else(|_| super::credentials::var("CI_SERVER_HOST"))
            .unwrap_or_else(|_| "gitlab.com".to_string());

        let project_path = super::credentials::var("CI_PROJECT_PATH")
            .ok()
            .or_else(|| detect_project_from_git_remote(&host));

        Ok(Self {
            host,
            token,
            project_path,
        })
    }

    pub fn api_url(&self, endpoint: &str) -> String {
        // Loopback API fixtures speak plain HTTP; production is HTTPS only.
        // Also in the unit-test harnesses above the Engine (`test-support`),
        // never in the `lean-ctx` binary.
        #[cfg(any(test, feature = "test-support"))]
        if crate::core::data_dir::sandboxed()
            && let Some(fixture) = self.host.strip_prefix("http://127.0.0.1:")
        {
            return format!("http://127.0.0.1:{fixture}/api/v4{endpoint}");
        }
        format!("https://{}/api/v4{}", self.host, endpoint)
    }
}

fn detect_project_from_git_remote(host: &str) -> Option<String> {
    let output = std::process::Command::new("git")
        .args(["remote", "get-url", "origin"])
        .output()
        .ok()?;
    if !output.status.success() {
        return None;
    }
    let url = String::from_utf8_lossy(&output.stdout).trim().to_string();

    // Handle SSH: git@gitlab.com:group/project.git
    if let Some(rest) = url.strip_prefix(&format!("git@{host}:")) {
        return Some(rest.trim_end_matches(".git").to_string());
    }
    // Handle HTTPS: https://gitlab.com/group/project.git
    if let Some(rest) = url.strip_prefix(&format!("https://{host}/")) {
        return Some(rest.trim_end_matches(".git").to_string());
    }
    None
}