# 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)