diff --git a/headroom/cli/wrap.py b/headroom/cli/wrap.py index 8911c883f..094454206 100644 --- a/headroom/cli/wrap.py +++ b/headroom/cli/wrap.py @@ -1710,8 +1710,10 @@ def _index_serena_project(*, verbose: bool = False) -> None: result = run( [ "uvx", + # PyPI (prebuilt wheels), not the git source that fails to build + # under proot-based filesystems (#2871). "--from", - "git+https://github.com/oraios/serena", + "serena-agent", "serena", "project", "index", diff --git a/headroom/mcp_registry/install.py b/headroom/mcp_registry/install.py index d8a9f7f09..e550f6ded 100644 --- a/headroom/mcp_registry/install.py +++ b/headroom/mcp_registry/install.py @@ -59,8 +59,11 @@ def build_serena_spec(context: str) -> ServerSpec: name="serena", command="uvx", args=( + # The PyPI package (serena-agent) ships prebuilt wheels; the git + # source forced a from-source build that fails under proot-based + # filesystems where uv cannot hardlink into a build venv (#2871). "--from", - "git+https://github.com/oraios/serena", + "serena-agent", "serena", "start-mcp-server", "--project-from-cwd", diff --git a/tests/test_cli/test_wrap_serena_boost.py b/tests/test_cli/test_wrap_serena_boost.py index 8a29086b3..bb08cd628 100644 --- a/tests/test_cli/test_wrap_serena_boost.py +++ b/tests/test_cli/test_wrap_serena_boost.py @@ -122,7 +122,9 @@ def test_preindex_runs_serena_in_cwd(tmp_path: Path, monkeypatch: pytest.MonkeyP cmd = args[0] assert cmd[0] == "uvx" assert cmd[-3:] == ["serena", "project", "index"] - assert "git+https://github.com/oraios/serena" in cmd + # PyPI package with prebuilt wheels, not the git source (#2871). + assert "serena-agent" in cmd + assert "git+https://github.com/oraios/serena" not in cmd assert kwargs["cwd"] == str(tmp_path) # invoked in the project cwd assert "timeout" in kwargs # timeout-guarded diff --git a/tests/test_mcp_registry/test_install.py b/tests/test_mcp_registry/test_install.py index 674199992..3e22e5b1e 100644 --- a/tests/test_mcp_registry/test_install.py +++ b/tests/test_mcp_registry/test_install.py @@ -89,8 +89,9 @@ def test_build_serena_spec_uses_agent_context() -> None: assert spec.name == "serena" assert spec.command == "uvx" assert spec.args == ( + # PyPI package with prebuilt wheels, not the git source (#2871). "--from", - "git+https://github.com/oraios/serena", + "serena-agent", "serena", "start-mcp-server", "--project-from-cwd", @@ -102,6 +103,15 @@ def test_build_serena_spec_uses_agent_context() -> None: assert spec.env == {} +def test_build_serena_spec_uses_pypi_not_git_source() -> None: + """Serena is installed from the PyPI package (prebuilt wheels), not the git + source, which forces a from-source build that fails under proot-based + filesystems where uv cannot hardlink into a build venv (#2871).""" + spec = build_serena_spec("codex") + assert "serena-agent" in spec.args + assert not any("git+" in arg for arg in spec.args) + + def test_build_serena_spec_disables_dashboard_popup_by_default() -> None: # Headroom installs Serena by default; the dashboard browser tab must not # auto-open. The flag overrides the user's serena_config.yml at startup,