From b898ce77f85979a7e767b0320d94ead8516e5c39 Mon Sep 17 00:00:00 2001 From: wehub-skill-sync Date: Mon, 13 Jul 2026 21:36:01 +0800 Subject: [PATCH] chore: import zh skill smart-explore --- README.wehub.md | 9 + SKILL.md | 509 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 518 insertions(+) create mode 100644 README.wehub.md create mode 100644 SKILL.md diff --git a/README.wehub.md b/README.wehub.md new file mode 100644 index 0000000..d106a60 --- /dev/null +++ b/README.wehub.md @@ -0,0 +1,9 @@ +# WeHub 来源说明 + +- Skill 名称:`smart-explore` +- 中文类目:把代码库结构化为可检索工件 +- 上游仓库:`thedotmack__claude-mem` +- 上游路径:`plugin/skills/smart-explore/SKILL.md` +- 上游链接:https://github.com/thedotmack/claude-mem/blob/HEAD/plugin/skills/smart-explore/SKILL.md +- 本仓库为 WeHub 中文 Skill 汉化包,基于 skill 市场筛选 Top200 清单整理 +- 原作者、版权和许可证信息以上游仓库为准 diff --git a/SKILL.md b/SKILL.md new file mode 100644 index 0000000..ceb1a52 --- /dev/null +++ b/SKILL.md @@ -0,0 +1,509 @@ +--- +name: smart-explore +description: "使用 tree-sitter AST 解析进行渐进式代码探索——先看结构,再深入细节。将每个文件的代码阅读量从 10-15k token 减少到 200-500 token。" +effort: low +--- + +# Smart Explore——渐进式代码探索 + +> **技能**:先阅读代码结构,再阅读代码。先让 Claude 展示函数签名和类型,然后仅在需要时深入查看特定函数。 + +**灵感来源**:Alex Newman(Claude-MEM)+ Aider 仓库地图模式(在 40k+ star 项目中得到验证) + +## 问题 + +当 Claude 读取文件以理解代码库时,它会读取全部内容: + +``` +# 实际发生的情况 +Read src/auth.rs → 400 行 → ~2,800 tokens +Read src/session.rs → 300 行 → ~2,100 tokens +Read src/user.rs → 500 行 → ~3,500 tokens +# 总计:3 个文件消耗 8,400 tokens +``` + +其中大部分内容都是无关的。Claude 只需要知道 `auth.rs` 中有 `fn login()` 和 `fn logout()`——而不是 400 行的实现细节。 + +**渐进式探索解决了这个问题**: + +``` +步骤 1:auth.rs 里有什么? → ~200 tokens(仅签名) +步骤 2:展示 fn login() 主体 → ~350 tokens(一个函数) +步骤 3:谁调用了 login()? → ~150 tokens(交叉引用) +# 总计:700 tokens,而不是 8,400——减少 92% +``` + +## 何时使用 + +| 信号 | 使用 smart-explore | 使用标准 Read | +|--------|-------------------|-------------------| +| "理解这个模块/功能" | ✅ | ❌ | +| 探索不熟悉的代码库 | ✅ | ❌ | +| 查找在何处添加功能 | ✅ | ❌ | +| 需要阅读某个特定函数 | ❌ | ✅ | +| 调试已知行 | ❌ | ✅ | +| 文件 < 100 行 | ❌ | ✅(直接读取即可) | + +**不适用场景**: +- 小型项目(< 20 个文件)——额外开销不划算 +- 单文件任务——直接 Read 更快 +- 已经知道要读什么——直接跳转 + +## 决策树 + +``` +探索任务? +├─ 是,理解一个模块 +│ └─ 每个文件超过 200 行? +│ ├─ 是 → smart-explore(先看结构) +│ └─ 否 → 直接 Read(文件很小) +├─ 搜索特定内容 +│ └─ 按名称/模式 → Grep +│ └─ 按含义 → grepai 语义搜索 +└─ 需要某个特定函数 → 使用 Read 加偏移量 +``` + +## 三种方案(从易到难) + +### 方案 A:无需设置——渐进式阅读规范 + +无需安装。只需改变你提示 Claude 的方式。 + +**添加到你的 CLAUDE.md**(或直接指示 Claude): + +```markdown +## 代码探索协议 + +当被要求探索代码库或理解模块时: + +1. **先看结构**:使用 Grep 查找函数/类定义 + + Rust: + `rg "^\s*(pub\s+)?(async\s+)?fn |^\s*(pub\s+)?(struct|enum|trait|impl)\s" src/ --no-heading -n` + + Python/TypeScript/JS: + `rg "^\s*(async\s+)?(def |function |class |export (function|class|const))" src/ --no-heading -n` + + 注意:使用 `^\s*` 而不是 `^`——impl 块和类主体内部的方法是有缩进的。 + `^` 模式会漏掉约 70% 的 Rust 方法。 + +2. **识别相关符号**:根据名称,挑选 2-3 个来阅读 + +3. **定向阅读**:使用 Read 加偏移量/行数限制来阅读特定函数 + - 只读 auth.rs 的第 45-90 行,而不是整个文件 + +4. **交叉引用**:仅在需要时使用 Grep 查找调用方 + - `rg "fn_name" --type rust -n` + +探索时切勿从头到尾阅读文件。始终先看结构。 +``` + +**适用**:任何 Claude Code 会话,零依赖。 + +--- + +### 方案 B:tree-sitter CLI + 提取脚本 + +安装 tree-sitter CLI 并使用轻量级 Python 脚本提取签名。 + +**安装**: + +```bash +# macOS +brew install tree-sitter + +# 验证 +tree-sitter --version +``` + +**提取签名脚本**——保存为 `~/.claude/scripts/extract-signatures.py`: + +```python +#!/usr/bin/env python3 +"""Extract function/class signatures from source files using tree-sitter CLI.""" + +import subprocess +import sys +import json +import re +from pathlib import Path + + +def extract_signatures(file_path: str) -> list[str]: + """Extract function and type signatures without bodies.""" + path = Path(file_path) + + # Detect language from extension + lang_map = { + ".rs": "rust", ".py": "python", ".ts": "typescript", + ".tsx": "tsx", ".js": "javascript", ".jsx": "jsx", + ".go": "go", ".rb": "ruby", ".java": "java", + } + lang = lang_map.get(path.suffix) + if not lang: + return [f"# Unsupported: {path.suffix}"] + + # Use tree-sitter to parse and get JSON AST + try: + result = subprocess.run( + ["tree-sitter", "parse", file_path, "--json"], + capture_output=True, text=True, timeout=10 + ) + if result.returncode != 0: + return [f"# Parse error: {result.stderr[:100]}"] + except FileNotFoundError: + return ["# tree-sitter not installed: brew install tree-sitter"] + except subprocess.TimeoutExpired: + return ["# Parse timeout"] + + # Read actual source for signature extraction + source_lines = path.read_text().splitlines() + + signatures = [] + + # Regex-based signature extraction (faster than full AST for this use case) + patterns = { + "rust": [ + (r"^(\s*(?:pub\s+)?(?:async\s+)?fn\s+\w+[^{]*?)(?:\{|$)", "fn"), + (r"^(\s*(?:pub\s+)?struct\s+\w+[^{]*?)(?:\{|$)", "struct"), + (r"^(\s*(?:pub\s+)?enum\s+\w+[^{]*?)(?:\{|$)", "enum"), + (r"^(\s*(?:pub\s+)?trait\s+\w+[^{]*?)(?:\{|$)", "trait"), + (r"^(\s*impl\s+[^{]+?)(?:\{|$)", "impl"), + ], + "python": [ + (r"^(\s*(?:async\s+)?def\s+\w+[^:]*:)", "fn"), + (r"^(\s*class\s+\w+[^:]*:)", "class"), + ], + "typescript": [ + (r"^(\s*(?:export\s+)?(?:async\s+)?function\s+\w+[^{]*?)(?:\{|$)", "fn"), + (r"^(\s*(?:export\s+)?(?:default\s+)?class\s+\w+[^{]*?)(?:\{|$)", "class"), + (r"^(\s*(?:export\s+)?(?:const|let)\s+\w+\s*=\s*(?:async\s+)?\([^)]*\)\s*=>)", "arrow"), + (r"^(\s*(?:export\s+)?(?:interface|type)\s+\w+[^{=]*?)(?:\{|=|$)", "type"), + ], + "go": [ + (r"^(\s*func\s+[^{]+?)(?:\{|$)", "fn"), + (r"^(\s*type\s+\w+\s+(?:struct|interface)[^{]*?)(?:\{|$)", "type"), + ], + "javascript": [ + (r"^(\s*(?:export\s+)?(?:default\s+)?(?:async\s+)?function\s+\w+[^{]*?)(?:\{|$)", "fn"), + (r"^(\s*(?:export\s+)?(?:default\s+)?class\s+\w+[^{]*?)(?:\{|$)", "class"), + (r"^(\s*(?:export\s+)?(?:const|let)\s+\w+\s*=\s*(?:async\s+)?\([^)]*\)\s*=>)", "arrow"), + ], + } + + lang_patterns = patterns.get(lang, []) + + for i, line in enumerate(source_lines, 1): + for pattern, sig_type in lang_patterns: + match = re.match(pattern, line) + if match: + sig = match.group(1).strip().rstrip("{").strip() + signatures.append(f" {sig_type} {sig} (line {i})") + break + + return signatures + + +def explore_directory(directory: str, extensions: list[str] | None = None) -> None: + """Print structure of all source files in directory.""" + if extensions is None: + extensions = [".rs", ".py", ".ts", ".tsx", ".js", ".go"] + + path = Path(directory) + files = sorted( + f for ext in extensions + for f in path.rglob(f"*{ext}") + if not any(part.startswith(".") or part in ("node_modules", "target", "__pycache__", "dist") + for part in f.parts) + ) + + for file in files: + rel_path = file.relative_to(path) + sigs = extract_signatures(str(file)) + if sigs: + print(f"\n{rel_path}:") + for sig in sigs: + print(sig) + + +if __name__ == "__main__": + if len(sys.argv) < 2: + print("Usage: extract-signatures.py [ext1 ext2 ...]") + sys.exit(1) + + target = sys.argv[1] + exts = sys.argv[2:] if len(sys.argv) > 2 else None + + if Path(target).is_file(): + sigs = extract_signatures(target) + for sig in sigs: + print(sig) + else: + explore_directory(target, exts) +``` + +**设为可执行**: + +```bash +chmod +x ~/.claude/scripts/extract-signatures.py +``` + +**用法**: + +```bash +# 单个文件 +python3 ~/.claude/scripts/extract-signatures.py src/auth.rs + +# 整个目录 +python3 ~/.claude/scripts/extract-signatures.py src/ + +# 指定扩展名 +python3 ~/.claude/scripts/extract-signatures.py src/ .ts .tsx +``` + +**输出示例**(针对一个 500 行的 Rust 文件): + +``` +src/auth.rs: + fn pub fn new(config: AuthConfig) -> Self (line 12) + fn pub async fn login(username: &str, password: &str) -> Result (line 28) + fn pub async fn logout(session_id: Uuid) -> Result<()> (line 67) + fn pub fn validate_session(token: &str) -> bool (line 89) + struct pub struct AuthConfig (line 110) + struct pub struct Session (line 125) + impl impl AuthService (line 140) +``` + +**Token 消耗**:每个文件约 50-150,而完整读取需要 2,000-5,000。 + +**添加到 CLAUDE.md** 以自动执行此操作: + +```markdown +## 代码结构工具 + +在读取多个文件之前,运行: +`python3 ~/.claude/scripts/extract-signatures.py ` + +这会显示所有函数签名(不含文件主体)。用于识别需要阅读的特定函数, +然后使用 Read 加行偏移量。 +``` + +--- + +### 方案 C:MCP 服务器(推荐用于大型项目) + +对于超过 50 个文件的代码库,索引化 MCP 服务器提供更快的查找速度并能处理跨文件引用。 + +**按使用场景的最佳选择**: + +| 使用场景 | 推荐工具 | 安装 | +|---|---|---| +| 通用代码探索 | mcp-server-tree-sitter | `pip install mcp-server-tree-sitter` | +| PR 代码审查 | code-review-graph | `pip install code-review-graph` | +| 符号密集型工作流 | jCodeMunch(非商业用途) | `claude mcp add jcodemunch uvx jcodemunch-mcp` | + +#### 选项 C1:mcp-server-tree-sitter + +```bash +pip install mcp-server-tree-sitter + +# 添加到 Claude Code +claude mcp add tree-sitter python -m mcp_server_tree_sitter +``` + +**安装后可用的工具**: +- `get_file_structure`——文件的签名和类型 +- `run_ast_query`——自定义 tree-sitter 查询(高级) +- `find_symbols`——按名称在整个代码库中搜索 +- `analyze_dependencies`——跨文件引用分析 + +**在 Claude Code 中配置**(`~/.claude/settings.json`): +```json +{ + "mcpServers": { + "tree-sitter": { + "command": "python", + "args": ["-m", "mcp_server_tree_sitter"] + } + } +} +``` + +#### 选项 C2:code-review-graph(最适合 PR 审查) + +```bash +pip install code-review-graph +code-review-graph install +``` + +**新增功能**:审查 PR 时,Claude 会自动获取变更文件及其依赖关系图。Claude 无需读取 30 个文件来理解变更影响,只需查看实际相关的 5 个文件。 + +**用法**: + +``` +/review-pr 123 +# code-review-graph 自动提供: +# - 变更的文件 +# - 导入了已变更模块的文件 +# - 受影响的类型定义 +# - 变更代码的测试覆盖情况 +``` + +#### 选项 C3:jCodeMunch(符号查找) + +```bash +claude mcp add jcodemunch uvx jcodemunch-mcp +``` + +**注意**:个人/开源项目免费。商业使用 $79/开发者。团队采用前请检查许可条款。 + +添加后,Claude 可以调用: +``` +get_symbol("login") → 函数主体 +find_callers("login") → 谁调用了它 +get_class_hierarchy("User") → 继承树 +get_dependencies("auth.rs") → 它导入了什么 +``` + +--- + +## 工作流示例 + +### 示例 1:理解不熟悉的模块 + +**旧方式**(4 次读取,约 12k tokens): +``` +Read src/payments/processor.rs # 400 行 +Read src/payments/validator.rs # 300 行 +Read src/payments/gateway.rs # 500 行 +Read src/payments/types.rs # 200 行 +``` + +**Smart explore 方式**(1 次结构扫描 + 2 次定向读取,约 1.5k tokens): +```bash +# 步骤 1:获取结构(4 个文件共约 400 tokens) +python3 ~/.claude/scripts/extract-signatures.py src/payments/ + +# 步骤 2:从签名中识别关键内容 +# "process_payment() 调用了 validate_amount()——读取这两个" + +# 步骤 3:只读取这些函数(带行偏移量) +Read src/payments/processor.rs (lines 45-90) # ~300 tokens +Read src/payments/validator.rs (lines 12-40) # ~200 tokens +``` + +**结果**:相同的理解程度,减少约 87% 的 tokens。 + +### 示例 2:查找在何处添加功能 + +```bash +# 目标:为认证服务添加速率限制 +# 步骤 1:auth 模块里有什么? +python3 ~/.claude/scripts/extract-signatures.py src/auth/ + +# 输出: +# src/auth/middleware.rs: +# fn pub fn authenticate(req: &Request) -> Result (line 15) +# fn pub fn refresh_token(token: &str) -> Result (line 45) +# +# src/auth/service.rs: +# fn pub fn validate(claims: &Claims) -> bool (line 8) +# fn pub async fn login(creds: &Credentials) -> Result (line 20) + +# 步骤 2:速率限制应加在 middleware.rs 的 authenticate() 之前 +# 只读取 authenticate 函数以了解注入点 +Read src/auth/middleware.rs lines 15-44 + +# 步骤 3:添加功能——完成 +``` + +### 示例 3:Claude Code CLAUDE.md 集成 + +添加到项目的 `CLAUDE.md`: + +```markdown +## 代码探索协议 + +**对于此代码库上的任何探索/重构任务:** + +1. **探索时切勿读取完整文件**——先进行结构扫描 +2. 运行 `python3 ~/.claude/scripts/extract-signatures.py ` +3. 从输出中识别 2-3 个相关函数 +4. 只读取这些函数(使用 Read 加签名输出中的行偏移量) +5. 对于跨文件依赖:使用 Grep 搜索函数名称,不要读取调用方文件 + +**理由**:此代码库约有 80 个文件,平均 300 行。完整读取 = 每任务 15k+ tokens。结构优先 = 1-2k tokens。 +``` + +--- + +## Token 基准测试(真实数据) + +实测模式,非宣传数据: + +| 操作 | 未使用 smart-explore | 使用 smart-explore | 节省 | +|---|---|---|---| +| 理解 5 个文件的模块 | ~18,000 tokens | ~2,500 tokens | ~86% | +| 查找在何处添加功能 | ~8,000 tokens | ~800 tokens | ~90% | +| PR 审查(10 个变更文件) | ~25,000 tokens | ~3,500 tokens | ~86% | +| 单个函数查找 | ~3,000 tokens | ~350 tokens | ~88% | + +**背景说明**:数据基于典型文件(200-500 行)。文件越大节省越多,文件越小节省越少。Aider 项目(40k+ stars)独立验证了这种方法可以为整个大型仓库生成约 1,000 token 的摘要。 + +--- + +## 与互补工具的比较 + +| 工具 | 节省什么 | 何时使用 | +|---|---|---| +| **RTK** | 命令输出 tokens(git、cargo、npm) | 运行 CLI 命令后 | +| **smart-explore**(本技能) | 代码读取 tokens | 读取源文件之前 | +| **grepai** | 多次 Grep 轮次→一次语义查询 | 按概念/意图搜索时 | +| **ast-grep** | 复杂结构重构 | 大规模代码转换 | + +这些工具是互补的,而非竞争关系。一次典型的 30 分钟 Claude Code 会话中,四个工具都会用到。 + +--- + +## 故障排除 + +**tree-sitter CLI 未找到**: +```bash +brew install tree-sitter # macOS +# 或:npm install -g tree-sitter-cli +``` + +**脚本未提取任何内容**: +- 检查文件扩展名是否在支持列表中 +- 验证正则表达式模式是否匹配你的语言风格 +- 如有需要,将语言模式添加到脚本的 `patterns` 字典中 + +**MCP 服务器无法连接**: +```bash +# 验证安装 +python -m mcp_server_tree_sitter --help + +# 添加 MCP 服务器后重启 Claude Code +# 检查 ~/.claude/settings.json 配置是否正确 +``` + +**结果过于冗长**(签名太多): +- 过滤到特定子目录:`extract-signatures.py src/payments/` +- 使用扩展名过滤:`extract-signatures.py src/ .rs`(仅 Rust) +- 对于大型代码库,按功能区域查询,而非整个 src/ + +--- + +## 资源 + +- [Aider Repo Map Architecture](https://aider.chat/docs/repomap.html)——参考实现(PageRank + tree-sitter) +- [mcp-server-tree-sitter](https://github.com/wrale/mcp-server-tree-sitter)——纯 MCP 方案 +- [code-review-graph](https://github.com/tirth8205/code-review-graph)——专注于 PR 审查,MIT,约 2k stars +- [jCodeMunch](https://github.com/jgravelle/jcodemunch-mcp)——符号查找 MCP(非商业免费) +- [tree-sitter.github.io](https://tree-sitter.github.io/tree-sitter/)——官方文档 + +--- + +**最后更新**:2026 年 3 月 +**兼容**:Claude Code 2.0+ +**依赖**:tree-sitter CLI(方案 B),Python 3.10+(脚本)