refactor: rename review tools for clarity and consistency
- Renamed `review_code` tool to `codereview` for better naming convention - Renamed `review_changes` tool to `precommit` to better reflect its purpose - Updated all tool descriptions to remove "Triggers:" sections and improve clarity - Updated all imports and references throughout the codebase - Renamed test files to match new tool names - Updated server.py tool registrations - All existing functionality preserved with improved naming This refactoring improves code organization and makes tool purposes clearer. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
12
README.md
12
README.md
@@ -19,8 +19,8 @@ The ultimate development partner for Claude - a Model Context Protocol server th
|
||||
- **Tools Reference**
|
||||
- [`chat`](#1-chat---general-development-chat--collaborative-thinking) - Collaborative thinking
|
||||
- [`think_deeper`](#2-think_deeper---extended-reasoning-partner) - Extended reasoning
|
||||
- [`review_code`](#3-review_code---professional-code-review) - Code review
|
||||
- [`review_changes`](#4-review_changes---pre-commit-validation) - Pre-commit validation
|
||||
- [`codereview`](#3-codereview---professional-code-review) - Code review
|
||||
- [`precommit`](#4-precommit---pre-commit-validation) - Pre-commit validation
|
||||
- [`debug`](#5-debug---expert-debugging-assistant) - Debugging help
|
||||
- [`analyze`](#6-analyze---smart-file-analysis) - File analysis
|
||||
|
||||
@@ -42,8 +42,8 @@ The ultimate development partner for Claude - a Model Context Protocol server th
|
||||
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_changes`](#4-review_changes---pre-commit-validation))
|
||||
- **Professional code reviews** with actionable feedback across entire repositories ([`codereview`](#3-codereview---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 ([`precommit`](#4-precommit---pre-commit-validation))
|
||||
- **Expert debugging** for tricky issues with full system context ([`debug`](#5-debug---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))
|
||||
@@ -562,7 +562,7 @@ about event ordering and failure scenarios. Then integrate gemini's insights and
|
||||
|
||||
**Triggers:** think deeper, ultrathink, extend my analysis, validate my approach
|
||||
|
||||
### 3. `review_code` - Professional Code Review
|
||||
### 3. `codereview` - Professional Code Review
|
||||
**Comprehensive code analysis with prioritized feedback**
|
||||
|
||||
**Thinking Mode:** Default is `medium` (8,192 tokens). Use `high` for security-critical code (worth the extra tokens) or `low` for quick style checks (saves ~6k tokens).
|
||||
@@ -607,7 +607,7 @@ make any necessary adjustments and show me the final secure implementation."
|
||||
|
||||
**Triggers:** review code, check for issues, find bugs, security check
|
||||
|
||||
### 4. `review_changes` - Pre-Commit Validation
|
||||
### 4. `precommit` - Pre-Commit Validation
|
||||
**Comprehensive review of staged/unstaged git changes across multiple repositories**
|
||||
|
||||
**Thinking Mode:** Default is `medium` (8,192 tokens). Use `high` or `max` for critical releases when thorough validation justifies the token cost.
|
||||
|
||||
@@ -5,14 +5,14 @@ System prompts for Gemini tools
|
||||
from .tool_prompts import (
|
||||
ANALYZE_PROMPT,
|
||||
CHAT_PROMPT,
|
||||
CODEREVIEW_PROMPT,
|
||||
DEBUG_ISSUE_PROMPT,
|
||||
REVIEW_CODE_PROMPT,
|
||||
THINK_DEEPER_PROMPT,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"THINK_DEEPER_PROMPT",
|
||||
"REVIEW_CODE_PROMPT",
|
||||
"CODEREVIEW_PROMPT",
|
||||
"DEBUG_ISSUE_PROMPT",
|
||||
"ANALYZE_PROMPT",
|
||||
"CHAT_PROMPT",
|
||||
|
||||
@@ -38,7 +38,7 @@ Be direct and technical. Assume Claude and the user are experienced developers w
|
||||
deep, nuanced analysis rather than basic explanations. Your goal is to be the perfect
|
||||
development partner that extends Claude's capabilities."""
|
||||
|
||||
REVIEW_CODE_PROMPT = """You are an expert code reviewer with deep knowledge of software engineering best practices.
|
||||
CODEREVIEW_PROMPT = """You are an expert code reviewer with deep knowledge of software engineering best practices.
|
||||
Your expertise spans security, performance, maintainability, and architectural patterns.
|
||||
|
||||
IMPORTANT: If you need additional context (e.g., related files, configuration, dependencies) to provide
|
||||
@@ -171,7 +171,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_CHANGES_PROMPT = """You are an expert code change analyst specializing in pre-commit review of git diffs.
|
||||
PRECOMMIT_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)
|
||||
|
||||
@@ -40,9 +40,9 @@ from config import (
|
||||
from tools import (
|
||||
AnalyzeTool,
|
||||
ChatTool,
|
||||
CodeReviewTool,
|
||||
DebugIssueTool,
|
||||
ReviewChanges,
|
||||
ReviewCodeTool,
|
||||
Precommit,
|
||||
ThinkDeeperTool,
|
||||
)
|
||||
|
||||
@@ -60,11 +60,11 @@ server: Server = Server("gemini-server")
|
||||
# Tools are instantiated once and reused across requests (stateless design)
|
||||
TOOLS = {
|
||||
"think_deeper": ThinkDeeperTool(), # Extended reasoning for complex problems
|
||||
"review_code": ReviewCodeTool(), # Comprehensive code review and quality analysis
|
||||
"codereview": CodeReviewTool(), # Comprehensive code review and quality analysis
|
||||
"debug": DebugIssueTool(), # Root cause analysis and debugging assistance
|
||||
"analyze": AnalyzeTool(), # General-purpose file and code analysis
|
||||
"chat": ChatTool(), # Interactive development chat and brainstorming
|
||||
"review_changes": ReviewChanges(), # Pre-commit review of git changes
|
||||
"precommit": Precommit(), # Pre-commit validation of git changes
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -156,10 +156,10 @@ def test_review_changes_docker_path_translation():
|
||||
utils.file_utils.CONTAINER_WORKSPACE = container_workspace
|
||||
|
||||
# Import after reloading to get updated environment
|
||||
from tools.review_changes import ReviewChanges
|
||||
from tools.precommit import Precommit
|
||||
|
||||
# Create tool instance
|
||||
tool = ReviewChanges()
|
||||
tool = Precommit()
|
||||
|
||||
# Test path translation in prepare_prompt
|
||||
request = tool.get_request_model()(
|
||||
@@ -209,10 +209,10 @@ def test_review_changes_docker_path_error():
|
||||
utils.file_utils.CONTAINER_WORKSPACE = container_workspace
|
||||
|
||||
# Import after reloading to get updated environment
|
||||
from tools.review_changes import ReviewChanges
|
||||
from tools.precommit import Precommit
|
||||
|
||||
# Create tool instance
|
||||
tool = ReviewChanges()
|
||||
tool = Precommit()
|
||||
|
||||
# Test path translation with an inaccessible path
|
||||
request = tool.get_request_model()(
|
||||
|
||||
@@ -18,9 +18,9 @@ from mcp.types import TextContent
|
||||
from config import MCP_PROMPT_SIZE_LIMIT
|
||||
from tools.analyze import AnalyzeTool
|
||||
from tools.chat import ChatTool
|
||||
from tools.codereview import CodeReviewTool
|
||||
from tools.debug import DebugIssueTool
|
||||
from tools.review_changes import ReviewChanges
|
||||
from tools.review_code import ReviewCodeTool
|
||||
from tools.precommit import Precommit
|
||||
from tools.think_deeper import ThinkDeeperTool
|
||||
|
||||
|
||||
@@ -141,9 +141,9 @@ class TestLargePromptHandling:
|
||||
assert output["status"] == "requires_file_prompt"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_review_code_large_focus(self, large_prompt):
|
||||
"""Test that review_code tool detects large focus_on field."""
|
||||
tool = ReviewCodeTool()
|
||||
async def test_codereview_large_focus(self, large_prompt):
|
||||
"""Test that codereview tool detects large focus_on field."""
|
||||
tool = CodeReviewTool()
|
||||
result = await tool.execute(
|
||||
{
|
||||
"files": ["/some/file.py"],
|
||||
@@ -159,7 +159,7 @@ class TestLargePromptHandling:
|
||||
@pytest.mark.asyncio
|
||||
async def test_review_changes_large_original_request(self, large_prompt):
|
||||
"""Test that review_changes tool detects large original_request."""
|
||||
tool = ReviewChanges()
|
||||
tool = Precommit()
|
||||
result = await tool.execute({"path": "/some/path", "original_request": large_prompt})
|
||||
|
||||
assert len(result) == 1
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
"""
|
||||
Tests for the review_changes tool
|
||||
Tests for the precommit tool
|
||||
"""
|
||||
|
||||
import json
|
||||
@@ -7,22 +7,22 @@ from unittest.mock import Mock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
from tools.review_changes import ReviewChanges, ReviewChangesRequest
|
||||
from tools.precommit import Precommit, PrecommitRequest
|
||||
|
||||
|
||||
class TestReviewChangesTool:
|
||||
"""Test the review_changes tool"""
|
||||
class TestPrecommitTool:
|
||||
"""Test the precommit tool"""
|
||||
|
||||
@pytest.fixture
|
||||
def tool(self):
|
||||
"""Create tool instance"""
|
||||
return ReviewChanges()
|
||||
return Precommit()
|
||||
|
||||
def test_tool_metadata(self, tool):
|
||||
"""Test tool metadata"""
|
||||
assert tool.get_name() == "review_changes"
|
||||
assert "REVIEW PENDING GIT CHANGES" in tool.get_description()
|
||||
assert "pre-commit review" in tool.get_description()
|
||||
assert tool.get_name() == "precommit"
|
||||
assert "PRECOMMIT VALIDATION" in tool.get_description()
|
||||
assert "pre-commit" in tool.get_description()
|
||||
|
||||
# Check schema
|
||||
schema = tool.get_input_schema()
|
||||
@@ -34,7 +34,7 @@ class TestReviewChangesTool:
|
||||
|
||||
def test_request_model_defaults(self):
|
||||
"""Test request model default values"""
|
||||
request = ReviewChangesRequest(path="/some/absolute/path")
|
||||
request = PrecommitRequest(path="/some/absolute/path")
|
||||
assert request.path == "/some/absolute/path"
|
||||
assert request.original_request is None
|
||||
assert request.compare_to is None
|
||||
@@ -56,21 +56,21 @@ class TestReviewChangesTool:
|
||||
assert "./relative/path" in response["content"]
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@patch("tools.review_changes.find_git_repositories")
|
||||
@patch("tools.precommit.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 = ReviewChangesRequest(path="/absolute/path/no-git")
|
||||
request = PrecommitRequest(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_changes.find_git_repositories")
|
||||
@patch("tools.review_changes.get_git_status")
|
||||
@patch("tools.review_changes.run_git_command")
|
||||
@patch("tools.precommit.find_git_repositories")
|
||||
@patch("tools.precommit.get_git_status")
|
||||
@patch("tools.precommit.run_git_command")
|
||||
async def test_no_changes_found(self, mock_run_git, mock_status, mock_find_repos, tool):
|
||||
"""Test when repositories have no changes"""
|
||||
mock_find_repos.return_value = ["/test/repo"]
|
||||
@@ -89,15 +89,15 @@ class TestReviewChangesTool:
|
||||
(True, ""), # unstaged files (empty)
|
||||
]
|
||||
|
||||
request = ReviewChangesRequest(path="/absolute/repo/path")
|
||||
request = PrecommitRequest(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_changes.find_git_repositories")
|
||||
@patch("tools.review_changes.get_git_status")
|
||||
@patch("tools.review_changes.run_git_command")
|
||||
@patch("tools.precommit.find_git_repositories")
|
||||
@patch("tools.precommit.get_git_status")
|
||||
@patch("tools.precommit.run_git_command")
|
||||
async def test_staged_changes_review(
|
||||
self,
|
||||
mock_run_git,
|
||||
@@ -126,7 +126,7 @@ class TestReviewChangesTool:
|
||||
(True, ""), # unstaged files (empty)
|
||||
]
|
||||
|
||||
request = ReviewChangesRequest(
|
||||
request = PrecommitRequest(
|
||||
path="/absolute/repo/path",
|
||||
original_request="Add hello message",
|
||||
review_type="security",
|
||||
@@ -143,9 +143,9 @@ class TestReviewChangesTool:
|
||||
assert "## Git Diffs" in result
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@patch("tools.review_changes.find_git_repositories")
|
||||
@patch("tools.review_changes.get_git_status")
|
||||
@patch("tools.review_changes.run_git_command")
|
||||
@patch("tools.precommit.find_git_repositories")
|
||||
@patch("tools.precommit.get_git_status")
|
||||
@patch("tools.precommit.run_git_command")
|
||||
async def test_compare_to_invalid_ref(self, mock_run_git, mock_status, mock_find_repos, tool):
|
||||
"""Test comparing to an invalid git ref"""
|
||||
mock_find_repos.return_value = ["/test/repo"]
|
||||
@@ -156,14 +156,14 @@ class TestReviewChangesTool:
|
||||
(False, "fatal: not a valid ref"), # rev-parse fails
|
||||
]
|
||||
|
||||
request = ReviewChangesRequest(path="/absolute/repo/path", compare_to="invalid-branch")
|
||||
request = PrecommitRequest(path="/absolute/repo/path", compare_to="invalid-branch")
|
||||
result = await tool.prepare_prompt(request)
|
||||
|
||||
# When all repos have errors and no changes, we get this message
|
||||
assert "No pending changes found in any of the git repositories." in result
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@patch("tools.review_changes.ReviewChanges.execute")
|
||||
@patch("tools.precommit.Precommit.execute")
|
||||
async def test_execute_integration(self, mock_execute, tool):
|
||||
"""Test execute method integration"""
|
||||
# Mock the execute to return a standardized response
|
||||
@@ -183,9 +183,9 @@ class TestReviewChangesTool:
|
||||
assert tool.get_default_temperature() == TEMPERATURE_ANALYTICAL
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@patch("tools.review_changes.find_git_repositories")
|
||||
@patch("tools.review_changes.get_git_status")
|
||||
@patch("tools.review_changes.run_git_command")
|
||||
@patch("tools.precommit.find_git_repositories")
|
||||
@patch("tools.precommit.get_git_status")
|
||||
@patch("tools.precommit.run_git_command")
|
||||
async def test_mixed_staged_unstaged_changes(
|
||||
self,
|
||||
mock_run_git,
|
||||
@@ -211,7 +211,7 @@ class TestReviewChangesTool:
|
||||
(True, "diff --git a/file2.py..."), # diff for file2.py
|
||||
]
|
||||
|
||||
request = ReviewChangesRequest(
|
||||
request = PrecommitRequest(
|
||||
path="/absolute/repo/path",
|
||||
focus_on="error handling",
|
||||
severity_filter="high",
|
||||
@@ -225,10 +225,10 @@ class TestReviewChangesTool:
|
||||
assert "Reviewing: staged and unstaged changes" in result
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@patch("tools.review_changes.find_git_repositories")
|
||||
@patch("tools.review_changes.get_git_status")
|
||||
@patch("tools.review_changes.run_git_command")
|
||||
@patch("tools.review_changes.read_files")
|
||||
@patch("tools.precommit.find_git_repositories")
|
||||
@patch("tools.precommit.get_git_status")
|
||||
@patch("tools.precommit.run_git_command")
|
||||
@patch("tools.precommit.read_files")
|
||||
async def test_files_parameter_with_context(
|
||||
self,
|
||||
mock_read_files,
|
||||
@@ -257,7 +257,7 @@ class TestReviewChangesTool:
|
||||
# Mock read_files
|
||||
mock_read_files.return_value = "=== FILE: config.py ===\nCONFIG_VALUE = 42\n=== END FILE ==="
|
||||
|
||||
request = ReviewChangesRequest(
|
||||
request = PrecommitRequest(
|
||||
path="/absolute/repo/path",
|
||||
files=["/absolute/repo/path/config.py"],
|
||||
)
|
||||
@@ -271,9 +271,9 @@ class TestReviewChangesTool:
|
||||
assert "CONFIG_VALUE = 42" in result
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@patch("tools.review_changes.find_git_repositories")
|
||||
@patch("tools.review_changes.get_git_status")
|
||||
@patch("tools.review_changes.run_git_command")
|
||||
@patch("tools.precommit.find_git_repositories")
|
||||
@patch("tools.precommit.get_git_status")
|
||||
@patch("tools.precommit.run_git_command")
|
||||
async def test_files_request_instruction(
|
||||
self,
|
||||
mock_run_git,
|
||||
@@ -298,7 +298,7 @@ class TestReviewChangesTool:
|
||||
]
|
||||
|
||||
# Request without files
|
||||
request = ReviewChangesRequest(path="/absolute/repo/path")
|
||||
request = PrecommitRequest(path="/absolute/repo/path")
|
||||
result = await tool.prepare_prompt(request)
|
||||
|
||||
# Should include instruction for requesting files
|
||||
@@ -306,7 +306,7 @@ class TestReviewChangesTool:
|
||||
assert "standardized JSON response format" in result
|
||||
|
||||
# Request with files - should not include instruction
|
||||
request_with_files = ReviewChangesRequest(path="/absolute/repo/path", files=["/some/file.py"])
|
||||
request_with_files = PrecommitRequest(path="/absolute/repo/path", files=["/some/file.py"])
|
||||
|
||||
# Need to reset mocks for second call
|
||||
mock_find_repos.return_value = ["/test/repo"]
|
||||
@@ -317,7 +317,7 @@ class TestReviewChangesTool:
|
||||
]
|
||||
|
||||
# Mock read_files to return empty (file not found)
|
||||
with patch("tools.review_changes.read_files") as mock_read:
|
||||
with patch("tools.precommit.read_files") as mock_read:
|
||||
mock_read.return_value = ""
|
||||
result_with_files = await tool.prepare_prompt(request_with_files)
|
||||
|
||||
@@ -12,9 +12,9 @@ import pytest
|
||||
|
||||
from tools.analyze import AnalyzeTool
|
||||
from tools.chat import ChatTool
|
||||
from tools.codereview import CodeReviewTool
|
||||
from tools.debug import DebugIssueTool
|
||||
from tools.review_changes import ReviewChanges
|
||||
from tools.review_code import ReviewCodeTool
|
||||
from tools.precommit import Precommit
|
||||
from tools.think_deeper import ThinkDeeperTool
|
||||
|
||||
|
||||
@@ -105,9 +105,9 @@ class TestPromptRegression:
|
||||
assert "deeper analysis" in output["content"]
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_review_code_normal_review(self, mock_model_response):
|
||||
"""Test review_code tool with normal inputs."""
|
||||
tool = ReviewCodeTool()
|
||||
async def test_codereview_normal_review(self, mock_model_response):
|
||||
"""Test codereview tool with normal inputs."""
|
||||
tool = CodeReviewTool()
|
||||
|
||||
with patch.object(tool, "create_model") as mock_create_model:
|
||||
mock_model = MagicMock()
|
||||
@@ -117,7 +117,7 @@ class TestPromptRegression:
|
||||
mock_create_model.return_value = mock_model
|
||||
|
||||
# Mock file reading
|
||||
with patch("tools.review_code.read_files") as mock_read_files:
|
||||
with patch("tools.codereview.read_files") as mock_read_files:
|
||||
mock_read_files.return_value = "def main(): pass"
|
||||
|
||||
result = await tool.execute(
|
||||
@@ -137,7 +137,7 @@ class TestPromptRegression:
|
||||
@pytest.mark.asyncio
|
||||
async def test_review_changes_normal_request(self, mock_model_response):
|
||||
"""Test review_changes tool with normal original_request."""
|
||||
tool = ReviewChanges()
|
||||
tool = Precommit()
|
||||
|
||||
with patch.object(tool, "create_model") as mock_create_model:
|
||||
mock_model = MagicMock()
|
||||
@@ -147,8 +147,8 @@ class TestPromptRegression:
|
||||
mock_create_model.return_value = mock_model
|
||||
|
||||
# Mock git operations
|
||||
with patch("tools.review_changes.find_git_repositories") as mock_find_repos:
|
||||
with patch("tools.review_changes.get_git_status") as mock_git_status:
|
||||
with patch("tools.precommit.find_git_repositories") as mock_find_repos:
|
||||
with patch("tools.precommit.get_git_status") as mock_git_status:
|
||||
mock_find_repos.return_value = ["/path/to/repo"]
|
||||
mock_git_status.return_value = {
|
||||
"modified": ["file.py"],
|
||||
|
||||
@@ -20,11 +20,11 @@ class TestServerTools:
|
||||
|
||||
# Check all core tools are present
|
||||
assert "think_deeper" in tool_names
|
||||
assert "review_code" in tool_names
|
||||
assert "codereview" in tool_names
|
||||
assert "debug" in tool_names
|
||||
assert "analyze" in tool_names
|
||||
assert "chat" in tool_names
|
||||
assert "review_changes" in tool_names
|
||||
assert "precommit" in tool_names
|
||||
assert "get_version" in tool_names
|
||||
|
||||
# Should have exactly 7 tools
|
||||
|
||||
@@ -7,8 +7,8 @@ from unittest.mock import Mock, patch
|
||||
import pytest
|
||||
|
||||
from tools.analyze import AnalyzeTool
|
||||
from tools.codereview import CodeReviewTool
|
||||
from tools.debug import DebugIssueTool
|
||||
from tools.review_code import ReviewCodeTool
|
||||
from tools.think_deeper import ThinkDeeperTool
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ class TestThinkingModes:
|
||||
tools = [
|
||||
(ThinkDeeperTool(), "high"),
|
||||
(AnalyzeTool(), "medium"),
|
||||
(ReviewCodeTool(), "medium"),
|
||||
(CodeReviewTool(), "medium"),
|
||||
(DebugIssueTool(), "medium"),
|
||||
]
|
||||
|
||||
@@ -77,7 +77,7 @@ class TestThinkingModes:
|
||||
)
|
||||
mock_create_model.return_value = mock_model
|
||||
|
||||
tool = ReviewCodeTool()
|
||||
tool = CodeReviewTool()
|
||||
result = await tool.execute(
|
||||
{
|
||||
"files": ["/absolute/path/test.py"],
|
||||
|
||||
@@ -7,7 +7,7 @@ from unittest.mock import Mock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
from tools import AnalyzeTool, ChatTool, DebugIssueTool, ReviewCodeTool, ThinkDeeperTool
|
||||
from tools import AnalyzeTool, ChatTool, CodeReviewTool, DebugIssueTool, ThinkDeeperTool
|
||||
|
||||
|
||||
class TestThinkDeeperTool:
|
||||
@@ -54,16 +54,16 @@ class TestThinkDeeperTool:
|
||||
assert "Extended analysis" in output["content"]
|
||||
|
||||
|
||||
class TestReviewCodeTool:
|
||||
"""Test the review_code tool"""
|
||||
class TestCodeReviewTool:
|
||||
"""Test the codereview tool"""
|
||||
|
||||
@pytest.fixture
|
||||
def tool(self):
|
||||
return ReviewCodeTool()
|
||||
return CodeReviewTool()
|
||||
|
||||
def test_tool_metadata(self, tool):
|
||||
"""Test tool metadata"""
|
||||
assert tool.get_name() == "review_code"
|
||||
assert tool.get_name() == "codereview"
|
||||
assert "PROFESSIONAL CODE REVIEW" in tool.get_description()
|
||||
assert tool.get_default_temperature() == 0.2
|
||||
|
||||
@@ -214,9 +214,9 @@ class TestAbsolutePathValidation:
|
||||
assert "./relative/path.py" in response["content"]
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_review_code_tool_relative_path_rejected(self):
|
||||
"""Test that review_code tool rejects relative paths"""
|
||||
tool = ReviewCodeTool()
|
||||
async def test_codereview_tool_relative_path_rejected(self):
|
||||
"""Test that codereview tool rejects relative paths"""
|
||||
tool = CodeReviewTool()
|
||||
result = await tool.execute(
|
||||
{
|
||||
"files": ["../parent/file.py"],
|
||||
|
||||
@@ -4,16 +4,16 @@ Tool implementations for Gemini MCP Server
|
||||
|
||||
from .analyze import AnalyzeTool
|
||||
from .chat import ChatTool
|
||||
from .codereview import CodeReviewTool
|
||||
from .debug import DebugIssueTool
|
||||
from .review_changes import ReviewChanges
|
||||
from .review_code import ReviewCodeTool
|
||||
from .precommit import Precommit
|
||||
from .think_deeper import ThinkDeeperTool
|
||||
|
||||
__all__ = [
|
||||
"ThinkDeeperTool",
|
||||
"ReviewCodeTool",
|
||||
"CodeReviewTool",
|
||||
"DebugIssueTool",
|
||||
"AnalyzeTool",
|
||||
"ChatTool",
|
||||
"ReviewChanges",
|
||||
"Precommit",
|
||||
]
|
||||
|
||||
@@ -37,8 +37,7 @@ class AnalyzeTool(BaseTool):
|
||||
return (
|
||||
"ANALYZE FILES & CODE - General-purpose analysis for understanding code. "
|
||||
"Supports both individual files and entire directories. "
|
||||
"Use this for examining files, understanding architecture, or investigating specific aspects. "
|
||||
"Triggers: 'analyze these files', 'examine this code', 'understand this'. "
|
||||
"Use this when you need to analyze files, examine code, or understand specific aspects of a codebase. "
|
||||
"Perfect for: codebase exploration, dependency analysis, pattern detection. "
|
||||
"Always uses file paths for clean terminal output."
|
||||
)
|
||||
|
||||
@@ -40,8 +40,8 @@ class ChatTool(BaseTool):
|
||||
"Perfect for: bouncing ideas during your own analysis, getting second opinions on your plans, "
|
||||
"collaborative brainstorming, validating your checklists and approaches, exploring alternatives. "
|
||||
"Also great for: explanations, comparisons, general development questions. "
|
||||
"Triggers: 'ask gemini', 'brainstorm with gemini', 'get gemini's opinion', 'discuss with gemini', "
|
||||
"'share my thinking with gemini', 'explain', 'what is', 'how do I'."
|
||||
"Use this when you want to ask Gemini questions, brainstorm ideas, get opinions, discuss topics, "
|
||||
"share your thinking, or need explanations about concepts and approaches."
|
||||
)
|
||||
|
||||
def get_input_schema(self) -> dict[str, Any]:
|
||||
|
||||
@@ -20,14 +20,14 @@ from mcp.types import TextContent
|
||||
from pydantic import Field
|
||||
|
||||
from config import TEMPERATURE_ANALYTICAL
|
||||
from prompts import REVIEW_CODE_PROMPT
|
||||
from prompts import CODEREVIEW_PROMPT
|
||||
from utils import read_files
|
||||
|
||||
from .base import BaseTool, ToolRequest
|
||||
from .models import ToolOutput
|
||||
|
||||
|
||||
class ReviewCodeRequest(ToolRequest):
|
||||
class CodeReviewRequest(ToolRequest):
|
||||
"""
|
||||
Request model for the code review tool.
|
||||
|
||||
@@ -53,7 +53,7 @@ class ReviewCodeRequest(ToolRequest):
|
||||
)
|
||||
|
||||
|
||||
class ReviewCodeTool(BaseTool):
|
||||
class CodeReviewTool(BaseTool):
|
||||
"""
|
||||
Professional code review tool implementation.
|
||||
|
||||
@@ -63,14 +63,13 @@ class ReviewCodeTool(BaseTool):
|
||||
"""
|
||||
|
||||
def get_name(self) -> str:
|
||||
return "review_code"
|
||||
return "codereview"
|
||||
|
||||
def get_description(self) -> str:
|
||||
return (
|
||||
"PROFESSIONAL CODE REVIEW - Comprehensive analysis for bugs, security, and quality. "
|
||||
"Supports both individual files and entire directories/projects. "
|
||||
"Use this for thorough code review with actionable feedback. "
|
||||
"Triggers: 'review this code', 'check for issues', 'find bugs', 'security audit'. "
|
||||
"Use this when you need to review code, check for issues, find bugs, or perform security audits. "
|
||||
"I'll identify issues by severity (Critical→High→Medium→Low) with specific fixes. "
|
||||
"Supports focused reviews: security, performance, or quick checks. "
|
||||
"Choose thinking_mode based on review scope: 'low' for small code snippets, "
|
||||
@@ -132,13 +131,13 @@ class ReviewCodeTool(BaseTool):
|
||||
}
|
||||
|
||||
def get_system_prompt(self) -> str:
|
||||
return REVIEW_CODE_PROMPT
|
||||
return CODEREVIEW_PROMPT
|
||||
|
||||
def get_default_temperature(self) -> float:
|
||||
return TEMPERATURE_ANALYTICAL
|
||||
|
||||
def get_request_model(self):
|
||||
return ReviewCodeRequest
|
||||
return CodeReviewRequest
|
||||
|
||||
async def execute(self, arguments: dict[str, Any]) -> list[TextContent]:
|
||||
"""Override execute to check focus_on size before processing"""
|
||||
@@ -155,7 +154,7 @@ class ReviewCodeTool(BaseTool):
|
||||
# Continue with normal execution
|
||||
return await super().execute(arguments)
|
||||
|
||||
async def prepare_prompt(self, request: ReviewCodeRequest) -> str:
|
||||
async def prepare_prompt(self, request: CodeReviewRequest) -> str:
|
||||
"""
|
||||
Prepare the code review prompt with customized instructions.
|
||||
|
||||
@@ -239,7 +238,7 @@ Please provide a code review aligned with the user's context and expectations, f
|
||||
|
||||
return full_prompt
|
||||
|
||||
def format_response(self, response: str, request: ReviewCodeRequest) -> str:
|
||||
def format_response(self, response: str, request: CodeReviewRequest) -> str:
|
||||
"""
|
||||
Format the review response with appropriate headers.
|
||||
|
||||
@@ -37,8 +37,8 @@ class DebugIssueTool(BaseTool):
|
||||
def get_description(self) -> str:
|
||||
return (
|
||||
"DEBUG & ROOT CAUSE ANALYSIS - Expert debugging for complex issues with 1M token capacity. "
|
||||
"Use this when you need help tracking down bugs or understanding errors. "
|
||||
"Triggers: 'debug this', 'why is this failing', 'root cause', 'trace error', 'diagnose issue'. "
|
||||
"Use this when you need to debug code, find out why something is failing, identify root causes, "
|
||||
"trace errors, or diagnose issues. "
|
||||
"IMPORTANT: Share diagnostic files liberally! Gemini can handle up to 1M tokens, so include: "
|
||||
"large log files, full stack traces, memory dumps, diagnostic outputs, multiple related files, "
|
||||
"entire modules, test results, configuration files - anything that might help debug the issue. "
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
"""
|
||||
Tool for reviewing pending git changes across multiple repositories.
|
||||
Tool for pre-commit validation of git changes across multiple repositories.
|
||||
"""
|
||||
|
||||
import os
|
||||
@@ -9,7 +9,7 @@ from mcp.types import TextContent
|
||||
from pydantic import Field
|
||||
|
||||
from config import MAX_CONTEXT_TOKENS
|
||||
from prompts.tool_prompts import REVIEW_CHANGES_PROMPT
|
||||
from prompts.tool_prompts import PRECOMMIT_PROMPT
|
||||
from utils.file_utils import read_files, translate_file_paths, translate_path_for_environment
|
||||
from utils.git_utils import find_git_repositories, get_git_status, run_git_command
|
||||
from utils.token_utils import estimate_tokens
|
||||
@@ -18,8 +18,8 @@ from .base import BaseTool, ToolRequest
|
||||
from .models import ToolOutput
|
||||
|
||||
|
||||
class ReviewChangesRequest(ToolRequest):
|
||||
"""Request model for review_changes tool"""
|
||||
class PrecommitRequest(ToolRequest):
|
||||
"""Request model for precommit tool"""
|
||||
|
||||
path: str = Field(
|
||||
...,
|
||||
@@ -71,21 +71,21 @@ class ReviewChangesRequest(ToolRequest):
|
||||
)
|
||||
|
||||
|
||||
class ReviewChanges(BaseTool):
|
||||
"""Tool for reviewing git changes across multiple repositories."""
|
||||
class Precommit(BaseTool):
|
||||
"""Tool for pre-commit validation of git changes across multiple repositories."""
|
||||
|
||||
def get_name(self) -> str:
|
||||
return "review_changes"
|
||||
return "precommit"
|
||||
|
||||
def get_description(self) -> str:
|
||||
return (
|
||||
"REVIEW PENDING GIT CHANGES BEFORE COMMITTING - ALWAYS use this tool before creating any git commit! "
|
||||
"PRECOMMIT VALIDATION FOR GIT CHANGES - ALWAYS use this tool before creating any git commit! "
|
||||
"Comprehensive pre-commit validation that catches bugs, security issues, incomplete implementations, "
|
||||
"and ensures changes match the original requirements. Searches all git repositories recursively and "
|
||||
"provides deep analysis of staged/unstaged changes. Essential for code quality and preventing bugs. "
|
||||
"Triggers: 'before commit', 'review changes', 'check my changes', 'validate changes', 'pre-commit review', "
|
||||
"'about to commit', 'ready to commit'. Claude should proactively suggest using this tool whenever "
|
||||
"the user mentions committing or when changes are complete. "
|
||||
"Use this before committing, when reviewing changes, checking your changes, validating changes, "
|
||||
"or when you're about to commit or ready to commit. Claude should proactively suggest using this tool "
|
||||
"whenever the user mentions committing or when changes are complete. "
|
||||
"Choose thinking_mode based on changeset size: 'low' for small focused changes, "
|
||||
"'medium' for standard commits (default), 'high' for large feature branches or complex refactoring, "
|
||||
"'max' for critical releases or when reviewing extensive changes across multiple systems."
|
||||
@@ -103,10 +103,10 @@ class ReviewChanges(BaseTool):
|
||||
return schema
|
||||
|
||||
def get_system_prompt(self) -> str:
|
||||
return REVIEW_CHANGES_PROMPT
|
||||
return PRECOMMIT_PROMPT
|
||||
|
||||
def get_request_model(self):
|
||||
return ReviewChangesRequest
|
||||
return PrecommitRequest
|
||||
|
||||
def get_default_temperature(self) -> float:
|
||||
"""Use analytical temperature for code review."""
|
||||
@@ -129,7 +129,7 @@ class ReviewChanges(BaseTool):
|
||||
# Continue with normal execution
|
||||
return await super().execute(arguments)
|
||||
|
||||
async def prepare_prompt(self, request: ReviewChangesRequest) -> str:
|
||||
async def prepare_prompt(self, request: PrecommitRequest) -> str:
|
||||
"""Prepare the prompt with git diff information."""
|
||||
# Check for prompt.txt in files
|
||||
prompt_content, updated_files = self.handle_prompt_file(request.files)
|
||||
@@ -409,6 +409,6 @@ class ReviewChanges(BaseTool):
|
||||
|
||||
return full_prompt
|
||||
|
||||
def format_response(self, response: str, request: ReviewChangesRequest) -> str:
|
||||
def format_response(self, response: str, request: PrecommitRequest) -> str:
|
||||
"""Format the response with commit guidance"""
|
||||
return f"{response}\n\n---\n\n**Commit Status:** If no critical issues found, changes are ready for commit. Otherwise, address issues first and re-run review. Check with user before proceeding with any commit."
|
||||
@@ -39,9 +39,8 @@ class ThinkDeeperTool(BaseTool):
|
||||
def get_description(self) -> str:
|
||||
return (
|
||||
"EXTENDED THINKING & REASONING - Your deep thinking partner for complex problems. "
|
||||
"Use this when you need to extend your analysis, explore alternatives, or validate approaches. "
|
||||
"Use this when you need to think deeper about a problem, extend your analysis, explore alternatives, or validate approaches. "
|
||||
"Perfect for: architecture decisions, complex bugs, performance challenges, security analysis. "
|
||||
"Triggers: 'think deeper', 'ultrathink', 'extend my analysis', 'explore alternatives'. "
|
||||
"I'll challenge assumptions, find edge cases, and provide alternative solutions. "
|
||||
"IMPORTANT: Choose the appropriate thinking_mode based on task complexity - "
|
||||
"'low' for quick analysis, 'medium' for standard problems, 'high' for complex issues (default), "
|
||||
|
||||
Reference in New Issue
Block a user