Skip to main content
Glama
repo.ts4.72 kB
import fs from "node:fs"; import path from "node:path"; import os from "node:os"; import fse from "fs-extra"; import { simpleGit } from "simple-git"; import { createError, envBoolean, envString, normalizePath } from "./util.js"; let resolvedRepoPath: string | null = null; const DEFAULT_REMOTE = "https://github.com/FedRAMP/docs"; const DEFAULT_BRANCH = "main"; function getCachePath(): string { return path.join(os.homedir(), ".cache", "fedramp-docs"); } export interface RepoConfig { repoPath: string; remote: string; branch: string; allowAutoClone: boolean; } export function getRepoConfig(): RepoConfig { const repoPath = envString("FEDRAMP_DOCS_PATH") ?? normalizePath(path.resolve(getCachePath())); return { repoPath, remote: envString("FEDRAMP_DOCS_REMOTE", DEFAULT_REMOTE) ?? DEFAULT_REMOTE, branch: envString("FEDRAMP_DOCS_BRANCH", DEFAULT_BRANCH) ?? DEFAULT_BRANCH, allowAutoClone: envBoolean("FEDRAMP_DOCS_ALLOW_AUTO_CLONE", true), }; } async function pathExists(targetPath: string): Promise<boolean> { try { await fse.access(targetPath, fs.constants.F_OK); return true; } catch { return false; } } async function cloneRepoIfNeeded(config: RepoConfig): Promise<void> { if (await pathExists(config.repoPath)) { return; } if (!config.allowAutoClone) { throw createError({ code: "REPO_CLONE_FAILED", message: "FedRAMP docs repository not found locally and auto clone is disabled.", hint: "Set FEDRAMP_DOCS_PATH to a local clone or enable FEDRAMP_DOCS_ALLOW_AUTO_CLONE=1.", }); } await fse.ensureDir(path.dirname(config.repoPath)); const git = simpleGit(); try { await git.clone(config.remote, config.repoPath, [ "--depth", "1", "--branch", config.branch, ]); } catch (error) { throw createError({ code: "REPO_CLONE_FAILED", message: `Failed to clone FedRAMP docs repository: ${(error as Error).message}`, hint: "Check network connectivity or set FEDRAMP_DOCS_PATH to an existing local checkout.", }); } } async function shouldUpdateRepo(repoPath: string): Promise<boolean> { const autoUpdate = envBoolean("FEDRAMP_DOCS_AUTO_UPDATE", true); if (!autoUpdate) { return false; } const maxAgeHours = parseInt( envString("FEDRAMP_DOCS_UPDATE_CHECK_HOURS", "24") ?? "24", 10, ); try { const gitDir = path.join(repoPath, ".git"); if (!(await pathExists(gitDir))) { return false; // Not a git repo, can't update } // Check last fetch time from FETCH_HEAD const fetchHeadPath = path.join(gitDir, "FETCH_HEAD"); if (await pathExists(fetchHeadPath)) { const stats = await fse.stat(fetchHeadPath); const ageHours = (Date.now() - stats.mtime.getTime()) / (1000 * 60 * 60); if (ageHours < maxAgeHours) { return false; // Recently updated } } return true; } catch { return false; // Error checking, skip update } } async function updateRepo(repoPath: string): Promise<void> { try { const git = simpleGit(repoPath); await git.fetch(["origin"]); await git.reset(["--hard", "origin/main"]); console.error( `fedramp-docs-mcp: Updated repository at ${repoPath}`, ); } catch (error) { console.error( `fedramp-docs-mcp: Failed to update repository: ${(error as Error).message}`, ); // Don't throw - continue with existing cache } } export async function ensureRepoReady(): Promise<string> { if (resolvedRepoPath) { return resolvedRepoPath; } const config = getRepoConfig(); if (await pathExists(config.repoPath)) { resolvedRepoPath = config.repoPath; // Check if we should update the repo if (await shouldUpdateRepo(config.repoPath)) { await updateRepo(config.repoPath); } return resolvedRepoPath; } await cloneRepoIfNeeded(config); resolvedRepoPath = config.repoPath; return resolvedRepoPath; } export async function forceUpdateRepo(): Promise<{ success: boolean; message: string; }> { try { const repoPath = getRepoPath(); await updateRepo(repoPath); return { success: true, message: `Successfully updated repository at ${repoPath}`, }; } catch (error) { return { success: false, message: `Failed to update repository: ${(error as Error).message}`, }; } } export function getRepoPath(): string { if (!resolvedRepoPath) { throw new Error("Repository path not resolved. Call ensureRepoReady first."); } return resolvedRepoPath; } export function resolveRepoPath(relativePath: string): string { return path.join(getRepoPath(), relativePath); }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ethanolivertroy/fedramp-docs-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server