# browseable

`browseable` is a Unix-style CLI backed by a local daemon that keeps browser sessions alive between commands.

## What it does

- API 1 (`elements`): given a session, list interactable form/navigation elements.
- API 2 (`action`): given a session, perform an action (`click`, `type`, or `interact`).

The daemon holds browser + page state so each CLI command is short-lived.

## Install

```bash
uv sync
uv run playwright install chromium
```

## Quick start

```bash
# Optional convenience.
alias browseable='uv run browseable'

# 1) start daemon
browseable daemon start

# 2) create a session (returns session ID)
browseable session create https://example.com/signup

# 3) list elements for that session
browseable elements <session_id>

# 4) focus an element
browseable action <session_id> click 2

# 5) type into an element
browseable action <session_id> type 3 "my@email.com"

# 6) open interactive browser window for the same session
browseable action <session_id> interact

# 7) close session + stop daemon
browseable session close <session_id>
browseable daemon stop
```

## Commands

```text
browseable daemon start|run|status|stop
browseable session create <url>
browseable session close <session_id>
browseable elements <session_id> [--json]
browseable action <session_id> click <element_or_index> [--timeout-ms]
browseable action <session_id> type <element_or_index> <text> [--timeout-ms]
browseable action <session_id> interact [--timeout-ms]
```

`interact` focuses the session in a real browser window. If daemon started headless, `interact` promotes the session into a headed browser context.

`BROWSEABLE_DAEMON_URL` can override the daemon address if needed.

## Daemon JSON API

The daemon exposes local HTTP endpoints:

- `POST /sessions` with `{"url":"..."}` -> create session.
- `GET /sessions/<session_id>/elements` -> list interactable elements.
- `POST /sessions/<session_id>/actions` with `{"action":"click"|"type","element_id":"...","text":"..."}`.
- `POST /sessions/<session_id>/actions` with `{"action":"interact"}` -> promote/focus session in a headed browser window.
- `DELETE /sessions/<session_id>` -> close session.

## E2E Example

Run the telemetry register flow:

```bash
uv run scripts/e2e_telemetry_register.sh
```

## GitHub Workflows

- `/.github/workflows/ci.yml`: compile + CLI smoke checks on `push`/`pull_request`.
- `/.github/workflows/publish-testpypi.yml`: manual publish to TestPyPI.
- `/.github/workflows/publish-pypi.yml`: publish to PyPI on `v*` tags (or manual dispatch).

## How to Publish to PyPI

1. Create package projects:
   - [https://test.pypi.org/](https://test.pypi.org/)
   - [https://pypi.org/](https://pypi.org/)
2. Configure Trusted Publishing on each project:
   - Owner/repo: your GitHub repo.
   - Workflow file:
     - TestPyPI: `.github/workflows/publish-testpypi.yml`
     - PyPI: `.github/workflows/publish-pypi.yml`
   - Environment name:
     - TestPyPI: `testpypi`
     - PyPI: `pypi`
3. Test release on TestPyPI by running `Publish to TestPyPI` (workflow dispatch).
4. Release to PyPI:
   - Bump version in `pyproject.toml`.
   - Commit and push.
   - Tag and push `vX.Y.Z` (must match `pyproject.toml` version).
5. Verify install:

```bash
python -m pip install browseable==0.1.1
```

### Optional Manual Publish (No GitHub Actions)

```bash
uv build
uvx twine check dist/*
uvx twine upload dist/*
```

For manual upload, create a PyPI API token and use `TWINE_USERNAME=__token__` and `TWINE_PASSWORD=<token>` (or `~/.pypirc`).
