Skip to main content
Glama
blade47

ShadowGit MCP Server

by blade47
checkpoint-handler.ts5.77 kB
/** * Handler for checkpoint tool - creates git commits */ import { RepositoryManager } from '../core/repository-manager'; import { GitExecutor } from '../core/git-executor'; import { createErrorResponse } from '../utils/response-utils'; import type { MCPToolResponse, ManualCheckpointArgs } from '../types'; export class CheckpointHandler { constructor( private repositoryManager: RepositoryManager, private gitExecutor: GitExecutor ) {} /** * Validate checkpoint arguments */ private isValidArgs(args: unknown): args is ManualCheckpointArgs { return ( typeof args === 'object' && args !== null && 'repo' in args && 'title' in args && typeof (args as ManualCheckpointArgs).repo === 'string' && typeof (args as ManualCheckpointArgs).title === 'string' ); } /** * Handle checkpoint tool execution */ async handle(args: unknown): Promise<MCPToolResponse> { if (!this.isValidArgs(args)) { return createErrorResponse( "Error: Both 'repo' and 'title' parameters are required.", `Example usage: checkpoint({ repo: "my-project", title: "Fix authentication bug", author: "Claude" }) Use list_repos() to see available repositories.` ); } // Validate title length if (args.title.length > 50) { return createErrorResponse( `Error: Title must be 50 characters or less (current: ${args.title.length} chars).` ); } // Validate message length if provided if (args.message && args.message.length > 1000) { return createErrorResponse( `Error: Message must be 1000 characters or less (current: ${args.message.length} chars).` ); } const repoPath = this.repositoryManager.resolveRepoPath(args.repo); if (!repoPath) { const repos = this.repositoryManager.getRepositories(); if (repos.length === 0) { return createErrorResponse( 'Error: No repositories found. Please add repositories to ShadowGit first.' ); } return createErrorResponse( `Error: Repository '${args.repo}' not found.`, `Available repositories: ${repos.map(r => ` - ${r.name}: ${r.path}`).join('\n')}` ); } // Check for changes const statusOutput = await this.gitExecutor.execute(['status', '--porcelain'], repoPath, true); if (!statusOutput || statusOutput.trim() === '' || statusOutput === '(empty output)') { return createErrorResponse( `❌ **No Changes Detected** ${'='.repeat(50)} 📁 Repository has no changes to commit. ⚠️ **Important:** Do NOT call end_session() - no commit was created. 💡 **NEXT STEP:** Make some changes first, then call checkpoint() again.` ); } // Build commit message const commitTitle = args.title; const commitBody = args.message || ''; const author = args.author || 'AI Assistant'; // Add all changes const addOutput = await this.gitExecutor.execute(['add', '-A'], repoPath, true); if (addOutput.startsWith('Error:')) { return createErrorResponse( `❌ **Failed to Stage Changes** ${'='.repeat(50)} 🚨 **Error:** ${addOutput} ⚠️ **Important:** Do NOT call end_session() - commit was not created. 💡 **NEXT STEP:** Check the error and try again.` ); } // Build full commit message let fullMessage = commitTitle; if (commitBody) { fullMessage += `\n\n${commitBody}`; } fullMessage += `\n\nAuthor: ${author} (via ShadowGit MCP)`; // Create commit with author information const commitEnv = { GIT_AUTHOR_NAME: author, GIT_AUTHOR_EMAIL: `${author.toLowerCase().replace(/\s+/g, '-')}@shadowgit.local`, GIT_COMMITTER_NAME: 'ShadowGit MCP', GIT_COMMITTER_EMAIL: 'shadowgit-mcp@shadowgit.local' }; // Use array-based command to avoid parsing issues const commitOutput = await this.gitExecutor.execute( ['commit', '-m', fullMessage], repoPath, true, commitEnv ); if (commitOutput.startsWith('Error:')) { return createErrorResponse( `❌ **Failed to Create Commit** ${'='.repeat(50)} 🚨 **Error:** ${commitOutput} ⚠️ **Important:** Do NOT call end_session() - commit was not created. 💡 **NEXT STEP:** Check the error message and try checkpoint() again.` ); } // Extract commit hash from output let commitHash: string | undefined; const hashMatch = commitOutput.match(/\[[\w\-]+ ([a-f0-9]+)\]/); if (hashMatch) { commitHash = hashMatch[1]; } // Get summary of changes const showOutput = await this.gitExecutor.execute(['show', '--stat', '--format=short', 'HEAD'], repoPath, true); return { content: [ { type: 'text', text: `✅ **Checkpoint Created Successfully!** ${'='.repeat(50)} 📦 **Commit Details:** ${commitOutput} 📊 **Changes Summary:** ${showOutput} 🔑 **Commit Hash:** \`${commitHash || 'unknown'}\` ${'='.repeat(50)} 📋 **Workflow Progress:** - [x] Session started - [x] Changes made - [x] Checkpoint created ✨ - [ ] Session ended 🚨 **REQUIRED NEXT STEP:** You MUST now call \`end_session()\` to resume auto-commits: \`\`\`javascript end_session({ sessionId: "your-session-id", commitHash: "${commitHash || 'unknown'}" }) \`\`\` ⚠️ **Important:** Only call end_session() because the commit was SUCCESSFUL.` } ], success: true }; } }

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/blade47/shadowgit-mcp'

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