hanzo-mcp 0.7.7__py3-none-any.whl → 0.8.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 (178) hide show
  1. hanzo_mcp/__init__.py +6 -0
  2. hanzo_mcp/__main__.py +1 -1
  3. hanzo_mcp/analytics/__init__.py +2 -2
  4. hanzo_mcp/analytics/posthog_analytics.py +76 -82
  5. hanzo_mcp/cli.py +31 -36
  6. hanzo_mcp/cli_enhanced.py +94 -72
  7. hanzo_mcp/cli_plugin.py +27 -17
  8. hanzo_mcp/config/__init__.py +2 -2
  9. hanzo_mcp/config/settings.py +112 -88
  10. hanzo_mcp/config/tool_config.py +32 -34
  11. hanzo_mcp/dev_server.py +66 -67
  12. hanzo_mcp/prompts/__init__.py +94 -12
  13. hanzo_mcp/prompts/enhanced_prompts.py +809 -0
  14. hanzo_mcp/prompts/example_custom_prompt.py +6 -5
  15. hanzo_mcp/prompts/project_todo_reminder.py +0 -1
  16. hanzo_mcp/prompts/tool_explorer.py +10 -7
  17. hanzo_mcp/server.py +17 -21
  18. hanzo_mcp/server_enhanced.py +15 -22
  19. hanzo_mcp/tools/__init__.py +56 -28
  20. hanzo_mcp/tools/agent/__init__.py +16 -19
  21. hanzo_mcp/tools/agent/agent.py +82 -65
  22. hanzo_mcp/tools/agent/agent_tool.py +152 -122
  23. hanzo_mcp/tools/agent/agent_tool_v1_deprecated.py +66 -62
  24. hanzo_mcp/tools/agent/clarification_protocol.py +55 -50
  25. hanzo_mcp/tools/agent/clarification_tool.py +11 -10
  26. hanzo_mcp/tools/agent/claude_cli_tool.py +21 -20
  27. hanzo_mcp/tools/agent/claude_desktop_auth.py +130 -144
  28. hanzo_mcp/tools/agent/cli_agent_base.py +59 -53
  29. hanzo_mcp/tools/agent/code_auth.py +102 -107
  30. hanzo_mcp/tools/agent/code_auth_tool.py +28 -27
  31. hanzo_mcp/tools/agent/codex_cli_tool.py +20 -19
  32. hanzo_mcp/tools/agent/critic_tool.py +86 -73
  33. hanzo_mcp/tools/agent/gemini_cli_tool.py +21 -20
  34. hanzo_mcp/tools/agent/grok_cli_tool.py +21 -20
  35. hanzo_mcp/tools/agent/iching_tool.py +404 -139
  36. hanzo_mcp/tools/agent/network_tool.py +89 -73
  37. hanzo_mcp/tools/agent/prompt.py +2 -1
  38. hanzo_mcp/tools/agent/review_tool.py +101 -98
  39. hanzo_mcp/tools/agent/swarm_alias.py +87 -0
  40. hanzo_mcp/tools/agent/swarm_tool.py +246 -161
  41. hanzo_mcp/tools/agent/swarm_tool_v1_deprecated.py +134 -92
  42. hanzo_mcp/tools/agent/tool_adapter.py +21 -11
  43. hanzo_mcp/tools/common/__init__.py +1 -1
  44. hanzo_mcp/tools/common/base.py +3 -5
  45. hanzo_mcp/tools/common/batch_tool.py +46 -39
  46. hanzo_mcp/tools/common/config_tool.py +120 -84
  47. hanzo_mcp/tools/common/context.py +1 -5
  48. hanzo_mcp/tools/common/context_fix.py +5 -3
  49. hanzo_mcp/tools/common/critic_tool.py +4 -8
  50. hanzo_mcp/tools/common/decorators.py +58 -56
  51. hanzo_mcp/tools/common/enhanced_base.py +29 -32
  52. hanzo_mcp/tools/common/fastmcp_pagination.py +91 -94
  53. hanzo_mcp/tools/common/forgiving_edit.py +91 -87
  54. hanzo_mcp/tools/common/mode.py +15 -17
  55. hanzo_mcp/tools/common/mode_loader.py +27 -24
  56. hanzo_mcp/tools/common/paginated_base.py +61 -53
  57. hanzo_mcp/tools/common/paginated_response.py +72 -79
  58. hanzo_mcp/tools/common/pagination.py +50 -53
  59. hanzo_mcp/tools/common/permissions.py +4 -4
  60. hanzo_mcp/tools/common/personality.py +186 -138
  61. hanzo_mcp/tools/common/plugin_loader.py +54 -54
  62. hanzo_mcp/tools/common/stats.py +65 -47
  63. hanzo_mcp/tools/common/test_helpers.py +31 -0
  64. hanzo_mcp/tools/common/thinking_tool.py +4 -8
  65. hanzo_mcp/tools/common/tool_disable.py +17 -12
  66. hanzo_mcp/tools/common/tool_enable.py +13 -14
  67. hanzo_mcp/tools/common/tool_list.py +36 -28
  68. hanzo_mcp/tools/common/truncate.py +23 -23
  69. hanzo_mcp/tools/config/__init__.py +4 -4
  70. hanzo_mcp/tools/config/config_tool.py +42 -29
  71. hanzo_mcp/tools/config/index_config.py +37 -34
  72. hanzo_mcp/tools/config/mode_tool.py +175 -55
  73. hanzo_mcp/tools/database/__init__.py +15 -12
  74. hanzo_mcp/tools/database/database_manager.py +77 -75
  75. hanzo_mcp/tools/database/graph.py +137 -91
  76. hanzo_mcp/tools/database/graph_add.py +30 -18
  77. hanzo_mcp/tools/database/graph_query.py +178 -102
  78. hanzo_mcp/tools/database/graph_remove.py +33 -28
  79. hanzo_mcp/tools/database/graph_search.py +97 -75
  80. hanzo_mcp/tools/database/graph_stats.py +91 -59
  81. hanzo_mcp/tools/database/sql.py +107 -79
  82. hanzo_mcp/tools/database/sql_query.py +30 -24
  83. hanzo_mcp/tools/database/sql_search.py +29 -25
  84. hanzo_mcp/tools/database/sql_stats.py +47 -35
  85. hanzo_mcp/tools/editor/neovim_command.py +25 -28
  86. hanzo_mcp/tools/editor/neovim_edit.py +21 -23
  87. hanzo_mcp/tools/editor/neovim_session.py +60 -54
  88. hanzo_mcp/tools/filesystem/__init__.py +31 -30
  89. hanzo_mcp/tools/filesystem/ast_multi_edit.py +329 -249
  90. hanzo_mcp/tools/filesystem/ast_tool.py +4 -4
  91. hanzo_mcp/tools/filesystem/base.py +1 -1
  92. hanzo_mcp/tools/filesystem/batch_search.py +316 -224
  93. hanzo_mcp/tools/filesystem/content_replace.py +4 -4
  94. hanzo_mcp/tools/filesystem/diff.py +71 -59
  95. hanzo_mcp/tools/filesystem/directory_tree.py +7 -7
  96. hanzo_mcp/tools/filesystem/directory_tree_paginated.py +49 -37
  97. hanzo_mcp/tools/filesystem/edit.py +4 -4
  98. hanzo_mcp/tools/filesystem/find.py +173 -80
  99. hanzo_mcp/tools/filesystem/find_files.py +73 -52
  100. hanzo_mcp/tools/filesystem/git_search.py +157 -104
  101. hanzo_mcp/tools/filesystem/grep.py +8 -8
  102. hanzo_mcp/tools/filesystem/multi_edit.py +4 -8
  103. hanzo_mcp/tools/filesystem/read.py +12 -10
  104. hanzo_mcp/tools/filesystem/rules_tool.py +59 -43
  105. hanzo_mcp/tools/filesystem/search_tool.py +263 -207
  106. hanzo_mcp/tools/filesystem/symbols_tool.py +94 -54
  107. hanzo_mcp/tools/filesystem/tree.py +35 -33
  108. hanzo_mcp/tools/filesystem/unix_aliases.py +13 -18
  109. hanzo_mcp/tools/filesystem/watch.py +37 -36
  110. hanzo_mcp/tools/filesystem/write.py +4 -8
  111. hanzo_mcp/tools/jupyter/__init__.py +4 -4
  112. hanzo_mcp/tools/jupyter/base.py +4 -5
  113. hanzo_mcp/tools/jupyter/jupyter.py +67 -47
  114. hanzo_mcp/tools/jupyter/notebook_edit.py +4 -4
  115. hanzo_mcp/tools/jupyter/notebook_read.py +4 -7
  116. hanzo_mcp/tools/llm/__init__.py +5 -7
  117. hanzo_mcp/tools/llm/consensus_tool.py +72 -52
  118. hanzo_mcp/tools/llm/llm_manage.py +101 -60
  119. hanzo_mcp/tools/llm/llm_tool.py +226 -166
  120. hanzo_mcp/tools/llm/provider_tools.py +25 -26
  121. hanzo_mcp/tools/lsp/__init__.py +1 -1
  122. hanzo_mcp/tools/lsp/lsp_tool.py +228 -143
  123. hanzo_mcp/tools/mcp/__init__.py +2 -3
  124. hanzo_mcp/tools/mcp/mcp_add.py +27 -25
  125. hanzo_mcp/tools/mcp/mcp_remove.py +7 -8
  126. hanzo_mcp/tools/mcp/mcp_stats.py +23 -22
  127. hanzo_mcp/tools/mcp/mcp_tool.py +129 -98
  128. hanzo_mcp/tools/memory/__init__.py +39 -21
  129. hanzo_mcp/tools/memory/knowledge_tools.py +124 -99
  130. hanzo_mcp/tools/memory/memory_tools.py +90 -108
  131. hanzo_mcp/tools/search/__init__.py +7 -2
  132. hanzo_mcp/tools/search/find_tool.py +297 -212
  133. hanzo_mcp/tools/search/unified_search.py +366 -314
  134. hanzo_mcp/tools/shell/__init__.py +8 -7
  135. hanzo_mcp/tools/shell/auto_background.py +56 -49
  136. hanzo_mcp/tools/shell/base.py +1 -1
  137. hanzo_mcp/tools/shell/base_process.py +75 -75
  138. hanzo_mcp/tools/shell/bash_session.py +2 -2
  139. hanzo_mcp/tools/shell/bash_session_executor.py +4 -4
  140. hanzo_mcp/tools/shell/bash_tool.py +24 -31
  141. hanzo_mcp/tools/shell/command_executor.py +12 -12
  142. hanzo_mcp/tools/shell/logs.py +43 -33
  143. hanzo_mcp/tools/shell/npx.py +13 -13
  144. hanzo_mcp/tools/shell/npx_background.py +24 -21
  145. hanzo_mcp/tools/shell/npx_tool.py +18 -22
  146. hanzo_mcp/tools/shell/open.py +19 -21
  147. hanzo_mcp/tools/shell/pkill.py +31 -26
  148. hanzo_mcp/tools/shell/process_tool.py +32 -32
  149. hanzo_mcp/tools/shell/processes.py +57 -58
  150. hanzo_mcp/tools/shell/run_background.py +24 -25
  151. hanzo_mcp/tools/shell/run_command.py +5 -5
  152. hanzo_mcp/tools/shell/run_command_windows.py +5 -5
  153. hanzo_mcp/tools/shell/session_storage.py +3 -3
  154. hanzo_mcp/tools/shell/streaming_command.py +141 -126
  155. hanzo_mcp/tools/shell/uvx.py +24 -25
  156. hanzo_mcp/tools/shell/uvx_background.py +35 -33
  157. hanzo_mcp/tools/shell/uvx_tool.py +18 -22
  158. hanzo_mcp/tools/todo/__init__.py +6 -2
  159. hanzo_mcp/tools/todo/todo.py +50 -37
  160. hanzo_mcp/tools/todo/todo_read.py +5 -8
  161. hanzo_mcp/tools/todo/todo_write.py +5 -7
  162. hanzo_mcp/tools/vector/__init__.py +40 -28
  163. hanzo_mcp/tools/vector/ast_analyzer.py +176 -143
  164. hanzo_mcp/tools/vector/git_ingester.py +170 -179
  165. hanzo_mcp/tools/vector/index_tool.py +96 -44
  166. hanzo_mcp/tools/vector/infinity_store.py +283 -228
  167. hanzo_mcp/tools/vector/mock_infinity.py +39 -40
  168. hanzo_mcp/tools/vector/project_manager.py +88 -78
  169. hanzo_mcp/tools/vector/vector.py +59 -42
  170. hanzo_mcp/tools/vector/vector_index.py +30 -27
  171. hanzo_mcp/tools/vector/vector_search.py +64 -45
  172. hanzo_mcp/types.py +6 -4
  173. {hanzo_mcp-0.7.7.dist-info → hanzo_mcp-0.8.0.dist-info}/METADATA +1 -1
  174. hanzo_mcp-0.8.0.dist-info/RECORD +185 -0
  175. hanzo_mcp-0.7.7.dist-info/RECORD +0 -182
  176. {hanzo_mcp-0.7.7.dist-info → hanzo_mcp-0.8.0.dist-info}/WHEEL +0 -0
  177. {hanzo_mcp-0.7.7.dist-info → hanzo_mcp-0.8.0.dist-info}/entry_points.txt +0 -0
  178. {hanzo_mcp-0.7.7.dist-info → hanzo_mcp-0.8.0.dist-info}/top_level.txt +0 -0
