From 28d8bd84a5ac912b79416aeced95f74fd71876bb Mon Sep 17 00:00:00 2001 From: kaitranntt Date: Tue, 27 Jan 2026 15:43:21 -0500 Subject: [PATCH] feat(cliproxy): add Claude (Anthropic) OAuth provider support Add Claude as a first-class OAuth provider in CCS CLI and dashboard. Backend support already exists in CLIProxyAPIPlus (port 54545). Changes: - Add 'claude' to CLIProxyProvider type and profile detector - Add Claude OAuth config (port 54545, --anthropic-login flag) - Add Claude to oauth-port-diagnostics flow types - Add Claude token discovery prefixes (claude-, anthropic-) - Add Claude model catalog (Opus 4.5, Sonnet 4.5/4, Haiku 4.5) - Add Claude logo and provider display name - Update variant config types and adapters Closes #380 --- src/auth/profile-detector.ts | 1 + src/cliproxy/auth/auth-types.ts | 10 ++++ src/cliproxy/config-generator.ts | 1 + src/cliproxy/model-catalog.ts | 49 +++++++++++++++++++ .../services/variant-config-adapter.ts | 2 +- src/cliproxy/types.ts | 11 ++++- src/config/unified-config-types.ts | 2 +- src/management/oauth-port-diagnostics.ts | 15 +++++- src/types/config.ts | 2 +- ui/public/assets/providers/claude.svg | 1 + ui/src/components/cliproxy/provider-logo.tsx | 1 + ui/src/lib/model-catalogs.ts | 45 +++++++++++++++++ 12 files changed, 134 insertions(+), 6 deletions(-) create mode 100644 ui/public/assets/providers/claude.svg diff --git a/src/auth/profile-detector.ts b/src/auth/profile-detector.ts index bde28265..d5db7ae1 100644 --- a/src/auth/profile-detector.ts +++ b/src/auth/profile-detector.ts @@ -28,6 +28,7 @@ export const CLIPROXY_PROFILES = [ 'iflow', 'kiro', 'ghcp', + 'claude', ] as const; export type CLIProxyProfileName = (typeof CLIPROXY_PROFILES)[number]; diff --git a/src/cliproxy/auth/auth-types.ts b/src/cliproxy/auth/auth-types.ts index 42e3cc9e..d3af8c76 100644 --- a/src/cliproxy/auth/auth-types.ts +++ b/src/cliproxy/auth/auth-types.ts @@ -27,6 +27,7 @@ export const OAUTH_CALLBACK_PORTS: Partial> = { codex: 1455, agy: 51121, iflow: 11451, + claude: 54545, // qwen: Device Code Flow - no callback port // ghcp: Device Code Flow - no callback port }; @@ -121,6 +122,13 @@ export const OAUTH_CONFIGS: Record = { scopes: ['copilot'], authFlag: '--github-copilot-login', }, + claude: { + provider: 'claude', + displayName: 'Claude (Anthropic)', + authUrl: 'https://console.anthropic.com/oauth/authorize', + scopes: ['user:inference', 'user:profile'], + authFlag: '--anthropic-login', + }, }; /** @@ -136,6 +144,7 @@ export const PROVIDER_AUTH_PREFIXES: Record = { iflow: ['iflow-'], kiro: ['kiro-', 'aws-', 'codewhisperer-'], ghcp: ['github-copilot-', 'copilot-', 'gh-'], + claude: ['claude-', 'anthropic-'], }; /** @@ -150,6 +159,7 @@ export const PROVIDER_TYPE_VALUES: Record = { iflow: ['iflow'], kiro: ['kiro', 'codewhisperer'], ghcp: ['github-copilot', 'copilot'], + claude: ['claude', 'anthropic'], }; /** diff --git a/src/cliproxy/config-generator.ts b/src/cliproxy/config-generator.ts index a4652417..a5772bf1 100644 --- a/src/cliproxy/config-generator.ts +++ b/src/cliproxy/config-generator.ts @@ -299,6 +299,7 @@ const PROVIDER_DISPLAY_NAMES: Record = { iflow: 'iFlow', kiro: 'Kiro (AWS)', ghcp: 'GitHub Copilot (OAuth)', + claude: 'Claude (Anthropic)', }; /** diff --git a/src/cliproxy/model-catalog.ts b/src/cliproxy/model-catalog.ts index 78c86d38..7f035350 100644 --- a/src/cliproxy/model-catalog.ts +++ b/src/cliproxy/model-catalog.ts @@ -166,6 +166,55 @@ export const MODEL_CATALOG: Partial> = }, ], }, + claude: { + provider: 'claude', + displayName: 'Claude (Anthropic)', + defaultModel: 'claude-sonnet-4-5-20250514', + models: [ + { + id: 'claude-opus-4-5-20250220', + name: 'Claude Opus 4.5', + description: 'Most capable Claude model', + thinking: { + type: 'budget', + min: 1024, + max: 128000, + zeroAllowed: false, + dynamicAllowed: true, + }, + }, + { + id: 'claude-sonnet-4-5-20250514', + name: 'Claude Sonnet 4.5', + description: 'Balanced performance and speed', + thinking: { + type: 'budget', + min: 1024, + max: 128000, + zeroAllowed: false, + dynamicAllowed: true, + }, + }, + { + id: 'claude-sonnet-4-20250514', + name: 'Claude Sonnet 4', + description: 'Previous generation Sonnet', + thinking: { + type: 'budget', + min: 1024, + max: 128000, + zeroAllowed: false, + dynamicAllowed: true, + }, + }, + { + id: 'claude-haiku-4-5-20250514', + name: 'Claude Haiku 4.5', + description: 'Fast and efficient', + thinking: { type: 'none' }, + }, + ], + }, }; /** diff --git a/src/cliproxy/services/variant-config-adapter.ts b/src/cliproxy/services/variant-config-adapter.ts index 4294b956..1fb0ec65 100644 --- a/src/cliproxy/services/variant-config-adapter.ts +++ b/src/cliproxy/services/variant-config-adapter.ts @@ -132,7 +132,7 @@ export function saveVariantUnified( if (!config.cliproxy) { config.cliproxy = { oauth_accounts: {}, - providers: ['gemini', 'codex', 'agy', 'qwen', 'iflow', 'kiro', 'ghcp'], + providers: ['gemini', 'codex', 'agy', 'qwen', 'iflow', 'kiro', 'ghcp', 'claude'], variants: {}, }; } diff --git a/src/cliproxy/types.ts b/src/cliproxy/types.ts index 9759bba2..3ecc56bb 100644 --- a/src/cliproxy/types.ts +++ b/src/cliproxy/types.ts @@ -118,8 +118,17 @@ export interface DownloadResult { * - iflow: iFlow via OAuth * - kiro: Kiro (AWS CodeWhisperer) via OAuth * - ghcp: GitHub Copilot via Device Code (OAuth through CLIProxyAPIPlus) + * - claude: Claude (Anthropic) via OAuth */ -export type CLIProxyProvider = 'gemini' | 'codex' | 'agy' | 'qwen' | 'iflow' | 'kiro' | 'ghcp'; +export type CLIProxyProvider = + | 'gemini' + | 'codex' + | 'agy' + | 'qwen' + | 'iflow' + | 'kiro' + | 'ghcp' + | 'claude'; /** * CLIProxy backend selection diff --git a/src/config/unified-config-types.ts b/src/config/unified-config-types.ts index f2d3618e..0df03c27 100644 --- a/src/config/unified-config-types.ts +++ b/src/config/unified-config-types.ts @@ -61,7 +61,7 @@ export type OAuthAccounts = Record; */ export interface CLIProxyVariantConfig { /** Base provider to use */ - provider: 'gemini' | 'codex' | 'agy' | 'qwen' | 'iflow' | 'kiro' | 'ghcp'; + provider: 'gemini' | 'codex' | 'agy' | 'qwen' | 'iflow' | 'kiro' | 'ghcp' | 'claude'; /** Account nickname (references oauth_accounts) */ account?: string; /** Path to settings file (e.g., "~/.ccs/gemini-custom.settings.json") */ diff --git a/src/management/oauth-port-diagnostics.ts b/src/management/oauth-port-diagnostics.ts index 262d963d..48db2348 100644 --- a/src/management/oauth-port-diagnostics.ts +++ b/src/management/oauth-port-diagnostics.ts @@ -34,6 +34,7 @@ export const OAUTH_CALLBACK_PORTS: Record = { iflow: 11451, // Authorization Code Flow kiro: 9876, // Authorization Code Flow ghcp: null, // Device Code Flow - no callback port + claude: 54545, // Authorization Code Flow (Anthropic OAuth) }; /** @@ -52,6 +53,7 @@ export const OAUTH_FLOW_TYPES: Record = { iflow: 'authorization_code', kiro: 'authorization_code', ghcp: 'device_code', + claude: 'authorization_code', }; /** @@ -138,7 +140,16 @@ export async function checkOAuthPort(provider: CLIProxyProvider): Promise { - const providers: CLIProxyProvider[] = ['gemini', 'codex', 'agy', 'qwen', 'iflow', 'kiro', 'ghcp']; + const providers: CLIProxyProvider[] = [ + 'gemini', + 'codex', + 'agy', + 'qwen', + 'iflow', + 'kiro', + 'ghcp', + 'claude', + ]; const results: OAuthPortDiagnostic[] = []; for (const provider of providers) { @@ -153,7 +164,7 @@ export async function checkAllOAuthPorts(): Promise { * Check OAuth ports for providers that use Authorization Code flow only */ export async function checkAuthCodePorts(): Promise { - const providers: CLIProxyProvider[] = ['gemini', 'codex', 'agy', 'kiro']; + const providers: CLIProxyProvider[] = ['gemini', 'codex', 'agy', 'kiro', 'claude']; const results: OAuthPortDiagnostic[] = []; for (const provider of providers) { diff --git a/src/types/config.ts b/src/types/config.ts index a00195a3..db910441 100644 --- a/src/types/config.ts +++ b/src/types/config.ts @@ -18,7 +18,7 @@ export interface ProfilesConfig { */ export interface CLIProxyVariantConfig { /** CLIProxy provider to use */ - provider: 'gemini' | 'codex' | 'agy' | 'qwen' | 'iflow' | 'kiro' | 'ghcp'; + provider: 'gemini' | 'codex' | 'agy' | 'qwen' | 'iflow' | 'kiro' | 'ghcp' | 'claude'; /** Path to settings.json with custom model configuration (optional) */ settings?: string; /** Account identifier for multi-account support (optional, defaults to 'default') */ diff --git a/ui/public/assets/providers/claude.svg b/ui/public/assets/providers/claude.svg new file mode 100644 index 00000000..62dc0db1 --- /dev/null +++ b/ui/public/assets/providers/claude.svg @@ -0,0 +1 @@ +Claude \ No newline at end of file diff --git a/ui/src/components/cliproxy/provider-logo.tsx b/ui/src/components/cliproxy/provider-logo.tsx index 66ad0420..ee762285 100644 --- a/ui/src/components/cliproxy/provider-logo.tsx +++ b/ui/src/components/cliproxy/provider-logo.tsx @@ -20,6 +20,7 @@ const PROVIDER_IMAGES: Record = { iflow: '/assets/providers/iflow.png', kiro: '/assets/providers/kiro.png', ghcp: '/assets/providers/copilot.svg', + claude: '/assets/providers/claude.svg', }; /** Provider color configuration (for fallback only - no background for image logos) */ diff --git a/ui/src/lib/model-catalogs.ts b/ui/src/lib/model-catalogs.ts index 09c056ba..9c6065a1 100644 --- a/ui/src/lib/model-catalogs.ts +++ b/ui/src/lib/model-catalogs.ts @@ -311,4 +311,49 @@ export const MODEL_CATALOGS: Record = { }, ], }, + claude: { + provider: 'claude', + displayName: 'Claude (Anthropic)', + defaultModel: 'claude-sonnet-4-5-20250514', + models: [ + { + id: 'claude-opus-4-5-20250220', + name: 'Claude Opus 4.5', + description: 'Most capable Claude model', + presetMapping: { + default: 'claude-opus-4-5-20250220', + opus: 'claude-opus-4-5-20250220', + sonnet: 'claude-sonnet-4-5-20250514', + haiku: 'claude-haiku-4-5-20250514', + }, + }, + { + id: 'claude-sonnet-4-5-20250514', + name: 'Claude Sonnet 4.5', + description: 'Balanced performance and speed', + presetMapping: { + default: 'claude-sonnet-4-5-20250514', + opus: 'claude-opus-4-5-20250220', + sonnet: 'claude-sonnet-4-5-20250514', + haiku: 'claude-haiku-4-5-20250514', + }, + }, + { + id: 'claude-sonnet-4-20250514', + name: 'Claude Sonnet 4', + description: 'Previous generation Sonnet', + presetMapping: { + default: 'claude-sonnet-4-20250514', + opus: 'claude-opus-4-5-20250220', + sonnet: 'claude-sonnet-4-20250514', + haiku: 'claude-haiku-4-5-20250514', + }, + }, + { + id: 'claude-haiku-4-5-20250514', + name: 'Claude Haiku 4.5', + description: 'Fast and efficient', + }, + ], + }, };