Skip to content

Commit 82d942d

Browse files
committed
feat/replace --overview (list of files) with --outline (symbols
1. repomap_class.py: Replaced generate_overview_only with generate_outline - Extracts symbols via tree-sitter - Lists definitions (classes/functions) with line numbers - Skips PageRank (faster than full map) 2. repomap.py: Renamed --overview to --outline with updated help text 3. README.md: Updated the example Output format: src\repomapper\repomap_class.py FileReport (23) RepoMap (37) __init__ (40) load_tags_cache (80) ... src\repomapper\utils.py Tag (16) count_tokens (19) read_text (33) README.md: - Updated installation section from pip install -r requirements.txt to use uv sync and uv pip install -e . - The old requirements.txt didn't even exist; the project uses pyproject.toml src/repomapper/repomap.py: - Fixed --outline mode to include files from --chat-files (previously only --other-files and positional args were used) - Moved the "Chat files:" print to only execute in non-outline mode CLI args with --outline: - --chat-files and positional args/--other-files now all work correctly with --outline - Args like --mentioned-files, --mentioned-idents, --force-refresh, --exclude-unranked, --map-tokens, --max-context-window have no effect in outline mode (they're for PageRank which outline skips) but this is by design - outline is a simpler/faster mode Updated readme to use `uv...`
1 parent b373f60 commit 82d942d

3 files changed

Lines changed: 77 additions & 50 deletions

File tree

README.md

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ I then used a combination of Aider w/Claude 3.7, Cline w/Gemini 2.5 Pro Preview
4141
## Example Output
4242

4343
```
44-
> python repomap.py . --chat-files repomap_class.py
44+
> uv run repomapper . --chat-files repomap_class.py
4545
Chat files: ['/mnt/programming/RepoMapper/repomap_class.py']
4646
repomap_class.py:
4747
(Rank value: 10.8111)
@@ -94,7 +94,11 @@ importance.py:
9494
## Installation
9595

9696
```bash
97-
pip install -r requirements.txt
97+
# Install with uv (recommended)
98+
uv sync
99+
100+
# Or install as editable package
101+
uv pip install -e .
98102
```
99103

100104
----------
@@ -105,37 +109,37 @@ pip install -r requirements.txt
105109

106110
```bash
107111
# Map current directory
108-
python repomap.py .
112+
uv run repomapper .
109113

110114
# Map specific directory with custom token limit
111-
python repomap.py src/ --map-tokens 2048
115+
uv run repomapper src/ --map-tokens 2048
112116

113117
# Map specific files
114-
python repomap.py file1.py file2.py
118+
uv run repomapper file1.py file2.py
115119

116120
# Specify chat files (higher priority) vs other files
117-
python repomap.py --chat-files main.py --other-files src/
121+
uv run repomapper --chat-files main.py --other-files src/
118122

119123
# Specify mentioned files and identifiers
120-
python repomap.py --mentioned-files config.py --mentioned-idents "main_function"
124+
uv run repomapper --mentioned-files config.py --mentioned-idents "main_function"
121125

122126
# Enable verbose output
123-
python repomap.py . --verbose
127+
uv run repomapper . --verbose
124128

125129
# Force refresh of caches
126-
python repomap.py . --force-refresh
130+
uv run repomapper . --force-refresh
127131

128132
# Specify model for token counting
129-
python repomap.py . --model gpt-3.5-turbo
133+
uv run repomapper . --model gpt-3.5-turbo
130134

131135
# Set maximum context window
132-
python repomap.py . --max-context-window 8192
136+
uv run repomapper . --max-context-window 8192
133137

134138
# Exclude files with Page Rank 0
135-
python repomap.py . --exclude-unranked
139+
uv run repomapper . --exclude-unranked
136140

137-
# Only list files in directory
138-
python repomap.py . --overview
141+
# Output code outline (classes/functions per file)
142+
uv run repomapper . --outline
139143
```
140144

141145
The tool prioritizes files in the following order:
@@ -148,22 +152,22 @@ The tool prioritizes files in the following order:
148152

149153
```bash
150154
# Enable verbose output
151-
python repomap.py . --verbose
155+
uv run repomapper . --verbose
152156

153157
# Force refresh of caches
154-
python repomap.py . --force-refresh
158+
uv run repomapper . --force-refresh
155159

156160
# Specify model for token counting
157-
python repomap.py . --model gpt-3.5-turbo
161+
uv run repomapper . --model gpt-3.5-turbo
158162

159163
# Set maximum context window
160-
python repomap.py . --max-context-window 8192
164+
uv run repomapper . --max-context-window 8192
161165

162166
# Exclude files with Page Rank 0
163-
python repomap.py . --exclude-unranked
167+
uv run repomapper . --exclude-unranked
164168

165169
# Mention specific files or identifiers for higher priority
166-
python repomap.py . --mentioned-files config.py --mentioned-idents "main_function"
170+
uv run repomapper . --mentioned-files config.py --mentioned-idents "main_function"
167171
```
168172

169173
----------
@@ -274,23 +278,26 @@ RepoMap can also be run as an MCP (Model Context Protocol) server, allowing othe
274278
"disabled": false,
275279
"timeout": 60,
276280
"type": "stdio",
277-
"command": "/usr/bin/python3",
281+
"command": "uv",
278282
"args": [
279-
"/absolute/path/to/repomap_server.py"
283+
"run",
284+
"--directory",
285+
"/absolute/path/to/RepoMapper",
286+
"repomap-mcp"
280287
]
281288
}
282289
}
283290
}
284291
```
285292

286-
- Replace `"/absolute/path/to/repomap_server.py"` with the actual path to your `repomap_server.py` file.
293+
- Replace `"/absolute/path/to/RepoMapper"` with the actual path to your RepoMapper installation directory.
287294