@@ -1,16 +1,17 @@
1
1
  """Review tool for agents to request balanced code review from main loop."""
2
2
 
3
- import json
4
- from typing import Any, Dict, List, Optional, override
5
3
  from enum import Enum
4
+ from typing import List, Optional, override
6
5
 
7
- from hanzo_mcp.tools.common.base import BaseTool
8
- from mcp.server.fastmcp import Context as MCPContext
9
6
  from mcp.server import FastMCP
7
+ from mcp.server.fastmcp import Context as MCPContext
8
+
9
+ from hanzo_mcp.tools.common.base import BaseTool
10
10
 
11
11
 
12
12
  class ReviewFocus(Enum):
13
13
  """Types of review focus areas."""
14
+
14
15
  GENERAL = "general"
15
16
  FUNCTIONALITY = "functionality"
16
17
  READABILITY = "readability"
@@ -22,9 +23,9 @@ class ReviewFocus(Enum):
22
23
 
23
24
  class ReviewTool(BaseTool):
24
25
  """Tool for agents to request balanced code review from the main loop."""
25
-
26
+
26
27
  name = "review"
27
-
28
+
28
29
  @property
29
30
  @override
30
31
  def description(self) -> str:
@@ -55,7 +56,7 @@ review(
55
56
  file_paths=["/path/to/import_handler.go"],
56
57
  context="This will be used to automatically fix missing imports in Go files"
57
58
  )"""
58
-
59
+
59
60
  async def call(
60
61
  self,
61
62
  ctx: MCPContext,
@@ -63,16 +64,16 @@ review(
63
64
  work_description: str,
64
65
  code_snippets: Optional[List[str]] = None,
65
66
  file_paths: Optional[List[str]] = None,
66
- context: Optional[str] = None
67
+ context: Optional[str] = None,
67
68
  ) -> str:
68
69
  """This is a placeholder - actual implementation happens in AgentTool."""
69
70
  # This tool is handled specially in the agent execution
70
71
  return f"Review requested for: {work_description}"
71
-
72
+
72
73
  def register(self, server: FastMCP) -> None:
73
74
  """Register the tool with the MCP server."""
74
75
  tool_self = self
75
-
76
+
76
77
  @server.tool(name=self.name, description=self.description)
77
78
  async def review(
78
79
  ctx: MCPContext,
@@ -80,21 +81,16 @@ review(
80
81
  work_description: str,
81
82
  code_snippets: Optional[List[str]] = None,
82
83
  file_paths: Optional[List[str]] = None,
83
- context: Optional[str] = None
84
+ context: Optional[str] = None,
84
85
  ) -> str:
85
86
  return await tool_self.call(
86
- ctx,
87
- focus,
88
- work_description,
89
- code_snippets,
90
- file_paths,
91
- context
87
+ ctx, focus, work_description, code_snippets, file_paths, context
92
88
  )
93
89
 
94
90
 
95
91
  class BalancedReviewer:
96
92
  """Provides balanced, constructive code reviews."""
97
-
93
+
98
94
  def __init__(self):
99
95
  self.review_handlers = {
100
96
  ReviewFocus.GENERAL: self._review_general,
@@ -105,30 +101,30 @@ class BalancedReviewer:
105
101
  ReviewFocus.DOCUMENTATION: self._review_documentation,
106
102
  ReviewFocus.ARCHITECTURE: self._review_architecture,
107
103
  }
108
-
104
+
109
105
  def review(
110
106
  self,
111
107
  focus: ReviewFocus,
112
108
  work_description: str,
113
109
  code_snippets: Optional[List[str]] = None,
114
110
  file_paths: Optional[List[str]] = None,
115
- context: Optional[str] = None
111
+ context: Optional[str] = None,
116
112
  ) -> str:
117
113
  """Perform a balanced code review."""
118
114
  review_func = self.review_handlers.get(focus, self._review_general)
119
115
  return review_func(work_description, code_snippets, file_paths, context)
120
-
116
+
121
117
  def _review_general(
122
118
  self,
123
119
  work_description: str,
124
120
  code_snippets: Optional[List[str]],
125
121
  file_paths: Optional[List[str]],
126
- context: Optional[str]
122
+ context: Optional[str],
127
123
  ) -> str:
128
124
  """Provide a general balanced review."""
129
125
  response = "📋 GENERAL CODE REVIEW:\n\n"
130
126
  response += f"**Work Reviewed:** {work_description}\n\n"
131
-
127
+
132
128
  # Positive observations
133
129
  response += "**Positive Aspects:**\n"
134
130
  if "fix" in work_description.lower():
@@ -141,293 +137,300 @@ class BalancedReviewer:
141
137
  response += "✓ Focused changes in a single file (good for reviewability)\n"
142
138
  elif file_paths and len(file_paths) > 1:
143
139
  response += "✓ Comprehensive approach across multiple files\n"
144
-
140
+
145
141
  # Constructive suggestions
146
142
  response += "\n**Suggestions for Consideration:**\n"
147
143
  response += "• Ensure all edge cases are handled appropriately\n"
148
144
  response += "• Consider adding unit tests if not already present\n"
149
145
  response += "• Verify the changes integrate well with existing code\n"
150
-
146
+
151
147
  if context:
152
148
  response += f"\n**Context Consideration:**\n{context}\n"
153
149
  response += "→ This context helps understand the implementation choices.\n"
154
-
150
+
155
151
  # Summary
156
152
  response += "\n**Summary:**\n"
157
153
  response += "The implementation appears sound. Consider the suggestions above to further strengthen the code."
158
-
154
+
159
155
  return response
160
-
156
+
161
157
  def _review_functionality(
162
158
  self,
163
159
  work_description: str,
164
160
  code_snippets: Optional[List[str]],
165
161
  file_paths: Optional[List[str]],
166
- context: Optional[str]
162
+ context: Optional[str],
167
163
  ) -> str:
168
164
  """Review functionality aspects."""
169
165
  response = "📋 FUNCTIONALITY REVIEW:\n\n"
170
166
  response += f"**Implementation:** {work_description}\n\n"
171
-
167
+
172
168
  response += "**Functional Assessment:**\n"
173
-
169
+
174
170
  # Analyze code snippets if provided
175
171
  if code_snippets:
176
172
  for i, snippet in enumerate(code_snippets, 1):
177
173
  response += f"\nCode Snippet {i}:\n"
178
-
174
+
179
175
  # Check for function definitions
180
176
  if "func " in snippet or "def " in snippet or "function " in snippet:
181
177
  response += "✓ Function definition looks properly structured\n"
182
-
178
+
183
179
  # Check for error handling
184
180
  if "error" in snippet or "err" in snippet or "try" in snippet:
185
181
  response += "✓ Error handling is present\n"
186
182
  elif "return" in snippet:
187
183
  response += "• Consider adding error handling if applicable\n"
188
-
184
+
189
185
  # Check for input validation
190
186
  if "if " in snippet or "check" in snippet.lower():
191
187
  response += "✓ Input validation appears to be present\n"
192
-
188
+
193
189
  response += "\n**Functional Considerations:**\n"
194
190
  response += "• Does the implementation handle all expected inputs?\n"
195
191
  response += "• Are return values meaningful and consistent?\n"
196
192
  response += "• Is the functionality easily testable?\n"
197
193
  response += "• Does it integrate well with existing features?\n"
198
-
194
+
199
195
  response += "\n**Overall:** The functionality appears to meet the described requirements."
200
-
196
+
201
197
  return response
202
-
198
+
203
199
  def _review_readability(
204
200
  self,
205
201
  work_description: str,
206
202
  code_snippets: Optional[List[str]],
207
203
  file_paths: Optional[List[str]],
208
- context: Optional[str]
204
+ context: Optional[str],
209
205
  ) -> str:
210
206
  """Review code readability."""
211
207
  response = "📋 READABILITY REVIEW:\n\n"
212
-
208
+
213
209
  response += "**Readability Factors:**\n"
214
-
210
+
215
211
  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
-
212
+ total_lines = sum(snippet.count("\n") + 1 for snippet in code_snippets)
213
+ avg_line_length = sum(
214
+ len(line) for snippet in code_snippets for line in snippet.split("\n")
215
+ ) / max(total_lines, 1)
216
+
219
217
  if avg_line_length < 80:
220
218
  response += "✓ Line lengths are reasonable\n"
221
219
  else:
222
- response += "• Some lines might be too long, consider breaking them up\n"
223
-
220
+ response += (
221
+ "• Some lines might be too long, consider breaking them up\n"
222
+ )
223
+
224
224
  # Check naming
225
225
  has_good_names = any(
226
- any(word in snippet for word in ['Add', 'Get', 'Set', 'Create', 'Update', 'Delete'])
226
+ any(
227
+ word in snippet
228
+ for word in ["Add", "Get", "Set", "Create", "Update", "Delete"]
229
+ )
227
230
  for snippet in code_snippets
228
231
  )
229
232
  if has_good_names:
230
233
  response += "✓ Function/method names appear descriptive\n"
231
-
234
+
232
235
  response += "\n**Readability Suggestions:**\n"
233
236
  response += "• Use meaningful variable and function names\n"
234
237
  response += "• Keep functions focused on a single responsibility\n"
235
238
  response += "• Add comments for complex logic sections\n"
236
239
  response += "• Maintain consistent indentation and formatting\n"
237
-
240
+
238
241
  response += "\n**Overall:** Code readability appears acceptable with room for minor improvements."
239
-
242
+
240
243
  return response
241
-
244
+
242
245
  def _review_maintainability(
243
246
  self,
244
247
  work_description: str,
245
248
  code_snippets: Optional[List[str]],
246
249
  file_paths: Optional[List[str]],
247
- context: Optional[str]
250
+ context: Optional[str],
248
251
  ) -> str:
249
252
  """Review maintainability aspects."""
250
253
  response = "📋 MAINTAINABILITY REVIEW:\n\n"
251
-
254
+
252
255
  response += "**Maintainability Factors:**\n"
253
-
256
+
254
257
  # Check file organization
255
258
  if file_paths:
256
259
  if len(file_paths) == 1:
257
260
  response += "✓ Changes are localized to a single file\n"
258
261
  else:
259
262
  response += "✓ Changes are logically distributed across files\n"
260
-
263
+
261
264
  # Check for modularity in code
262
265
  if code_snippets:
263
266
  function_count = sum(
264
- snippet.count('func ') + snippet.count('def ') + snippet.count('function ')
267
+ snippet.count("func ")
268
+ + snippet.count("def ")
269
+ + snippet.count("function ")
265
270
  for snippet in code_snippets
266
271
  )
267
272
  if function_count > 0:
268
273
  response += "✓ Code is broken into functions/methods\n"
269
-
274
+
270
275
  response += "\n**Maintainability Considerations:**\n"
271
276
  response += "• Is the code modular and reusable?\n"
272
277
  response += "• Are dependencies clearly defined?\n"
273
278
  response += "• Will future developers understand the intent?\n"
274
279
  response += "• Is the code structured to allow easy updates?\n"
275
-
280
+
276
281
  response += "\n**Recommendations:**\n"
277
282
  response += "• Consider extracting common patterns into utilities\n"
278
283
  response += "• Ensure consistent patterns across the codebase\n"
279
284
  response += "• Document any non-obvious design decisions\n"
280
-
285
+
281
286
  return response
282
-
287
+
283
288
  def _review_testing(
284
289
  self,
285
290
  work_description: str,
286
291
  code_snippets: Optional[List[str]],
287
292
  file_paths: Optional[List[str]],
288
- context: Optional[str]
293
+ context: Optional[str],
289
294
  ) -> str:
290
295
  """Review testing aspects."""
291
296
  response = "📋 TESTING REVIEW:\n\n"
292
-
297
+
293
298
  has_test_files = any("test" in str(path).lower() for path in (file_paths or []))
294
-
299
+
295
300
  if has_test_files:
296
301
  response += "✓ Test files are included with the changes\n\n"
297
302
  else:
298
303
  response += "⚠️ No test files detected in the changes\n\n"
299
-
304
+
300
305
  response += "**Testing Checklist:**\n"
301
306
  response += "□ Unit tests for new functions\n"
302
307
  response += "□ Integration tests for feature interactions\n"
303
308
  response += "□ Edge case coverage\n"
304
309
  response += "□ Error condition testing\n"
305
310
  response += "□ Performance tests (if applicable)\n"
306
-
311
+
307
312
  response += "\n**Testing Recommendations:**\n"
308
313
  response += "• Write tests that document expected behavior\n"
309
314
  response += "• Include both positive and negative test cases\n"
310
315
  response += "• Ensure tests are maintainable and clear\n"
311
316
  response += "• Aim for good coverage of critical paths\n"
312
-
317
+
313
318
  if not has_test_files:
314
319
  response += "\n💡 Consider adding tests to ensure reliability and prevent regressions."
315
-
320
+
316
321
  return response
317
-
322
+
318
323
  def _review_documentation(
319
324
  self,
320
325
  work_description: str,
321
326
  code_snippets: Optional[List[str]],
322
327
  file_paths: Optional[List[str]],
323
- context: Optional[str]
328
+ context: Optional[str],
324
329
  ) -> str:
325
330
  """Review documentation aspects."""
326
331
  response = "📋 DOCUMENTATION REVIEW:\n\n"
327
-
332
+
328
333
  # Check for documentation in code
329
334
  has_comments = False
330
335
  if code_snippets:
331
336
  has_comments = any(
332
- '//' in snippet or '/*' in snippet or '#' in snippet or '"""' in snippet
337
+ "//" in snippet or "/*" in snippet or "#" in snippet or '"""' in snippet
333
338
  for snippet in code_snippets
