# cli-framework

Shared Typer/Rich/Loguru CLI patterns

## Installation

### From DevPi (private registry)

```bash
uv add cli-framework
```

> Requires the DevPi index to be configured in `~/.config/uv/uv.toml`:
> ```toml
> index-strategy = "unsafe-best-match"
>
> [[index]]
> name = "devpi"
> url = "https://pypi.registry.hochguertel.work/root/dev/+simple/"
> ```

### From source (monorepo)

```bash
git clone https://pastoral-oyster.pikapod.net/tools/ai-session-tools.git
cd ai-session-tools
uv sync --all-packages
```

## Usage

`cli-framework` provides a `create_app()` factory, a singleton `Console` with
`NO_COLOR`/`FORCE_COLOR` support, a typed `AppContext` for Typer commands,
reusable color option types, and Loguru logging setup.

```python
import typer
from cli_framework import (
    create_app,
    get_console,
    AppContext,
    NoColorOption,
    ForceColorOption,
    setup_logging,
)

app = create_app(
    name="my-cli",
    help="My CLI app.",
)


@app.callback()
def main(
    ctx: typer.Context,
    no_color: NoColorOption = False,
    color: ForceColorOption = False,
    verbose: bool = typer.Option(False, "--verbose", "-v"),
) -> None:
    """My CLI app."""
    setup_logging(verbose)
    ctx.obj = AppContext(console=get_console(), verbose=verbose)


@app.command()
def greet(ctx: typer.Context, name: str = typer.Argument("world")) -> None:
    """Greet someone."""
    console = ctx.obj.console
    console.print(f"Hello, {name}!")


if __name__ == "__main__":
    app()
```

Apps that need additional context fields can subclass `AppContext`:

```python
from dataclasses import dataclass

@dataclass
class MyAppContext(AppContext):
    debug: bool = False
    dry_run: bool = False
```

## Development

```bash
# Run tests
uv run pytest libs/cli-framework/tests/

# Lint
uv run ruff check libs/cli-framework/

# Type check
uv run mypy
```

## License

MIT
