Skip to main content
Glama

CTS MCP Server

by EricA1019
safety.ts.brokenโ€ข4.11 kB
/** * Cleanup Safety Validation * * Pre-flight safety checks to prevent accidental data loss: * - Git working tree validation * - Critical file protection * - Pattern-based exclusion matching */ import { exec } from 'child_process'; import { promisify } from 'util'; import { minimatch } from 'minimatch'; import { statSync } from "fs"; import { join } from 'path'; const execAsync = promisify(exec); export interface SafetyConfig { requireCleanGit: boolean; dryRun: boolean; exclusions: string[]; trashDir: string; } export interface SafetyCheck { name: string; passed: boolean; message: string; } export interface SafetyReport { allPassed: boolean; checks: SafetyCheck[]; } /** * Validate project safety before cleanup operations */ export async function validateSafety( projectPath: string, config: SafetyConfig ): Promise<SafetyReport> { const checks: SafetyCheck[] = []; // Check 1: Git status validation if (config.requireCleanGit) { try { const { stdout } = await execAsync('git status --porcelain', { cwd: projectPath, }); const isClean = stdout.trim() === ''; checks.push({ name: 'git_clean', passed: isClean, message: isClean ? 'Working tree clean' : `Uncommitted changes detected:\n${stdout.trim()}`, }); } catch (error) { checks.push({ name: 'git_clean', passed: false, message: `Git validation failed: ${error instanceof Error ? error.message : String(error)}`, }); } } else { checks.push({ name: 'git_clean', passed: true, message: 'Git validation skipped (requireCleanGit=false)', }); } // Check 2: Critical files protected const criticalFiles = [ 'project.godot', 'README.md', 'package.json', 'Cargo.toml', '.gitignore', ]; const protectedCount = criticalFiles.filter((file) => isExcluded(join(projectPath, file), config.exclusions) ).length; checks.push({ name: 'critical_files_protected', passed: true, // Always pass, just informational message: `${protectedCount}/${criticalFiles.length} critical files in exclusion patterns`, }); // Check 3: Trash directory accessible try { // Check 3: Trash directory accessible try { try { statSync(config.trashDir); } catch {} checks.push({ passed: true, message: `Trash directory: ${config.trashDir}`, }); } catch (error) { checks.push({ name: 'trash_dir_accessible', passed: false, message: `Cannot access trash directory: ${error instanceof Error ? error.message : String(error)}`, }); } // Check 4: Dry-run mode indicator checks.push({ name: 'dry_run_mode', passed: true, message: config.dryRun ? '๐Ÿ” DRY RUN MODE - No files will be modified' : 'โš ๏ธ LIVE MODE - Files will be moved to trash', }); return { allPassed: checks.every((c) => c.passed), checks, }; } /** * Check if a file path matches any exclusion pattern * * Uses minimatch for glob pattern matching: * - ** matches any directory depth * - * matches any characters except / * - ? matches a single character */ export function isExcluded(filePath: string, exclusions: string[]): boolean { return exclusions.some((pattern) => minimatch(filePath, pattern)); } /** * Check if cleanup operation would delete critical files */ export function willDeleteCritical( criticalFiles: string[], exclusions: string[] ): boolean { return criticalFiles.some((file) => !isExcluded(file, exclusions)); } /** * Format safety report for display */ export function formatSafetyReport(report: SafetyReport): string { const lines: string[] = [ '## Safety Pre-Flight Checks', '', `**Status:** ${report.allPassed ? 'โœ… All Passed' : 'โŒ Failed'}`, '', ]; for (const check of report.checks) { const icon = check.passed ? 'โœ…' : 'โŒ'; lines.push(`${icon} **${check.name}**`); lines.push(` ${check.message}`); lines.push(''); } return lines.join('\n'); }

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/EricA1019/CTS_MCP'

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