From aaa97ef3223799f1232c97081e9bfcada5640d78 Mon Sep 17 00:00:00 2001 From: Sasan Date: Thu, 23 Apr 2026 10:53:38 -0400 Subject: [PATCH 1/2] fix: align get_docs_section with serve --repo and validate paths - get_docs_section_tool: pass repo_root through _resolve_repo_root() so code-review-graph serve --repo applies like other MCP tools. - get_docs_section: only search under _validate_repo_root (explicit) or find_project_root (default); drop unvalidated Path(repo_root) scan. - Test: add .code-review-graph to tmp fixture so explicit repo_root passes validation. - Update _resolve_repo_root docstring to match current behavior. --- code_review_graph/main.py | 11 +++++++---- code_review_graph/tools/docs.py | 18 ++++++++---------- tests/test_tools.py | 1 + 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/code_review_graph/main.py b/code_review_graph/main.py index 733336e1..f299c055 100644 --- a/code_review_graph/main.py +++ b/code_review_graph/main.py @@ -68,9 +68,9 @@ def _resolve_repo_root(repo_root: Optional[str]) -> Optional[str]: (captured in ``_default_repo_root``). 3. None — the underlying impl will fall back to the server's cwd. - Previously, only ``get_docs_section_tool`` consulted ``_default_repo_root``, - so ``serve --repo `` had no effect for the other 21 tools. See: #222 - follow-up. + All MCP tools that accept ``repo_root`` should use this helper so + ``serve --repo `` applies consistently, including + ``get_docs_section_tool``. See: #222. """ return repo_root if repo_root else _default_repo_root @@ -378,7 +378,10 @@ def get_docs_section_tool( section_name: The section to retrieve (e.g. "review-delta", "usage"). repo_root: Repository root path. Auto-detected if omitted. """ - return get_docs_section(section_name=section_name, repo_root=repo_root) + return get_docs_section( + section_name=section_name, + repo_root=_resolve_repo_root(repo_root), + ) @mcp.tool() diff --git a/code_review_graph/tools/docs.py b/code_review_graph/tools/docs.py index ce47b31c..44d1e97b 100644 --- a/code_review_graph/tools/docs.py +++ b/code_review_graph/tools/docs.py @@ -6,8 +6,8 @@ from typing import Any from ..embeddings import EmbeddingStore, embed_all_nodes -from ..incremental import get_db_path -from ._common import _get_store +from ..incremental import find_project_root, get_db_path +from ._common import _get_store, _validate_repo_root # --------------------------------------------------------------------------- # Tool 7: embed_graph @@ -110,14 +110,12 @@ def get_docs_section( search_roots: list[Path] = [] if repo_root: - search_roots.append(Path(repo_root)) - - try: - _, root = _get_store(repo_root) - if root not in search_roots: - search_roots.append(root) - except (RuntimeError, ValueError): - pass + try: + search_roots.append(_validate_repo_root(Path(repo_root))) + except ValueError: + pass + else: + search_roots.append(find_project_root()) # Fallback: package directory (for uvx/pip installs) pkg_docs = ( diff --git a/tests/test_tools.py b/tests/test_tools.py index 68b69834..a9fbc64b 100644 --- a/tests/test_tools.py +++ b/tests/test_tools.py @@ -155,6 +155,7 @@ class TestGetDocsSection: """Tests for the get_docs_section tool.""" def test_explicit_repo_root_uses_that_docs_file(self, tmp_path): + (tmp_path / ".code-review-graph").mkdir() docs_dir = tmp_path / "docs" docs_dir.mkdir() (docs_dir / "LLM-OPTIMIZED-REFERENCE.md").write_text( From 4405115ee2af7753893aa68bb3a3c7a6439a84b3 Mon Sep 17 00:00:00 2001 From: Sasan Date: Thu, 23 Apr 2026 11:13:04 -0400 Subject: [PATCH 2/2] docs: troubleshoot pipx/PyPI failures; add pypi diagnostic script - README: hatchling/Errno 9, try Terminal.app, uv tool install, or uv sync - scripts/diagnose_pypi_connectivity.py: one-shot check; suggests uv on failure - Remove reliance on unvalidated pipx-only instructions when TLS is broken --- README.md | 18 ++++++++ scripts/diagnose_pypi_connectivity.py | 62 +++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 scripts/diagnose_pypi_connectivity.py diff --git a/README.md b/README.md index 07249031..1452f0e7 100644 --- a/README.md +++ b/README.md @@ -472,6 +472,24 @@ all tools are available. This is especially useful for MCP client configurations ## Troubleshooting +### `pip` / `pipx` cannot download `hatchling` (or `Errno 9` / `Bad file descriptor` to PyPI) + +Installing from a **source tree** (for example `pipx install .`) needs build dependencies from **PyPI** (for example `hatchling`). If you see `Could not find a version that satisfies the requirement hatchling` after connection warnings, the Python/pip in that **terminal** may not be able to open an HTTPS client to `pypi.org` (sometimes seen in an integrated editor terminal; less often system-wide with VPN, firewall, or proxy). + +**Options:** + +1. Run the same command from **macOS Terminal.app** (or iTerm) instead of the IDE’s terminal, then retry `pipx install .` or `pipx install "git+https://..."` . +2. Use **[uv](https://docs.astral.sh/uv/)** to install the CLI from a checkout (uses different download machinery than `pip` in many cases): + + ```bash + cd /path/to/code-review-graph + uv tool install . --force + ``` + +3. For **development in a clone** without a global install, use `uv sync` and `uv run code-review-graph …` (or activate `.venv` after `uv sync`). + +**Diagnose (optional):** `python3 scripts/diagnose_pypi_connectivity.py` — if it prints `FAILED`, the issue is environment/network, not a wrong package name in this repo. + ### Windows Configuration Issues (Invalid JSON / Connection Closed) If you are using Windows and encounter `Invalid JSON: EOF while parsing` or `MCP error -32000: Connection closed` when connecting via Claude Code, do not use the `cmd /c` wrapper in your config. diff --git a/scripts/diagnose_pypi_connectivity.py b/scripts/diagnose_pypi_connectivity.py new file mode 100644 index 00000000..059b3cfb --- /dev/null +++ b/scripts/diagnose_pypi_connectivity.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python3 +"""Check whether this Python can reach PyPI (same path pip/pipx use for hatchling, etc.). + +If TLS to pypi.org fails (e.g. Errno 9 in some IDE terminals), a user-wide +install from a git checkout may still work via uv (different downloader): + + uv tool install /path/to/code-review-graph --force + +Run: python3 scripts/diagnose_pypi_connectivity.py +""" +from __future__ import annotations + +import json +import os +import socket +import ssl +import sys +import time +import urllib.error +import urllib.request + + +def main() -> int: + ok_tls = _try_tls_pypi() + ok_url = _try_urllib() + if ok_tls and ok_url: + print("PyPI check: OK (this Python can use HTTPS to pypi.org).") + return 0 + print("PyPI check: FAILED (pip/pipx may be unable to download build deps like hatchling).") + print("Workaround: from the repo root, with https://github.com/astral-sh/uv installed:") + print(' uv tool install . --force') + print("Or run pipx from macOS Terminal.app (outside the IDE) if the failure is terminal-specific.") + return 1 + + +def _try_tls_pypi() -> bool: + try: + ctx = ssl.create_default_context() + with socket.create_connection(("pypi.org", 443), timeout=15) as sock: + with ctx.wrap_socket(sock, server_hostname="pypi.org") as tsock: + return bool(tsock.version()) + except OSError as e: + print(f" TLS pypi.org:443 -> {e!r}", file=sys.stderr) + return False + + +def _try_urllib() -> bool: + try: + req = urllib.request.Request( + "https://pypi.org/simple/hatchling/", + headers={"User-Agent": "code-review-graph-diagnostic/1.0"}, + ) + with urllib.request.urlopen(req, timeout=30) as resp: + resp.read(256) + return True + except (urllib.error.URLError, OSError) as e: + print(f" urllib hatchling index -> {e!r}", file=sys.stderr) + return False + + +if __name__ == "__main__": + raise SystemExit(main())