Commit 2241040

mo khan <mo@mokhan.ca>
2025-06-22 20:06:09
feat: add commit-message prompt to git server
- Add registerPrompts method to git server with commit message prompt - Implement HandleCommitMessagePrompt for interactive commit message guidance - Support conventional commit format with type, breaking change flags - Generate user/assistant conversation for commit message crafting - Fix git server tests to accommodate new constructor signature Features: - changes (required): Description of changes being committed - type (optional): Commit type (feat, fix, docs, etc.) - defaults to "feat" - breaking (optional): Whether this is a breaking change Prompt provides: - Conventional commit format guidance - Breaking change notation with \! prefix - Best practices for commit messages (imperative mood, length limits) - Context-aware descriptions and examples Testing shows: - Proper prompt registration and listing - Correct message generation for basic and advanced scenarios - Breaking change handling with appropriate formatting - Error validation for missing required arguments - Dynamic descriptions based on commit type and breaking status 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent f635690
Changed files (2)
pkg/git/server.go
@@ -26,8 +26,9 @@ func New(repoPath string) *Server {
 		repoPath: repoPath,
 	}
 
-	// Register all git tools
+	// Register all git tools and prompts
 	gitServer.registerTools()
+	gitServer.registerPrompts()
 
 	return gitServer
 }
@@ -48,6 +49,33 @@ func (gs *Server) registerTools() {
 	gs.RegisterTool("git_init", gs.HandleGitInit)
 }
 
+// registerPrompts registers all Git prompts with the server
+func (gs *Server) registerPrompts() {
+	commitPrompt := mcp.Prompt{
+		Name:        "commit-message",
+		Description: "Prompt for crafting a well-structured git commit message",
+		Arguments: []mcp.PromptArgument{
+			{
+				Name:        "changes",
+				Description: "Description of the changes being committed",
+				Required:    true,
+			},
+			{
+				Name:        "type",
+				Description: "Type of change (feat, fix, docs, style, refactor, test, chore)",
+				Required:    false,
+			},
+			{
+				Name:        "breaking",
+				Description: "Whether this is a breaking change (true/false)",
+				Required:    false,
+			},
+		},
+	}
+	
+	gs.RegisterPrompt(commitPrompt, gs.HandleCommitMessagePrompt)
+}
+
 // ListTools returns all available Git tools
 func (gs *Server) ListTools() []mcp.Tool {
 	return []mcp.Tool{
@@ -512,6 +540,102 @@ func (gs *Server) runGitCommand(repoPath string, args ...string) (string, error)
 	return strings.TrimSpace(string(output)), nil
 }
 
+// Prompt handlers
+
+func (gs *Server) HandleCommitMessagePrompt(req mcp.GetPromptRequest) (mcp.GetPromptResult, error) {
+	changes, hasChanges := req.Arguments["changes"].(string)
+	commitType, hasType := req.Arguments["type"].(string)
+	breaking, hasBreaking := req.Arguments["breaking"]
+
+	if !hasChanges || changes == "" {
+		return mcp.GetPromptResult{}, fmt.Errorf("changes argument is required")
+	}
+
+	// Default type if not provided
+	if !hasType || commitType == "" {
+		commitType = "feat" // Default to feature
+	}
+
+	// Parse breaking change flag
+	isBreaking := false
+	if hasBreaking {
+		if breakingBool, ok := breaking.(bool); ok {
+			isBreaking = breakingBool
+		} else if breakingStr, ok := breaking.(string); ok {
+			isBreaking = breakingStr == "true"
+		}
+	}
+
+	// Create the prompt messages
+	var messages []mcp.PromptMessage
+
+	// User message describing the changes
+	userContent := fmt.Sprintf(`I need help writing a git commit message for the following changes:
+
+%s
+
+Please help me craft a well-structured commit message following conventional commit format.`, changes)
+
+	if hasType {
+		userContent += fmt.Sprintf("\n\nCommit type: %s", commitType)
+	}
+	if isBreaking {
+		userContent += "\n\nThis is a BREAKING CHANGE."
+	}
+
+	messages = append(messages, mcp.PromptMessage{
+		Role:    "user",
+		Content: mcp.NewTextContent(userContent),
+	})
+
+	// Assistant message with suggested commit format
+	breakingPrefix := ""
+	if isBreaking {
+		breakingPrefix = "!"
+	}
+
+	assistantContent := fmt.Sprintf(`I'll help you create a conventional commit message. Here's the suggested format:
+
+**Commit message:**
+%s%s: %s
+
+**Format explanation:**
+- Type: %s (indicates the nature of the change)
+- Description: Clear, concise summary in present tense
+%s
+
+**Additional guidelines:**
+- Keep the subject line under 50 characters
+- Use imperative mood ("add" not "added")
+- Don't end subject line with a period
+- Include body if needed to explain what and why`, 
+		commitType, breakingPrefix, changes,
+		commitType,
+		func() string {
+			if isBreaking {
+				return "- Breaking change: This change breaks backward compatibility"
+			}
+			return ""
+		}())
+
+	messages = append(messages, mcp.PromptMessage{
+		Role:    "assistant",
+		Content: mcp.NewTextContent(assistantContent),
+	})
+
+	description := fmt.Sprintf("Commit message guidance for %s changes", commitType)
+	if isBreaking {
+		description += " (BREAKING)"
+	}
+
+	return mcp.GetPromptResult{
+		Description: description,
+		Messages:    messages,
+	}, nil
+}
+
+// Helper methods
+
 func (gs *Server) convertToStringSlice(input interface{}) ([]string, error) {
 	switch v := input.(type) {
 	case []interface{}:
pkg/git/server_test.go
@@ -22,7 +22,7 @@ func TestGitServer_GitStatus(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	server := New()
+	server := New(".")
 
 	// Test git status
 	req := mcp.CallToolRequest{
@@ -64,7 +64,7 @@ func TestGitServer_GitInit(t *testing.T) {
 	}
 	defer os.RemoveAll(tempDir)
 
-	server := New()
+	server := New(".")
 
 	// Test git init
 	req := mcp.CallToolRequest{
@@ -119,7 +119,7 @@ func TestGitServer_GitAdd(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	server := New()
+	server := New(".")
 
 	// Test git add
 	req := mcp.CallToolRequest{
@@ -151,7 +151,7 @@ func TestGitServer_GitAdd(t *testing.T) {
 }
 
 func TestGitServer_ListTools(t *testing.T) {
-	server := New()
+	server := New(".")
 	tools := server.ListTools()
 
 	expectedTools := []string{
@@ -179,7 +179,7 @@ func TestGitServer_ListTools(t *testing.T) {
 // Helper functions
 func initGitRepo(dir string) error {
 	// Use actual git init command for testing
-	server := New()
+	server := New(".")
 	req := mcp.CallToolRequest{
 		Name: "git_init",
 		Arguments: map[string]interface{}{