refactor: rename review_pending_changes to review_changes

- Renamed tool from review_pending_changes to review_changes for brevity
- Enhanced tool descriptions for better MCP auto-discovery
- Updated all references throughout codebase including:
  - Tool implementation (tools/review_changes.py)
  - Test files (tests/test_review_changes.py)
  - Server registration and imports
  - Documentation in README.md
  - Tool prompts in prompts/tool_prompts.py
- Enhanced review_changes description to emphasize pre-commit usage
- All tests pass, linting and formatting checks pass

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Fahad
2025-06-09 14:37:03 +04:00
parent dc366d3a23
commit fd6e2f9b64
8 changed files with 48 additions and 48 deletions

View File

@@ -14,7 +14,7 @@ Claude is brilliant, but sometimes you need:
- **A senior developer partner** to validate and extend ideas ([`chat`](#1-chat---general-development-chat--collaborative-thinking))
- **A second opinion** on complex architectural decisions - augment Claude's extended thinking with Gemini's perspective ([`think_deeper`](#2-think_deeper---extended-reasoning-partner))
- **Professional code reviews** with actionable feedback across entire repositories ([`review_code`](#3-review_code---professional-code-review))
- **Pre-commit validation** with deep analysis that finds edge cases, validates your implementation against original requirements, and catches subtle bugs Claude might miss ([`review_pending_changes`](#4-review_pending_changes---pre-commit-validation))
- **Pre-commit validation** with deep analysis that finds edge cases, validates your implementation against original requirements, and catches subtle bugs Claude might miss ([`review_changes`](#4-review_changes---pre-commit-validation))
- **Expert debugging** for tricky issues with full system context ([`debug_issue`](#5-debug_issue---expert-debugging-assistant))
- **Massive context window** (1M tokens) - Gemini 2.5 Pro can analyze entire codebases, read hundreds of files at once, and provide comprehensive insights ([`analyze`](#6-analyze---smart-file-analysis))
- **Deep code analysis** across massive codebases that exceed Claude's context limits ([`analyze`](#6-analyze---smart-file-analysis))
@@ -119,7 +119,7 @@ Just ask Claude naturally:
- **Need a thinking partner?** → `chat` (brainstorm ideas, get second opinions, validate approaches)
- **Need deeper thinking?** → `think_deeper` (extends Claude's analysis, finds edge cases)
- **Code needs review?** → `review_code` (bugs, security, performance issues)
- **Pre-commit validation?** → `review_pending_changes` (validate git changes before committing)
- **Pre-commit validation?** → `review_changes` (validate git changes before committing)
- **Something's broken?** → `debug_issue` (root cause analysis, error tracing)
- **Want to understand code?** → `analyze` (architecture, patterns, dependencies)
- **Check models?** → `list_models` (see available Gemini models)
@@ -129,7 +129,7 @@ Just ask Claude naturally:
1. [`chat`](#1-chat---general-development-chat--collaborative-thinking) - Collaborative thinking and development conversations
2. [`think_deeper`](#2-think_deeper---extended-reasoning-partner) - Extended reasoning and problem-solving
3. [`review_code`](#3-review_code---professional-code-review) - Professional code review with severity levels
4. [`review_pending_changes`](#4-review_pending_changes---pre-commit-validation) - Validate git changes before committing
4. [`review_changes`](#4-review_changes---pre-commit-validation) - Validate git changes before committing
5. [`debug_issue`](#5-debug_issue---expert-debugging-assistant) - Root cause analysis and debugging
6. [`analyze`](#6-analyze---smart-file-analysis) - General-purpose file and code analysis
7. [`list_models`](#7-list_models---see-available-gemini-models) - List available Gemini models
@@ -244,7 +244,7 @@ make any necessary adjustments and show me the final secure implementation."
**Triggers:** review code, check for issues, find bugs, security check
### 4. `review_pending_changes` - Pre-Commit Validation
### 4. `review_changes` - Pre-Commit Validation
**Comprehensive review of staged/unstaged git changes across multiple repositories**
#### Example Prompts:

View File

@@ -137,7 +137,7 @@ the ideal thinking partner who helps explore ideas deeply, validates approaches,
insights that might be missed in solo analysis. Think step by step through complex problems
and don't hesitate to explore tangential but relevant considerations."""
REVIEW_PENDING_CHANGES_PROMPT = """You are an expert code change analyst specializing in pre-commit review of git diffs.
REVIEW_CHANGES_PROMPT = """You are an expert code change analyst specializing in pre-commit review of git diffs.
Your role is to act as a seasoned senior developer performing a final review before code is committed.
IMPORTANT: If you need additional context (e.g., related files not in the diff, test files, configuration)

View File

@@ -26,8 +26,8 @@ from tools import (
AnalyzeTool,
ChatTool,
DebugIssueTool,
ReviewChanges,
ReviewCodeTool,
ReviewPendingChanges,
ThinkDeeperTool,
)
@@ -45,7 +45,7 @@ TOOLS = {
"debug_issue": DebugIssueTool(),
"analyze": AnalyzeTool(),
"chat": ChatTool(),
"review_pending_changes": ReviewPendingChanges(),
"review_changes": ReviewChanges(),
}

View File

@@ -1,5 +1,5 @@
"""
Tests for the review_pending_changes tool
Tests for the review_changes tool
"""
import json
@@ -7,23 +7,23 @@ from unittest.mock import Mock, patch
import pytest
from tools.review_pending_changes import (
ReviewPendingChanges,
ReviewPendingChangesRequest,
from tools.review_changes import (
ReviewChanges,
ReviewChangesRequest,
)
class TestReviewPendingChangesTool:
"""Test the review_pending_changes tool"""
class TestReviewChangesTool:
"""Test the review_changes tool"""
@pytest.fixture
def tool(self):
"""Create tool instance"""
return ReviewPendingChanges()
return ReviewChanges()
def test_tool_metadata(self, tool):
"""Test tool metadata"""
assert tool.get_name() == "review_pending_changes"
assert tool.get_name() == "review_changes"
assert "REVIEW PENDING GIT CHANGES" in tool.get_description()
assert "pre-commit review" in tool.get_description()
@@ -37,7 +37,7 @@ class TestReviewPendingChangesTool:
def test_request_model_defaults(self):
"""Test request model default values"""
request = ReviewPendingChangesRequest(path="/some/absolute/path")
request = ReviewChangesRequest(path="/some/absolute/path")
assert request.path == "/some/absolute/path"
assert request.original_request is None
assert request.compare_to is None
@@ -77,21 +77,21 @@ class TestReviewPendingChangesTool:
assert "./relative/path" in response["content"]
@pytest.mark.asyncio
@patch("tools.review_pending_changes.find_git_repositories")
@patch("tools.review_changes.find_git_repositories")
async def test_no_repositories_found(self, mock_find_repos, tool):
"""Test when no git repositories are found"""
mock_find_repos.return_value = []
request = ReviewPendingChangesRequest(path="/absolute/path/no-git")
request = ReviewChangesRequest(path="/absolute/path/no-git")
result = await tool.prepare_prompt(request)
assert result == "No git repositories found in the specified path."
mock_find_repos.assert_called_once_with("/absolute/path/no-git", 5)
@pytest.mark.asyncio
@patch("tools.review_pending_changes.find_git_repositories")
@patch("tools.review_pending_changes.get_git_status")
@patch("tools.review_pending_changes.run_git_command")
@patch("tools.review_changes.find_git_repositories")
@patch("tools.review_changes.get_git_status")
@patch("tools.review_changes.run_git_command")
async def test_no_changes_found(
self, mock_run_git, mock_status, mock_find_repos, tool
):
@@ -112,15 +112,15 @@ class TestReviewPendingChangesTool:
(True, ""), # unstaged files (empty)
]
request = ReviewPendingChangesRequest(path="/absolute/repo/path")
request = ReviewChangesRequest(path="/absolute/repo/path")
result = await tool.prepare_prompt(request)
assert result == "No pending changes found in any of the git repositories."
@pytest.mark.asyncio
@patch("tools.review_pending_changes.find_git_repositories")
@patch("tools.review_pending_changes.get_git_status")
@patch("tools.review_pending_changes.run_git_command")
@patch("tools.review_changes.find_git_repositories")
@patch("tools.review_changes.get_git_status")
@patch("tools.review_changes.run_git_command")
async def test_staged_changes_review(
self,
mock_run_git,
@@ -149,7 +149,7 @@ class TestReviewPendingChangesTool:
(True, ""), # unstaged files (empty)
]
request = ReviewPendingChangesRequest(
request = ReviewChangesRequest(
path="/absolute/repo/path",
original_request="Add hello message",
review_type="security",
@@ -166,9 +166,9 @@ class TestReviewPendingChangesTool:
assert "## Git Diffs" in result
@pytest.mark.asyncio
@patch("tools.review_pending_changes.find_git_repositories")
@patch("tools.review_pending_changes.get_git_status")
@patch("tools.review_pending_changes.run_git_command")
@patch("tools.review_changes.find_git_repositories")
@patch("tools.review_changes.get_git_status")
@patch("tools.review_changes.run_git_command")
async def test_compare_to_invalid_ref(
self, mock_run_git, mock_status, mock_find_repos, tool
):
@@ -181,7 +181,7 @@ class TestReviewPendingChangesTool:
(False, "fatal: not a valid ref"), # rev-parse fails
]
request = ReviewPendingChangesRequest(
request = ReviewChangesRequest(
path="/absolute/repo/path", compare_to="invalid-branch"
)
result = await tool.prepare_prompt(request)
@@ -190,7 +190,7 @@ class TestReviewPendingChangesTool:
assert "No pending changes found in any of the git repositories." in result
@pytest.mark.asyncio
@patch("tools.review_pending_changes.ReviewPendingChanges.execute")
@patch("tools.review_changes.ReviewChanges.execute")
async def test_execute_integration(self, mock_execute, tool):
"""Test execute method integration"""
# Mock the execute to return a standardized response
@@ -212,9 +212,9 @@ class TestReviewPendingChangesTool:
assert tool.get_default_temperature() == TEMPERATURE_ANALYTICAL
@pytest.mark.asyncio
@patch("tools.review_pending_changes.find_git_repositories")
@patch("tools.review_pending_changes.get_git_status")
@patch("tools.review_pending_changes.run_git_command")
@patch("tools.review_changes.find_git_repositories")
@patch("tools.review_changes.get_git_status")
@patch("tools.review_changes.run_git_command")
async def test_mixed_staged_unstaged_changes(
self,
mock_run_git,
@@ -240,7 +240,7 @@ class TestReviewPendingChangesTool:
(True, "diff --git a/file2.py..."), # diff for file2.py
]
request = ReviewPendingChangesRequest(
request = ReviewChangesRequest(
path="/absolute/repo/path",
focus_on="error handling",
severity_filter="high",

View File

@@ -25,7 +25,7 @@ class TestServerTools:
assert "debug_issue" in tool_names
assert "analyze" in tool_names
assert "chat" in tool_names
assert "review_pending_changes" in tool_names
assert "review_changes" in tool_names
assert "list_models" in tool_names
assert "get_version" in tool_names

View File

@@ -6,7 +6,7 @@ from .analyze import AnalyzeTool
from .chat import ChatTool
from .debug_issue import DebugIssueTool
from .review_code import ReviewCodeTool
from .review_pending_changes import ReviewPendingChanges
from .review_changes import ReviewChanges
from .think_deeper import ThinkDeeperTool
__all__ = [
@@ -15,5 +15,5 @@ __all__ = [
"DebugIssueTool",
"AnalyzeTool",
"ChatTool",
"ReviewPendingChanges",
"ReviewChanges",
]

View File

@@ -86,7 +86,7 @@ class BaseTool(ABC):
f"Please provide the full absolute path starting with '/'"
)
# Check if request has 'path' attribute (for review_pending_changes)
# Check if request has 'path' attribute (for review_changes)
if hasattr(request, "path") and request.path:
if not os.path.isabs(request.path):
return (

View File

@@ -9,15 +9,15 @@ from typing import Any, Dict, Literal, Optional
from pydantic import Field
from config import MAX_CONTEXT_TOKENS
from prompts.tool_prompts import REVIEW_PENDING_CHANGES_PROMPT
from prompts.tool_prompts import REVIEW_CHANGES_PROMPT
from utils.git_utils import find_git_repositories, get_git_status, run_git_command
from utils.token_utils import estimate_tokens
from .base import BaseTool, ToolRequest
class ReviewPendingChangesRequest(ToolRequest):
"""Request model for review_pending_changes tool"""
class ReviewChangesRequest(ToolRequest):
"""Request model for review_changes tool"""
path: str = Field(
...,
@@ -65,11 +65,11 @@ class ReviewPendingChangesRequest(ToolRequest):
)
class ReviewPendingChanges(BaseTool):
"""Tool for reviewing pending git changes across multiple repositories."""
class ReviewChanges(BaseTool):
"""Tool for reviewing git changes across multiple repositories."""
def get_name(self) -> str:
return "review_pending_changes"
return "review_changes"
def get_description(self) -> str:
return (
@@ -86,10 +86,10 @@ class ReviewPendingChanges(BaseTool):
return self.get_request_model().model_json_schema()
def get_system_prompt(self) -> str:
return REVIEW_PENDING_CHANGES_PROMPT
return REVIEW_CHANGES_PROMPT
def get_request_model(self):
return ReviewPendingChangesRequest
return ReviewChangesRequest
def get_default_temperature(self) -> float:
"""Use analytical temperature for code review."""
@@ -106,7 +106,7 @@ class ReviewPendingChanges(BaseTool):
# Limit length to avoid filesystem issues
return name[:100]
async def prepare_prompt(self, request: ReviewPendingChangesRequest) -> str:
async def prepare_prompt(self, request: ReviewChangesRequest) -> str:
"""Prepare the prompt with git diff information."""
# Find all git repositories
repositories = find_git_repositories(request.path, request.max_depth)