|
| 1 | +# teams-cli |
| 2 | + |
| 3 | +Rust CLI for Microsoft Teams — agent-first design via Microsoft Graph API. |
| 4 | + |
| 5 | +## Build Commands |
| 6 | + |
| 7 | +```bash |
| 8 | +cargo build # Debug build |
| 9 | +cargo build --release # Release build |
| 10 | +cargo check # Type check only |
| 11 | +cargo test --all-targets # All tests (unit + integration) |
| 12 | +cargo test --lib --bins # Unit tests only |
| 13 | +cargo test --features integration # Integration tests (needs auth) |
| 14 | +cargo fmt -- --check # Check formatting |
| 15 | +cargo clippy --all-targets -- -D warnings # Lint |
| 16 | +``` |
| 17 | + |
| 18 | +## Architecture |
| 19 | + |
| 20 | +Single-crate Rust binary. Key modules: |
| 21 | + |
| 22 | +- `src/main.rs` — Entry point, tracing init, config load, CLI dispatch |
| 23 | +- `src/cli/` — Clap command definitions and handlers |
| 24 | + - `auth.rs` — login (PKCE, device code, client credentials), status, list, switch, logout, token |
| 25 | + - `team.rs` — list, get, create, update, delete, clone, archive, unarchive, members |
| 26 | + - `channel.rs` — list, get, create, update, delete, members |
| 27 | + - `message.rs` — send, list, get, reply, delete, react, unreact, pin, unpin |
| 28 | + - `chat.rs` — list, get, create, hide, unhide, members |
| 29 | + - `presence.rs` — get, set, clear, status, get-batch |
| 30 | + - `search.rs` — messages, users, teams |
| 31 | + - `tag.rs` — list, get, create, delete, add-member, remove-member |
| 32 | + - `meeting.rs` — list, get, create, delete, join-url, attendance |
| 33 | + - `notification.rs` — send, send-to-team, send-to-chat |
| 34 | + - `app.rs` — list, install, uninstall |
| 35 | + - `tab.rs` — list, create, delete |
| 36 | + - `file.rs` — list, get, upload, download, delete, share |
| 37 | + - `subscribe.rs` — create, list, renew, delete |
| 38 | + - `listen.rs` — webhook listener entry point |
| 39 | + - `config_cmd.rs` — init, show, get, set, path |
| 40 | + - `user.rs` — me, get, list |
| 41 | +- `src/api/` — Microsoft Graph HTTP client and endpoint wrappers |
| 42 | + - `client.rs` — GraphClient with retry/backoff, rate-limit handling, pagination |
| 43 | + - `endpoints.rs` — URL builders for all Graph API endpoints |
| 44 | + - `teams.rs`, `channels.rs`, `messages.rs`, `chats.rs`, `presence.rs`, `search.rs`, `tags.rs`, `meetings.rs`, `notifications.rs`, `apps.rs`, `files.rs`, `subscriptions.rs`, `users.rs` |
| 45 | +- `src/models/` — Serde data models for Graph API resources |
| 46 | + - `team.rs`, `channel.rs`, `message.rs`, `chat.rs`, `presence.rs`, `search.rs`, `tag.rs`, `meeting.rs`, `notification.rs`, `app.rs`, `file.rs`, `subscription.rs`, `member.rs`, `user.rs`, `common.rs` |
| 47 | +- `src/listen/` — Webhook listener HTTP server |
| 48 | + - `mod.rs` — hyper server with Ctrl+C graceful shutdown |
| 49 | + - `handler.rs` — validation token echo, NDJSON notification output, health check |
| 50 | +- `src/auth/` — Authentication flows and token management |
| 51 | + - `auth_code_pkce.rs` — Authorization Code + PKCE (browser flow) |
| 52 | + - `device_code.rs` — Device Code flow |
| 53 | + - `client_credentials.rs` — Client Credentials flow |
| 54 | + - `token.rs` — TokenInfo struct, expiry checking |
| 55 | + - `keyring.rs` — OS keyring storage (macOS Keychain, Windows Credential Manager, Linux Secret Service) |
| 56 | +- `src/output/` — Output formatters (JSON envelope, human tables, plain text) |
| 57 | +- `src/config.rs` — TOML config file management, profile/credential resolution |
| 58 | +- `src/error.rs` — TeamsError enum with exit codes per PRD |
| 59 | + |
| 60 | +## Key Design Patterns |
| 61 | + |
| 62 | +### Output Contract |
| 63 | +All commands emit a JSON envelope: `{ "success": bool, "data": ..., "metadata": { "request_id", "timestamp", "duration_ms" } }`. |
| 64 | +When stdout is a TTY, defaults to human-readable table format. When piped, defaults to JSON. |
| 65 | + |
| 66 | +### Exit Codes |
| 67 | +0=success, 1=general, 2=invalid input, 3=auth, 4=permission denied, 5=not found, 6=rate limited, 7=network, 8=server error, 10=config error |
| 68 | + |
| 69 | +### Credential Resolution |
| 70 | +CLI flags > env vars (TEAMS_CLI_CLIENT_ID, TEAMS_CLI_CLIENT_SECRET, TEAMS_CLI_TENANT_ID) > config file profiles |
| 71 | + |
| 72 | +### Token Management |
| 73 | +- Login stores tokens in OS keyring via `keyring` crate |
| 74 | +- Subsequent commands load tokens from keyring — no re-login needed |
| 75 | +- Multiple named profiles supported (--profile flag) |
| 76 | +- Profile index tracked in keyring for `auth list` |
| 77 | + |
| 78 | +### Graph API Client |
| 79 | +- Automatic retry with exponential backoff on 429/5xx |
| 80 | +- Respects `Retry-After` header for rate limiting |
| 81 | +- Pagination via `@odata.nextLink` with `--all-pages` flag |
| 82 | +- `$top` parameter for page size control |
| 83 | + |
| 84 | +### Webhook Listener |
| 85 | +- `teams listen --port 8080` starts a hyper HTTP server |
| 86 | +- Handles Graph subscription validation (echoes `?validationToken`) |
| 87 | +- Outputs change notifications as NDJSON to stdout |
| 88 | +- Multi-connection, graceful Ctrl+C shutdown |
| 89 | +- Requires HTTPS via reverse proxy (ngrok) for production use |
| 90 | + |
| 91 | +## Environment Variables |
| 92 | +- `TEAMS_CLI_CLIENT_ID` — Azure AD application (client) ID |
| 93 | +- `TEAMS_CLI_CLIENT_SECRET` — Azure AD client secret |
| 94 | +- `TEAMS_CLI_TENANT_ID` — Azure AD tenant ID |
| 95 | +- `TEAMS_CLI_ACCESS_TOKEN` — Pre-obtained access token |
| 96 | +- `RUST_LOG` — Tracing filter level |
| 97 | + |
| 98 | +## Config |
| 99 | +- Config file: `~/.config/teams-cli/config.toml` (Linux) or `~/Library/Application Support/teams-cli/config.toml` (macOS) |
| 100 | +- Profiles define client_id, tenant_id, auth_flow per account |
| 101 | +- Network section: timeout, max_retries, retry_backoff_base |
| 102 | +- Output section: format, color, page_size |
0 commit comments