334
339
  )
335
-
340
+
336
341
  if has_comments:
337
342
  response += "✓ Code includes some documentation\n"
338
343
  else:
339
344
  response += "• Consider adding documentation comments\n"
340
-
345
+
341
346
  response += "\n**Documentation Guidelines:**\n"
342
347
  response += "• Document the 'why' not just the 'what'\n"
343
348
  response += "• Include examples for complex functions\n"
344
349
  response += "• Document any assumptions or limitations\n"
345
350
  response += "• Keep documentation up-to-date with code changes\n"
346
-
351
+
347
352
  response += "\n**Recommended Documentation:**\n"
348
353
  response += "• Function/method purpose and parameters\n"
349
354
  response += "• Complex algorithm explanations\n"
350
355
  response += "• API usage examples\n"
351
356
  response += "• Configuration requirements\n"
352
-
357
+
353
358
  return response
354
-
359
+
355
360
  def _review_architecture(
356
361
  self,
357
362
  work_description: str,
358
363
  code_snippets: Optional[List[str]],
359
364
  file_paths: Optional[List[str]],
360
- context: Optional[str]
365
+ context: Optional[str],
361
366
  ) -> str:
362
367
  """Review architectural aspects."""
363
368
  response = "📋 ARCHITECTURE REVIEW:\n\n"