288295
### Usage
289296

290-
1. Run the `repomap_server.py` script:
297+
1. Run the MCP server:
291298

292299
```bash
293-
python repomap_server.py
300+
uv run repomap-mcp
294301
```
295302

296303
2. The server will start and listen for requests via STDIO.

src/repomapper/repomap.py

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,9 @@ def main():
113113
)
114114

115115
parser.add_argument(
116-
"--overview",
116+
"--outline",
117117
action="store_true",
118-
help="Output only the repository overview (file list with status)",
118+
help="Output code outline (classes/functions per file, no ranking)",
119119
)
120120

121121
args = parser.parse_args()
@@ -152,8 +152,6 @@ def token_counter(text: str) -> int:
152152
# other_files for RepoMap are the effective_other_files, resolved after expansion.
153153
other_files = [str(Path(f).resolve()) for f in effective_other_files_unresolved]
154154

155-
print(f"Chat files: {chat_files}")
156-
157155
# Convert mentioned files to sets
158156
mentioned_fnames = set(args.mentioned_files) if args.mentioned_files else None
159157
mentioned_idents = set(args.mentioned_idents) if args.mentioned_idents else None
@@ -170,12 +168,16 @@ def token_counter(text: str) -> int:
170168
exclude_unranked=args.exclude_unranked,
171169
)
172170

173-
# Handle --overview mode (fast path, no code analysis)
174-
if args.overview:
175-
overview = repo_map.generate_overview_only(other_files)
176-
tool_output(overview)
171+
# Handle --outline mode (symbols only, no PageRank)
172+
if args.outline:
173+
# Combine chat_files and other_files for outline
174+
all_files = list(set(chat_files + other_files))
175+
outline = repo_map.generate_outline(all_files)
176+
tool_output(outline)
177177
return
178178

179+
print(f"Chat files: {chat_files}")
180+
179181
# Generate the map
180182
try:
181183
map_content, file_report = repo_map.get_repo_map(

src/repomapper/repomap_class.py

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -334,10 +334,15 @@ def normalize_path(path):
334334
if personalization:
335335
ranks = nx.pagerank(G, personalization=personalization, alpha=0.85)
336336
else:
337+
ranks = nx.pagerank(G, alpha=0.85)
338+
except Exception as e:
339+
print(f"Error during PageRank: {e}")
340+
try:
341+
# If personalization caused the crash, try standard PageRank
342+
ranks = nx.pagerank(G, alpha=0.85)
343+
except Exception:
344+
# If both fail, fallback to uniform
337345
ranks = {node: 1.0 for node in G.nodes()}
338-
except Exception:
339-
# Fallback to uniform ranking
340-
ranks = {node: 1.0 for node in G.nodes()}
341346

342347
# Update excluded dictionary with status information
343348
for fname in set(chat_fnames + other_fnames):
@@ -483,28 +488,39 @@ def get_ranked_tags_map(
483488
self.map_cache[cache_key] = result
484489
return result
485490

486-
def generate_overview_only(self, all_files: list[str]) -> str:
487-
"""Generate a fast file overview without any code analysis.
491+
def generate_outline(self, all_files: list[str]) -> str:
492+
"""Generate a code outline showing all classes/functions per file.
488493
489-
This skips tree-sitter parsing, PageRank, etc. for maximum speed.
494+
This extracts symbols via tree-sitter but skips PageRank ranking.
495+
Faster than full repo map, provides structural overview.
490496
"""
491497
if not all_files:
492498
return ""
493499

494-
overview_lines = ["=== REPOSITORY OVERVIEW ==="]
495-
overview_lines.append(f"Total files: {len(all_files)}")
496-
overview_lines.append("")
497-
498500
# Sort files for consistent output
499501
sorted_files = sorted(all_files, key=lambda f: self.get_rel_fname(f))
500502

503+
outline_parts = []
504+
501505
for fname in sorted_files:
502506
rel_fname = self.get_rel_fname(fname)
503-
overview_lines.append(f" {rel_fname}")
504507

505-
overview_lines.append("")
508+
if not os.path.exists(fname):
509+
continue
506510

507-
return "\n".join(overview_lines)
511+
tags = self.get_tags(fname, rel_fname)
512+
513+
# Filter to definitions only and sort by line number
514+
definitions = [(tag.name, tag.line) for tag in tags if tag.kind == "def"]
515+
definitions.sort(key=lambda x: x[1])
516+
517+
if definitions:
518+
file_lines = [rel_fname]
519+
for name, line in definitions:
520+
file_lines.append(f" {name} ({line})")
521+
outline_parts.append("\n".join(file_lines))
522+
523+
return "\n\n".join(outline_parts)
508524

509525
def generate_file_overview(
510526
self, all_files: list[str], files_in_map: set[str], file_report: FileReport
@@ -608,11 +624,13 @@ def try_tags(num_tags: int) -> tuple[str | None, int, set[str]]:
608624
else:
609625
right = mid - 1
610626

611-
# Generate file overview if we have a tree
627+
# Generate file overview if we have a tree (only when verbose)
612628
if best_tree:
613-
all_files = list(set(chat_fnames + other_fnames))
614-
overview = self.generate_file_overview(all_files, best_files, file_report)
615-
best_tree = overview + "=== DETAILED CODE MAP ===\n\n" + best_tree
629+
if self.verbose:
630+
all_files = list(set(chat_fnames + other_fnames))
631+
overview = self.generate_file_overview(all_files, best_files, file_report)
632+
if overview:
633+
best_tree = best_tree + "\n\n" + overview
616634

617635
return best_tree, file_report
618636

0 commit comments

Comments
 (0)