hanzo-mcp 0.6.13__py3-none-any.whl → 0.7.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of hanzo-mcp might be problematic. Click here for more details.
- hanzo_mcp/analytics/__init__.py +5 -0
- hanzo_mcp/analytics/posthog_analytics.py +364 -0
- hanzo_mcp/cli.py +3 -3
- hanzo_mcp/cli_enhanced.py +3 -3
- hanzo_mcp/config/settings.py +1 -1
- hanzo_mcp/config/tool_config.py +18 -4
- hanzo_mcp/server.py +34 -1
- hanzo_mcp/tools/__init__.py +65 -2
- hanzo_mcp/tools/agent/__init__.py +84 -3
- hanzo_mcp/tools/agent/agent_tool.py +102 -4
- hanzo_mcp/tools/agent/agent_tool_v2.py +459 -0
- hanzo_mcp/tools/agent/clarification_protocol.py +220 -0
- hanzo_mcp/tools/agent/clarification_tool.py +68 -0
- hanzo_mcp/tools/agent/claude_cli_tool.py +125 -0
- hanzo_mcp/tools/agent/claude_desktop_auth.py +508 -0
- hanzo_mcp/tools/agent/cli_agent_base.py +191 -0
- hanzo_mcp/tools/agent/code_auth.py +436 -0
- hanzo_mcp/tools/agent/code_auth_tool.py +194 -0
- hanzo_mcp/tools/agent/codex_cli_tool.py +123 -0
- hanzo_mcp/tools/agent/critic_tool.py +376 -0
- hanzo_mcp/tools/agent/gemini_cli_tool.py +128 -0
- hanzo_mcp/tools/agent/grok_cli_tool.py +128 -0
- hanzo_mcp/tools/agent/iching_tool.py +380 -0
- hanzo_mcp/tools/agent/network_tool.py +273 -0
- hanzo_mcp/tools/agent/prompt.py +62 -20
- hanzo_mcp/tools/agent/review_tool.py +433 -0
- hanzo_mcp/tools/agent/swarm_tool.py +535 -0
- hanzo_mcp/tools/agent/swarm_tool_v2.py +594 -0
- hanzo_mcp/tools/common/base.py +1 -0
- hanzo_mcp/tools/common/batch_tool.py +102 -10
- hanzo_mcp/tools/common/fastmcp_pagination.py +369 -0
- hanzo_mcp/tools/common/forgiving_edit.py +243 -0
- hanzo_mcp/tools/common/paginated_base.py +230 -0
- hanzo_mcp/tools/common/paginated_response.py +307 -0
- hanzo_mcp/tools/common/pagination.py +226 -0
- hanzo_mcp/tools/common/tool_list.py +3 -0
- hanzo_mcp/tools/common/truncate.py +101 -0
- hanzo_mcp/tools/filesystem/__init__.py +29 -0
- hanzo_mcp/tools/filesystem/ast_multi_edit.py +562 -0
- hanzo_mcp/tools/filesystem/directory_tree_paginated.py +338 -0
- hanzo_mcp/tools/lsp/__init__.py +5 -0
- hanzo_mcp/tools/lsp/lsp_tool.py +512 -0
- hanzo_mcp/tools/memory/__init__.py +76 -0
- hanzo_mcp/tools/memory/knowledge_tools.py +518 -0
- hanzo_mcp/tools/memory/memory_tools.py +456 -0
- hanzo_mcp/tools/search/__init__.py +6 -0
- hanzo_mcp/tools/search/find_tool.py +581 -0
- hanzo_mcp/tools/search/unified_search.py +953 -0
- hanzo_mcp/tools/shell/__init__.py +5 -0
- hanzo_mcp/tools/shell/auto_background.py +203 -0
- hanzo_mcp/tools/shell/base_process.py +53 -27
- hanzo_mcp/tools/shell/bash_tool.py +17 -33
- hanzo_mcp/tools/shell/npx_tool.py +15 -32
- hanzo_mcp/tools/shell/streaming_command.py +594 -0
- hanzo_mcp/tools/shell/uvx_tool.py +15 -32
- hanzo_mcp/types.py +23 -0
- {hanzo_mcp-0.6.13.dist-info → hanzo_mcp-0.7.0.dist-info}/METADATA +228 -71
- {hanzo_mcp-0.6.13.dist-info → hanzo_mcp-0.7.0.dist-info}/RECORD +61 -24
- hanzo_mcp-0.6.13.dist-info/licenses/LICENSE +0 -21
- {hanzo_mcp-0.6.13.dist-info → hanzo_mcp-0.7.0.dist-info}/WHEEL +0 -0
- {hanzo_mcp-0.6.13.dist-info → hanzo_mcp-0.7.0.dist-info}/entry_points.txt +0 -0
- {hanzo_mcp-0.6.13.dist-info → hanzo_mcp-0.7.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,433 @@
|
|
|
1
|
+
"""Review tool for agents to request balanced code review from main loop."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from typing import Any, Dict, List, Optional, override
|
|
5
|
+
from enum import Enum
|
|
6
|
+
|
|
7
|
+
from hanzo_mcp.tools.common.base import BaseTool
|
|
8
|
+
from mcp.server.fastmcp import Context as MCPContext
|
|
9
|
+
from mcp.server import FastMCP
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ReviewFocus(Enum):
|
|
13
|
+
"""Types of review focus areas."""
|
|
14
|
+
GENERAL = "general"
|
|
15
|
+
FUNCTIONALITY = "functionality"
|
|
16
|
+
READABILITY = "readability"
|
|
17
|
+
MAINTAINABILITY = "maintainability"
|
|
18
|
+
TESTING = "testing"
|
|
19
|
+
DOCUMENTATION = "documentation"
|
|
20
|
+
ARCHITECTURE = "architecture"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class ReviewTool(BaseTool):
|
|
24
|
+
"""Tool for agents to request balanced code review from the main loop."""
|
|
25
|
+
|
|
26
|
+
name = "review"
|
|
27
|
+
|
|
28
|
+
@property
|
|
29
|
+
@override
|
|
30
|
+
def description(self) -> str:
|
|
31
|
+
"""Get the tool description."""
|
|
32
|
+
return """Request a balanced, constructive code review from the main loop.
|
|
33
|
+
|
|
34
|
+
Unlike the critic tool (which plays devil's advocate), this provides:
|
|
35
|
+
- Objective assessment of code quality
|
|
36
|
+
- Recognition of what's done well
|
|
37
|
+
- Constructive suggestions for improvement
|
|
38
|
+
- Focus on practical concerns
|
|
39
|
+
- No predetermined bias or harsh judgment
|
|
40
|
+
|
|
41
|
+
Parameters:
|
|
42
|
+
- focus: Review focus area (GENERAL, FUNCTIONALITY, READABILITY, MAINTAINABILITY, TESTING, DOCUMENTATION, ARCHITECTURE)
|
|
43
|
+
- work_description: Clear description of what you've implemented
|
|
44
|
+
- code_snippets: Optional code snippets to review (as a list of strings)
|
|
45
|
+
- file_paths: Optional list of file paths you've modified
|
|
46
|
+
- context: Optional additional context about the implementation
|
|
47
|
+
|
|
48
|
+
The review will be balanced, highlighting both strengths and areas for improvement.
|
|
49
|
+
|
|
50
|
+
Example:
|
|
51
|
+
review(
|
|
52
|
+
focus="FUNCTIONALITY",
|
|
53
|
+
work_description="Implemented auto-import feature for Go files",
|
|
54
|
+
code_snippets=["func AddImport(file string, importPath string) error { ... }"],
|
|
55
|
+
file_paths=["/path/to/import_handler.go"],
|
|
56
|
+
context="This will be used to automatically fix missing imports in Go files"
|
|
57
|
+
)"""
|
|
58
|
+
|
|
59
|
+
async def call(
|
|
60
|
+
self,
|
|
61
|
+
ctx: MCPContext,
|
|
62
|
+
focus: str,
|
|
63
|
+
work_description: str,
|
|
64
|
+
code_snippets: Optional[List[str]] = None,
|
|
65
|
+
file_paths: Optional[List[str]] = None,
|
|
66
|
+
context: Optional[str] = None
|
|
67
|
+
) -> str:
|
|
68
|
+
"""This is a placeholder - actual implementation happens in AgentTool."""
|
|
69
|
+
# This tool is handled specially in the agent execution
|
|
70
|
+
return f"Review requested for: {work_description}"
|
|
71
|
+
|
|
72
|
+
def register(self, server: FastMCP) -> None:
|
|
73
|
+
"""Register the tool with the MCP server."""
|
|
74
|
+
tool_self = self
|
|
75
|
+
|
|
76
|
+
@server.tool(name=self.name, description=self.description)
|
|
77
|
+
async def review(
|
|
78
|
+
ctx: MCPContext,
|
|
79
|
+
focus: str,
|
|
80
|
+
work_description: str,
|
|
81
|
+
code_snippets: Optional[List[str]] = None,
|
|
82
|
+
file_paths: Optional[List[str]] = None,
|
|
83
|
+
context: Optional[str] = None
|
|
84
|
+
) -> str:
|
|
85
|
+
return await tool_self.call(
|
|
86
|
+
ctx,
|
|
87
|
+
focus,
|
|
88
|
+
work_description,
|
|
89
|
+
code_snippets,
|
|
90
|
+
file_paths,
|
|
91
|
+
context
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class BalancedReviewer:
|
|
96
|
+
"""Provides balanced, constructive code reviews."""
|
|
97
|
+
|
|
98
|
+
def __init__(self):
|
|
99
|
+
self.review_handlers = {
|
|
100
|
+
ReviewFocus.GENERAL: self._review_general,
|
|
101
|
+
ReviewFocus.FUNCTIONALITY: self._review_functionality,
|
|
102
|
+
ReviewFocus.READABILITY: self._review_readability,
|
|
103
|
+
ReviewFocus.MAINTAINABILITY: self._review_maintainability,
|
|
104
|
+
ReviewFocus.TESTING: self._review_testing,
|
|
105
|
+
ReviewFocus.DOCUMENTATION: self._review_documentation,
|
|
106
|
+
ReviewFocus.ARCHITECTURE: self._review_architecture,
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
def review(
|
|
110
|
+
self,
|
|
111
|
+
focus: ReviewFocus,
|
|
112
|
+
work_description: str,
|
|
113
|
+
code_snippets: Optional[List[str]] = None,
|
|
114
|
+
file_paths: Optional[List[str]] = None,
|
|
115
|
+
context: Optional[str] = None
|
|
116
|
+
) -> str:
|
|
117
|
+
"""Perform a balanced code review."""
|
|
118
|
+
review_func = self.review_handlers.get(focus, self._review_general)
|
|
119
|
+
return review_func(work_description, code_snippets, file_paths, context)
|
|
120
|
+
|
|
121
|
+
def _review_general(
|
|
122
|
+
self,
|
|
123
|
+
work_description: str,
|
|
124
|
+
code_snippets: Optional[List[str]],
|
|
125
|
+
file_paths: Optional[List[str]],
|
|
126
|
+
context: Optional[str]
|
|
127
|
+
) -> str:
|
|
128
|
+
"""Provide a general balanced review."""
|
|
129
|
+
response = "📋 GENERAL CODE REVIEW:\n\n"
|
|
130
|
+
response += f"**Work Reviewed:** {work_description}\n\n"
|
|
131
|
+
|
|
132
|
+
# Positive observations
|
|
133
|
+
response += "**Positive Aspects:**\n"
|
|
134
|
+
if "fix" in work_description.lower():
|
|
135
|
+
response += "✓ Addressing identified issues proactively\n"
|
|
136
|
+
if "implement" in work_description.lower():
|
|
137
|
+
response += "✓ Adding new functionality to enhance the system\n"
|
|
138
|
+
if code_snippets:
|
|
139
|
+
response += "✓ Code structure appears organized\n"
|
|
140
|
+
if file_paths and len(file_paths) == 1:
|
|
141
|
+
response += "✓ Focused changes in a single file (good for reviewability)\n"
|
|
142
|
+
elif file_paths and len(file_paths) > 1:
|
|
143
|
+
response += "✓ Comprehensive approach across multiple files\n"
|
|
144
|
+
|
|
145
|
+
# Constructive suggestions
|
|
146
|
+
response += "\n**Suggestions for Consideration:**\n"
|
|
147
|
+
response += "• Ensure all edge cases are handled appropriately\n"
|
|
148
|
+
response += "• Consider adding unit tests if not already present\n"
|
|
149
|
+
response += "• Verify the changes integrate well with existing code\n"
|
|
150
|
+
|
|
151
|
+
if context:
|
|
152
|
+
response += f"\n**Context Consideration:**\n{context}\n"
|
|
153
|
+
response += "→ This context helps understand the implementation choices.\n"
|
|
154
|
+
|
|
155
|
+
# Summary
|
|
156
|
+
response += "\n**Summary:**\n"
|
|
157
|
+
response += "The implementation appears sound. Consider the suggestions above to further strengthen the code."
|
|
158
|
+
|
|
159
|
+
return response
|
|
160
|
+
|
|
161
|
+
def _review_functionality(
|
|
162
|
+
self,
|
|
163
|
+
work_description: str,
|
|
164
|
+
code_snippets: Optional[List[str]],
|
|
165
|
+
file_paths: Optional[List[str]],
|
|
166
|
+
context: Optional[str]
|
|
167
|
+
) -> str:
|
|
168
|
+
"""Review functionality aspects."""
|
|
169
|
+
response = "📋 FUNCTIONALITY REVIEW:\n\n"
|
|
170
|
+
response += f"**Implementation:** {work_description}\n\n"
|
|
171
|
+
|
|
172
|
+
response += "**Functional Assessment:**\n"
|
|
173
|
+
|
|
174
|
+
# Analyze code snippets if provided
|
|
175
|
+
if code_snippets:
|
|
176
|
+
for i, snippet in enumerate(code_snippets, 1):
|
|
177
|
+
response += f"\nCode Snippet {i}:\n"
|
|
178
|
+
|
|
179
|
+
# Check for function definitions
|
|
180
|
+
if "func " in snippet or "def " in snippet or "function " in snippet:
|
|
181
|
+
response += "✓ Function definition looks properly structured\n"
|
|
182
|
+
|
|
183
|
+
# Check for error handling
|
|
184
|
+
if "error" in snippet or "err" in snippet or "try" in snippet:
|
|
185
|
+
response += "✓ Error handling is present\n"
|
|
186
|
+
elif "return" in snippet:
|
|
187
|
+
response += "• Consider adding error handling if applicable\n"
|
|
188
|
+
|
|
189
|
+
# Check for input validation
|
|
190
|
+
if "if " in snippet or "check" in snippet.lower():
|
|
191
|
+
response += "✓ Input validation appears to be present\n"
|
|
192
|
+
|
|
193
|
+
response += "\n**Functional Considerations:**\n"
|
|
194
|
+
response += "• Does the implementation handle all expected inputs?\n"
|
|
195
|
+
response += "• Are return values meaningful and consistent?\n"
|
|
196
|
+
response += "• Is the functionality easily testable?\n"
|
|
197
|
+
response += "• Does it integrate well with existing features?\n"
|
|
198
|
+
|
|
199
|
+
response += "\n**Overall:** The functionality appears to meet the described requirements."
|
|
200
|
+
|
|
201
|
+
return response
|
|
202
|
+
|
|
203
|
+
def _review_readability(
|
|
204
|
+
self,
|
|
205
|
+
work_description: str,
|
|
206
|
+
code_snippets: Optional[List[str]],
|
|
207
|
+
file_paths: Optional[List[str]],
|
|
208
|
+
context: Optional[str]
|
|
209
|
+
) -> str:
|
|
210
|
+
"""Review code readability."""
|
|
211
|
+
response = "📋 READABILITY REVIEW:\n\n"
|
|
212
|
+
|
|
213
|
+
response += "**Readability Factors:**\n"
|
|
214
|
+
|
|
215
|
+
if code_snippets:
|
|
216
|
+
total_lines = sum(snippet.count('\n') + 1 for snippet in code_snippets)
|
|
217
|
+
avg_line_length = sum(len(line) for snippet in code_snippets for line in snippet.split('\n')) / max(total_lines, 1)
|
|
218
|
+
|
|
219
|
+
if avg_line_length < 80:
|
|
220
|
+
response += "✓ Line lengths are reasonable\n"
|
|
221
|
+
else:
|
|
222
|
+
response += "• Some lines might be too long, consider breaking them up\n"
|
|
223
|
+
|
|
224
|
+
# Check naming
|
|
225
|
+
has_good_names = any(
|
|
226
|
+
any(word in snippet for word in ['Add', 'Get', 'Set', 'Create', 'Update', 'Delete'])
|
|
227
|
+
for snippet in code_snippets
|
|
228
|
+
)
|
|
229
|
+
if has_good_names:
|
|
230
|
+
response += "✓ Function/method names appear descriptive\n"
|
|
231
|
+
|
|
232
|
+
response += "\n**Readability Suggestions:**\n"
|
|
233
|
+
response += "• Use meaningful variable and function names\n"
|
|
234
|
+
response += "• Keep functions focused on a single responsibility\n"
|
|
235
|
+
response += "• Add comments for complex logic sections\n"
|
|
236
|
+
response += "• Maintain consistent indentation and formatting\n"
|
|
237
|
+
|
|
238
|
+
response += "\n**Overall:** Code readability appears acceptable with room for minor improvements."
|
|
239
|
+
|
|
240
|
+
return response
|
|
241
|
+
|
|
242
|
+
def _review_maintainability(
|
|
243
|
+
self,
|
|
244
|
+
work_description: str,
|
|
245
|
+
code_snippets: Optional[List[str]],
|
|
246
|
+
file_paths: Optional[List[str]],
|
|
247
|
+
context: Optional[str]
|
|
248
|
+
) -> str:
|
|
249
|
+
"""Review maintainability aspects."""
|
|
250
|
+
response = "📋 MAINTAINABILITY REVIEW:\n\n"
|
|
251
|
+
|
|
252
|
+
response += "**Maintainability Factors:**\n"
|
|
253
|
+
|
|
254
|
+
# Check file organization
|
|
255
|
+
if file_paths:
|
|
256
|
+
if len(file_paths) == 1:
|
|
257
|
+
response += "✓ Changes are localized to a single file\n"
|
|
258
|
+
else:
|
|
259
|
+
response += "✓ Changes are logically distributed across files\n"
|
|
260
|
+
|
|
261
|
+
# Check for modularity in code
|
|
262
|
+
if code_snippets:
|
|
263
|
+
function_count = sum(
|
|
264
|
+
snippet.count('func ') + snippet.count('def ') + snippet.count('function ')
|
|
265
|
+
for snippet in code_snippets
|
|
266
|
+
)
|
|
267
|
+
if function_count > 0:
|
|
268
|
+
response += "✓ Code is broken into functions/methods\n"
|
|
269
|
+
|
|
270
|
+
response += "\n**Maintainability Considerations:**\n"
|
|
271
|
+
response += "• Is the code modular and reusable?\n"
|
|
272
|
+
response += "• Are dependencies clearly defined?\n"
|
|
273
|
+
response += "• Will future developers understand the intent?\n"
|
|
274
|
+
response += "• Is the code structured to allow easy updates?\n"
|
|
275
|
+
|
|
276
|
+
response += "\n**Recommendations:**\n"
|
|
277
|
+
response += "• Consider extracting common patterns into utilities\n"
|
|
278
|
+
response += "• Ensure consistent patterns across the codebase\n"
|
|
279
|
+
response += "• Document any non-obvious design decisions\n"
|
|
280
|
+
|
|
281
|
+
return response
|
|
282
|
+
|
|
283
|
+
def _review_testing(
|
|
284
|
+
self,
|
|
285
|
+
work_description: str,
|
|
286
|
+
code_snippets: Optional[List[str]],
|
|
287
|
+
file_paths: Optional[List[str]],
|
|
288
|
+
context: Optional[str]
|
|
289
|
+
) -> str:
|
|
290
|
+
"""Review testing aspects."""
|
|
291
|
+
response = "📋 TESTING REVIEW:\n\n"
|
|
292
|
+
|
|
293
|
+
has_test_files = any("test" in str(path).lower() for path in (file_paths or []))
|
|
294
|
+
|
|
295
|
+
if has_test_files:
|
|
296
|
+
response += "✓ Test files are included with the changes\n\n"
|
|
297
|
+
else:
|
|
298
|
+
response += "⚠️ No test files detected in the changes\n\n"
|
|
299
|
+
|
|
300
|
+
response += "**Testing Checklist:**\n"
|
|
301
|
+
response += "□ Unit tests for new functions\n"
|
|
302
|
+
response += "□ Integration tests for feature interactions\n"
|
|
303
|
+
response += "□ Edge case coverage\n"
|
|
304
|
+
response += "□ Error condition testing\n"
|
|
305
|
+
response += "□ Performance tests (if applicable)\n"
|
|
306
|
+
|
|
307
|
+
response += "\n**Testing Recommendations:**\n"
|
|
308
|
+
response += "• Write tests that document expected behavior\n"
|
|
309
|
+
response += "• Include both positive and negative test cases\n"
|
|
310
|
+
response += "• Ensure tests are maintainable and clear\n"
|
|
311
|
+
response += "• Aim for good coverage of critical paths\n"
|
|
312
|
+
|
|
313
|
+
if not has_test_files:
|
|
314
|
+
response += "\n💡 Consider adding tests to ensure reliability and prevent regressions."
|
|
315
|
+
|
|
316
|
+
return response
|
|
317
|
+
|
|
318
|
+
def _review_documentation(
|
|
319
|
+
self,
|
|
320
|
+
work_description: str,
|
|
321
|
+
code_snippets: Optional[List[str]],
|
|
322
|
+
file_paths: Optional[List[str]],
|
|
323
|
+
context: Optional[str]
|
|
324
|
+
) -> str:
|
|
325
|
+
"""Review documentation aspects."""
|
|
326
|
+
response = "📋 DOCUMENTATION REVIEW:\n\n"
|
|
327
|
+
|
|
328
|
+
# Check for documentation in code
|
|
329
|
+
has_comments = False
|
|
330
|
+
if code_snippets:
|
|
331
|
+
has_comments = any(
|
|
332
|
+
'//' in snippet or '/*' in snippet or '#' in snippet or '"""' in snippet
|
|
333
|
+
for snippet in code_snippets
|
|
334
|
+
)
|
|
335
|
+
|
|
336
|
+
if has_comments:
|
|
337
|
+
response += "✓ Code includes some documentation\n"
|
|
338
|
+
else:
|
|
339
|
+
response += "• Consider adding documentation comments\n"
|
|
340
|
+
|
|
341
|
+
response += "\n**Documentation Guidelines:**\n"
|
|
342
|
+
response += "• Document the 'why' not just the 'what'\n"
|
|
343
|
+
response += "• Include examples for complex functions\n"
|
|
344
|
+
response += "• Document any assumptions or limitations\n"
|
|
345
|
+
response += "• Keep documentation up-to-date with code changes\n"
|
|
346
|
+
|
|
347
|
+
response += "\n**Recommended Documentation:**\n"
|
|
348
|
+
response += "• Function/method purpose and parameters\n"
|
|
349
|
+
response += "• Complex algorithm explanations\n"
|
|
350
|
+
response += "• API usage examples\n"
|
|
351
|
+
response += "• Configuration requirements\n"
|
|
352
|
+
|
|
353
|
+
return response
|
|
354
|
+
|
|
355
|
+
def _review_architecture(
|
|
356
|
+
self,
|
|
357
|
+
work_description: str,
|
|
358
|
+
code_snippets: Optional[List[str]],
|
|
359
|
+
file_paths: Optional[List[str]],
|
|
360
|
+
context: Optional[str]
|
|
361
|
+
) -> str:
|
|
362
|
+
"""Review architectural aspects."""
|
|
363
|
+
response = "📋 ARCHITECTURE REVIEW:\n\n"
|
|
364
|
+
|
|
365
|
+
response += "**Architectural Considerations:**\n"
|
|
366
|
+
|
|
367
|
+
# Analyze file structure
|
|
368
|
+
if file_paths:
|
|
369
|
+
# Check for separation of concerns
|
|
370
|
+
has_separation = len(set(str(p).split('/')[-2] for p in file_paths if '/' in str(p))) > 1
|
|
371
|
+
if has_separation:
|
|
372
|
+
response += "✓ Changes span multiple modules (good separation)\n"
|
|
373
|
+
else:
|
|
374
|
+
response += "✓ Changes are cohesive within a module\n"
|
|
375
|
+
|
|
376
|
+
response += "\n**Architectural Principles:**\n"
|
|
377
|
+
response += "• Single Responsibility - Each component has one clear purpose\n"
|
|
378
|
+
response += "• Open/Closed - Open for extension, closed for modification\n"
|
|
379
|
+
response += "• Dependency Inversion - Depend on abstractions, not concretions\n"
|
|
380
|
+
response += "• Interface Segregation - Keep interfaces focused and minimal\n"
|
|
381
|
+
|
|
382
|
+
response += "\n**Questions to Consider:**\n"
|
|
383
|
+
response += "• Does this fit well with the existing architecture?\n"
|
|
384
|
+
response += "• Are the right abstractions in place?\n"
|
|
385
|
+
response += "• Is the coupling between components appropriate?\n"
|
|
386
|
+
response += "• Will this scale as requirements grow?\n"
|
|
387
|
+
|
|
388
|
+
if context:
|
|
389
|
+
response += f"\n**Context Impact:**\n{context}\n"
|
|
390
|
+
response += "→ Ensure the architectural choices align with this context.\n"
|
|
391
|
+
|
|
392
|
+
return response
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
class ReviewProtocol:
|
|
396
|
+
"""Protocol for review interactions."""
|
|
397
|
+
|
|
398
|
+
def __init__(self):
|
|
399
|
+
self.reviewer = BalancedReviewer()
|
|
400
|
+
self.review_count = 0
|
|
401
|
+
self.max_reviews = 3 # Allow up to 3 reviews per task
|
|
402
|
+
|
|
403
|
+
def request_review(
|
|
404
|
+
self,
|
|
405
|
+
focus: str,
|
|
406
|
+
work_description: str,
|
|
407
|
+
code_snippets: Optional[List[str]] = None,
|
|
408
|
+
file_paths: Optional[List[str]] = None,
|
|
409
|
+
context: Optional[str] = None
|
|
410
|
+
) -> str:
|
|
411
|
+
"""Request a balanced review."""
|
|
412
|
+
if self.review_count >= self.max_reviews:
|
|
413
|
+
return "📋 Review limit reached. You've received comprehensive feedback - time to finalize your implementation."
|
|
414
|
+
|
|
415
|
+
self.review_count += 1
|
|
416
|
+
|
|
417
|
+
try:
|
|
418
|
+
focus_enum = ReviewFocus[focus.upper()]
|
|
419
|
+
except KeyError:
|
|
420
|
+
focus_enum = ReviewFocus.GENERAL
|
|
421
|
+
|
|
422
|
+
review = self.reviewer.review(
|
|
423
|
+
focus_enum,
|
|
424
|
+
work_description,
|
|
425
|
+
code_snippets,
|
|
426
|
+
file_paths,
|
|
427
|
+
context
|
|
428
|
+
)
|
|
429
|
+
|
|
430
|
+
header = f"Review {self.review_count}/{self.max_reviews} (Focus: {focus_enum.value}):\n\n"
|
|
431
|
+
footer = "\n\n💡 This is a balanced review - consider both strengths and suggestions."
|
|
432
|
+
|
|
433
|
+
return header + review + footer
|