364
-
369
+
365
370
  response += "**Architectural Considerations:**\n"
366
-
371
+
367
372
  # Analyze file structure
368
373
  if file_paths:
369
374
  # Check for separation of concerns
370
- has_separation = len(set(str(p).split('/')[-2] for p in file_paths if '/' in str(p))) > 1
375
+ has_separation = (
376
+ len(set(str(p).split("/")[-2] for p in file_paths if "/" in str(p))) > 1
377
+ )
371
378
  if has_separation:
372
379
  response += "✓ Changes span multiple modules (good separation)\n"
373
380
  else:
374
381
  response += "✓ Changes are cohesive within a module\n"
375
-
382
+
376
383
  response += "\n**Architectural Principles:**\n"
377
384
  response += "• Single Responsibility - Each component has one clear purpose\n"
378
385
  response += "• Open/Closed - Open for extension, closed for modification\n"
379
386
  response += "• Dependency Inversion - Depend on abstractions, not concretions\n"
380
387
  response += "• Interface Segregation - Keep interfaces focused and minimal\n"
381
-
388
+
382
389
  response += "\n**Questions to Consider:**\n"
383
390
  response += "• Does this fit well with the existing architecture?\n"
384
391
  response += "• Are the right abstractions in place?\n"
385
392
  response += "• Is the coupling between components appropriate?\n"
