# P2-9: CLI Tool

## Status
Complete — committed to `feat/P2-9-cli-tool` branch. 35 tests passing.

## Deliverables

| File | Description |
|------|-------------|
| `app/cli/__init__.py` | Package init |
| `app/cli/__main__.py` | `python -m app.cli` entry point |
| `app/cli/auth.py` | Token storage (save/load/expiry), API URL config, auth header helper |
| `app/cli/http.py` | HTTP wrapper with consistent error handling (401/403/404 messages) |
| `app/cli/main.py` | Click CLI group with all subcommands |
| `app/management/routes.py` | Added `POST /admin/auth/callback` (unauthenticated login endpoint) |
| `tests/test_cli.py` | 35 tests covering all commands and error paths |

## Commands

| Command | Description |
|---------|-------------|
| `wikibot login` | Browser OAuth flow → WorkOS AuthKit → localhost callback → exchange code → store JWT. Prompts for username if `needs_username` is true. |
| `wikibot wiki create <slug>` | Create wiki (options: `--name`, `--purpose`) |
| `wikibot wiki list` | List wikis in table format |
| `wikibot wiki delete <slug>` | Delete wiki (confirmation prompt, `--yes` to skip) |
| `wikibot wiki token <slug>` | Regenerate MCP token |
| `wikibot wiki grant <slug> <email> <role>` | Grant access (editor/viewer only) |
| `wikibot wiki revoke <slug> <email>` | Revoke access (resolves email → grantee_id via ACL list) |
| `wikibot wiki acl <slug>` | List access grants in table format |

## Configuration

- `WIKIBOT_API_URL` — Base URL (default: `https://dev.wikibot.io`)
- `WIKIBOT_WORKOS_CLIENT_ID` — WorkOS client ID (required for login)
- `WIKIBOT_WORKOS_AUTHKIT_DOMAIN` — WorkOS AuthKit domain (required for login)
- JWT stored at `~/.wikibot/token` with 0600 permissions

## Architecture Decisions

- **HTTP wrapper (`http.py`)** provides `api_request()` and `handle_response()` for consistent error handling across all commands.
- **Login flow** constructs the WorkOS auth URL client-side using env vars, rather than redirecting through the server.
- **Auth callback** added as unauthenticated route in management middleware (`POST /admin/auth/callback`), since it IS the login endpoint.
- **Grant command** restricts roles to editor/viewer only (matching the management API's validation).
- **Revoke command** resolves email to grantee_id by fetching the ACL list first.

## Test Coverage (35 tests)

- Auth module: 7 (save/load/empty/missing token, auth header, API URL)
- HTTP module: 6 (auth injection, no-auth, response handling 200/401/403/404)
- Login: 4 (success, needs_username, exchange failure, missing env vars)
- Wiki CRUD: 10 (create success/purpose/error, list/empty, delete confirm/flag/abort)
- Token: 1
- Grant: 3 (success, invalid role, owner role rejected)
- Revoke: 2 (success, email not found)
- ACL list: 2 (with entries, empty)
- Error handling: 2 (401 message, network error)
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9