Skip to main content
Glama
safety-warnings.ts12.6 kB
/** * Safety Warnings System * * Provides safety warnings and confirmations for destructive Git operations. * Helps prevent accidental data loss by clearly communicating risks. */ export type WarningLevel = 'WARNING' | 'DANGER' | 'CRITICAL'; export interface SafetyWarning { level: WarningLevel; operation: string; title: string; message: string; whatWillBeLost: string[]; suggestions: string[]; confirmationRequired: boolean; alternatives?: string[]; } export interface DestructiveOperationInfo { operation: string; riskLevel: WarningLevel; irreversible: boolean; dataLoss: boolean; workLoss: boolean; } export class SafetyWarnings { private static readonly DESTRUCTIVE_OPERATIONS: Record<string, DestructiveOperationInfo> = { 'git-reset-hard': { operation: 'git reset --hard', riskLevel: 'CRITICAL', irreversible: true, dataLoss: true, workLoss: true }, 'git-reset-mixed': { operation: 'git reset --mixed', riskLevel: 'DANGER', irreversible: false, dataLoss: false, workLoss: true }, 'delete-repository': { operation: 'delete repository', riskLevel: 'CRITICAL', irreversible: true, dataLoss: true, workLoss: true }, 'delete-branch': { operation: 'delete branch', riskLevel: 'WARNING', irreversible: true, dataLoss: true, workLoss: false }, 'delete-remote-branch': { operation: 'delete remote branch', riskLevel: 'DANGER', irreversible: true, dataLoss: true, workLoss: false }, 'force-push': { operation: 'force push', riskLevel: 'CRITICAL', irreversible: true, dataLoss: true, workLoss: false }, 'clean-untracked': { operation: 'git clean -f', riskLevel: 'DANGER', irreversible: true, dataLoss: true, workLoss: true } }; /** * Generate safety warning for a destructive operation */ public static generateWarning(operationType: string, context?: any): SafetyWarning { const operationInfo = this.DESTRUCTIVE_OPERATIONS[operationType]; if (!operationInfo) { throw new Error(`Unknown destructive operation: ${operationType}`); } return this.createWarningForOperation(operationType, operationInfo, context); } /** * Check if an operation is destructive and requires warning */ public static isDestructiveOperation(operation: string): boolean { return Object.keys(this.DESTRUCTIVE_OPERATIONS).includes(operation); } /** * Get operation risk level */ public static getRiskLevel(operation: string): WarningLevel | null { const operationInfo = this.DESTRUCTIVE_OPERATIONS[operation]; return operationInfo ? operationInfo.riskLevel : null; } /** * Format warning message for display */ public static formatWarning(warning: SafetyWarning): string { const levelEmoji = this.getLevelEmoji(warning.level); const levelColor = this.getLevelColor(warning.level); let message = `${levelEmoji} **${warning.title}**\n\n`; message += `${warning.message}\n\n`; if (warning.whatWillBeLost.length > 0) { message += `**⚠️ What will be lost:**\n`; warning.whatWillBeLost.forEach(item => { message += ` • ${item}\n`; }); message += '\n'; } if (warning.suggestions.length > 0) { message += `**💡 Suggestions:**\n`; warning.suggestions.forEach(suggestion => { message += ` • ${suggestion}\n`; }); message += '\n'; } if (warning.alternatives && warning.alternatives.length > 0) { message += `**🔄 Safer alternatives:**\n`; warning.alternatives.forEach(alternative => { message += ` • ${alternative}\n`; }); message += '\n'; } if (warning.confirmationRequired) { message += `**🚨 This operation requires explicit confirmation.**\n`; } return message; } /** * Create warning for specific operation */ private static createWarningForOperation( operationType: string, operationInfo: DestructiveOperationInfo, context?: any ): SafetyWarning { switch (operationType) { case 'git-reset-hard': return { level: 'CRITICAL', operation: 'git reset --hard', title: 'CRITICAL: Hard Reset Will Permanently Delete Changes', message: 'This operation will permanently delete all uncommitted changes and reset your working directory to the specified commit.', whatWillBeLost: [ 'All uncommitted changes in tracked files', 'All staged changes', 'Any local modifications since the last commit' ], suggestions: [ 'Create a backup or stash your changes first', 'Use `git stash` to temporarily save your work', 'Check `git status` to see what will be lost', 'Consider using `git reset --soft` or `git reset --mixed` for safer alternatives' ], confirmationRequired: true, alternatives: [ 'git reset --soft HEAD~1 (keeps changes staged)', 'git reset --mixed HEAD~1 (keeps changes unstaged)', 'git stash (saves changes temporarily)', 'git checkout -- <file> (reset specific files only)' ] }; case 'git-reset-mixed': return { level: 'DANGER', operation: 'git reset --mixed', title: 'DANGER: Mixed Reset Will Unstage Changes', message: 'This operation will unstage all staged changes but keep them in your working directory.', whatWillBeLost: [ 'All staged changes (will become unstaged)', 'Commit history will be modified' ], suggestions: [ 'Check what files are currently staged with `git status`', 'Ensure you want to unstage all changes', 'Consider committing changes first if they\'re important' ], confirmationRequired: false, alternatives: [ 'git reset HEAD <file> (unstage specific files only)', 'git commit (commit staged changes)', 'git stash (save changes temporarily)' ] }; case 'delete-repository': return { level: 'CRITICAL', operation: 'delete repository', title: 'CRITICAL: Repository Deletion is Permanent', message: `This will permanently delete the repository "${context?.repo || 'unknown'}" and all its contents.`, whatWillBeLost: [ 'Entire repository and all files', 'All commit history', 'All branches and tags', 'All issues and pull requests', 'All project settings and configurations' ], suggestions: [ 'Create a backup of the repository first', 'Download/clone the repository locally', 'Archive the repository instead of deleting', 'Double-check you have the right repository' ], confirmationRequired: true, alternatives: [ 'Archive repository (preserves data)', 'Make repository private (restricts access)', 'Transfer repository ownership', 'Clone/download repository before deletion' ] }; case 'delete-branch': return { level: 'WARNING', operation: 'delete branch', title: 'WARNING: Branch Deletion May Cause Data Loss', message: `This will permanently delete the branch "${context?.branch || 'unknown'}" and its commit history.`, whatWillBeLost: [ 'Branch and its commit history', 'Any unmerged commits on this branch' ], suggestions: [ 'Ensure the branch has been merged to main/master', 'Check for any unmerged commits with `git log main..branch-name`', 'Create a backup branch before deletion', 'Verify no one else is working on this branch' ], confirmationRequired: true, alternatives: [ 'Merge branch to main first', 'Create backup branch before deletion', 'Archive branch instead of deleting' ] }; case 'delete-remote-branch': return { level: 'DANGER', operation: 'delete remote branch', title: 'DANGER: Remote Branch Deletion Affects All Users', message: `This will delete the remote branch "${context?.branch || 'unknown'}" for all repository users.`, whatWillBeLost: [ 'Remote branch access for all team members', 'Remote tracking branches', 'Any CI/CD configurations tied to this branch' ], suggestions: [ 'Coordinate with team members before deletion', 'Ensure no active pull requests depend on this branch', 'Check if branch is referenced in documentation', 'Verify CI/CD pipelines don\'t depend on this branch' ], confirmationRequired: true, alternatives: [ 'Coordinate deletion with team first', 'Archive branch instead of deleting', 'Make branch read-only instead' ] }; case 'force-push': return { level: 'CRITICAL', operation: 'force push', title: 'CRITICAL: Force Push Will Overwrite Remote History', message: 'This will forcefully overwrite the remote branch history, potentially losing commits.', whatWillBeLost: [ 'Remote commit history may be lost', 'Other developers\' work may be overwritten', 'Any commits that exist only on the remote' ], suggestions: [ 'Coordinate with all team members before force pushing', 'Ensure no one else has pushed to the remote branch', 'Consider using `git push --force-with-lease` for safer force push', 'Create a backup branch before force pushing' ], confirmationRequired: true, alternatives: [ 'git push --force-with-lease (safer force push)', 'git rebase -i (rebase instead of force push)', 'Coordinate with team and merge normally' ] }; case 'clean-untracked': return { level: 'DANGER', operation: 'git clean -f', title: 'DANGER: Clean Will Permanently Delete Untracked Files', message: 'This will permanently delete all untracked files and directories.', whatWillBeLost: [ 'All untracked files', 'All untracked directories', 'Any temporary files or build artifacts' ], suggestions: [ 'Review what will be deleted with `git clean -n` first', 'Backup important untracked files', 'Add important files to .gitignore before cleaning', 'Use `git clean -i` for interactive cleaning' ], confirmationRequired: true, alternatives: [ 'git clean -n (dry run to see what would be deleted)', 'git clean -i (interactive mode)', 'git clean -d (include directories)', 'Manually delete specific files' ] }; default: return { level: 'WARNING', operation: operationType, title: 'WARNING: Potentially Destructive Operation', message: 'This operation may cause data loss or permanent changes.', whatWillBeLost: ['Unknown data may be lost'], suggestions: ['Review the operation carefully before proceeding'], confirmationRequired: true }; } } /** * Get emoji for warning level */ private static getLevelEmoji(level: WarningLevel): string { switch (level) { case 'WARNING': return '⚠️'; case 'DANGER': return '🚨'; case 'CRITICAL': return '💥'; default: return '⚠️'; } } /** * Get color indicator for warning level */ private static getLevelColor(level: WarningLevel): string { switch (level) { case 'WARNING': return 'yellow'; case 'DANGER': return 'orange'; case 'CRITICAL': return 'red'; default: return 'yellow'; } } }

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/Andre-Buzeli/git-mcp'

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