Repository navigation
feat: multi-provider OAuth pool — OpenAI, Cursor, Google AI Pro (#22) - #23
superdav42 wants to merge 3 commits into
Conversation
Recovered after worktree was unexpectedly deleted. Original Write tool calls extracted from /home/dave/.local/share/opencode/opencode.db part table. Files restored: - src/OAuthPool/ProviderConfig.php (new, 291 lines) - src/OAuthPool/ProviderPool.php (new, 809 lines) - src/OAuthPool/PoolRegistry.php (new, 84 lines) - src/OAuthPool/PoolManager.php (refactored to facade, 233 lines) - inc/rest-api.php (rewritten with per-provider routes, 698 lines) - js/connector.jsx (rewritten with 4 cards, 785 lines) - build/connector.js (rebuilt, 15.4 KiB) - wp-multi-provider-test.mjs (new browser smoke test, 97 lines) REST API smoke-tested end-to-end against host WP at wordpress.local:8080. All 4 provider endpoints work (anthropic/openai/cursor/google), legacy /accounts route preserved, error paths verified.
…8080 - Use Multisite Ultimate's custom login form selectors (input name=log/pwd). - Use correct Gutenberg connectors page slug (options-connectors-wp-admin). - Relax waitUntil and increase timeout for React-heavy admin page. - Improve per-card setup button targeting using row-scoped locators. Verified: all four provider cards (Anthropic Max, OpenAI ChatGPT/Codex, Cursor Pro, Google AI Pro) render at /wp-admin/options-general.php?page=options-connectors-wp-admin with the correct labels, badges (MAX/GPT/CUR/GAI), and descriptions. No plugin-related JS console errors.
Updates the plugin header, version constant, plugin description, and readme.txt to reflect the multi-provider scope. The plugin now supports four OAuth/manual-token providers (Anthropic Max, OpenAI, Cursor, Google) instead of being Anthropic-only. Stored option key conventions: - anthropic_max_oauth_pool (Anthropic — unchanged from 1.1.0) - anthropic_max_oauth_pool_openai - anthropic_max_oauth_pool_cursor - anthropic_max_oauth_pool_google Resolves #22.
|
Caution Review failedFailed to post review comments 📝 WalkthroughWalkthroughThe PR transforms the plugin from a single-provider (Anthropic Max) OAuth integration into a multi-provider OAuth pool supporting Anthropic, OpenAI, Cursor Pro, and Google AI Pro. New infrastructure classes (ProviderConfig, PoolRegistry, ProviderPool) manage per-provider account pools with independent token refresh and rate-limit handling. REST API routes are restructured to serve per-provider endpoints while maintaining legacy Anthropic-only compatibility. The connector UI is refactored to dynamically render provider cards from a centralized registry. ChangesMulti-Provider OAuth Pool Architecture
Sequence DiagramsequenceDiagram
actor Admin as WordPress Admin
participant UI as Connector UI<br/>(js/connector.jsx)
participant REST as REST API<br/>(inc/rest-api.php)
participant Reg as PoolRegistry
participant Cfg as ProviderConfig
participant Pool as ProviderPool
participant WPOpt as WordPress Options
Admin->>UI: Click Settings > Connectors
UI->>UI: Load Provider Config for all providers
UI->>UI: Register 4 provider cards dynamically
Admin->>UI: Click "Add Account" for OpenAI
UI->>REST: POST /openai/authorize?login_hint=user@example.com
REST->>Reg: resolve_pool('openai')
Reg->>Cfg: ProviderConfig::forId('openai')
Cfg->>Reg: Return openai config
Reg->>Pool: Create ProviderPool(openai_config)
Pool->>WPOpt: Load openai accounts pool
REST->>REST: Generate PKCE verifier/challenge
REST-->>UI: Return {authorize_url, state}
UI->>Admin: Display OAuth login link
Admin->>Admin: Complete login on auth.openai.com
Admin->>UI: Paste code + state
UI->>REST: POST /openai/exchange {code, state, email}
REST->>Reg: resolve_pool('openai')
Reg->>Pool: Call exchangeCode(...)
Pool->>Pool: POST token request to openai token endpoint
Pool->>WPOpt: Save tokens to openai pool
REST-->>UI: Return {access_token, refresh_token}
UI->>UI: Render account in list (OpenAI provider)
Admin->>UI: Click "Add Account" for Cursor
UI->>UI: Switch to ManualTokenAddForm
Admin->>UI: Paste access & refresh tokens
UI->>REST: POST /cursor/manual {access_token, refresh_token, email}
REST->>Reg: resolve_pool('cursor')
Reg->>Pool: Call addAccountManual(...)
Pool->>WPOpt: Save manual tokens to cursor pool
REST-->>UI: Return success
UI->>UI: Render account list (both OpenAI and Cursor accounts isolated)
Estimated Code Review Effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly Related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 PHPStan (2.1.54)PHPStan was skipped because the config uses disallowed Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Summary
ProviderPool+PoolRegistry, withPoolManagerretained as a back-compat facade for the Anthropic pool./anthropic-max-pool/v1/{provider}/…and a/providersindex endpoint. Legacy Anthropic-only routes (/accounts,/authorize,/exchange, …) are preserved unchanged.oauth-paste/manual-tokenform modes.Resolves #22.
What this enables
Users with paid AI subscriptions (ChatGPT Plus/Pro, Codex, Cursor Pro, Google AI Pro/Ultra) can now use those plans from WordPress without per-token API billing — same UX as the existing Anthropic Max flow.
claude.ai/oauthanthropic_max_oauth_pool(unchanged)localhost:1455/auth/callbackauth.openai.comanthropic_max_oauth_pool_openaianthropic_max_oauth_pool_cursoraccounts.google.comanthropic_max_oauth_pool_googleArchitecture
src/OAuthPool/ProviderConfig.phpsrc/OAuthPool/ProviderPool.phpcode#stateand full-URL paste), refreshTokens (provider-aware content-type)src/OAuthPool/PoolRegistry.phpsummary()for the/providersendpointsrc/OAuthPool/PoolManager.phpPoolRegistry::pool('anthropic'). Every public method, constant (OPTION_KEY,CLIENT_ID,TOKEN_ENDPOINT,AUTHORIZE_URL,REDIRECT_URI,SCOPES,USER_AGENT,REQUIRED_SCOPE,REMOVE_*), and signature used by 1.0/1.1 callers (AnthropicOAuthRequestAuthentication,provider-registration.php, models, REST handlers) is preserved.inc/rest-api.phpjs/connector.jsxregisterConnector()cards driven by aPROVIDERSmap; sharedProviderConnectorCard,OAuthAddForm,ManualTokenAddForm. Re-asserts registration on multiple ticks (workaround for WordPress/gutenberg#77116).wp-multi-provider-test.mjsBackward compatibility
anthropic_max_oauth_pooloption key; new providers use*_{openai,cursor,google}suffixed keys./anthropic-max-pool/v1/{accounts,authorize,exchange,health,...}routes remain Anthropic-only with identical request/response shapes.PoolManageris fully back-compat. Every public method (getActiveTokenWithEmail,addAccount,removeAccount,markRateLimited,refreshAccount,count,getRequiredScope, etc.) and constant is preserved.Out of scope
AI Client SDK provider classes (
*\Provider\OpenAiCodexProvideretc.) for OpenAI/Cursor/Google are explicitly not wired intoWordPress\AiClientin this PR. Storage and rotation are fully implemented; SDK integration ships in a follow-up so this PR stays focused on pool infrastructure. Anthropic Max remains the only fully SDK-wired provider.The OAuth callback handler bound to
localhost:1455(used by the OpenAI Codex CLI) is also out of scope — the WP server cannot bind that port; users paste the code from the redirected URL instead, mirroring how the upstreamoauth-pool-add.shshell helper works in headless environments.Verification
REST smoke tests (host WP at
http://wordpress.local:8080)All authenticated cookie + nonce calls against the live plugin:
GET /providers200— returns all 4 providers with correct labels, counts,supportsOAuthflagsGET /openai/authorize200—https://auth.openai.com/oauth/authorize?...&redirect_uri=http%3A%2F%2Flocalhost%3A1455%2Fauth%2FcallbackGET /google/authorize200—https://accounts.google.com/o/oauth2/v2/auth?...&redirect_uri=urn:ietf:wg:oauth:2.0:oobGET /anthropic/authorize200—https://claude.ai/oauth/authorize?...(existing flow)GET /cursor/authorize400 oauth_unsupported(correct — Cursor uses manual token)POST /cursor/manual(fake JWT)200— derives email fromsubclaim, persistsGET /cursor/accounts200— returns list with status, expiry, JWT-derived emailPOST /cursor/accounts/remove200— count returns to 0GET /accounts(legacy)200— Anthropic pool unchangedGET /madeup/accounts404 unknown_providerBrowser test
Playwright run against
http://wordpress.local:8080/wp-admin/options-general.php?page=options-connectors-wp-adminafter admin login:All four cards render with provider-specific badges (MAX, GPT, CUR, GAI), descriptions, and Set up buttons.
Lint
php -lclean on all 4 new + 2 modified PHP files.phpstan analyse src/OAuthPool/{ProviderConfig,ProviderPool,PoolRegistry}.php inc/rest-api.php→ No errors. Repo-wide phpstan delta vsmain: -2 errors (no regressions; remaining 235 are pre-existing AI Client SDK class-not-found, unrelated to this PR).npm run buildsucceeds;build/connector.jsis 15.4 KiB minified (was 12.5 KiB on main).Recovery note
The
wip: recover ...commit at the base of this branch reflects a recovery operation: the original worktree was deleted by an aidevops worktree-cleanup background job that misclassified the branch as merged. All file content was recovered from the OpenCode session database (.local/share/opencode/opencode.dbparttable) and matches the originally-tested versions byte-for-byte. The subsequent commits are the post-recovery version bump and test-fixture adjustment.aidevops.sh v3.14.80 plugin for OpenCode v1.14.33 with claude-sonnet-4-6 spent 2d 12h on this as a headless worker.
Summary by CodeRabbit
New Features
Documentation