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.
- hanzo_mcp/__init__.py +6 -0
- hanzo_mcp/__main__.py +1 -1
- hanzo_mcp/analytics/__init__.py +2 -2
- hanzo_mcp/analytics/posthog_analytics.py +76 -82
- hanzo_mcp/cli.py +31 -36
- hanzo_mcp/cli_enhanced.py +94 -72
- hanzo_mcp/cli_plugin.py +27 -17
- hanzo_mcp/config/__init__.py +2 -2
- hanzo_mcp/config/settings.py +112 -88
- hanzo_mcp/config/tool_config.py +32 -34
- hanzo_mcp/dev_server.py +66 -67
- hanzo_mcp/prompts/__init__.py +94 -12
- hanzo_mcp/prompts/enhanced_prompts.py +809 -0
- hanzo_mcp/prompts/example_custom_prompt.py +6 -5
- hanzo_mcp/prompts/project_todo_reminder.py +0 -1
- hanzo_mcp/prompts/tool_explorer.py +10 -7
- hanzo_mcp/server.py +17 -21
- hanzo_mcp/server_enhanced.py +15 -22
- hanzo_mcp/tools/__init__.py +56 -28
- hanzo_mcp/tools/agent/__init__.py +16 -19
- hanzo_mcp/tools/agent/agent.py +82 -65
- hanzo_mcp/tools/agent/agent_tool.py +152 -122
- hanzo_mcp/tools/agent/agent_tool_v1_deprecated.py +66 -62
- hanzo_mcp/tools/agent/clarification_protocol.py +55 -50
- hanzo_mcp/tools/agent/clarification_tool.py +11 -10
- hanzo_mcp/tools/agent/claude_cli_tool.py +21 -20
- hanzo_mcp/tools/agent/claude_desktop_auth.py +130 -144
- hanzo_mcp/tools/agent/cli_agent_base.py +59 -53
- hanzo_mcp/tools/agent/code_auth.py +102 -107
- hanzo_mcp/tools/agent/code_auth_tool.py +28 -27
- hanzo_mcp/tools/agent/codex_cli_tool.py +20 -19
- hanzo_mcp/tools/agent/critic_tool.py +86 -73
- hanzo_mcp/tools/agent/gemini_cli_tool.py +21 -20
- hanzo_mcp/tools/agent/grok_cli_tool.py +21 -20
- hanzo_mcp/tools/agent/iching_tool.py +404 -139
- hanzo_mcp/tools/agent/network_tool.py +89 -73
- hanzo_mcp/tools/agent/prompt.py +2 -1
- hanzo_mcp/tools/agent/review_tool.py +101 -98
- hanzo_mcp/tools/agent/swarm_alias.py +87 -0
- hanzo_mcp/tools/agent/swarm_tool.py +246 -161
- hanzo_mcp/tools/agent/swarm_tool_v1_deprecated.py +134 -92
- hanzo_mcp/tools/agent/tool_adapter.py +21 -11
- hanzo_mcp/tools/common/__init__.py +1 -1
- hanzo_mcp/tools/common/base.py +3 -5
- hanzo_mcp/tools/common/batch_tool.py +46 -39
- hanzo_mcp/tools/common/config_tool.py +120 -84
- hanzo_mcp/tools/common/context.py +1 -5
- hanzo_mcp/tools/common/context_fix.py +5 -3
- hanzo_mcp/tools/common/critic_tool.py +4 -8
- hanzo_mcp/tools/common/decorators.py +58 -56
- hanzo_mcp/tools/common/enhanced_base.py +29 -32
- hanzo_mcp/tools/common/fastmcp_pagination.py +91 -94
- hanzo_mcp/tools/common/forgiving_edit.py +91 -87
- hanzo_mcp/tools/common/mode.py +15 -17
- hanzo_mcp/tools/common/mode_loader.py +27 -24
- hanzo_mcp/tools/common/paginated_base.py +61 -53
- hanzo_mcp/tools/common/paginated_response.py +72 -79
- hanzo_mcp/tools/common/pagination.py +50 -53
- hanzo_mcp/tools/common/permissions.py +4 -4
- hanzo_mcp/tools/common/personality.py +186 -138
- hanzo_mcp/tools/common/plugin_loader.py +54 -54
- hanzo_mcp/tools/common/stats.py +65 -47
- hanzo_mcp/tools/common/test_helpers.py +31 -0
- hanzo_mcp/tools/common/thinking_tool.py +4 -8
- hanzo_mcp/tools/common/tool_disable.py +17 -12
- hanzo_mcp/tools/common/tool_enable.py +13 -14
- hanzo_mcp/tools/common/tool_list.py +36 -28
- hanzo_mcp/tools/common/truncate.py +23 -23
- hanzo_mcp/tools/config/__init__.py +4 -4
- hanzo_mcp/tools/config/config_tool.py +42 -29
- hanzo_mcp/tools/config/index_config.py +37 -34
- hanzo_mcp/tools/config/mode_tool.py +175 -55
- hanzo_mcp/tools/database/__init__.py +15 -12
- hanzo_mcp/tools/database/database_manager.py +77 -75
- hanzo_mcp/tools/database/graph.py +137 -91
- hanzo_mcp/tools/database/graph_add.py +30 -18
- hanzo_mcp/tools/database/graph_query.py +178 -102
- hanzo_mcp/tools/database/graph_remove.py +33 -28
- hanzo_mcp/tools/database/graph_search.py +97 -75
- hanzo_mcp/tools/database/graph_stats.py +91 -59
- hanzo_mcp/tools/database/sql.py +107 -79
- hanzo_mcp/tools/database/sql_query.py +30 -24
- hanzo_mcp/tools/database/sql_search.py +29 -25
- hanzo_mcp/tools/database/sql_stats.py +47 -35
- hanzo_mcp/tools/editor/neovim_command.py +25 -28
- hanzo_mcp/tools/editor/neovim_edit.py +21 -23
- hanzo_mcp/tools/editor/neovim_session.py +60 -54
- hanzo_mcp/tools/filesystem/__init__.py +31 -30
- hanzo_mcp/tools/filesystem/ast_multi_edit.py +329 -249
- hanzo_mcp/tools/filesystem/ast_tool.py +4 -4
- hanzo_mcp/tools/filesystem/base.py +1 -1
- hanzo_mcp/tools/filesystem/batch_search.py +316 -224
- hanzo_mcp/tools/filesystem/content_replace.py +4 -4
- hanzo_mcp/tools/filesystem/diff.py +71 -59
- hanzo_mcp/tools/filesystem/directory_tree.py +7 -7
- hanzo_mcp/tools/filesystem/directory_tree_paginated.py +49 -37
- hanzo_mcp/tools/filesystem/edit.py +4 -4
- hanzo_mcp/tools/filesystem/find.py +173 -80
- hanzo_mcp/tools/filesystem/find_files.py +73 -52
- hanzo_mcp/tools/filesystem/git_search.py +157 -104
- hanzo_mcp/tools/filesystem/grep.py +8 -8
- hanzo_mcp/tools/filesystem/multi_edit.py +4 -8
- hanzo_mcp/tools/filesystem/read.py +12 -10
- hanzo_mcp/tools/filesystem/rules_tool.py +59 -43
- hanzo_mcp/tools/filesystem/search_tool.py +263 -207
- hanzo_mcp/tools/filesystem/symbols_tool.py +94 -54
- hanzo_mcp/tools/filesystem/tree.py +35 -33
- hanzo_mcp/tools/filesystem/unix_aliases.py +13 -18
- hanzo_mcp/tools/filesystem/watch.py +37 -36
- hanzo_mcp/tools/filesystem/write.py +4 -8
- hanzo_mcp/tools/jupyter/__init__.py +4 -4
- hanzo_mcp/tools/jupyter/base.py +4 -5
- hanzo_mcp/tools/jupyter/jupyter.py +67 -47
- hanzo_mcp/tools/jupyter/notebook_edit.py +4 -4
- hanzo_mcp/tools/jupyter/notebook_read.py +4 -7
- hanzo_mcp/tools/llm/__init__.py +5 -7
- hanzo_mcp/tools/llm/consensus_tool.py +72 -52
- hanzo_mcp/tools/llm/llm_manage.py +101 -60
- hanzo_mcp/tools/llm/llm_tool.py +226 -166
- hanzo_mcp/tools/llm/provider_tools.py +25 -26
- hanzo_mcp/tools/lsp/__init__.py +1 -1
- hanzo_mcp/tools/lsp/lsp_tool.py +228 -143
- hanzo_mcp/tools/mcp/__init__.py +2 -3
- hanzo_mcp/tools/mcp/mcp_add.py +27 -25
- hanzo_mcp/tools/mcp/mcp_remove.py +7 -8
- hanzo_mcp/tools/mcp/mcp_stats.py +23 -22
- hanzo_mcp/tools/mcp/mcp_tool.py +129 -98
- hanzo_mcp/tools/memory/__init__.py +39 -21
- hanzo_mcp/tools/memory/knowledge_tools.py +124 -99
- hanzo_mcp/tools/memory/memory_tools.py +90 -108
- hanzo_mcp/tools/search/__init__.py +7 -2
- hanzo_mcp/tools/search/find_tool.py +297 -212
- hanzo_mcp/tools/search/unified_search.py +366 -314
- hanzo_mcp/tools/shell/__init__.py +8 -7
- hanzo_mcp/tools/shell/auto_background.py +56 -49
- hanzo_mcp/tools/shell/base.py +1 -1
- hanzo_mcp/tools/shell/base_process.py +75 -75
- hanzo_mcp/tools/shell/bash_session.py +2 -2
- hanzo_mcp/tools/shell/bash_session_executor.py +4 -4
- hanzo_mcp/tools/shell/bash_tool.py +24 -31
- hanzo_mcp/tools/shell/command_executor.py +12 -12
- hanzo_mcp/tools/shell/logs.py +43 -33
- hanzo_mcp/tools/shell/npx.py +13 -13
- hanzo_mcp/tools/shell/npx_background.py +24 -21
- hanzo_mcp/tools/shell/npx_tool.py +18 -22
- hanzo_mcp/tools/shell/open.py +19 -21
- hanzo_mcp/tools/shell/pkill.py +31 -26
- hanzo_mcp/tools/shell/process_tool.py +32 -32
- hanzo_mcp/tools/shell/processes.py +57 -58
- hanzo_mcp/tools/shell/run_background.py +24 -25
- hanzo_mcp/tools/shell/run_command.py +5 -5
- hanzo_mcp/tools/shell/run_command_windows.py +5 -5
- hanzo_mcp/tools/shell/session_storage.py +3 -3
- hanzo_mcp/tools/shell/streaming_command.py +141 -126
- hanzo_mcp/tools/shell/uvx.py +24 -25
- hanzo_mcp/tools/shell/uvx_background.py +35 -33
- hanzo_mcp/tools/shell/uvx_tool.py +18 -22
- hanzo_mcp/tools/todo/__init__.py +6 -2
- hanzo_mcp/tools/todo/todo.py +50 -37
- hanzo_mcp/tools/todo/todo_read.py +5 -8
- hanzo_mcp/tools/todo/todo_write.py +5 -7
- hanzo_mcp/tools/vector/__init__.py +40 -28
- hanzo_mcp/tools/vector/ast_analyzer.py +176 -143
- hanzo_mcp/tools/vector/git_ingester.py +170 -179
- hanzo_mcp/tools/vector/index_tool.py +96 -44
- hanzo_mcp/tools/vector/infinity_store.py +283 -228
- hanzo_mcp/tools/vector/mock_infinity.py +39 -40
- hanzo_mcp/tools/vector/project_manager.py +88 -78
- hanzo_mcp/tools/vector/vector.py +59 -42
- hanzo_mcp/tools/vector/vector_index.py +30 -27
- hanzo_mcp/tools/vector/vector_search.py +64 -45
- hanzo_mcp/types.py +6 -4
- {hanzo_mcp-0.7.7.dist-info → hanzo_mcp-0.8.0.dist-info}/METADATA +1 -1
- hanzo_mcp-0.8.0.dist-info/RECORD +185 -0
- hanzo_mcp-0.7.7.dist-info/RECORD +0 -182
- {hanzo_mcp-0.7.7.dist-info → hanzo_mcp-0.8.0.dist-info}/WHEEL +0 -0
- {hanzo_mcp-0.7.7.dist-info → hanzo_mcp-0.8.0.dist-info}/entry_points.txt +0 -0
- {hanzo_mcp-0.7.7.dist-info → hanzo_mcp-0.8.0.dist-info}/top_level.txt +0 -0
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
"""Find files using ffind library."""
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
|
-
from typing import
|
|
5
|
-
from pathlib import Path
|
|
4
|
+
from typing import Unpack, Optional, Annotated, TypedDict, final, override
|
|
6
5
|
|
|
7
|
-
from mcp.server.fastmcp import Context as MCPContext
|
|
8
6
|
from pydantic import Field
|
|
7
|
+
from mcp.server.fastmcp import Context as MCPContext
|
|
9
8
|
|
|
10
9
|
from hanzo_mcp.tools.common.base import BaseTool
|
|
11
10
|
from hanzo_mcp.tools.common.context import create_tool_context
|
|
@@ -13,6 +12,7 @@ from hanzo_mcp.tools.common.permissions import PermissionManager
|
|
|
13
12
|
|
|
14
13
|
try:
|
|
15
14
|
import ffind
|
|
15
|
+
|
|
16
16
|
FFIND_AVAILABLE = True
|
|
17
17
|
except ImportError:
|
|
18
18
|
FFIND_AVAILABLE = False
|
|
@@ -181,109 +181,126 @@ For database search, use 'sql_search' or 'vector_search'.
|
|
|
181
181
|
# If ffind is not available, fall back to basic implementation
|
|
182
182
|
if not FFIND_AVAILABLE:
|
|
183
183
|
return await self._find_files_fallback(
|
|
184
|
-
pattern,
|
|
185
|
-
|
|
184
|
+
pattern,
|
|
185
|
+
search_path,
|
|
186
|
+
recursive,
|
|
187
|
+
ignore_case,
|
|
188
|
+
hidden,
|
|
189
|
+
dirs_only,
|
|
190
|
+
files_only,
|
|
191
|
+
max_results,
|
|
186
192
|
)
|
|
187
193
|
|
|
188
194
|
try:
|
|
189
195
|
# Use ffind for efficient searching
|
|
190
196
|
results = []
|
|
191
197
|
count = 0
|
|
192
|
-
|
|
198
|
+
|
|
193
199
|
# Configure ffind options
|
|
194
200
|
options = {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
201
|
+
"pattern": pattern,
|
|
202
|
+
"path": search_path,
|
|
203
|
+
"recursive": recursive,
|
|
204
|
+
"ignore_case": ignore_case,
|
|
205
|
+
"hidden": hidden,
|
|
200
206
|
}
|
|
201
|
-
|
|
207
|
+
|
|
202
208
|
# Search with ffind
|
|
203
209
|
for filepath in ffind.find(**options):
|
|
204
210
|
# Check if it matches our criteria
|
|
205
211
|
is_dir = os.path.isdir(filepath)
|
|
206
|
-
|
|
212
|
+
|
|
207
213
|
if dirs_only and not is_dir:
|
|
208
214
|
continue
|
|
209
215
|
if files_only and is_dir:
|
|
210
216
|
continue
|
|
211
|
-
|
|
217
|
+
|
|
212
218
|
# Make path relative for cleaner output
|
|
213
219
|
try:
|
|
214
220
|
rel_path = os.path.relpath(filepath, search_path)
|
|
215
221
|
except ValueError:
|
|
216
222
|
rel_path = filepath
|
|
217
|
-
|
|
223
|
+
|
|
218
224
|
results.append(rel_path)
|
|
219
225
|
count += 1
|
|
220
|
-
|
|
226
|
+
|
|
221
227
|
if count >= max_results:
|
|
222
228
|
break
|
|
223
|
-
|
|
229
|
+
|
|
224
230
|
if not results:
|
|
225
231
|
return f"No files found matching '{pattern}'"
|
|
226
|
-
|
|
232
|
+
|
|
227
233
|
# Format output
|
|
228
234
|
output = [f"Found {len(results)} file(s) matching '{pattern}':"]
|
|
229
235
|
output.append("")
|
|
230
|
-
|
|
236
|
+
|
|
231
237
|
for filepath in sorted(results):
|
|
232
238
|
output.append(filepath)
|
|
233
|
-
|
|
239
|
+
|
|
234
240
|
if count >= max_results:
|
|
235
241
|
output.append(f"\n... (showing first {max_results} results)")
|
|
236
|
-
|
|
242
|
+
|
|
237
243
|
return "\n".join(output)
|
|
238
244
|
|
|
239
245
|
except Exception as e:
|
|
240
246
|
await tool_ctx.error(f"Error during search: {str(e)}")
|
|
241
247
|
# Fall back to basic implementation
|
|
242
248
|
return await self._find_files_fallback(
|
|
243
|
-
pattern,
|
|
244
|
-
|
|
249
|
+
pattern,
|
|
250
|
+
search_path,
|
|
251
|
+
recursive,
|
|
252
|
+
ignore_case,
|
|
253
|
+
hidden,
|
|
254
|
+
dirs_only,
|
|
255
|
+
files_only,
|
|
256
|
+
max_results,
|
|
245
257
|
)
|
|
246
258
|
|
|
247
259
|
async def _find_files_fallback(
|
|
248
|
-
self,
|
|
249
|
-
|
|
250
|
-
|
|
260
|
+
self,
|
|
261
|
+
pattern: str,
|
|
262
|
+
search_path: str,
|
|
263
|
+
recursive: bool,
|
|
264
|
+
ignore_case: bool,
|
|
265
|
+
hidden: bool,
|
|
266
|
+
dirs_only: bool,
|
|
267
|
+
files_only: bool,
|
|
268
|
+
max_results: int,
|
|
251
269
|
) -> str:
|
|
252
270
|
"""Fallback implementation when ffind is not available."""
|
|
253
|
-
|
|
254
|
-
|
|
271
|
+
|
|
255
272
|
results = []
|
|
256
273
|
count = 0
|
|
257
|
-
|
|
274
|
+
|
|
258
275
|
# Convert pattern for case-insensitive matching
|
|
259
276
|
if ignore_case:
|
|
260
277
|
pattern = pattern.lower()
|
|
261
|
-
|
|
278
|
+
|
|
262
279
|
try:
|
|
263
280
|
if recursive:
|
|
264
281
|
# Walk directory tree
|
|
265
282
|
for root, dirs, files in os.walk(search_path):
|
|
266
283
|
# Skip hidden directories if not requested
|
|
267
284
|
if not hidden:
|
|
268
|
-
dirs[:] = [d for d in dirs if not d.startswith(
|
|
269
|
-
|
|
285
|
+
dirs[:] = [d for d in dirs if not d.startswith(".")]
|
|
286
|
+
|
|
270
287
|
# Check directories
|
|
271
288
|
if not files_only:
|
|
272
289
|
for dirname in dirs:
|
|
273
290
|
if self._match_pattern(dirname, pattern, ignore_case):
|
|
274
291
|
filepath = os.path.join(root, dirname)
|
|
275
292
|
rel_path = os.path.relpath(filepath, search_path)
|
|
276
|
-
results.append(rel_path +
|
|
293
|
+
results.append(rel_path + "/")
|
|
277
294
|
count += 1
|
|
278
295
|
if count >= max_results:
|
|
279
296
|
break
|
|
280
|
-
|
|
297
|
+
|
|
281
298
|
# Check files
|
|
282
299
|
if not dirs_only:
|
|
283
300
|
for filename in files:
|
|
284
|
-
if not hidden and filename.startswith(
|
|
301
|
+
if not hidden and filename.startswith("."):
|
|
285
302
|
continue
|
|
286
|
-
|
|
303
|
+
|
|
287
304
|
if self._match_pattern(filename, pattern, ignore_case):
|
|
288
305
|
filepath = os.path.join(root, filename)
|
|
289
306
|
rel_path = os.path.relpath(filepath, search_path)
|
|
@@ -291,53 +308,57 @@ For database search, use 'sql_search' or 'vector_search'.
|
|
|
291
308
|
count += 1
|
|
292
309
|
if count >= max_results:
|
|
293
310
|
break
|
|
294
|
-
|
|
311
|
+
|
|
295
312
|
if count >= max_results:
|
|
296
313
|
break
|
|
297
314
|
else:
|
|
298
315
|
# Only search in the specified directory
|
|
299
316
|
for entry in os.listdir(search_path):
|
|
300
|
-
if not hidden and entry.startswith(
|
|
317
|
+
if not hidden and entry.startswith("."):
|
|
301
318
|
continue
|
|
302
|
-
|
|
319
|
+
|
|
303
320
|
filepath = os.path.join(search_path, entry)
|
|
304
321
|
is_dir = os.path.isdir(filepath)
|
|
305
|
-
|
|
322
|
+
|
|
306
323
|
if dirs_only and not is_dir:
|
|
307
324
|
continue
|
|
308
325
|
if files_only and is_dir:
|
|
309
326
|
continue
|
|
310
|
-
|
|
327
|
+
|
|
311
328
|
if self._match_pattern(entry, pattern, ignore_case):
|
|
312
|
-
results.append(entry +
|
|
329
|
+
results.append(entry + "/" if is_dir else entry)
|
|
313
330
|
count += 1
|
|
314
331
|
if count >= max_results:
|
|
315
332
|
break
|
|
316
|
-
|
|
333
|
+
|
|
317
334
|
if not results:
|
|
318
335
|
return f"No files found matching '{pattern}' (using fallback search)"
|
|
319
|
-
|
|
336
|
+
|
|
320
337
|
# Format output
|
|
321
|
-
output = [
|
|
338
|
+
output = [
|
|
339
|
+
f"Found {len(results)} file(s) matching '{pattern}' (using fallback search):"
|
|
340
|
+
]
|
|
322
341
|
output.append("")
|
|
323
|
-
|
|
342
|
+
|
|
324
343
|
for filepath in sorted(results):
|
|
325
344
|
output.append(filepath)
|
|
326
|
-
|
|
345
|
+
|
|
327
346
|
if count >= max_results:
|
|
328
347
|
output.append(f"\n... (showing first {max_results} results)")
|
|
329
|
-
|
|
330
|
-
output.append(
|
|
331
|
-
|
|
348
|
+
|
|
349
|
+
output.append(
|
|
350
|
+
"\nNote: Install 'ffind' for faster searching: pip install ffind"
|
|
351
|
+
)
|
|
352
|
+
|
|
332
353
|
return "\n".join(output)
|
|
333
|
-
|
|
354
|
+
|
|
334
355
|
except Exception as e:
|
|
335
356
|
return f"Error searching for files: {str(e)}"
|
|
336
357
|
|
|
337
358
|
def _match_pattern(self, filename: str, pattern: str, ignore_case: bool) -> bool:
|
|
338
359
|
"""Check if filename matches pattern."""
|
|
339
360
|
import fnmatch
|
|
340
|
-
|
|
361
|
+
|
|
341
362
|
if ignore_case:
|
|
342
363
|
return fnmatch.fnmatch(filename.lower(), pattern)
|
|
343
364
|
else:
|