""" Glob Tool - 文件模式匹配工具 参考:vendor/opencode/packages/opencode/src/tool/glob.ts 核心功能: - 使用 glob 模式匹配文件 - 按修改时间排序 - 限制返回数量 """ import glob as glob_module from pathlib import Path from typing import Optional from agent.tools import tool, ToolResult, ToolContext # 常量 LIMIT = 100 # 最大返回数量(参考 opencode glob.ts:35) @tool(description="使用 glob 模式匹配文件", hidden_params=["context"]) async def glob_files( pattern: str, path: Optional[str] = None, context: Optional[ToolContext] = None ) -> ToolResult: """ 使用 glob 模式匹配文件 参考 OpenCode 实现 Args: pattern: glob 模式(如 "*.py", "src/**/*.ts") path: 搜索目录(默认当前目录) context: 工具上下文 Returns: ToolResult: 匹配的文件列表 """ # 确定搜索路径 search_path = Path(path) if path else Path.cwd() if not search_path.is_absolute(): search_path = Path.cwd() / search_path if not search_path.exists(): return ToolResult( title="目录不存在", output=f"搜索目录不存在: {path}", error="Directory not found" ) # 执行 glob 搜索 try: # 使用 pathlib 的 glob(支持 ** 递归) if "**" in pattern: matches = list(search_path.glob(pattern)) else: # 使用标准 glob(更快) pattern_path = search_path / pattern matches = [Path(p) for p in glob_module.glob(str(pattern_path))] # 过滤掉目录,只保留文件 file_matches = [m for m in matches if m.is_file()] # 按修改时间排序(参考 opencode:47-56) file_matches_with_mtime = [] for file_path in file_matches: try: mtime = file_path.stat().st_mtime file_matches_with_mtime.append((file_path, mtime)) except Exception: file_matches_with_mtime.append((file_path, 0)) # 按修改时间降序排序(最新的在前) file_matches_with_mtime.sort(key=lambda x: x[1], reverse=True) # 限制数量 truncated = len(file_matches_with_mtime) > LIMIT file_matches_with_mtime = file_matches_with_mtime[:LIMIT] # 格式化输出 if not file_matches_with_mtime: output = "未找到匹配的文件" else: file_paths = [str(f[0]) for f in file_matches_with_mtime] output = "\n".join(file_paths) if truncated: output += f"\n\n(结果已截断。考虑使用更具体的路径或模式。)" return ToolResult( title=f"匹配: {pattern}", output=output, metadata={ "count": len(file_matches_with_mtime), "truncated": truncated, "pattern": pattern, "search_path": str(search_path) } ) except Exception as e: return ToolResult( title="Glob 错误", output=f"glob 匹配失败: {str(e)}", error=str(e) )