hanzo-mcp 0.6.12__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.

Files changed (117) hide show
  1. hanzo_mcp/__init__.py +2 -2
  2. hanzo_mcp/analytics/__init__.py +5 -0
  3. hanzo_mcp/analytics/posthog_analytics.py +364 -0
  4. hanzo_mcp/cli.py +5 -5
  5. hanzo_mcp/cli_enhanced.py +7 -7
  6. hanzo_mcp/cli_plugin.py +91 -0
  7. hanzo_mcp/config/__init__.py +1 -1
  8. hanzo_mcp/config/settings.py +70 -7
  9. hanzo_mcp/config/tool_config.py +20 -6
  10. hanzo_mcp/dev_server.py +3 -3
  11. hanzo_mcp/prompts/project_system.py +1 -1
  12. hanzo_mcp/server.py +40 -3
  13. hanzo_mcp/server_enhanced.py +69 -0
  14. hanzo_mcp/tools/__init__.py +140 -31
  15. hanzo_mcp/tools/agent/__init__.py +85 -4
  16. hanzo_mcp/tools/agent/agent_tool.py +104 -6
  17. hanzo_mcp/tools/agent/agent_tool_v2.py +459 -0
  18. hanzo_mcp/tools/agent/clarification_protocol.py +220 -0
  19. hanzo_mcp/tools/agent/clarification_tool.py +68 -0
  20. hanzo_mcp/tools/agent/claude_cli_tool.py +125 -0
  21. hanzo_mcp/tools/agent/claude_desktop_auth.py +508 -0
  22. hanzo_mcp/tools/agent/cli_agent_base.py +191 -0
  23. hanzo_mcp/tools/agent/code_auth.py +436 -0
  24. hanzo_mcp/tools/agent/code_auth_tool.py +194 -0
  25. hanzo_mcp/tools/agent/codex_cli_tool.py +123 -0
  26. hanzo_mcp/tools/agent/critic_tool.py +376 -0
  27. hanzo_mcp/tools/agent/gemini_cli_tool.py +128 -0
  28. hanzo_mcp/tools/agent/grok_cli_tool.py +128 -0
  29. hanzo_mcp/tools/agent/iching_tool.py +380 -0
  30. hanzo_mcp/tools/agent/network_tool.py +273 -0
  31. hanzo_mcp/tools/agent/prompt.py +62 -20
  32. hanzo_mcp/tools/agent/review_tool.py +433 -0
  33. hanzo_mcp/tools/agent/swarm_tool.py +535 -0
  34. hanzo_mcp/tools/agent/swarm_tool_v2.py +594 -0
  35. hanzo_mcp/tools/common/__init__.py +15 -1
  36. hanzo_mcp/tools/common/base.py +5 -4
  37. hanzo_mcp/tools/common/batch_tool.py +103 -11
  38. hanzo_mcp/tools/common/config_tool.py +2 -2
  39. hanzo_mcp/tools/common/context.py +2 -2
  40. hanzo_mcp/tools/common/context_fix.py +26 -0
  41. hanzo_mcp/tools/common/critic_tool.py +196 -0
  42. hanzo_mcp/tools/common/decorators.py +208 -0
  43. hanzo_mcp/tools/common/enhanced_base.py +106 -0
  44. hanzo_mcp/tools/common/fastmcp_pagination.py +369 -0
  45. hanzo_mcp/tools/common/forgiving_edit.py +243 -0
  46. hanzo_mcp/tools/common/mode.py +116 -0
  47. hanzo_mcp/tools/common/mode_loader.py +105 -0
  48. hanzo_mcp/tools/common/paginated_base.py +230 -0
  49. hanzo_mcp/tools/common/paginated_response.py +307 -0
  50. hanzo_mcp/tools/common/pagination.py +226 -0
  51. hanzo_mcp/tools/common/permissions.py +1 -1
  52. hanzo_mcp/tools/common/personality.py +936 -0
  53. hanzo_mcp/tools/common/plugin_loader.py +287 -0
  54. hanzo_mcp/tools/common/stats.py +4 -4
  55. hanzo_mcp/tools/common/tool_list.py +4 -1
  56. hanzo_mcp/tools/common/truncate.py +101 -0
  57. hanzo_mcp/tools/common/validation.py +1 -1
  58. hanzo_mcp/tools/config/__init__.py +3 -1
  59. hanzo_mcp/tools/config/config_tool.py +1 -1
  60. hanzo_mcp/tools/config/mode_tool.py +209 -0
  61. hanzo_mcp/tools/database/__init__.py +1 -1
  62. hanzo_mcp/tools/editor/__init__.py +1 -1
  63. hanzo_mcp/tools/filesystem/__init__.py +48 -14
  64. hanzo_mcp/tools/filesystem/ast_multi_edit.py +562 -0
  65. hanzo_mcp/tools/filesystem/batch_search.py +3 -3
  66. hanzo_mcp/tools/filesystem/diff.py +2 -2
  67. hanzo_mcp/tools/filesystem/directory_tree_paginated.py +338 -0
  68. hanzo_mcp/tools/filesystem/rules_tool.py +235 -0
  69. hanzo_mcp/tools/filesystem/{unified_search.py → search_tool.py} +12 -12
  70. hanzo_mcp/tools/filesystem/{symbols_unified.py → symbols_tool.py} +104 -5
  71. hanzo_mcp/tools/filesystem/watch.py +3 -2
  72. hanzo_mcp/tools/jupyter/__init__.py +2 -2
  73. hanzo_mcp/tools/jupyter/jupyter.py +1 -1
  74. hanzo_mcp/tools/llm/__init__.py +3 -3
  75. hanzo_mcp/tools/llm/llm_tool.py +648 -143
  76. hanzo_mcp/tools/lsp/__init__.py +5 -0
  77. hanzo_mcp/tools/lsp/lsp_tool.py +512 -0
  78. hanzo_mcp/tools/mcp/__init__.py +2 -2
  79. hanzo_mcp/tools/mcp/{mcp_unified.py → mcp_tool.py} +3 -3
  80. hanzo_mcp/tools/memory/__init__.py +76 -0
  81. hanzo_mcp/tools/memory/knowledge_tools.py +518 -0
  82. hanzo_mcp/tools/memory/memory_tools.py +456 -0
  83. hanzo_mcp/tools/search/__init__.py +6 -0
  84. hanzo_mcp/tools/search/find_tool.py +581 -0
  85. hanzo_mcp/tools/search/unified_search.py +953 -0
  86. hanzo_mcp/tools/shell/__init__.py +11 -6
  87. hanzo_mcp/tools/shell/auto_background.py +203 -0
  88. hanzo_mcp/tools/shell/base_process.py +57 -29
  89. hanzo_mcp/tools/shell/bash_session_executor.py +1 -1
  90. hanzo_mcp/tools/shell/{bash_unified.py → bash_tool.py} +18 -34
  91. hanzo_mcp/tools/shell/command_executor.py +2 -2
  92. hanzo_mcp/tools/shell/{npx_unified.py → npx_tool.py} +16 -33
  93. hanzo_mcp/tools/shell/open.py +2 -2
  94. hanzo_mcp/tools/shell/{process_unified.py → process_tool.py} +1 -1
  95. hanzo_mcp/tools/shell/run_command_windows.py +1 -1
  96. hanzo_mcp/tools/shell/streaming_command.py +594 -0
  97. hanzo_mcp/tools/shell/uvx.py +47 -2
  98. hanzo_mcp/tools/shell/uvx_background.py +47 -2
  99. hanzo_mcp/tools/shell/{uvx_unified.py → uvx_tool.py} +16 -33
  100. hanzo_mcp/tools/todo/__init__.py +14 -19
  101. hanzo_mcp/tools/todo/todo.py +22 -1
  102. hanzo_mcp/tools/vector/__init__.py +1 -1
  103. hanzo_mcp/tools/vector/infinity_store.py +2 -2
  104. hanzo_mcp/tools/vector/project_manager.py +1 -1
  105. hanzo_mcp/types.py +23 -0
  106. hanzo_mcp-0.7.0.dist-info/METADATA +516 -0
  107. hanzo_mcp-0.7.0.dist-info/RECORD +180 -0
  108. {hanzo_mcp-0.6.12.dist-info → hanzo_mcp-0.7.0.dist-info}/entry_points.txt +1 -0
  109. hanzo_mcp/tools/common/palette.py +0 -344
  110. hanzo_mcp/tools/common/palette_loader.py +0 -108
  111. hanzo_mcp/tools/config/palette_tool.py +0 -179
  112. hanzo_mcp/tools/llm/llm_unified.py +0 -851
  113. hanzo_mcp-0.6.12.dist-info/METADATA +0 -339
  114. hanzo_mcp-0.6.12.dist-info/RECORD +0 -135
  115. hanzo_mcp-0.6.12.dist-info/licenses/LICENSE +0 -21
  116. {hanzo_mcp-0.6.12.dist-info → hanzo_mcp-0.7.0.dist-info}/WHEEL +0 -0
  117. {hanzo_mcp-0.6.12.dist-info → hanzo_mcp-0.7.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,194 @@
1
+ """Claude Code authentication tool.
2
+
3
+ This tool manages API keys and accounts for Claude Code and other AI coding tools.
4
+ """
5
+
6
+ from typing import Annotated, Optional, TypedDict, Unpack, final, override
7
+ from mcp.server import FastMCP
8
+ from mcp.server.fastmcp import Context as MCPContext
9
+ from pydantic import Field
10
+
11
+ from hanzo_mcp.tools.common.base import BaseTool
12
+ from hanzo_mcp.tools.common.context import create_tool_context
13
+ from hanzo_mcp.tools.agent.code_auth import CodeAuthManager
14
+
15
+
16
+ class CodeAuthParams(TypedDict, total=False):
17
+ """Parameters for code auth tool."""
18
+ action: str
19
+ account: Optional[str]
20
+ provider: Optional[str]
21
+ api_key: Optional[str]
22
+ model: Optional[str]
23
+ description: Optional[str]
24
+ agent_id: Optional[str]
25
+ parent_account: Optional[str]
26
+
27
+
28
+ @final
29
+ class CodeAuthTool(BaseTool):
30
+ """Tool for managing Claude Code authentication and API keys."""
31
+
32
+ @property
33
+ @override
34
+ def name(self) -> str:
35
+ """Get the tool name."""
36
+ return "code_auth"
37
+
38
+ @property
39
+ @override
40
+ def description(self) -> str:
41
+ """Get the tool description."""
42
+ return """Manage Claude Code and AI provider authentication.
43
+
44
+ Actions:
45
+ - status: Show current login status
46
+ - list: List all accounts
47
+ - create: Create a new account
48
+ - login: Login to an account
49
+ - logout: Logout current account
50
+ - switch: Switch between accounts
51
+ - agent: Create/get agent account
52
+
53
+ Examples:
54
+ code_auth status
55
+ code_auth list
56
+ code_auth create --account work --provider claude
57
+ code_auth login --account work
58
+ code_auth logout
59
+ code_auth switch --account personal
60
+ code_auth agent --agent_id swarm_1 --parent_account work
61
+
62
+ Providers: claude, openai, azure, deepseek, google, groq"""
63
+
64
+ def __init__(self):
65
+ """Initialize the code auth tool."""
66
+ self.auth_manager = CodeAuthManager()
67
+
68
+ @override
69
+ async def call(
70
+ self,
71
+ ctx: MCPContext,
72
+ **params: Unpack[CodeAuthParams],
73
+ ) -> str:
74
+ """Execute the code auth tool.
75
+
76
+ Args:
77
+ ctx: MCP context
78
+ **params: Tool parameters
79
+
80
+ Returns:
81
+ Result message
82
+ """
83
+ tool_ctx = create_tool_context(ctx)
84
+ await tool_ctx.set_tool_info(self.name)
85
+
86
+ action = params.get("action", "status")
87
+
88
+ if action == "status":
89
+ current = self.auth_manager.get_active_account()
90
+ if current:
91
+ info = self.auth_manager.get_account_info(current)
92
+ if info:
93
+ return f"Logged in as: {current} ({info['provider']})"
94
+ return "Not logged in"
95
+
96
+ elif action == "list":
97
+ accounts = self.auth_manager.list_accounts()
98
+ if not accounts:
99
+ return "No accounts configured"
100
+
101
+ current = self.auth_manager.get_active_account()
102
+ lines = ["Configured accounts:"]
103
+ for account in accounts:
104
+ info = self.auth_manager.get_account_info(account)
105
+ marker = " (active)" if account == current else ""
106
+ lines.append(f" - {account}: {info['provider']}{marker}")
107
+ return "\n".join(lines)
108
+
109
+ elif action == "create":
110
+ account = params.get("account")
111
+ if not account:
112
+ return "Error: account name required"
113
+
114
+ provider = params.get("provider", "claude")
115
+ api_key = params.get("api_key")
116
+ model = params.get("model")
117
+ description = params.get("description")
118
+
119
+ success, msg = self.auth_manager.create_account(
120
+ account, provider, api_key, model, description
121
+ )
122
+ return msg
123
+
124
+ elif action == "login":
125
+ account = params.get("account", "default")
126
+ success, msg = self.auth_manager.login(account)
127
+ return msg
128
+
129
+ elif action == "logout":
130
+ success, msg = self.auth_manager.logout()
131
+ return msg
132
+
133
+ elif action == "switch":
134
+ account = params.get("account")
135
+ if not account:
136
+ return "Error: account name required"
137
+
138
+ success, msg = self.auth_manager.switch_account(account)
139
+ return msg
140
+
141
+ elif action == "agent":
142
+ agent_id = params.get("agent_id")
143
+ if not agent_id:
144
+ return "Error: agent_id required"
145
+
146
+ provider = params.get("provider", "claude")
147
+ parent_account = params.get("parent_account")
148
+
149
+ # Try to create agent account
150
+ success, result = self.auth_manager.create_agent_account(
151
+ agent_id, provider, parent_account
152
+ )
153
+
154
+ if success:
155
+ # Get credentials
156
+ creds = self.auth_manager.get_agent_credentials(agent_id)
157
+ if creds:
158
+ return f"Agent account ready: {result} ({creds.provider})"
159
+ else:
160
+ return f"Agent account created but no credentials: {result}"
161
+ else:
162
+ return f"Failed to create agent account: {result}"
163
+
164
+ else:
165
+ return f"Unknown action: {action}. Use: status, list, create, login, logout, switch, agent"
166
+
167
+ @override
168
+ def register(self, mcp_server: FastMCP) -> None:
169
+ """Register this tool with the MCP server."""
170
+ tool_self = self
171
+
172
+ @mcp_server.tool(name=self.name, description=self.description)
173
+ async def code_auth(
174
+ ctx: MCPContext,
175
+ action: str = "status",
176
+ account: Optional[str] = None,
177
+ provider: Optional[str] = None,
178
+ api_key: Optional[str] = None,
179
+ model: Optional[str] = None,
180
+ description: Optional[str] = None,
181
+ agent_id: Optional[str] = None,
182
+ parent_account: Optional[str] = None,
183
+ ) -> str:
184
+ return await tool_self.call(
185
+ ctx,
186
+ action=action,
187
+ account=account,
188
+ provider=provider,
189
+ api_key=api_key,
190
+ model=model,
191
+ description=description,
192
+ agent_id=agent_id,
193
+ parent_account=parent_account,
194
+ )
@@ -0,0 +1,123 @@
1
+ """OpenAI Codex CLI agent tool.
2
+
3
+ This tool provides integration with OpenAI's CLI (openai command),
4
+ allowing programmatic execution of GPT-4 and other models for code tasks.
5
+ """
6
+
7
+ from typing import List, Optional, override, final
8
+ from mcp.server import FastMCP
9
+ from mcp.server.fastmcp import Context as MCPContext
10
+
11
+ from hanzo_mcp.tools.agent.cli_agent_base import CLIAgentBase
12
+ from hanzo_mcp.tools.common.permissions import PermissionManager
13
+
14
+
15
+ @final
16
+ class CodexCLITool(CLIAgentBase):
17
+ """Tool for executing OpenAI CLI (formerly Codex)."""
18
+
19
+ def __init__(
20
+ self,
21
+ permission_manager: PermissionManager,
22
+ model: Optional[str] = None,
23
+ **kwargs
24
+ ):
25
+ """Initialize Codex CLI tool.
26
+
27
+ Args:
28
+ permission_manager: Permission manager for access control
29
+ model: Optional model override (defaults to gpt-4o)
30
+ **kwargs: Additional arguments
31
+ """
32
+ super().__init__(
33
+ permission_manager=permission_manager,
34
+ command_name="openai",
35
+ provider_name="OpenAI",
36
+ default_model=model or "gpt-4o",
37
+ env_vars=["OPENAI_API_KEY"],
38
+ **kwargs
39
+ )
40
+
41
+ @property
42
+ @override
43
+ def name(self) -> str:
44
+ """Get the tool name."""
45
+ return "codex_cli"
46
+
47
+ @property
48
+ @override
49
+ def description(self) -> str:
50
+ """Get the tool description."""
51
+ return """Execute OpenAI CLI for code generation and analysis.
52
+
53
+ This tool runs the OpenAI CLI (openai command) for code generation,
54
+ completion, and analysis tasks. It uses GPT-4o by default but supports
55
+ all OpenAI models.
56
+
57
+ Features:
58
+ - GPT-4 and GPT-4o for advanced reasoning
59
+ - Code generation and completion
60
+ - Multi-modal support (with gpt-4-vision)
61
+ - Function calling capabilities
62
+
63
+ Usage:
64
+ codex_cli(prompts="Generate a Python function to sort a binary tree")
65
+ codex_cli(prompts="Explain this code and suggest improvements", model="gpt-4-turbo")
66
+
67
+ Requirements:
68
+ - OpenAI CLI must be installed: pip install openai
69
+ - OPENAI_API_KEY environment variable
70
+ """
71
+
72
+ @override
73
+ def get_cli_args(self, prompt: str, **kwargs) -> List[str]:
74
+ """Get CLI arguments for OpenAI.
75
+
76
+ Args:
77
+ prompt: The prompt to send
78
+ **kwargs: Additional arguments (model, temperature, etc.)
79
+
80
+ Returns:
81
+ List of command arguments
82
+ """
83
+ args = ["api", "chat.completions.create"]
84
+
85
+ # Add model
86
+ model = kwargs.get("model", self.default_model)
87
+ args.extend(["-m", model])
88
+
89
+ # Add temperature if specified
90
+ if "temperature" in kwargs:
91
+ args.extend(["--temperature", str(kwargs["temperature"])])
92
+
93
+ # Add max tokens if specified
94
+ if "max_tokens" in kwargs:
95
+ args.extend(["--max-tokens", str(kwargs["max_tokens"])])
96
+
97
+ # Add the prompt as a message
98
+ args.extend(["-g", prompt])
99
+
100
+ return args
101
+
102
+ @override
103
+ def register(self, mcp_server: FastMCP) -> None:
104
+ """Register this tool with the MCP server."""
105
+ tool_self = self
106
+
107
+ @mcp_server.tool(name=self.name, description=self.description)
108
+ async def codex_cli(
109
+ ctx: MCPContext,
110
+ prompts: str,
111
+ model: Optional[str] = None,
112
+ temperature: Optional[float] = None,
113
+ max_tokens: Optional[int] = None,
114
+ working_dir: Optional[str] = None,
115
+ ) -> str:
116
+ return await tool_self.call(
117
+ ctx,
118
+ prompts=prompts,
119
+ model=model,
120
+ temperature=temperature,
121
+ max_tokens=max_tokens,
122
+ working_dir=working_dir,
123
+ )
@@ -0,0 +1,376 @@
1
+ """Critic tool for agents to request critical 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 ReviewType(Enum):
13
+ """Types of review requests."""
14
+ CODE_QUALITY = "code_quality"
15
+ CORRECTNESS = "correctness"
16
+ PERFORMANCE = "performance"
17
+ SECURITY = "security"
18
+ COMPLETENESS = "completeness"
19
+ BEST_PRACTICES = "best_practices"
20
+ GENERAL = "general"
21
+
22
+
23
+ class CriticTool(BaseTool):
24
+ """Tool for agents to request critical review from the main loop."""
25
+
26
+ name = "critic"
27
+
28
+ @property
29
+ @override
30
+ def description(self) -> str:
31
+ """Get the tool description."""
32
+ return """Request critical review and feedback from the main loop.
33
+
34
+ Use this tool to get automated critical analysis of your work. The main loop will:
35
+ - Review your implementation for bugs, edge cases, and improvements
36
+ - Check for security issues and best practices
37
+ - Suggest performance optimizations
38
+ - Ensure completeness and correctness
39
+ - Provide actionable feedback for improvements
40
+
41
+ Parameters:
42
+ - review_type: Type of review (CODE_QUALITY, CORRECTNESS, PERFORMANCE, SECURITY, COMPLETENESS, BEST_PRACTICES, GENERAL)
43
+ - work_description: Clear description of what you've done
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
+ - specific_concerns: Optional specific areas you want reviewed
47
+
48
+ The critic will provide harsh but constructive feedback to ensure high quality.
49
+
50
+ Example:
51
+ critic(
52
+ review_type="CODE_QUALITY",
53
+ work_description="Added import statements to fix undefined symbols in Go files",
54
+ code_snippets=["import (\n \"fmt\"\n \"github.com/luxfi/node/common\"\n)"],
55
+ file_paths=["/path/to/atomic.go", "/path/to/network.go"],
56
+ specific_concerns="Are the imports in the correct format and location?"
57
+ )"""
58
+
59
+ async def call(
60
+ self,
61
+ ctx: MCPContext,
62
+ review_type: str,
63
+ work_description: str,
64
+ code_snippets: Optional[List[str]] = None,
65
+ file_paths: Optional[List[str]] = None,
66
+ specific_concerns: 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"Critic 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 critic(
78
+ ctx: MCPContext,
79
+ review_type: str,
80
+ work_description: str,
81
+ code_snippets: Optional[List[str]] = None,
82
+ file_paths: Optional[List[str]] = None,
83
+ specific_concerns: Optional[str] = None
84
+ ) -> str:
85
+ return await tool_self.call(
86
+ ctx,
87
+ review_type,
88
+ work_description,
89
+ code_snippets,
90
+ file_paths,
91
+ specific_concerns
92
+ )
93
+
94
+
95
+ class AutoCritic:
96
+ """Automated critic that provides harsh but constructive feedback."""
97
+
98
+ def __init__(self):
99
+ self.review_patterns = {
100
+ ReviewType.CODE_QUALITY: self._review_code_quality,
101
+ ReviewType.CORRECTNESS: self._review_correctness,
102
+ ReviewType.PERFORMANCE: self._review_performance,
103
+ ReviewType.SECURITY: self._review_security,
104
+ ReviewType.COMPLETENESS: self._review_completeness,
105
+ ReviewType.BEST_PRACTICES: self._review_best_practices,
106
+ ReviewType.GENERAL: self._review_general,
107
+ }
108
+
109
+ def review(
110
+ self,
111
+ review_type: ReviewType,
112
+ work_description: str,
113
+ code_snippets: Optional[List[str]] = None,
114
+ file_paths: Optional[List[str]] = None,
115
+ specific_concerns: Optional[str] = None
116
+ ) -> str:
117
+ """Perform automated critical review."""
118
+ review_func = self.review_patterns.get(review_type, self._review_general)
119
+ return review_func(work_description, code_snippets, file_paths, specific_concerns)
120
+
121
+ def _review_code_quality(
122
+ self,
123
+ work_description: str,
124
+ code_snippets: Optional[List[str]],
125
+ file_paths: Optional[List[str]],
126
+ specific_concerns: Optional[str]
127
+ ) -> str:
128
+ """Review code quality aspects."""
129
+ issues = []
130
+ suggestions = []
131
+
132
+ # Check for common code quality issues
133
+ if code_snippets:
134
+ for snippet in code_snippets:
135
+ # Check for proper error handling
136
+ if "error" in snippet.lower() and "if err" not in snippet:
137
+ issues.append("❌ Missing error handling - always check errors in Go")
138
+
139
+ # Check for magic numbers
140
+ if any(char.isdigit() for char in snippet) and "const" not in snippet:
141
+ suggestions.append("💡 Consider extracting magic numbers to named constants")
142
+
143
+ # Check for proper imports
144
+ if "import" in snippet:
145
+ if '"fmt"' in snippet and snippet.count("fmt.") == 0:
146
+ issues.append("❌ Unused import 'fmt' - remove unused imports")
147
+ if not snippet.strip().endswith(")") and "import (" in snippet:
148
+ issues.append("❌ Import block not properly closed")
149
+
150
+ # General quality checks
151
+ if "fix" in work_description.lower():
152
+ suggestions.append("💡 Ensure you've tested the fix thoroughly")
153
+ suggestions.append("💡 Consider edge cases and error scenarios")
154
+
155
+ if file_paths and len(file_paths) > 5:
156
+ suggestions.append("💡 Large number of files modified - consider breaking into smaller PRs")
157
+
158
+ # Build response
159
+ response = "🔍 CODE QUALITY REVIEW:\n\n"
160
+
161
+ if issues:
162
+ response += "Issues Found:\n" + "\n".join(issues) + "\n\n"
163
+ else:
164
+ response += "✅ No major code quality issues detected.\n\n"
165
+
166
+ if suggestions:
167
+ response += "Suggestions for Improvement:\n" + "\n".join(suggestions) + "\n\n"
168
+
169
+ if specific_concerns:
170
+ response += f"Regarding your concern: '{specific_concerns}'\n"
171
+ if "import" in specific_concerns.lower():
172
+ response += "→ Imports look properly formatted. Ensure they're in the standard order: stdlib, external, internal.\n"
173
+
174
+ response += "\nOverall: " + ("⚠️ Address the issues before proceeding." if issues else "✅ Good work, but always room for improvement!")
175
+
176
+ return response
177
+
178
+ def _review_correctness(
179
+ self,
180
+ work_description: str,
181
+ code_snippets: Optional[List[str]],
182
+ file_paths: Optional[List[str]],
183
+ specific_concerns: Optional[str]
184
+ ) -> str:
185
+ """Review correctness aspects."""
186
+ return """🔍 CORRECTNESS REVIEW:
187
+
188
+ Critical Questions:
189
+ ❓ Have you verified the changes compile without errors?
190
+ ❓ Do the changes actually fix the reported issue?
191
+ ❓ Have you introduced any new bugs or regressions?
192
+ ❓ Are all edge cases handled properly?
193
+
194
+ Specific Checks:
195
+ - If fixing imports: Verify the import paths are correct for the project
196
+ - If modifying logic: Ensure the logic is sound and handles all cases
197
+ - If refactoring: Confirm behavior is preserved
198
+
199
+ ⚠️ Remember: Working code > elegant code. Make sure it works first!"""
200
+
201
+ def _review_performance(
202
+ self,
203
+ work_description: str,
204
+ code_snippets: Optional[List[str]],
205
+ file_paths: Optional[List[str]],
206
+ specific_concerns: Optional[str]
207
+ ) -> str:
208
+ """Review performance aspects."""
209
+ return """🔍 PERFORMANCE REVIEW:
210
+
211
+ Performance Considerations:
212
+ - Are you doing any operations in loops that could be moved outside?
213
+ - Are there any unnecessary allocations or copies?
214
+ - Could any synchronous operations be made concurrent?
215
+ - Are you caching results that might be reused?
216
+
217
+ For file operations:
218
+ - Consider batch operations over individual ones
219
+ - Use buffered I/O for large files
220
+ - Avoid reading entire files into memory if possible
221
+
222
+ 💡 Remember: Premature optimization is evil, but obvious inefficiencies should be fixed."""
223
+
224
+ def _review_security(
225
+ self,
226
+ work_description: str,
227
+ code_snippets: Optional[List[str]],
228
+ file_paths: Optional[List[str]],
229
+ specific_concerns: Optional[str]
230
+ ) -> str:
231
+ """Review security aspects."""
232
+ return """🔍 SECURITY REVIEW:
233
+
234
+ Security Checklist:
235
+ 🔐 No hardcoded secrets or credentials
236
+ 🔐 All user inputs are validated/sanitized
237
+ 🔐 File paths are properly validated
238
+ 🔐 No SQL injection vulnerabilities
239
+ 🔐 Proper access control checks
240
+ 🔐 Sensitive data is not logged
241
+
242
+ ⚠️ If in doubt, err on the side of caution!"""
243
+
244
+ def _review_completeness(
245
+ self,
246
+ work_description: str,
247
+ code_snippets: Optional[List[str]],
248
+ file_paths: Optional[List[str]],
249
+ specific_concerns: Optional[str]
250
+ ) -> str:
251
+ """Review completeness aspects."""
252
+ tasks_mentioned = work_description.lower()
253
+
254
+ response = "🔍 COMPLETENESS REVIEW:\n\n"
255
+
256
+ if "fix" in tasks_mentioned and "test" not in tasks_mentioned:
257
+ response += "❌ No mention of tests - have you verified the fix with tests?\n"
258
+
259
+ if "import" in tasks_mentioned:
260
+ response += "✓ Import fixes mentioned\n"
261
+ response += "❓ Have you checked for other files with similar issues?\n"
262
+ response += "❓ Are all undefined symbols now resolved?\n"
263
+
264
+ if file_paths:
265
+ response += f"\n✓ Modified {len(file_paths)} files\n"
266
+ response += "❓ Are there any related files that also need updates?\n"
267
+
268
+ response += "\n💡 Completeness means not just fixing the immediate issue, but considering the broader impact."
269
+
270
+ return response
271
+
272
+ def _review_best_practices(
273
+ self,
274
+ work_description: str,
275
+ code_snippets: Optional[List[str]],
276
+ file_paths: Optional[List[str]],
277
+ specific_concerns: Optional[str]
278
+ ) -> str:
279
+ """Review best practices."""
280
+ return """🔍 BEST PRACTICES REVIEW:
281
+
282
+ Go Best Practices (if applicable):
283
+ ✓ Imports are grouped: stdlib, external, internal
284
+ ✓ Error handling follows Go idioms
285
+ ✓ Variable names are clear and idiomatic
286
+ ✓ Comments explain why, not what
287
+ ✓ Functions do one thing well
288
+
289
+ General Best Practices:
290
+ ✓ Code is self-documenting
291
+ ✓ DRY principle is followed
292
+ ✓ SOLID principles are respected
293
+ ✓ Changes are minimal and focused
294
+
295
+ 💡 Good code is code that others (including future you) can understand and modify."""
296
+
297
+ def _review_general(
298
+ self,
299
+ work_description: str,
300
+ code_snippets: Optional[List[str]],
301
+ file_paths: Optional[List[str]],
302
+ specific_concerns: Optional[str]
303
+ ) -> str:
304
+ """General review covering multiple aspects."""
305
+ response = "🔍 GENERAL CRITICAL REVIEW:\n\n"
306
+ response += f"Work Description: {work_description}\n\n"
307
+
308
+ # Quick assessment
309
+ response += "Quick Assessment:\n"
310
+
311
+ if "fix" in work_description.lower():
312
+ response += "- Type: Bug fix / Error resolution\n"
313
+ response += "- Critical: Ensure the fix is complete and tested\n"
314
+ elif "add" in work_description.lower():
315
+ response += "- Type: Feature addition\n"
316
+ response += "- Critical: Ensure no regressions introduced\n"
317
+ elif "refactor" in work_description.lower():
318
+ response += "- Type: Code refactoring\n"
319
+ response += "- Critical: Ensure behavior is preserved\n"
320
+
321
+ if file_paths:
322
+ response += f"- Scope: {len(file_paths)} files affected\n"
323
+ if len(file_paths) > 10:
324
+ response += "- ⚠️ Large scope - consider breaking down\n"
325
+
326
+ response += "\nCritical Questions:\n"
327
+ response += "1. Is this the minimal change needed?\n"
328
+ response += "2. Have you considered all edge cases?\n"
329
+ response += "3. Will this work in production?\n"
330
+ response += "4. Is there a simpler solution?\n"
331
+
332
+ if specific_concerns:
333
+ response += f"\nYour Concern: {specific_concerns}\n"
334
+ response += "→ Valid concern. Double-check this area carefully.\n"
335
+
336
+ response += "\n🎯 Bottom Line: Good work needs critical thinking. Question everything, verify everything."
337
+
338
+ return response
339
+
340
+
341
+ class CriticProtocol:
342
+ """Protocol for critic interactions."""
343
+
344
+ def __init__(self):
345
+ self.auto_critic = AutoCritic()
346
+ self.review_count = 0
347
+ self.max_reviews = 2 # Allow up to 2 reviews per task
348
+
349
+ def request_review(
350
+ self,
351
+ review_type: str,
352
+ work_description: str,
353
+ code_snippets: Optional[List[str]] = None,
354
+ file_paths: Optional[List[str]] = None,
355
+ specific_concerns: Optional[str] = None
356
+ ) -> str:
357
+ """Request a critical review."""
358
+ if self.review_count >= self.max_reviews:
359
+ return "❌ Review limit exceeded. Time to move forward with what you have."
360
+
361
+ self.review_count += 1
362
+
363
+ try:
364
+ review_enum = ReviewType[review_type.upper()]
365
+ except KeyError:
366
+ review_enum = ReviewType.GENERAL
367
+
368
+ review = self.auto_critic.review(
369
+ review_enum,
370
+ work_description,
371
+ code_snippets,
372
+ file_paths,
373
+ specific_concerns
374
+ )
375
+
376
+ return f"Review {self.review_count}/{self.max_reviews}:\n\n{review}"