hanzo-mcp 0.8.11__py3-none-any.whl → 0.9.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 +1 -3
- hanzo_mcp/analytics/posthog_analytics.py +3 -9
- hanzo_mcp/bridge.py +9 -25
- hanzo_mcp/cli.py +6 -15
- hanzo_mcp/cli_enhanced.py +5 -14
- hanzo_mcp/cli_plugin.py +3 -9
- hanzo_mcp/config/settings.py +6 -20
- hanzo_mcp/config/tool_config.py +1 -3
- hanzo_mcp/core/base_agent.py +88 -88
- hanzo_mcp/core/model_registry.py +238 -210
- hanzo_mcp/dev_server.py +5 -15
- hanzo_mcp/prompts/__init__.py +2 -6
- hanzo_mcp/prompts/project_todo_reminder.py +3 -9
- hanzo_mcp/prompts/tool_explorer.py +1 -3
- hanzo_mcp/prompts/utils.py +7 -21
- hanzo_mcp/server.py +2 -6
- hanzo_mcp/tools/__init__.py +26 -27
- hanzo_mcp/tools/agent/__init__.py +2 -1
- hanzo_mcp/tools/agent/agent.py +10 -30
- hanzo_mcp/tools/agent/agent_tool.py +22 -15
- hanzo_mcp/tools/agent/claude_desktop_auth.py +3 -9
- hanzo_mcp/tools/agent/cli_agent_base.py +7 -24
- hanzo_mcp/tools/agent/cli_tools.py +75 -74
- hanzo_mcp/tools/agent/code_auth.py +1 -3
- hanzo_mcp/tools/agent/code_auth_tool.py +2 -6
- hanzo_mcp/tools/agent/critic_tool.py +8 -24
- hanzo_mcp/tools/agent/iching_tool.py +12 -36
- hanzo_mcp/tools/agent/network_tool.py +7 -18
- hanzo_mcp/tools/agent/prompt.py +1 -5
- hanzo_mcp/tools/agent/review_tool.py +10 -25
- hanzo_mcp/tools/agent/swarm_alias.py +1 -3
- hanzo_mcp/tools/agent/unified_cli_tools.py +38 -38
- hanzo_mcp/tools/common/batch_tool.py +15 -45
- hanzo_mcp/tools/common/config_tool.py +9 -28
- hanzo_mcp/tools/common/context.py +1 -3
- hanzo_mcp/tools/common/critic_tool.py +1 -3
- hanzo_mcp/tools/common/decorators.py +2 -6
- hanzo_mcp/tools/common/enhanced_base.py +2 -6
- hanzo_mcp/tools/common/fastmcp_pagination.py +4 -12
- hanzo_mcp/tools/common/forgiving_edit.py +9 -28
- hanzo_mcp/tools/common/mode.py +1 -5
- hanzo_mcp/tools/common/paginated_base.py +3 -11
- hanzo_mcp/tools/common/paginated_response.py +10 -30
- hanzo_mcp/tools/common/pagination.py +3 -9
- hanzo_mcp/tools/common/path_utils.py +34 -0
- hanzo_mcp/tools/common/permissions.py +14 -13
- hanzo_mcp/tools/common/personality.py +983 -701
- hanzo_mcp/tools/common/plugin_loader.py +3 -15
- hanzo_mcp/tools/common/stats.py +6 -18
- hanzo_mcp/tools/common/thinking_tool.py +1 -3
- hanzo_mcp/tools/common/tool_disable.py +2 -6
- hanzo_mcp/tools/common/tool_list.py +2 -6
- hanzo_mcp/tools/common/validation.py +1 -3
- hanzo_mcp/tools/compiler/__init__.py +8 -0
- hanzo_mcp/tools/compiler/sandboxed_compiler.py +681 -0
- hanzo_mcp/tools/config/config_tool.py +7 -13
- hanzo_mcp/tools/config/index_config.py +1 -3
- hanzo_mcp/tools/config/mode_tool.py +5 -15
- hanzo_mcp/tools/database/database_manager.py +3 -9
- hanzo_mcp/tools/database/graph.py +1 -3
- hanzo_mcp/tools/database/graph_add.py +3 -9
- hanzo_mcp/tools/database/graph_query.py +11 -34
- hanzo_mcp/tools/database/graph_remove.py +3 -9
- hanzo_mcp/tools/database/graph_search.py +6 -20
- hanzo_mcp/tools/database/graph_stats.py +11 -33
- hanzo_mcp/tools/database/sql.py +4 -12
- hanzo_mcp/tools/database/sql_query.py +6 -10
- hanzo_mcp/tools/database/sql_search.py +2 -6
- hanzo_mcp/tools/database/sql_stats.py +5 -15
- hanzo_mcp/tools/editor/neovim_command.py +1 -3
- hanzo_mcp/tools/editor/neovim_session.py +7 -13
- hanzo_mcp/tools/environment/__init__.py +8 -0
- hanzo_mcp/tools/environment/environment_detector.py +594 -0
- hanzo_mcp/tools/filesystem/__init__.py +28 -26
- hanzo_mcp/tools/filesystem/ast_multi_edit.py +14 -43
- hanzo_mcp/tools/filesystem/ast_tool.py +3 -0
- hanzo_mcp/tools/filesystem/base.py +20 -12
- hanzo_mcp/tools/filesystem/content_replace.py +7 -12
- hanzo_mcp/tools/filesystem/diff.py +2 -10
- hanzo_mcp/tools/filesystem/directory_tree.py +285 -51
- hanzo_mcp/tools/filesystem/edit.py +10 -18
- hanzo_mcp/tools/filesystem/find.py +312 -179
- hanzo_mcp/tools/filesystem/git_search.py +12 -24
- hanzo_mcp/tools/filesystem/multi_edit.py +10 -18
- hanzo_mcp/tools/filesystem/read.py +14 -30
- hanzo_mcp/tools/filesystem/rules_tool.py +9 -17
- hanzo_mcp/tools/filesystem/search.py +1160 -0
- hanzo_mcp/tools/filesystem/watch.py +2 -4
- hanzo_mcp/tools/filesystem/write.py +7 -10
- hanzo_mcp/tools/framework/__init__.py +8 -0
- hanzo_mcp/tools/framework/framework_modes.py +714 -0
- hanzo_mcp/tools/jupyter/base.py +6 -20
- hanzo_mcp/tools/jupyter/jupyter.py +4 -12
- hanzo_mcp/tools/llm/consensus_tool.py +8 -24
- hanzo_mcp/tools/llm/llm_manage.py +2 -6
- hanzo_mcp/tools/llm/llm_tool.py +17 -58
- hanzo_mcp/tools/llm/llm_unified.py +18 -59
- hanzo_mcp/tools/llm/provider_tools.py +1 -3
- hanzo_mcp/tools/lsp/lsp_tool.py +621 -481
- hanzo_mcp/tools/mcp/mcp_add.py +1 -3
- hanzo_mcp/tools/mcp/mcp_stats.py +1 -3
- hanzo_mcp/tools/mcp/mcp_tool.py +9 -23
- hanzo_mcp/tools/memory/__init__.py +10 -27
- hanzo_mcp/tools/memory/conversation_memory.py +636 -0
- hanzo_mcp/tools/memory/knowledge_tools.py +7 -25
- hanzo_mcp/tools/memory/memory_tools.py +6 -18
- hanzo_mcp/tools/search/find_tool.py +12 -34
- hanzo_mcp/tools/search/unified_search.py +24 -78
- hanzo_mcp/tools/shell/__init__.py +16 -4
- hanzo_mcp/tools/shell/auto_background.py +2 -6
- hanzo_mcp/tools/shell/base.py +1 -5
- hanzo_mcp/tools/shell/base_process.py +5 -7
- hanzo_mcp/tools/shell/bash_session.py +7 -24
- hanzo_mcp/tools/shell/bash_session_executor.py +5 -15
- hanzo_mcp/tools/shell/bash_tool.py +3 -7
- hanzo_mcp/tools/shell/command_executor.py +26 -79
- hanzo_mcp/tools/shell/logs.py +4 -16
- hanzo_mcp/tools/shell/npx.py +2 -8
- hanzo_mcp/tools/shell/npx_tool.py +1 -3
- hanzo_mcp/tools/shell/pkill.py +4 -12
- hanzo_mcp/tools/shell/process_tool.py +2 -8
- hanzo_mcp/tools/shell/processes.py +5 -17
- hanzo_mcp/tools/shell/run_background.py +1 -3
- hanzo_mcp/tools/shell/run_command.py +1 -3
- hanzo_mcp/tools/shell/run_command_windows.py +1 -3
- hanzo_mcp/tools/shell/run_tool.py +56 -0
- hanzo_mcp/tools/shell/session_manager.py +2 -6
- hanzo_mcp/tools/shell/session_storage.py +2 -6
- hanzo_mcp/tools/shell/streaming_command.py +7 -23
- hanzo_mcp/tools/shell/uvx.py +4 -14
- hanzo_mcp/tools/shell/uvx_background.py +2 -6
- hanzo_mcp/tools/shell/uvx_tool.py +1 -3
- hanzo_mcp/tools/shell/zsh_tool.py +12 -20
- hanzo_mcp/tools/todo/todo.py +1 -3
- hanzo_mcp/tools/vector/__init__.py +97 -50
- hanzo_mcp/tools/vector/ast_analyzer.py +6 -20
- hanzo_mcp/tools/vector/git_ingester.py +10 -30
- hanzo_mcp/tools/vector/index_tool.py +3 -9
- hanzo_mcp/tools/vector/infinity_store.py +7 -27
- hanzo_mcp/tools/vector/mock_infinity.py +1 -3
- hanzo_mcp/tools/vector/node_tool.py +538 -0
- hanzo_mcp/tools/vector/project_manager.py +4 -12
- hanzo_mcp/tools/vector/unified_vector.py +384 -0
- hanzo_mcp/tools/vector/vector.py +2 -6
- hanzo_mcp/tools/vector/vector_index.py +8 -8
- hanzo_mcp/tools/vector/vector_search.py +7 -21
- {hanzo_mcp-0.8.11.dist-info → hanzo_mcp-0.9.0.dist-info}/METADATA +2 -2
- hanzo_mcp-0.9.0.dist-info/RECORD +191 -0
- hanzo_mcp/tools/agent/agent_tool_v1_deprecated.py +0 -645
- hanzo_mcp/tools/agent/swarm_tool.py +0 -718
- hanzo_mcp/tools/agent/swarm_tool_v1_deprecated.py +0 -577
- hanzo_mcp/tools/filesystem/batch_search.py +0 -900
- hanzo_mcp/tools/filesystem/directory_tree_paginated.py +0 -350
- hanzo_mcp/tools/filesystem/find_files.py +0 -369
- hanzo_mcp/tools/filesystem/grep.py +0 -467
- hanzo_mcp/tools/filesystem/search_tool.py +0 -767
- hanzo_mcp/tools/filesystem/symbols_tool.py +0 -515
- hanzo_mcp/tools/filesystem/tree.py +0 -270
- hanzo_mcp/tools/jupyter/notebook_edit.py +0 -317
- hanzo_mcp/tools/jupyter/notebook_read.py +0 -147
- hanzo_mcp/tools/todo/todo_read.py +0 -143
- hanzo_mcp/tools/todo/todo_write.py +0 -374
- hanzo_mcp-0.8.11.dist-info/RECORD +0 -193
- {hanzo_mcp-0.8.11.dist-info → hanzo_mcp-0.9.0.dist-info}/WHEEL +0 -0
- {hanzo_mcp-0.8.11.dist-info → hanzo_mcp-0.9.0.dist-info}/entry_points.txt +0 -0
- {hanzo_mcp-0.8.11.dist-info → hanzo_mcp-0.9.0.dist-info}/top_level.txt +0 -0
|
@@ -1,369 +0,0 @@
|
|
|
1
|
-
"""Find files using ffind library."""
|
|
2
|
-
|
|
3
|
-
import os
|
|
4
|
-
from typing import Unpack, Optional, Annotated, TypedDict, final, override
|
|
5
|
-
|
|
6
|
-
from pydantic import Field
|
|
7
|
-
from mcp.server.fastmcp import Context as MCPContext
|
|
8
|
-
|
|
9
|
-
from hanzo_mcp.tools.common.base import BaseTool
|
|
10
|
-
from hanzo_mcp.tools.common.context import create_tool_context
|
|
11
|
-
from hanzo_mcp.tools.common.permissions import PermissionManager
|
|
12
|
-
|
|
13
|
-
try:
|
|
14
|
-
import ffind
|
|
15
|
-
|
|
16
|
-
FFIND_AVAILABLE = True
|
|
17
|
-
except ImportError:
|
|
18
|
-
FFIND_AVAILABLE = False
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
Pattern = Annotated[
|
|
22
|
-
str,
|
|
23
|
-
Field(
|
|
24
|
-
description="File name pattern to search for (supports wildcards)",
|
|
25
|
-
min_length=1,
|
|
26
|
-
),
|
|
27
|
-
]
|
|
28
|
-
|
|
29
|
-
Path_ = Annotated[
|
|
30
|
-
Optional[str],
|
|
31
|
-
Field(
|
|
32
|
-
description="Directory to search in (defaults to current directory)",
|
|
33
|
-
default=None,
|
|
34
|
-
),
|
|
35
|
-
]
|
|
36
|
-
|
|
37
|
-
Recursive = Annotated[
|
|
38
|
-
bool,
|
|
39
|
-
Field(
|
|
40
|
-
description="Search recursively in subdirectories",
|
|
41
|
-
default=True,
|
|
42
|
-
),
|
|
43
|
-
]
|
|
44
|
-
|
|
45
|
-
IgnoreCase = Annotated[
|
|
46
|
-
bool,
|
|
47
|
-
Field(
|
|
48
|
-
description="Case-insensitive search",
|
|
49
|
-
default=True,
|
|
50
|
-
),
|
|
51
|
-
]
|
|
52
|
-
|
|
53
|
-
Hidden = Annotated[
|
|
54
|
-
bool,
|
|
55
|
-
Field(
|
|
56
|
-
description="Include hidden files in search",
|
|
57
|
-
default=False,
|
|
58
|
-
),
|
|
59
|
-
]
|
|
60
|
-
|
|
61
|
-
DirsOnly = Annotated[
|
|
62
|
-
bool,
|
|
63
|
-
Field(
|
|
64
|
-
description="Only find directories",
|
|
65
|
-
default=False,
|
|
66
|
-
),
|
|
67
|
-
]
|
|
68
|
-
|
|
69
|
-
FilesOnly = Annotated[
|
|
70
|
-
bool,
|
|
71
|
-
Field(
|
|
72
|
-
description="Only find files (not directories)",
|
|
73
|
-
default=True,
|
|
74
|
-
),
|
|
75
|
-
]
|
|
76
|
-
|
|
77
|
-
MaxResults = Annotated[
|
|
78
|
-
int,
|
|
79
|
-
Field(
|
|
80
|
-
description="Maximum number of results",
|
|
81
|
-
default=100,
|
|
82
|
-
),
|
|
83
|
-
]
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
class FindFilesParams(TypedDict, total=False):
|
|
87
|
-
"""Parameters for find files tool."""
|
|
88
|
-
|
|
89
|
-
pattern: str
|
|
90
|
-
path: Optional[str]
|
|
91
|
-
recursive: bool
|
|
92
|
-
ignore_case: bool
|
|
93
|
-
hidden: bool
|
|
94
|
-
dirs_only: bool
|
|
95
|
-
files_only: bool
|
|
96
|
-
max_results: int
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
@final
|
|
100
|
-
class FindFilesTool(BaseTool):
|
|
101
|
-
"""Tool for finding files using ffind."""
|
|
102
|
-
|
|
103
|
-
def __init__(self, permission_manager: PermissionManager):
|
|
104
|
-
"""Initialize the find files tool.
|
|
105
|
-
|
|
106
|
-
Args:
|
|
107
|
-
permission_manager: Permission manager for access control
|
|
108
|
-
"""
|
|
109
|
-
self.permission_manager = permission_manager
|
|
110
|
-
|
|
111
|
-
@property
|
|
112
|
-
@override
|
|
113
|
-
def name(self) -> str:
|
|
114
|
-
"""Get the tool name."""
|
|
115
|
-
return "find_files"
|
|
116
|
-
|
|
117
|
-
@property
|
|
118
|
-
@override
|
|
119
|
-
def description(self) -> str:
|
|
120
|
-
"""Get the tool description."""
|
|
121
|
-
return """Find files by name pattern using efficient search.
|
|
122
|
-
|
|
123
|
-
Uses the ffind library for fast file searching with support for:
|
|
124
|
-
- Wildcards (* and ?)
|
|
125
|
-
- Case-insensitive search
|
|
126
|
-
- Hidden files
|
|
127
|
-
- Directory vs file filtering
|
|
128
|
-
|
|
129
|
-
Examples:
|
|
130
|
-
- find_files --pattern "*.py" # Find all Python files
|
|
131
|
-
- find_files --pattern "test_*" # Find files starting with test_
|
|
132
|
-
- find_files --pattern "README.*" # Find README files
|
|
133
|
-
- find_files --pattern "*config*" --hidden # Include hidden config files
|
|
134
|
-
- find_files --pattern "src" --dirs-only # Find directories named src
|
|
135
|
-
|
|
136
|
-
For content search, use 'grep' instead.
|
|
137
|
-
For database search, use 'sql_search' or 'vector_search'.
|
|
138
|
-
"""
|
|
139
|
-
|
|
140
|
-
@override
|
|
141
|
-
async def call(
|
|
142
|
-
self,
|
|
143
|
-
ctx: MCPContext,
|
|
144
|
-
**params: Unpack[FindFilesParams],
|
|
145
|
-
) -> str:
|
|
146
|
-
"""Find files matching pattern.
|
|
147
|
-
|
|
148
|
-
Args:
|
|
149
|
-
ctx: MCP context
|
|
150
|
-
**params: Tool parameters
|
|
151
|
-
|
|
152
|
-
Returns:
|
|
153
|
-
List of matching files
|
|
154
|
-
"""
|
|
155
|
-
tool_ctx = create_tool_context(ctx)
|
|
156
|
-
await tool_ctx.set_tool_info(self.name)
|
|
157
|
-
|
|
158
|
-
# Extract parameters
|
|
159
|
-
pattern = params.get("pattern")
|
|
160
|
-
if not pattern:
|
|
161
|
-
return "Error: pattern is required"
|
|
162
|
-
|
|
163
|
-
search_path = params.get("path") or os.getcwd()
|
|
164
|
-
recursive = params.get("recursive", True)
|
|
165
|
-
ignore_case = params.get("ignore_case", True)
|
|
166
|
-
hidden = params.get("hidden", False)
|
|
167
|
-
dirs_only = params.get("dirs_only", False)
|
|
168
|
-
files_only = params.get("files_only", True)
|
|
169
|
-
max_results = params.get("max_results", 100)
|
|
170
|
-
|
|
171
|
-
# Validate path
|
|
172
|
-
search_path = os.path.abspath(search_path)
|
|
173
|
-
if not self.permission_manager.has_permission(search_path):
|
|
174
|
-
return f"Error: No permission to access {search_path}"
|
|
175
|
-
|
|
176
|
-
if not os.path.exists(search_path):
|
|
177
|
-
return f"Error: Path does not exist: {search_path}"
|
|
178
|
-
|
|
179
|
-
await tool_ctx.info(f"Searching for '{pattern}' in {search_path}")
|
|
180
|
-
|
|
181
|
-
# If ffind is not available, fall back to basic implementation
|
|
182
|
-
if not FFIND_AVAILABLE:
|
|
183
|
-
return await self._find_files_fallback(
|
|
184
|
-
pattern,
|
|
185
|
-
search_path,
|
|
186
|
-
recursive,
|
|
187
|
-
ignore_case,
|
|
188
|
-
hidden,
|
|
189
|
-
dirs_only,
|
|
190
|
-
files_only,
|
|
191
|
-
max_results,
|
|
192
|
-
)
|
|
193
|
-
|
|
194
|
-
try:
|
|
195
|
-
# Use ffind for efficient searching
|
|
196
|
-
results = []
|
|
197
|
-
count = 0
|
|
198
|
-
|
|
199
|
-
# Configure ffind options
|
|
200
|
-
options = {
|
|
201
|
-
"pattern": pattern,
|
|
202
|
-
"path": search_path,
|
|
203
|
-
"recursive": recursive,
|
|
204
|
-
"ignore_case": ignore_case,
|
|
205
|
-
"hidden": hidden,
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
# Search with ffind
|
|
209
|
-
for filepath in ffind.find(**options):
|
|
210
|
-
# Check if it matches our criteria
|
|
211
|
-
is_dir = os.path.isdir(filepath)
|
|
212
|
-
|
|
213
|
-
if dirs_only and not is_dir:
|
|
214
|
-
continue
|
|
215
|
-
if files_only and is_dir:
|
|
216
|
-
continue
|
|
217
|
-
|
|
218
|
-
# Make path relative for cleaner output
|
|
219
|
-
try:
|
|
220
|
-
rel_path = os.path.relpath(filepath, search_path)
|
|
221
|
-
except ValueError:
|
|
222
|
-
rel_path = filepath
|
|
223
|
-
|
|
224
|
-
results.append(rel_path)
|
|
225
|
-
count += 1
|
|
226
|
-
|
|
227
|
-
if count >= max_results:
|
|
228
|
-
break
|
|
229
|
-
|
|
230
|
-
if not results:
|
|
231
|
-
return f"No files found matching '{pattern}'"
|
|
232
|
-
|
|
233
|
-
# Format output
|
|
234
|
-
output = [f"Found {len(results)} file(s) matching '{pattern}':"]
|
|
235
|
-
output.append("")
|
|
236
|
-
|
|
237
|
-
for filepath in sorted(results):
|
|
238
|
-
output.append(filepath)
|
|
239
|
-
|
|
240
|
-
if count >= max_results:
|
|
241
|
-
output.append(f"\n... (showing first {max_results} results)")
|
|
242
|
-
|
|
243
|
-
return "\n".join(output)
|
|
244
|
-
|
|
245
|
-
except Exception as e:
|
|
246
|
-
await tool_ctx.error(f"Error during search: {str(e)}")
|
|
247
|
-
# Fall back to basic implementation
|
|
248
|
-
return await self._find_files_fallback(
|
|
249
|
-
pattern,
|
|
250
|
-
search_path,
|
|
251
|
-
recursive,
|
|
252
|
-
ignore_case,
|
|
253
|
-
hidden,
|
|
254
|
-
dirs_only,
|
|
255
|
-
files_only,
|
|
256
|
-
max_results,
|
|
257
|
-
)
|
|
258
|
-
|
|
259
|
-
async def _find_files_fallback(
|
|
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,
|
|
269
|
-
) -> str:
|
|
270
|
-
"""Fallback implementation when ffind is not available."""
|
|
271
|
-
|
|
272
|
-
results = []
|
|
273
|
-
count = 0
|
|
274
|
-
|
|
275
|
-
# Convert pattern for case-insensitive matching
|
|
276
|
-
if ignore_case:
|
|
277
|
-
pattern = pattern.lower()
|
|
278
|
-
|
|
279
|
-
try:
|
|
280
|
-
if recursive:
|
|
281
|
-
# Walk directory tree
|
|
282
|
-
for root, dirs, files in os.walk(search_path):
|
|
283
|
-
# Skip hidden directories if not requested
|
|
284
|
-
if not hidden:
|
|
285
|
-
dirs[:] = [d for d in dirs if not d.startswith(".")]
|
|
286
|
-
|
|
287
|
-
# Check directories
|
|
288
|
-
if not files_only:
|
|
289
|
-
for dirname in dirs:
|
|
290
|
-
if self._match_pattern(dirname, pattern, ignore_case):
|
|
291
|
-
filepath = os.path.join(root, dirname)
|
|
292
|
-
rel_path = os.path.relpath(filepath, search_path)
|
|
293
|
-
results.append(rel_path + "/")
|
|
294
|
-
count += 1
|
|
295
|
-
if count >= max_results:
|
|
296
|
-
break
|
|
297
|
-
|
|
298
|
-
# Check files
|
|
299
|
-
if not dirs_only:
|
|
300
|
-
for filename in files:
|
|
301
|
-
if not hidden and filename.startswith("."):
|
|
302
|
-
continue
|
|
303
|
-
|
|
304
|
-
if self._match_pattern(filename, pattern, ignore_case):
|
|
305
|
-
filepath = os.path.join(root, filename)
|
|
306
|
-
rel_path = os.path.relpath(filepath, search_path)
|
|
307
|
-
results.append(rel_path)
|
|
308
|
-
count += 1
|
|
309
|
-
if count >= max_results:
|
|
310
|
-
break
|
|
311
|
-
|
|
312
|
-
if count >= max_results:
|
|
313
|
-
break
|
|
314
|
-
else:
|
|
315
|
-
# Only search in the specified directory
|
|
316
|
-
for entry in os.listdir(search_path):
|
|
317
|
-
if not hidden and entry.startswith("."):
|
|
318
|
-
continue
|
|
319
|
-
|
|
320
|
-
filepath = os.path.join(search_path, entry)
|
|
321
|
-
is_dir = os.path.isdir(filepath)
|
|
322
|
-
|
|
323
|
-
if dirs_only and not is_dir:
|
|
324
|
-
continue
|
|
325
|
-
if files_only and is_dir:
|
|
326
|
-
continue
|
|
327
|
-
|
|
328
|
-
if self._match_pattern(entry, pattern, ignore_case):
|
|
329
|
-
results.append(entry + "/" if is_dir else entry)
|
|
330
|
-
count += 1
|
|
331
|
-
if count >= max_results:
|
|
332
|
-
break
|
|
333
|
-
|
|
334
|
-
if not results:
|
|
335
|
-
return f"No files found matching '{pattern}' (using fallback search)"
|
|
336
|
-
|
|
337
|
-
# Format output
|
|
338
|
-
output = [
|
|
339
|
-
f"Found {len(results)} file(s) matching '{pattern}' (using fallback search):"
|
|
340
|
-
]
|
|
341
|
-
output.append("")
|
|
342
|
-
|
|
343
|
-
for filepath in sorted(results):
|
|
344
|
-
output.append(filepath)
|
|
345
|
-
|
|
346
|
-
if count >= max_results:
|
|
347
|
-
output.append(f"\n... (showing first {max_results} results)")
|
|
348
|
-
|
|
349
|
-
output.append(
|
|
350
|
-
"\nNote: Install 'ffind' for faster searching: pip install ffind"
|
|
351
|
-
)
|
|
352
|
-
|
|
353
|
-
return "\n".join(output)
|
|
354
|
-
|
|
355
|
-
except Exception as e:
|
|
356
|
-
return f"Error searching for files: {str(e)}"
|
|
357
|
-
|
|
358
|
-
def _match_pattern(self, filename: str, pattern: str, ignore_case: bool) -> bool:
|
|
359
|
-
"""Check if filename matches pattern."""
|
|
360
|
-
import fnmatch
|
|
361
|
-
|
|
362
|
-
if ignore_case:
|
|
363
|
-
return fnmatch.fnmatch(filename.lower(), pattern)
|
|
364
|
-
else:
|
|
365
|
-
return fnmatch.fnmatch(filename, pattern)
|
|
366
|
-
|
|
367
|
-
def register(self, mcp_server) -> None:
|
|
368
|
-
"""Register this tool with the MCP server."""
|
|
369
|
-
pass
|