feat: add support for GCC cloud environment and update endpoints#2
feat: add support for GCC cloud environment and update endpoints#2TheSethRose wants to merge 1 commit intofoeken:mainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
This pull request introduces centralized endpoint management to support multiple Microsoft cloud environments, specifically adding Office 365 US Government (GCC) support. The implementation replaces 25+ hardcoded URLs across the codebase with dynamic endpoint constants that can be switched via the --gcc CLI flag or CLIPPY_CLOUD environment variable.
Changes:
- Created centralized endpoint configuration module with support for commercial and GCC cloud environments
- Added
--gccCLI flag and dynamic import pattern to allow environment selection before module initialization - Added
--no-headlessoption for browser control during authentication (login command only)
Reviewed changes
Copilot reviewed 9 out of 10 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| src/lib/endpoints.ts | New centralized endpoint configuration supporting commercial and GCC cloud environments |
| src/cli.ts | Pre-parses --gcc flag before imports, uses dynamic imports for environment-aware initialization |
| src/lib/auth.ts | Updated to use endpoint constants, added headless parameter support |
| src/lib/owa-client.ts | Replaced 25+ hardcoded URLs with endpoint constants (OUTLOOK_BASE, OUTLOOK_API, GRAPH_BASE) |
| src/commands/login.ts | Uses endpoint constants, added --no-headless option |
| src/commands/find.ts | Updated to use OUTLOOK_API constant |
| src/commands/drafts.ts | Updated to use OUTLOOK_API constant |
| .env.example | New configuration template documenting CLIPPY_CLOUD and CLIPPY_TOKEN variables |
| .gitignore | Added .env.local, .env.*.local patterns and .claude/ directory |
| README.md | Added cloud environment configuration section and updated documentation |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| @@ -1,27 +1,36 @@ | |||
| #!/usr/bin/env bun | |||
There was a problem hiding this comment.
The export {} statement on line 2 appears to be a workaround to make this file a module. However, it's not clear why this is needed since the file already uses ES modules with dynamic imports. Consider adding a comment explaining why this empty export is necessary, or remove it if it's not required.
| #!/usr/bin/env bun | |
| #!/usr/bin/env bun | |
| // Ensure TypeScript treats this file as an ES module so that top-level await is allowed. |
| const playwrightResult = await extractTokenViaPlaywright(); | ||
| const playwrightResult = await extractTokenViaPlaywright({ | ||
| headless: headless !== undefined ? headless : true, | ||
| fallbackToVisible: headless !== false, |
There was a problem hiding this comment.
The logic for fallbackToVisible could be clearer. The expression headless !== false is confusing. Consider using fallbackToVisible: headless !== false with a comment explaining the logic, or more explicitly: fallbackToVisible: (headless === undefined || headless === true). This makes it clearer that fallback only happens when the user hasn't explicitly requested non-headless mode.
| fallbackToVisible: headless !== false, | |
| // Allow fallback to visible mode unless the user explicitly requested non-headless | |
| fallbackToVisible: headless === undefined || headless === true, |
| .option('--no-headless', 'Show the browser window (don\'t run headless)') | ||
| .option('--check', 'Only check if session is valid, do not save') | ||
| .action(async (options: { token?: string; interactive?: boolean; check?: boolean }) => { | ||
| .action(async (options: { token?: string; interactive?: boolean; headless?: boolean; check?: boolean }) => { |
There was a problem hiding this comment.
The --no-headless option was only added to the login command, but other commands like calendar, mail, send, etc. also support the --interactive flag and call resolveAuth. For consistency, all commands that support --interactive should also support --no-headless and pass the headless parameter to resolveAuth. Otherwise, users cannot control browser visibility when using interactive auth with other commands.
| --json # Output as JSON (for scripting) | ||
| --token <token> # Use a specific token | ||
| -i, --interactive # Force interactive browser login | ||
| --no-headless # Show the browser window during login (don't run headless) |
There was a problem hiding this comment.
The documentation states "All commands support: --no-headless" but this option was only added to the login command. This creates a discrepancy between the documentation and the implementation. Either update the documentation to clarify that --no-headless only works with the login command, or add the option to all commands that support --interactive.
| program.addCommand(sendCommand); | ||
| program.addCommand(draftsCommand); | ||
|
|
||
| if (CLOUD_ENV === 'gcc') { |
There was a problem hiding this comment.
The GCC cloud notification message is logged every time the CLI runs in GCC mode, including when displaying help or running any command. While this provides visibility, it could be verbose. Consider whether this message should only appear for authentication-related operations (login, refresh, etc.) or if the current behavior is intentional for cloud environment awareness.
| if (CLOUD_ENV === 'gcc') { | |
| const authCommands = ['login', 'refresh', 'keepalive']; | |
| if (CLOUD_ENV === 'gcc' && authCommands.includes(process.argv[2] ?? '')) { |
| | `CLIPPY_CLOUD` | `commercial`, `gcc` | `commercial` | Microsoft cloud environment | | ||
| | `CLIPPY_TOKEN` | Bearer token string | — | Skip browser login with a token directly | | ||
|
|
||
| ### Cloud Environments | ||
|
|
||
| - **`commercial`** — Standard Microsoft 365 (`outlook.office.com`) | ||
| - **`gcc`** — Office 365 US Government (`outlook.office365.us`) |
There was a problem hiding this comment.
The code accepts both 'gcc' and 'us' as values for CLIPPY_CLOUD (line 12 in endpoints.ts), but the documentation only mentions 'gcc' and 'commercial'. Either document the 'us' alias in the README and .env.example, or remove the alias to keep the API surface simpler and more predictable.
| | `CLIPPY_CLOUD` | `commercial`, `gcc` | `commercial` | Microsoft cloud environment | | |
| | `CLIPPY_TOKEN` | Bearer token string | — | Skip browser login with a token directly | | |
| ### Cloud Environments | |
| - **`commercial`** — Standard Microsoft 365 (`outlook.office.com`) | |
| - **`gcc`** — Office 365 US Government (`outlook.office365.us`) | |
| | `CLIPPY_CLOUD` | `commercial`, `gcc` (`us` alias) | `commercial` | Microsoft cloud environment | | |
| | `CLIPPY_TOKEN` | Bearer token string | — | Skip browser login with a token directly | | |
| ### Cloud Environments | |
| - **`commercial`** — Standard Microsoft 365 (`outlook.office.com`) | |
| - **`gcc`** (`us` alias) — Office 365 US Government (`outlook.office365.us`) |
| gcc: { | ||
| outlookBase: 'https://outlook.office365.us', | ||
| loginBase: 'https://login.microsoftonline.com', | ||
| graphBase: 'https://graph.microsoft.com', | ||
| }, |
There was a problem hiding this comment.
The GCC configuration uses the same Graph API and Login endpoints as commercial. While this is correct for Office 365 GCC (Government Community Cloud), the code should include a comment explaining this to avoid confusion. GCC High and DoD environments would need different endpoints (graph.microsoft.us and login.microsoftonline.us), so documenting why these are the same would help future maintainers understand the distinction.
| - **`gcc`** — Office 365 US Government (`outlook.office365.us`) | ||
|
|
There was a problem hiding this comment.
The documentation should clarify that this is specifically Office 365 GCC (Government Community Cloud), not GCC High or DoD, which would require different endpoints. Consider adding a note like "Note: This is for Office 365 GCC only. GCC High and DoD environments are not currently supported." This helps users understand the scope of government cloud support.
| - **`gcc`** — Office 365 US Government (`outlook.office365.us`) | |
| - **`gcc`** — Office 365 GCC (US Government Community Cloud) (`outlook.office365.us`) | |
| > Note: The `gcc` option targets the Office 365 GCC (Government Community Cloud) environment only. GCC High and DoD environments are not currently supported and require different endpoints. |
Summary
This PR introduces centralized endpoint management with support for multiple Microsoft cloud environments. The main addition is a new GCC (Office 365 US Government) environment option, allowing users to switch between commercial and government clouds.
Changes
src/lib/endpoints.ts) — Centralized configuration for Microsoft cloud endpoints--gccflag orCLIPPY_CLOUD=gccto switch to Office 365 US Government--gccflag to all commands.env.exampletemplate--no-headlessoption for browser control during authenticationHow to Use
Set environment variable:
```bash
export CLIPPY_CLOUD=gcc
clippy calendar
```
Or use CLI flag:
```bash
clippy --gcc login --interactive
clippy --gcc calendar
```
Files Changed
Testing