🚀 RepoMap - 命令行工具与MCP服务器
RepoMap是一款强大的工具,主要用于帮助大语言模型(LLMs)理解和导航复杂的代码库。它既可以作为命令行应用程序进行按需分析,也可以作为MCP(模型上下文协议)服务器,为其他应用程序提供持续的代码库映射功能。通过生成软件代码库的“地图”,RepoMap能够突出显示重要文件、代码定义及其相互关系。它利用Tree - sitter进行精确的代码解析,并使用PageRank算法按重要性对代码元素进行排序,确保始终优先显示最相关的信息。
🚀 快速开始
RepoMap功能强大且易于使用。你可以通过命令行快速对代码库进行分析,也可以将其作为MCP服务器为其他应用提供服务。以下是一些基本的使用示例:
python repomap.py .
python repomap.py src/ --map-tokens 2048
✨ 主要特性
- 智能代码分析:使用Tree - sitter解析源代码并提取函数/类定义。
- 相关性排序:采用PageRank算法按重要性对代码元素进行排序。
- 令牌感知:考虑令牌限制,以适应大语言模型的上下文窗口。
- 缓存机制:持久缓存,加快后续运行速度。
- 多语言支持:支持Python、JavaScript、TypeScript、Java、C/C++、Go、Rust等多种语言。
- 重要文件检测:自动识别并优先处理重要文件(如README、requirements.txt等)。
📦 安装指南
使用以下命令安装所需依赖:
pip install -r requirements.txt
💻 使用示例
基础用法
python repomap.py .
python repomap.py src/ --map-tokens 2048
python repomap.py file1.py file2.py
python repomap.py --chat-files main.py --other-files src/
python repomap.py --mentioned-files config.py --mentioned-idents "main_function"
python repomap.py . --verbose
python repomap.py . --force-refresh
python repomap.py . --model gpt-3.5-turbo
python repomap.py . --max-context-window 8192
python repomap.py . --exclude-unranked
该工具按以下顺序对文件进行优先级排序:
--chat-files:这些文件优先级最高,因为它们被认为是你当前正在处理的文件。
--mentioned-files:这些文件优先级较高,因为它们在当前上下文中被明确提及。
--other-files:这些文件优先级最低,用于提供额外的上下文信息。
高级用法
python repomap.py . --verbose
python repomap.py . --force-refresh
python repomap.py . --model gpt-3.5-turbo
python repomap.py . --max-context-window 8192
python repomap.py . --exclude-unranked
python repomap.py . --mentioned-files config.py --mentioned-idents "main_function"
📚 详细文档
工作原理
- 文件发现:扫描代码库以查找源文件。
- 代码解析:使用Tree - sitter解析代码并提取定义/引用。
- 图构建:创建一个图,其中文件为节点,符号引用为边。
- 排序:应用PageRank算法按重要性对文件和符号进行排序。
- 令牌优化:使用二分查找将最重要的内容适配到令牌限制内。
- 输出生成:将结果格式化为可读的代码地图。
输出格式
该工具生成代码库的结构化视图,显示以下内容:
- 文件路径和重要代码段。
- 函数和类定义。
- 代码元素之间的关键关系。
- 根据实际使用和引用进行优先级排序。
依赖项
tiktoken:用于各种大语言模型的令牌计数。
networkx:图算法(PageRank)。
diskcache:持久缓存。
grep - ast:用于代码解析的Tree - sitter集成。
tree - sitter:代码解析框架。
pygments:语法高亮和词法分析。
缓存机制
该工具使用持久缓存来加快后续运行速度:
- 缓存目录:
.repomap.tags.cache.v1/
- 文件更改时自动失效
- 可以使用
--force - refresh清除缓存
支持的语言
目前支持具有Tree - sitter语法的语言:
- arduino
- chatito
- commonlisp
- cpp
- csharp
- c
- dart
- d
- elisp
- elixir
- elm
- gleam
- go
- javascript
- java
- lua
- ocaml_interface
- ocaml
- pony
- properties
- python
- racket
- r
- ruby
- rust
- solidity
- swift
- udev
- c_sharp
- hcl
- kotlin
- php
- ql
- scala
许可证
此实现基于Aider项目的RepoMap设计。
作为MCP服务器运行
RepoMap还可以作为MCP(模型上下文协议)服务器运行,允许其他应用程序访问其代码库映射功能。
设置
- RepoMap MCP服务器使用STDIO(标准输入/输出)进行通信。传输层无需额外配置。
- 要将RepoMap设置为与Cline(或类似工具如Roo)配合使用的MCP服务器,请在Cline设置文件(例如
cline_mcp_settings.json)中添加以下配置:
{
"mcpServers": {
"RepoMapper": {
"disabled": false,
"timeout": 60,
"type": "stdio",
"command": "/usr/bin/python3",
"args": [
"/absolute/path/to/repomap_server.py"
]
}
}
}
请将"/absolute/path/to/repomap_server.py"替换为你实际的repomap_server.py文件路径。
使用
- 运行
repomap_server.py脚本:
python repomap_server.py
- 服务器将启动并通过STDIO监听请求。
- 其他应用程序可以使用服务器提供的
repo_map工具生成代码库映射。它们必须将project_root参数指定为要映射项目的绝对路径。
变更日志
2025年7月13日 - 移除了project.json依赖项。修复了MCP服务器,使其在文件名处理方面对大语言模型更友好。
🔧 技术细节
开发背景
RepoMap完全基于Aider的Repo map功能,但我认为它与Aider没有共享任何代码。最初,我试图从Aider中提取RepoMap类,移除所有与Aider特定的依赖项,然后将其变成一个命令行工具。但由于Python不是我的母语,我在实现过程中遇到了很大困难。
几小时前,我有了一个不同的想法。我从Aider中提取了RepoMap及其相关代码,并将其提供给一个大语言模型(可能是Claude或Gemini 2.5 Pro,记不清了),让它为这个应用程序生成规范。它生成了一个非常详细的应用程序规范(不包括MCP部分),然后我将其提供给Aider和Claude 3.7,由它们构建了这个命令行版本。
之后,我结合使用了Aider和Claude 3.7、Cline和Gemini 2.5 Pro Preview、Gemini 2.5 Flash Preview、Phind.com、Gemini.com、Claude.com和ChatGPT.com,经过几个小时的努力,终于完成了MCP服务器的开发。需要再次强调的是,Python并非我的母语。
示例输出
> python repomap.py . --chat-files repomap_class.py
Chat files: ['/mnt/programming/RepoMapper/repomap_class.py']
repomap_class.py:
(Rank value: 10.8111)
36: CACHE_VERSION = 1
39: TAGS_CACHE_DIR = os.path.join(os.getcwd(), f".repomap.tags.cache.v{CACHE_VERSION}")
40: SQLITE_ERRORS = (sqlite3.OperationalError, sqlite3.DatabaseError)
43: Tag = namedtuple("Tag", "rel_fname fname line name kind".split())
46: class RepoMap:
49: def __init__(
93: def load_tags_cache(self):
102: def save_tags_cache(self):
459: def get_ranked_tags_map_uncached(
483: def try_tags(num_tags: int) -> Tuple[Optional[str], int]:
512: def get_repo_map(
utils.py:
(Rank value: 0.2297)
18: Tag = namedtuple("Tag", "rel_fname fname line name kind".split())
21: def count_tokens(text: str, model_name: str = "gpt-4") -> int:
35: def read_text(filename: str, encoding: str = "utf-8", silent: bool = False) -> Optional[str]:
importance.py:
(Rank value: 0.1149)
8: IMPORTANT_FILENAMES = {
27: IMPORTANT_DIR_PATTERNS = {
34: def is_important(rel_file_path: str) -> bool:
56: def filter_important_files(file_paths: List[str]) -> List[str]:
...
...
...