Skip to content

Commit 8902d6c

Browse files
committed
add per-project installation and version bump script
1 parent 81a05c5 commit 8902d6c

7 files changed

Lines changed: 131 additions & 8 deletions

File tree

.claude-plugin/marketplace.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"name": "rex",
1010
"source": "./",
1111
"description": "Sub-second Python symbol search for .venv packages",
12-
"version": "0.1.3"
12+
"version": "0.1.4"
1313
}
1414
]
1515
}

.claude-plugin/plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "rex",
3-
"version": "0.1.3",
3+
"version": "0.1.4",
44
"description": "Sub-second Python symbol search for .venv packages. Find classes, functions, methods by name — faster than web search or grepping .venv.",
55
"author": {
66
"name": "Anton Vykhovanets",

README.md

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,36 @@ and project source code.
77
*Bonus*: MCP server for
88
[Claude Code](https://github.com/anthropics/claude-code).
99

10-
## Install as Claude Code plugin
10+
## Install
11+
12+
### Claude Code plugin
1113

1214
```bash
1315
claude plugin marketplace add vykhovanets/rex
1416
claude plugin install rex@rex
1517
```
1618

17-
This gives you MCP tools + SKILL.md (auto-approved
18-
tools, usage guidance).
19+
MCP tools + SKILL.md with usage guidance.
1920

20-
### Alternative: MCP-only
21+
### CLI + MCP
2122

2223
```bash
2324
uv tool install rex-index
2425
claude mcp add rex -s user -- rex-mcp serve
2526
```
2627

28+
Rex available in every project, no per-project setup.
29+
30+
### Project dependency
31+
32+
```bash
33+
uv add rex-index
34+
uv run rex init-mcp
35+
```
36+
37+
Adds Rex to `.mcp.json` with pre-approved tools.
38+
Commit both files — your team gets Rex on `uv sync`.
39+
2740
## How it works
2841

2942
Rex stores a single global index at
@@ -54,6 +67,7 @@ rex index # Build/update index
5467
rex index -f # Force full rebuild
5568
rex index -p ./lib # Also index extra directories
5669
rex clean # Remove stale packages
70+
rex init-mcp # Register MCP in .mcp.json
5771
```
5872

5973
## MCP Tools

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "rex-index"
3-
version = "0.1.3"
3+
version = "0.1.4"
44
description = "Fast Python symbol search for .venv packages"
55
readme = "README.md"
66
license = "Apache-2.0"

src/bump.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
"""Bump version across all Rex files.
2+
3+
Usage: uv run src/bump.py 0.2.0
4+
"""
5+
6+
from __future__ import annotations
7+
8+
import re
9+
import sys
10+
from pathlib import Path
11+
12+
ROOT = Path(__file__).resolve().parent.parent
13+
14+
TARGETS = [
15+
("src/rex/__init__.py", re.compile(r'(__version__\s*=\s*")([^"]+)(")')),
16+
("pyproject.toml", re.compile(r'(^version\s*=\s*")([^"]+)(")', re.MULTILINE)),
17+
(".claude-plugin/plugin.json", re.compile(r'("version":\s*")([^"]+)(")')),
18+
(".claude-plugin/marketplace.json", re.compile(r'("version":\s*")([^"]+)(")')),
19+
]
20+
21+
22+
def bump(new_version: str) -> None:
23+
for relpath, pattern in TARGETS:
24+
path = ROOT / relpath
25+
text = path.read_text()
26+
match = pattern.search(text)
27+
if not match:
28+
print(f" SKIP {relpath} (pattern not found)")
29+
continue
30+
old = match.group(2)
31+
if old == new_version:
32+
print(f" OK {relpath} (already {new_version})")
33+
continue
34+
text = pattern.sub(rf"\g<1>{new_version}\3", text, count=1)
35+
path.write_text(text)
36+
print(f" {old}{new_version} {relpath}")
37+
38+
39+
def _parse_version(v: str) -> tuple[int, ...]:
40+
return tuple(int(x) for x in v.split("."))
41+
42+
43+
def _current_version() -> str:
44+
path = ROOT / "src/rex/__init__.py"
45+
match = re.search(r'__version__\s*=\s*"([^"]+)"', path.read_text())
46+
return match.group(1) if match else "0.0.0"
47+
48+
49+
def main() -> None:
50+
if len(sys.argv) != 2:
51+
print("Usage: uv run src/bump.py <version>")
52+
sys.exit(1)
53+
54+
version = sys.argv[1].lstrip("v")
55+
if not re.match(r"^\d+\.\d+\.\d+$", version):
56+
print(f"Invalid version: {version}")
57+
sys.exit(1)
58+
59+
current = _current_version()
60+
if _parse_version(version) <= _parse_version(current):
61+
print(f"Error: {version} is not higher than current {current}")
62+
sys.exit(1)
63+
64+
print(f"Bumping {current}{version}:")
65+
bump(version)
66+
67+
68+
if __name__ == "__main__":
69+
main()

src/rex/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
"""Fast Python documentation browser with IDE-style navigation."""
22

3-
__version__ = "0.1.3"
3+
__version__ = "0.1.4"

src/rex/cli.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
from __future__ import annotations
44

5+
import json
56
import re
67
from pathlib import Path
78

@@ -200,6 +201,45 @@ def clean() -> None:
200201
typer.echo("No stale packages found")
201202

202203

204+
_REX_MCP_KEY = "rex"
205+
_REX_MCP_CONFIG = {
206+
"command": "uv",
207+
"args": ["run", "rex-mcp", "serve"],
208+
"autoApprove": ["rex_find", "rex_show", "rex_members"],
209+
}
210+
211+
212+
@app.command("init-mcp")
213+
def init_mcp(
214+
path: Path = typer.Option(".", "-p", "--path", help="Project root with .mcp.json"),
215+
) -> None:
216+
"""Register Rex MCP server in project .mcp.json with pre-approved tools."""
217+
mcp_path = path.resolve() / ".mcp.json"
218+
219+
if mcp_path.exists():
220+
data = json.loads(mcp_path.read_text())
221+
servers = data.get("mcpServers", {})
222+
223+
if _REX_MCP_KEY in servers:
224+
existing = servers[_REX_MCP_KEY]
225+
if existing == _REX_MCP_CONFIG:
226+
typer.echo("Rex MCP already configured — nothing to do.")
227+
raise typer.Exit(0)
228+
# Update existing rex entry to latest config
229+
servers[_REX_MCP_KEY] = _REX_MCP_CONFIG
230+
typer.echo("Updated Rex MCP config in .mcp.json")
231+
else:
232+
servers[_REX_MCP_KEY] = _REX_MCP_CONFIG
233+
typer.echo("Added Rex MCP to existing .mcp.json")
234+
235+
data["mcpServers"] = servers
236+
else:
237+
data = {"mcpServers": {_REX_MCP_KEY: _REX_MCP_CONFIG}}
238+
typer.echo("Created .mcp.json with Rex MCP")
239+
240+
mcp_path.write_text(json.dumps(data, indent=2) + "\n")
241+
242+
203243
def main() -> None:
204244
app()
205245

0 commit comments

Comments
 (0)