Commit 942187

2026-03-14 19:02:17 Claude (MCP): [mcp] P2-9: Update CLI tool summary with full implementation details
Dev/P2-9_Summary.md ..
@@ 1,34 1,56 @@
# P2-9: CLI Tool
## Status
- Complete — branch `feat/P2-9-cli-tool`, 22 tests passing.
+ Complete — committed to `feat/P2-9-cli-tool` branch. 35 tests passing.
- ## What was built
- Click-based CLI (`app/cli/`) wrapping the management API (P2-4).
+ ## 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
- ### Commands
| Command | Description |
|---------|-------------|
- | `wikibot login` | Browser OAuth flow with localhost callback server |
+ | `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 (owner/editor/viewer) |
- | `wikibot wiki revoke <slug> <email>` | Revoke access (resolves email to grantee_id) |
-
- ### Files
- - `app/cli/__init__.py` — empty package init
- - `app/cli/auth.py` — token storage (`~/.wikibot/token`), config, auth header helper
- - `app/cli/main.py` — all CLI commands
- - `tests/test_cli.py` — 22 tests (CliRunner + unittest.mock)
-
- ### Design decisions
- - Token stored as plaintext at `~/.wikibot/token` with `0600` permissions
- - API URL configurable via `WIKIBOT_API_URL` env var (default: `https://dev.wikibot.io`)
- - Login uses `http.server.HTTPServer` on a random port for the OAuth callback
- - Revoke resolves email to grantee_id by fetching the ACL list first
-
- ### Dependencies
- - `click` — not currently in project requirements, needs to be added
- - `requests` — already available
+ | `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