mirror of
https://github.com/tiennm99/ccs.git
synced 2026-07-16 04:18:05 +00:00
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
This commit is contained in:
@@ -28,6 +28,7 @@ export const CLIPROXY_PROFILES = [
|
||||
'iflow',
|
||||
'kiro',
|
||||
'ghcp',
|
||||
'claude',
|
||||
] as const;
|
||||
export type CLIProxyProfileName = (typeof CLIPROXY_PROFILES)[number];
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ export const OAUTH_CALLBACK_PORTS: Partial<Record<CLIProxyProvider, number>> = {
|
||||
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<CLIProxyProvider, ProviderOAuthConfig> = {
|
||||
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<CLIProxyProvider, string[]> = {
|
||||
iflow: ['iflow-'],
|
||||
kiro: ['kiro-', 'aws-', 'codewhisperer-'],
|
||||
ghcp: ['github-copilot-', 'copilot-', 'gh-'],
|
||||
claude: ['claude-', 'anthropic-'],
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -150,6 +159,7 @@ export const PROVIDER_TYPE_VALUES: Record<CLIProxyProvider, string[]> = {
|
||||
iflow: ['iflow'],
|
||||
kiro: ['kiro', 'codewhisperer'],
|
||||
ghcp: ['github-copilot', 'copilot'],
|
||||
claude: ['claude', 'anthropic'],
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -299,6 +299,7 @@ const PROVIDER_DISPLAY_NAMES: Record<CLIProxyProvider, string> = {
|
||||
iflow: 'iFlow',
|
||||
kiro: 'Kiro (AWS)',
|
||||
ghcp: 'GitHub Copilot (OAuth)',
|
||||
claude: 'Claude (Anthropic)',
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -166,6 +166,55 @@ export const MODEL_CATALOG: Partial<Record<CLIProxyProvider, ProviderCatalog>> =
|
||||
},
|
||||
],
|
||||
},
|
||||
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' },
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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: {},
|
||||
};
|
||||
}
|
||||
|
||||
+10
-1
@@ -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
|
||||
|
||||
@@ -61,7 +61,7 @@ export type OAuthAccounts = Record<string, string>;
|
||||
*/
|
||||
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") */
|
||||
|
||||
@@ -34,6 +34,7 @@ export const OAUTH_CALLBACK_PORTS: Record<CLIProxyProvider, number | null> = {
|
||||
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<CLIProxyProvider, OAuthFlowType> = {
|
||||
iflow: 'authorization_code',
|
||||
kiro: 'authorization_code',
|
||||
ghcp: 'device_code',
|
||||
claude: 'authorization_code',
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -138,7 +140,16 @@ export async function checkOAuthPort(provider: CLIProxyProvider): Promise<OAuthP
|
||||
* Check OAuth ports for all providers
|
||||
*/
|
||||
export async function checkAllOAuthPorts(): Promise<OAuthPortDiagnostic[]> {
|
||||
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<OAuthPortDiagnostic[]> {
|
||||
* Check OAuth ports for providers that use Authorization Code flow only
|
||||
*/
|
||||
export async function checkAuthCodePorts(): Promise<OAuthPortDiagnostic[]> {
|
||||
const providers: CLIProxyProvider[] = ['gemini', 'codex', 'agy', 'kiro'];
|
||||
const providers: CLIProxyProvider[] = ['gemini', 'codex', 'agy', 'kiro', 'claude'];
|
||||
const results: OAuthPortDiagnostic[] = [];
|
||||
|
||||
for (const provider of providers) {
|
||||
|
||||
+1
-1
@@ -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') */
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<svg height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>Claude</title><path d="M4.709 15.955l4.72-2.647.08-.23-.08-.128H9.2l-.79-.048-2.698-.073-2.339-.097-2.266-.122-.571-.121L0 11.784l.055-.352.48-.321.686.06 1.52.103 2.278.158 1.652.097 2.449.255h.389l.055-.157-.134-.098-.103-.097-2.358-1.596-2.552-1.688-1.336-.972-.724-.491-.364-.462-.158-1.008.656-.722.881.06.225.061.893.686 1.908 1.476 2.491 1.833.365.304.145-.103.019-.073-.164-.274-1.355-2.446-1.446-2.49-.644-1.032-.17-.619a2.97 2.97 0 01-.104-.729L6.283.134 6.696 0l.996.134.42.364.62 1.414 1.002 2.229 1.555 3.03.456.898.243.832.091.255h.158V9.01l.128-1.706.237-2.095.23-2.695.08-.76.376-.91.747-.492.584.28.48.685-.067.444-.286 1.851-.559 2.903-.364 1.942h.212l.243-.242.985-1.306 1.652-2.064.73-.82.85-.904.547-.431h1.033l.76 1.129-.34 1.166-1.064 1.347-.881 1.142-1.264 1.7-.79 1.36.073.11.188-.02 2.856-.606 1.543-.28 1.841-.315.833.388.091.395-.328.807-1.969.486-2.309.462-3.439.813-.042.03.049.061 1.549.146.662.036h1.622l3.02.225.79.522.474.638-.079.485-1.215.62-1.64-.389-3.829-.91-1.312-.329h-.182v.11l1.093 1.068 2.006 1.81 2.509 2.33.127.578-.322.455-.34-.049-2.205-1.657-.851-.747-1.926-1.62h-.128v.17l.444.649 2.345 3.521.122 1.08-.17.353-.608.213-.668-.122-1.374-1.925-1.415-2.167-1.143-1.943-.14.08-.674 7.254-.316.37-.729.28-.607-.461-.322-.747.322-1.476.389-1.924.315-1.53.286-1.9.17-.632-.012-.042-.14.018-1.434 1.967-2.18 2.945-1.726 1.845-.414.164-.717-.37.067-.662.401-.589 2.388-3.036 1.44-1.882.93-1.086-.006-.158h-.055L4.132 18.56l-1.13.146-.487-.456.061-.746.231-.243 1.908-1.312-.006.006z" fill="#D97757" fill-rule="nonzero"></path></svg>
|
||||
|
After Width: | Height: | Size: 1.7 KiB |
@@ -20,6 +20,7 @@ const PROVIDER_IMAGES: Record<string, string> = {
|
||||
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) */
|
||||
|
||||
@@ -311,4 +311,49 @@ export const MODEL_CATALOGS: Record<string, ProviderCatalog> = {
|
||||
},
|
||||
],
|
||||
},
|
||||
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',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user