# xnv — Python Virtual Environment Doctor

Diagnose and fix broken Python virtual environments, stale poetry locks, and pip issues.

## Install

```bash
pip install -e .
```

## Usage

```bash
# Diagnose environment health
xnv doctor

# Diagnose a specific project
xnv doctor /path/to/project

# Auto-fix all issues (recreate broken venv + install deps)
xnv fix

# Force recreate venv even if healthy
xnv fix --force

# Fix without installing dependencies
xnv fix --no-install

# Fix with dev dependencies
xnv fix --dev

# Remove venv completely
xnv nuke

# Create fresh venv
xnv create

# Regenerate poetry.lock
xnv lock
```

## What it detects

| Code | Severity | Description |
|---|---|---|
| `VENV_BROKEN_PYTHON` | error | Python symlink points to missing target |
| `VENV_NO_PYTHON` | error | Python binary missing from venv |
| `VENV_PYTHON_FAIL` | error | Python binary not executable |
| `VENV_BROKEN_PIP` | error | pip symlink broken |
| `VENV_NO_PIP` | error | pip binary missing |
| `VENV_PIP_FAIL` | error | pip not functional |
| `VENV_PIP_SHIM_BROKEN` | error | pip shim broken but `python -m pip` works |
| `VENV_STALE_HOME` | error | pyvenv.cfg points to missing Python install |
| `POETRY_LOCK_STALE` | error | poetry.lock out of sync with pyproject.toml |
| `NO_VENV` | warn | No virtual environment found |
| `VENV_MISMATCH` | warn | Active VIRTUAL_ENV differs from project venv |
| `NO_PYPROJECT` | warn | No pyproject.toml found |
| `CONDA_ACTIVE` | info | Conda environment detected |

## What `xnv fix` does

1. Runs full diagnosis
2. If poetry.lock is stale → `poetry lock`
3. If venv is broken → removes and recreates with system Python
4. Installs dependencies via Poetry (preferred) or pip
5. Verifies the fix

## Python API

```python
from xnv.diagnose import diagnose
from xnv.fix import fix

# Diagnose
diag = diagnose("/path/to/project")
print(diag.healthy)  # True/False
for issue in diag.issues:
    print(f"[{issue.severity}] {issue.code}: {issue.message}")

# Fix
ok = fix("/path/to/project", force_recreate=False, install=True, dev=False)
```

## License

MIT
