mirror of
https://github.com/tiennm99/ccs.git
synced 2026-09-03 08:18:23 +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',
|
'iflow',
|
||||||
'kiro',
|
'kiro',
|
||||||
'ghcp',
|
'ghcp',
|
||||||
|
'claude',
|
||||||
] as const;
|
] as const;
|
||||||
export type CLIProxyProfileName = (typeof CLIPROXY_PROFILES)[number];
|
export type CLIProxyProfileName = (typeof CLIPROXY_PROFILES)[number];
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ export const OAUTH_CALLBACK_PORTS: Partial<Record<CLIProxyProvider, number>> = {
|
|||||||
codex: 1455,
|
codex: 1455,
|
||||||
agy: 51121,
|
agy: 51121,
|
||||||
iflow: 11451,
|
iflow: 11451,
|
||||||
|
claude: 54545,
|
||||||
// qwen: Device Code Flow - no callback port
|
// qwen: Device Code Flow - no callback port
|
||||||
// ghcp: 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'],
|
scopes: ['copilot'],
|
||||||
authFlag: '--github-copilot-login',
|
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-'],
|
iflow: ['iflow-'],
|
||||||
kiro: ['kiro-', 'aws-', 'codewhisperer-'],
|
kiro: ['kiro-', 'aws-', 'codewhisperer-'],
|
||||||
ghcp: ['github-copilot-', 'copilot-', 'gh-'],
|
ghcp: ['github-copilot-', 'copilot-', 'gh-'],
|
||||||
|
claude: ['claude-', 'anthropic-'],
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -150,6 +159,7 @@ export const PROVIDER_TYPE_VALUES: Record<CLIProxyProvider, string[]> = {
|
|||||||
iflow: ['iflow'],
|
iflow: ['iflow'],
|
||||||
kiro: ['kiro', 'codewhisperer'],
|
kiro: ['kiro', 'codewhisperer'],
|
||||||
ghcp: ['github-copilot', 'copilot'],
|
ghcp: ['github-copilot', 'copilot'],
|
||||||
|
claude: ['claude', 'anthropic'],
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -299,6 +299,7 @@ const PROVIDER_DISPLAY_NAMES: Record<CLIProxyProvider, string> = {
|
|||||||
iflow: 'iFlow',
|
iflow: 'iFlow',
|
||||||
kiro: 'Kiro (AWS)',
|
kiro: 'Kiro (AWS)',
|
||||||
ghcp: 'GitHub Copilot (OAuth)',
|
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) {
|
if (!config.cliproxy) {
|
||||||
config.cliproxy = {
|
config.cliproxy = {
|
||||||
oauth_accounts: {},
|
oauth_accounts: {},
|
||||||
providers: ['gemini', 'codex', 'agy', 'qwen', 'iflow', 'kiro', 'ghcp'],
|
providers: ['gemini', 'codex', 'agy', 'qwen', 'iflow', 'kiro', 'ghcp', 'claude'],
|
||||||
variants: {},
|
variants: {},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-1
@@ -118,8 +118,17 @@ export interface DownloadResult {
|
|||||||
* - iflow: iFlow via OAuth
|
* - iflow: iFlow via OAuth
|
||||||
* - kiro: Kiro (AWS CodeWhisperer) via OAuth
|
* - kiro: Kiro (AWS CodeWhisperer) via OAuth
|
||||||
* - ghcp: GitHub Copilot via Device Code (OAuth through CLIProxyAPIPlus)
|
* - 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
|
* CLIProxy backend selection
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ export type OAuthAccounts = Record<string, string>;
|
|||||||
*/
|
*/
|
||||||
export interface CLIProxyVariantConfig {
|
export interface CLIProxyVariantConfig {
|
||||||
/** Base provider to use */
|
/** 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 nickname (references oauth_accounts) */
|
||||||
account?: string;
|
account?: string;
|
||||||
/** Path to settings file (e.g., "~/.ccs/gemini-custom.settings.json") */
|
/** 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
|
iflow: 11451, // Authorization Code Flow
|
||||||
kiro: 9876, // Authorization Code Flow
|
kiro: 9876, // Authorization Code Flow
|
||||||
ghcp: null, // Device Code Flow - no callback port
|
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',
|
iflow: 'authorization_code',
|
||||||
kiro: 'authorization_code',
|
kiro: 'authorization_code',
|
||||||
ghcp: 'device_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
|
* Check OAuth ports for all providers
|
||||||
*/
|
*/
|
||||||
export async function checkAllOAuthPorts(): Promise<OAuthPortDiagnostic[]> {
|
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[] = [];
|
const results: OAuthPortDiagnostic[] = [];
|
||||||
|
|
||||||
for (const provider of providers) {
|
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
|
* Check OAuth ports for providers that use Authorization Code flow only
|
||||||
*/
|
*/
|
||||||
export async function checkAuthCodePorts(): Promise<OAuthPortDiagnostic[]> {
|
export async function checkAuthCodePorts(): Promise<OAuthPortDiagnostic[]> {
|
||||||
const providers: CLIProxyProvider[] = ['gemini', 'codex', 'agy', 'kiro'];
|
const providers: CLIProxyProvider[] = ['gemini', 'codex', 'agy', 'kiro', 'claude'];
|
||||||
const results: OAuthPortDiagnostic[] = [];
|
const results: OAuthPortDiagnostic[] = [];
|
||||||
|
|
||||||
for (const provider of providers) {
|
for (const provider of providers) {
|
||||||
|
|||||||
+1
-1
@@ -18,7 +18,7 @@ export interface ProfilesConfig {
|
|||||||
*/
|
*/
|
||||||
export interface CLIProxyVariantConfig {
|
export interface CLIProxyVariantConfig {
|
||||||
/** CLIProxy provider to use */
|
/** 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) */
|
/** Path to settings.json with custom model configuration (optional) */
|
||||||
settings?: string;
|
settings?: string;
|
||||||
/** Account identifier for multi-account support (optional, defaults to 'default') */
|
/** 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',
|
iflow: '/assets/providers/iflow.png',
|
||||||
kiro: '/assets/providers/kiro.png',
|
kiro: '/assets/providers/kiro.png',
|
||||||
ghcp: '/assets/providers/copilot.svg',
|
ghcp: '/assets/providers/copilot.svg',
|
||||||
|
claude: '/assets/providers/claude.svg',
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Provider color configuration (for fallback only - no background for image logos) */
|
/** 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