386
393
  response += "• Will this scale as requirements grow?\n"
387
-
394
+
388
395
  if context:
389
396
  response += f"\n**Context Impact:**\n{context}\n"
390
397
  response += "→ Ensure the architectural choices align with this context.\n"
391
-
398
+
392
399
  return response
393
400
 
394
401
 
395
402
  class ReviewProtocol:
396
403
  """Protocol for review interactions."""
397
-
404
+
398
405
  def __init__(self):
399
406
  self.reviewer = BalancedReviewer()
400
407
  self.review_count = 0
401
408
  self.max_reviews = 3 # Allow up to 3 reviews per task
402
-
409
+
403
410
  def request_review(
404
411
  self,
405
412
  focus: str,
406
413
  work_description: str,
407
414
  code_snippets: Optional[List[str]] = None,
408
415
  file_paths: Optional[List[str]] = None,
409
- context: Optional[str] = None
416
+ context: Optional[str] = None,
410
417
  ) -> str:
411
418
  """Request a balanced review."""
412
419
  if self.review_count >= self.max_reviews:
413
420
  return "📋 Review limit reached. You've received comprehensive feedback - time to finalize your implementation."
414
-
421
+
415
422
  self.review_count += 1
416
-
423
+
417
424
  try:
418
425
  focus_enum = ReviewFocus[focus.upper()]
