Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## [Unreleased]

### Added

- **`code-review-graph uninstall` command** ([#482](https://github.com/tirth8205/code-review-graph/issues/482)): symmetric counterpart to `install` that walks the full inventory of artifacts `install` creates and removes them. Per-repo it removes the `.code-review-graph/` data directory, the generated `.claude/skills/`, `.gemini/skills/`, and `.qoder/skills/` directories, our pre-commit hook block (preserving any user hooks), the `.code-review-graph/` line in `.gitignore`, and the `<!-- code-review-graph MCP tools -->` section from `CLAUDE.md`, `AGENTS.md`, `GEMINI.md`, `.cursorrules`, `.windsurfrules`, `QODER.md`, and the GitHub Copilot instruction file. User-level it removes `~/.code-review-graph/` (registry + daemon state + logs), the OpenCode plugin, and our entry from every MCP / hooks config we ever write (Codex TOML, Cursor, Windsurf, Zed, Continue, Antigravity, Qwen, Copilot CLI). Surgical edits preserve unrelated entries — uninstalling code-review-graph never deletes another tool's MCP server or hook. Supports `--dry-run`, `--yes`, `--keep-data`, `--keep-user-configs`, `--repo PATH`, and `--all-repos`.

## [2.3.3] - 2026-05-08

Large additive release accumulated since v2.3.2 — 141 non-merge commits, 8 new languages/extensions, 5 new platform install targets, 6 new framework call resolvers, comprehensive Windows hardening, VS Code accessibility pass, and a full sweep of community PRs.
Expand Down
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,21 @@ Build the code review graph for this project

The initial build takes ~10 seconds for a 500-file project. After that, the graph updates automatically on every file edit and git commit.

### Uninstalling

Decided to stop using code-review-graph? A single command removes every artifact `install` ever wrote — graph database, generated skills, MCP entries, hooks, and the user-level registry — without touching unrelated entries other tools have written into the same config files.

```sh
code-review-graph uninstall # preview + confirm, then clean current repo + ~/
code-review-graph uninstall --dry-run # show every planned action, change nothing
code-review-graph uninstall --yes # skip the confirmation prompt
code-review-graph uninstall --all-repos # also sweep every repo in the registry
code-review-graph uninstall --keep-data # only remove configs, keep the graph DB
code-review-graph uninstall --keep-user-configs --repo . # only clean this repo
```

MCP entries, hook entries, and instruction-file sections are edited surgically: only the `code-review-graph` entry is removed; other servers, hooks, and content survive untouched.


## How It Works

Expand Down
88 changes: 88 additions & 0 deletions code_review_graph/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
Usage:
code-review-graph install
code-review-graph init
code-review-graph uninstall [--repo PATH] [--all-repos] [--keep-data]
[--keep-user-configs] [--dry-run] [--yes]
code-review-graph build [--base BASE]
code-review-graph update [--base BASE]
code-review-graph watch
Expand Down Expand Up @@ -440,6 +442,39 @@ def main() -> None:
help="Target platform for MCP config (default: all detected)",
)

# uninstall
uninstall_cmd = sub.add_parser(
"uninstall",
help=(
"Remove files installed by code-review-graph "
"(MCP configs, hooks, skills, graph DB, registry)."
),
)
uninstall_cmd.add_argument(
"--repo", default=None,
help="Repository root to clean up (default: current directory).",
)
uninstall_cmd.add_argument(
"--all-repos", action="store_true",
help="Also clean up every repo in ~/.code-review-graph/registry.json.",
)
uninstall_cmd.add_argument(
"--keep-data", action="store_true",
help="Keep the .code-review-graph/ data directories (only remove configs).",
)
uninstall_cmd.add_argument(
"--keep-user-configs", action="store_true",
help="Skip user-level (~/) configs; only clean the target repo(s).",
)
uninstall_cmd.add_argument(
"--dry-run", action="store_true",
help="Show what would be removed without changing anything.",
)
uninstall_cmd.add_argument(
"--yes", "-y", action="store_true",
help="Skip the confirmation prompt.",
)

# build
build_cmd = sub.add_parser("build", help="Full graph build (re-parse all files)")
build_cmd.add_argument("--repo", default=None, help="Repository root (auto-detected)")
Expand Down Expand Up @@ -811,6 +846,59 @@ def main() -> None:
print("Run 'code-review-graph eval --report' to generate tables.")
return

if args.command == "uninstall":
from .uninstall import run as run_uninstall

target_repo = Path(args.repo).expanduser().resolve() if args.repo else None
# Always do a dry-run first so we can show the user what we are
# about to do; ask for confirmation unless --yes (or --dry-run
# which doesn't need one).
preview = run_uninstall(
repo=target_repo,
all_repos=args.all_repos,
keep_data=args.keep_data,
keep_user_configs=args.keep_user_configs,
dry_run=True,
)
print("code-review-graph uninstall — planned actions:")
if not preview.removed_paths and not preview.edited_paths:
print(" (nothing to do — no code-review-graph artifacts found)")
return
for line in preview.removed_paths:
print(f" delete {line}")
for line in preview.edited_paths:
print(f" edit {line}")
for line in preview.skipped_paths:
print(f" skip {line}")
if args.dry_run:
print()
print("[dry-run] No changes made. Re-run without --dry-run to apply.")
return
if not args.yes and not _confirm_yes_no(
"\nProceed with uninstall?",
default_yes=False,
):
print("Aborted.")
return
result = run_uninstall(
repo=target_repo,
all_repos=args.all_repos,
keep_data=args.keep_data,
keep_user_configs=args.keep_user_configs,
dry_run=False,
)
print()
print(
f"Done. Removed {len(result.removed_paths)} path(s), "
f"edited {len(result.edited_paths)} config(s)."
)
if result.errors:
print("Errors:")
for err in result.errors:
print(f" {err}")
sys.exit(1)
return

if args.command in ("init", "install"):
_handle_init(args)
return
Expand Down
Loading