mirror of
https://github.com/tiennm99/ccs.git
synced 2026-07-16 04:18:05 +00:00
refactor(cliproxy): DRY provider lists into single source of truth
- unify CLIPROXY_SUPPORTED_PROVIDERS to import from CLIPROXY_PROVIDER_IDS - replace 4 inline union types with CLIProxyProvider import - replace hardcoded provider arrays in migration-manager and proxy-routes - remove duplicate PROVIDER_DISPLAY_NAMES, use getProviderDisplayName() - sync test now imports from ui/src/lib/provider-config instead of hardcoded array Adding a new CLIProxy provider no longer requires updating 14+ hardcoded lists.
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import { CLIProxyProvider, ProviderConfig } from '../types';
|
||||
import { getProviderDisplayName } from '../provider-capabilities';
|
||||
import { getModelMappingFromConfig } from '../base-config-loader';
|
||||
import { loadOrCreateUnifiedConfig } from '../../config/unified-config-loader';
|
||||
import { getEffectiveApiKey, getEffectiveManagementSecret } from '../auth-token-manager';
|
||||
@@ -46,34 +47,17 @@ const DEFAULT_ANTIGRAVITY_ALIASES: Array<{ name: string; alias: string; fork?: b
|
||||
{ name: 'claude-opus-4-6-thinking', alias: 'gemini-claude-opus-4-6-thinking', fork: true },
|
||||
];
|
||||
|
||||
/** Provider display names (static metadata) */
|
||||
const PROVIDER_DISPLAY_NAMES: Record<CLIProxyProvider, string> = {
|
||||
gemini: 'Gemini',
|
||||
codex: 'Codex',
|
||||
agy: 'Antigravity',
|
||||
qwen: 'Qwen Code',
|
||||
iflow: 'iFlow',
|
||||
kiro: 'Kiro (AWS)',
|
||||
ghcp: 'GitHub Copilot (OAuth)',
|
||||
claude: 'Claude (Anthropic)',
|
||||
};
|
||||
|
||||
/**
|
||||
* Get provider configuration
|
||||
* Model mappings are loaded from config/base-{provider}.settings.json
|
||||
*/
|
||||
export function getProviderConfig(provider: CLIProxyProvider): ProviderConfig {
|
||||
const displayName = PROVIDER_DISPLAY_NAMES[provider];
|
||||
if (!displayName) {
|
||||
throw new Error(`Unknown provider: ${provider}`);
|
||||
}
|
||||
|
||||
// Load models from base config file
|
||||
const models = getModelMappingFromConfig(provider);
|
||||
|
||||
return {
|
||||
name: provider,
|
||||
displayName,
|
||||
displayName: getProviderDisplayName(provider),
|
||||
models,
|
||||
requiresOAuth: true, // All CLIProxy providers require OAuth
|
||||
};
|
||||
|
||||
@@ -18,6 +18,7 @@ import { getCcsDir } from '../utils/config-manager';
|
||||
import { expandPath } from '../utils/helpers';
|
||||
import type { ProfileConfig, AccountConfig, CLIProxyVariantConfig } from './unified-config-types';
|
||||
import { createEmptyUnifiedConfig } from './unified-config-types';
|
||||
import { CLIPROXY_PROVIDER_IDS } from '../cliproxy/provider-capabilities';
|
||||
import { saveUnifiedConfig, hasUnifiedConfig, loadUnifiedConfig } from './unified-config-loader';
|
||||
import { infoBox, warn } from '../utils/ui';
|
||||
|
||||
@@ -203,7 +204,7 @@ export async function migrate(dryRun = false): Promise<MigrationResult> {
|
||||
// 6b. Migrate built-in CLIProxy OAuth profile settings (gemini, codex, agy, qwen, iflow)
|
||||
// Keep settings in *.settings.json files - only record reference in config.yaml
|
||||
// This matches Claude's ~/.claude/settings.json pattern for user familiarity
|
||||
const builtInProviders = ['gemini', 'codex', 'agy', 'qwen', 'iflow'];
|
||||
const builtInProviders = [...CLIPROXY_PROVIDER_IDS];
|
||||
for (const provider of builtInProviders) {
|
||||
const settingsFile = `${provider}.settings.json`;
|
||||
const settingsPath = path.join(ccsDir, settingsFile);
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
*/
|
||||
|
||||
import type { TargetType } from '../targets/target-adapter';
|
||||
import type { CLIProxyProvider } from '../cliproxy/types';
|
||||
import { CLIPROXY_PROVIDER_IDS } from '../cliproxy/provider-capabilities';
|
||||
|
||||
/**
|
||||
* Unified config version.
|
||||
@@ -25,18 +27,9 @@ export const UNIFIED_CONFIG_VERSION = 8;
|
||||
|
||||
/**
|
||||
* Supported CLIProxy providers.
|
||||
* Includes all OAuth-based providers supported by CLIProxyAPI.
|
||||
* Derived from CLIPROXY_PROVIDER_IDS — single source of truth in provider-capabilities.ts.
|
||||
*/
|
||||
export const CLIPROXY_SUPPORTED_PROVIDERS = [
|
||||
'gemini',
|
||||
'codex',
|
||||
'agy',
|
||||
'qwen',
|
||||
'iflow',
|
||||
'kiro',
|
||||
'ghcp',
|
||||
'claude',
|
||||
] as const;
|
||||
export const CLIPROXY_SUPPORTED_PROVIDERS = CLIPROXY_PROVIDER_IDS;
|
||||
|
||||
/**
|
||||
* Account configuration (formerly in profiles.json).
|
||||
@@ -80,7 +73,7 @@ export type OAuthAccounts = Record<string, string>;
|
||||
*/
|
||||
export interface CLIProxyVariantConfig {
|
||||
/** Base provider to use */
|
||||
provider: 'gemini' | 'codex' | 'agy' | 'qwen' | 'iflow' | 'kiro' | 'ghcp' | 'claude';
|
||||
provider: CLIProxyProvider;
|
||||
/** Account nickname (references oauth_accounts) */
|
||||
account?: string;
|
||||
/** Path to settings file (e.g., "~/.ccs/gemini-custom.settings.json") */
|
||||
@@ -98,14 +91,14 @@ export interface CLIProxyVariantConfig {
|
||||
*/
|
||||
export interface CompositeTierConfig {
|
||||
/** Provider for this tier */
|
||||
provider: 'gemini' | 'codex' | 'agy' | 'qwen' | 'iflow' | 'kiro' | 'ghcp' | 'claude';
|
||||
provider: CLIProxyProvider;
|
||||
/** Model ID to use for this tier */
|
||||
model: string;
|
||||
/** Account nickname (optional, references oauth_accounts) */
|
||||
account?: string;
|
||||
/** Fallback provider+model if primary fails */
|
||||
fallback?: {
|
||||
provider: 'gemini' | 'codex' | 'agy' | 'qwen' | 'iflow' | 'kiro' | 'ghcp' | 'claude';
|
||||
provider: CLIProxyProvider;
|
||||
model: string;
|
||||
account?: string;
|
||||
};
|
||||
|
||||
+3
-1
@@ -3,6 +3,8 @@
|
||||
* Source: ~/.ccs/config.json
|
||||
*/
|
||||
|
||||
import type { CLIProxyProvider } from '../cliproxy/types';
|
||||
|
||||
/**
|
||||
* Profile configuration mapping
|
||||
* Maps profile names to settings.json paths
|
||||
@@ -18,7 +20,7 @@ export interface ProfilesConfig {
|
||||
*/
|
||||
export interface CLIProxyVariantConfig {
|
||||
/** CLIProxy provider to use */
|
||||
provider: 'gemini' | 'codex' | 'agy' | 'qwen' | 'iflow' | 'kiro' | 'ghcp' | 'claude';
|
||||
provider: CLIProxyProvider;
|
||||
/** Path to settings.json with custom model configuration (optional) */
|
||||
settings?: string;
|
||||
/** Account identifier for multi-account support (optional, defaults to 'default') */
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
DEFAULT_CLIPROXY_SERVER_CONFIG,
|
||||
CliproxyServerConfig,
|
||||
} from '../../config/unified-config-types';
|
||||
import { CLIPROXY_PROVIDER_IDS } from '../../cliproxy/provider-capabilities';
|
||||
|
||||
const router = Router();
|
||||
|
||||
@@ -113,7 +114,7 @@ router.put('/backend', async (req: Request, res: Response) => {
|
||||
config.cliproxy = {
|
||||
backend,
|
||||
oauth_accounts: {},
|
||||
providers: ['gemini', 'codex', 'agy', 'qwen', 'iflow', 'kiro', 'ghcp'],
|
||||
providers: [...CLIPROXY_PROVIDER_IDS],
|
||||
variants: {},
|
||||
};
|
||||
} else {
|
||||
|
||||
@@ -7,34 +7,23 @@
|
||||
|
||||
import { describe, expect, test } from 'bun:test';
|
||||
import { CLIPROXY_PROFILES } from '../../../src/auth/profile-detector';
|
||||
|
||||
// UI providers (must manually sync - this test validates the sync)
|
||||
const UI_CLIPROXY_PROVIDERS = [
|
||||
'gemini',
|
||||
'codex',
|
||||
'agy',
|
||||
'qwen',
|
||||
'iflow',
|
||||
'kiro',
|
||||
'ghcp',
|
||||
'claude',
|
||||
] as const;
|
||||
import { CLIPROXY_PROVIDERS } from '../../../ui/src/lib/provider-config';
|
||||
|
||||
describe('Provider Sync', () => {
|
||||
test('backend CLIPROXY_PROFILES matches UI CLIPROXY_PROVIDERS', () => {
|
||||
const backend = [...CLIPROXY_PROFILES].sort();
|
||||
const ui = [...UI_CLIPROXY_PROVIDERS].sort();
|
||||
const ui = [...CLIPROXY_PROVIDERS].sort();
|
||||
|
||||
expect(backend).toEqual(ui);
|
||||
});
|
||||
|
||||
test('both arrays have same length', () => {
|
||||
expect(CLIPROXY_PROFILES.length).toBe(UI_CLIPROXY_PROVIDERS.length);
|
||||
expect(CLIPROXY_PROFILES.length).toBe(CLIPROXY_PROVIDERS.length);
|
||||
});
|
||||
|
||||
test('UI array contains all backend providers', () => {
|
||||
for (const provider of CLIPROXY_PROFILES) {
|
||||
expect(UI_CLIPROXY_PROVIDERS).toContain(provider);
|
||||
expect(CLIPROXY_PROVIDERS).toContain(provider);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user