419
426
  except KeyError:
420
427
  focus_enum = ReviewFocus.GENERAL
421
-
428
+
422
429
  review = self.reviewer.review(
423
- focus_enum,
424
- work_description,
425
- code_snippets,
426
- file_paths,
427
- context
430
+ focus_enum, work_description, code_snippets, file_paths, context
428
431
  )
429
-
432
+
430
433
  header = f"Review {self.review_count}/{self.max_reviews} (Focus: {focus_enum.value}):\n\n"
431
434
  footer = "\n\n💡 This is a balanced review - consider both strengths and suggestions."
432
-
433
- return header + review + footer
435
+
436
+ return header + review + footer
@@ -0,0 +1,87 @@
1
+ """Swarm tool as an alias to Network tool for backward compatibility.
2
+
3
+ This module makes swarm an alias to the network tool, as network is the
4
+ evolution of swarm with better distributed execution capabilities.
5
+ """
6
+
7
+ from hanzo_mcp.tools.agent.network_tool import NetworkTool
8
+ from hanzo_mcp.tools.common.permissions import PermissionManager
9
+
10
+
11
+ class SwarmTool(NetworkTool):
12
+ """Swarm tool - alias to Network tool for backward compatibility.
13
+
14
+ The swarm tool is now an alias to the network tool, which provides
15
+ all the same functionality plus additional distributed execution modes.
16
+ Use 'network' for new code, 'swarm' is maintained for compatibility.
17
+ """
18
+
19
+ @property
20
+ def name(self) -> str:
21
+ """Get the tool name."""
22
+ return "swarm"
23
+
24
+ @property
25
+ def description(self) -> str:
26
+ """Get the tool description."""
27
+ return """Execute a network of AI agents (alias to 'network' tool).
28
+
29
+ The 'swarm' tool is now an alias to the 'network' tool for backward compatibility.
30
+ All swarm functionality is available through network, which additionally provides:
31
+
32
+ - Local-first execution with privacy preservation
33
+ - Distributed compute across devices
34
+ - Hybrid mode with cloud fallback
35
+ - Integration with hanzo-network for MCP-connected agents
36
+
37
+ Examples:
38
+ ```python
39
+ # These are equivalent:
40
+ swarm(task="Analyze code", agents=["analyzer", "reviewer"])
41
+ network(task="Analyze code", agents=["analyzer", "reviewer"])
42
+
43
+ # Network adds new modes:
44
+ network(task="Process data", mode="local") # Privacy-first
45
+ network(task="Large analysis", mode="distributed") # Scale out
46
+ ```
47
+
48
+ For new code, prefer using 'network' directly."""
49
+
50
+ def __init__(
51
+ self,
52
+ permission_manager: PermissionManager,
53
+ default_mode: str = "hybrid",
54
+ **kwargs,
55
+ ):
56
+ """Initialize swarm as an alias to network.
57
+
58
+ Args:
59
+ permission_manager: Permission manager
60
+ default_mode: Default execution mode (hybrid/local/distributed)
61
+ **kwargs: Additional arguments passed to NetworkTool
62
+ """
63
+ # Just pass through to NetworkTool
64
+ super().__init__(
65
+ permission_manager=permission_manager, default_mode=default_mode, **kwargs
66
+ )
67
+
68
+ async def call(self, **kwargs) -> str:
69
+ """Execute swarm via network tool.
70
+
71
+ All parameters are passed through to the network tool.
72
+ """
73
+ # For backward compatibility, rename some parameters if needed
74
+ if "config" in kwargs and "agents" not in kwargs:
75
+ # Old swarm used 'config' for agent definitions
76
+ config = kwargs.pop("config")
77
+ if isinstance(config, dict) and "agents" in config:
78
+ kwargs["agents"] = config["agents"]
79
+ if "topology" in config:
80
+ kwargs["routing"] = config["topology"]
81
+
82
+ # Pass through to network tool
83
+ return await super().call(**kwargs)
84
+
85
+
86
+ # For backward compatibility exports
87
+ __all__ = ["SwarmTool"]