Metadata-Version: 2.4
Name: tokenmaxxr
Version: 1.0.0
Summary: Aggregate AI subscription quota usage (OpenCode Go, ClinePass, Ollama Cloud) into one view.
Project-URL: Homepage, https://github.com/Izzur/tokenmaxxr
Project-URL: Bug Tracker, https://github.com/Izzur/tokenmaxxr/issues
Author-email: Izzur <13365626+Izzur@users.noreply.github.com>
Maintainer-email: Izzur <13365626+Izzur@users.noreply.github.com>
License: MIT
License-File: LICENSE
Keywords: ai,cline,fastfetch,ollama,opencode,quota,usage,waybar
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Utilities
Requires-Python: >=3.10
Requires-Dist: beautifulsoup4>=4.12
Requires-Dist: browser-cookie3>=0.20
Requires-Dist: requests>=2.31
Provides-Extra: dev
Requires-Dist: httpx>=0.27; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=8; extra == 'dev'
Provides-Extra: serve
Requires-Dist: fastapi>=0.110; extra == 'serve'
Requires-Dist: uvicorn>=0.27; extra == 'serve'
Description-Content-Type: text/markdown

# tokenmaxxr

Aggregate AI subscription quota usage (OpenCode Go, ClinePass, Ollama Cloud) into one view.

Three providers, one engine, one versioned JSON contract. CLI for bars/dashboards, optional WebUI, optional HTTP API.

## Install

```bash
# from PyPI (recommended)
uvx tokenmaxxr --json

# from source
git clone https://github.com/Izzur/tokenmaxxr
cd tokenmaxxr
uv pip install -e ".[serve]"  # add [serve] for `tokenmaxxr serve`
```

## Quickstart

```bash
tokenmaxxr              # human table
tokenmaxxr --json       # machine-readable schema:1
tokenmaxxr --refresh    # bypass the 300s cache
tokenmaxxr doctor       # diagnose cookie discovery
tokenmaxxr serve        # WebUI + HTTP API
```

## Web UI

`tokenmaxxr serve` (requires `pip install 'tokenmaxxr[serve]'`) starts a small FastAPI app on `127.0.0.1:8765`:

- `GET  /api/usage`   — schema:1 document (same as `tokenmaxxr --json`)
- `POST /api/refresh` — force a live re-fetch
- `GET  /api/history?provider=&window=` — appended history rows
- `GET  /`           — vanilla-JS dashboard (cards + history chart, opt-in 60s auto-refresh)

The dashboard degrades gracefully: with no cookies, every card shows `no-auth` and a hint.

## Output contract

`tokenmaxxr --json` returns a stable, versioned document:

```json
{
  "schema": 1,
  "fetched_at": "2026-07-22T12:00:00Z",
  "providers": [
    {
      "id": "ollama-cloud",
      "name": "Ollama Cloud",
      "status": "ok",
      "windows": [
        {"label": "5h", "pct_used": 47, "reset_at": "2026-07-22T20:00:00Z"}
      ]
    }
  ]
}
```

`status` is one of `ok` | `stale` | `no-auth` | `error`.

## Cookie sources

1. `--cookie-file SLUG=/path/to/cookies.sqlite` or `TOKENMAXXR_COOKIE_<DOMAIN>` env
2. Firefox-family stores (globbed: `~/.mozilla/firefox/*`, `~/.zen/*`, Zen/Firefox Flatpak paths, Floorp/LibreWolf/Waterfox)
3. Chromium-family via `browser_cookie3` (best-effort, locked keyring → skip)
4. No match → `no-auth` status + remediation in `doctor`

Cookies are copied to a temp file before reading (WAL lock-safe). Cache and history live under `~/.local/state/tokenmaxxr/`.

## Waybar

```json
"custom/tokenmaxxr": {
  "exec": "tokenmaxxr --json --provider ollama-cloud",
  "return-type": "json",
  "format": "Ollama 5h: {}%",
  "exec-on-event": true,
  "interval": 600
}
```

`--json` is the stable schema:1 contract — `jq '.providers[0].windows[0].pct_used'` always returns an integer.

## fastfetch

```text
"tokenmaxxr": {
  "type": "command",
  "key": "TKN",
  "command": "tokenmaxxr --json | jq -r '.providers[] | select(.status==\"ok\") | \"\\(.id): \\(.windows[0].pct_used)%\"' | paste -sd, -"
}
```

## Headless / `--cookie-file`

```bash
tokenmaxxr --cookie-file ollama-cloud=/srv/cookies/ollama.sqlite --json
# or
TOKENMAXXR_COOKIE_OLLAMA_COM=/srv/cookies/ollama.sqlite tokenmaxxr --json

## Development

```bash
uv sync --extra dev           # set up dev deps (pytest, fastapi, etc.)
uv run python3 -m pytest      # 32 tests, <1s
uv run python3 -m pytest tests/test_providers.py -v   # one file
```

Provider parser tests live in `tests/test_providers.py` against HTML/JSON
fixtures under `tests/fixtures/`. To add a fixture, drop a real captured
payload into `tests/fixtures/<slug>.<ext>` and write a `test_<slug>` that
feeds it through `RawHtml` and asserts on the parsed `UsageWindow`s.

## License

MIT
