diff --git a/src/ucode/agents/claude.py b/src/ucode/agents/claude.py index d5bcd6f..d0d0380 100644 --- a/src/ucode/agents/claude.py +++ b/src/ucode/agents/claude.py @@ -398,10 +398,10 @@ def _ensure_mlflow_cli() -> bool: return False print_note(f"{'Replacing' if current else 'Installing'} the mlflow CLI ({MLFLOW_CLI_SPEC})...") - # --force replaces an existing (out-of-range) uv-managed mlflow in place. - cmd = ["uv", "tool", "install", MLFLOW_CLI_SPEC] - if current: - cmd.append("--force") + # Always --force: it installs fresh when absent and replaces in place when + # present. Keying it on `current` broke when an mlflow existed but its + # version couldn't be parsed — uv still errors "Executable already exists". + cmd = ["uv", "tool", "install", "--force", MLFLOW_CLI_SPEC] try: subprocess.run(cmd, check=True, timeout=600) except (OSError, subprocess.CalledProcessError, subprocess.TimeoutExpired) as exc: diff --git a/tests/test_tracing.py b/tests/test_tracing.py index 9170f5f..088b2e1 100644 --- a/tests/test_tracing.py +++ b/tests/test_tracing.py @@ -650,7 +650,9 @@ def test_installs_when_missing(self, monkeypatch): cmd = run.call_args[0][0] assert cmd[:3] == ["uv", "tool", "install"] assert claude.MLFLOW_CLI_SPEC in cmd - assert "--force" not in cmd + # Always --force so an unparseable-version mlflow on disk doesn't trip + # uv's "Executable already exists" error. + assert "--force" in cmd def test_force_replaces_when_below_minimum(self, monkeypatch): monkeypatch.setattr(claude, "_installed_mlflow_version", lambda: (3, 4))