@@ -23,7 +23,17 @@ interface ProviderSettings {
2323export const CLIPROXY_DEFAULT_PORT = 8317 ;
2424
2525/** Internal API key for CCS-managed requests */
26- const CCS_INTERNAL_API_KEY = 'ccs-internal-managed' ;
26+ export const CCS_INTERNAL_API_KEY = 'ccs-internal-managed' ;
27+
28+ /** Simple secret key for Control Panel login (user-facing) */
29+ export const CCS_CONTROL_PANEL_SECRET = 'ccs' ;
30+
31+ /**
32+ * Config version - bump when config format changes to trigger regeneration
33+ * v1: Initial config (port, auth-dir, api-keys only)
34+ * v2: Full-featured config with dashboard, quota mgmt, simplified key
35+ */
36+ export const CLIPROXY_CONFIG_VERSION = 2 ;
2737
2838/** Provider display names (static metadata) */
2939const PROVIDER_DISPLAY_NAMES : Record < CLIProxyProvider , string > = {
@@ -112,26 +122,68 @@ export function getBinDir(): string {
112122function generateUnifiedConfigContent ( port : number = CLIPROXY_DEFAULT_PORT ) : string {
113123 const authDir = getAuthDir ( ) ; // Base auth dir - CLIProxyAPI scans subdirectories
114124
115- // Unified config with all providers
116- const config = `# CLIProxyAPI unified config generated by CCS
117- # Supports: gemini, codex, agy, qwen (concurrent usage)
125+ // Unified config with enhanced CLIProxyAPI features
126+ const config = `# CLIProxyAPI config generated by CCS v ${ CLIPROXY_CONFIG_VERSION }
127+ # Supports: gemini, codex, agy, qwen, iflow (concurrent usage)
118128# Generated: ${ new Date ( ) . toISOString ( ) }
129+ #
130+ # This config is auto-managed by CCS. Manual edits may be overwritten.
131+ # Use 'ccs doctor' to regenerate with latest settings.
132+
133+ # =============================================================================
134+ # Server Settings
135+ # =============================================================================
119136
120137port: ${ port }
121138debug: false
122- logging-to-file: false
123- usage-statistics-enabled: false
124139
125- # CCS internal authentication
140+ # =============================================================================
141+ # Logging
142+ # =============================================================================
143+
144+ # Write logs to file (stored in ~/.ccs/cliproxy/logs/)
145+ logging-to-file: true
146+
147+ # Log individual API requests for debugging/analytics
148+ request-log: true
149+
150+ # =============================================================================
151+ # Dashboard & Management
152+ # =============================================================================
153+
154+ # Enable usage statistics for CCS dashboard analytics
155+ usage-statistics-enabled: true
156+
157+ # Remote management API for CCS dashboard integration
158+ remote-management:
159+ allow-remote: true
160+ secret-key: "${ CCS_CONTROL_PANEL_SECRET } "
161+ disable-control-panel: false
162+
163+ # =============================================================================
164+ # Reliability & Quota Management
165+ # =============================================================================
166+
167+ # Auto-retry on transient errors (403, 408, 500, 502, 503, 504)
168+ request-retry: 0
169+ max-retry-interval: 0
170+
171+ # Auto-switch accounts on quota exceeded (429)
172+ # This enables seamless multi-account rotation when rate limited
173+ quota-exceeded:
174+ switch-project: true
175+ switch-preview-model: true
176+
177+ # =============================================================================
178+ # Authentication
179+ # =============================================================================
180+
181+ # API keys for CCS internal requests
126182api-keys:
127183 - "${ CCS_INTERNAL_API_KEY } "
128184
129- # OAuth tokens stored in auth/ directory
130- # CLIProxyAPI auto-discovers auth files in subdirectories
131- auth-dir: "${ authDir . replace ( / \\ / g, '/' ) } "
132-
133- # All providers configured - routes by model name
134- # No provider-specific sections needed - OAuth auth files provide credentials
185+ # OAuth tokens directory (auto-discovered by CLIProxyAPI)
186+ auth-dir: "${ authDir . replace ( / \\ \\ / g, '/' ) } "
135187` ;
136188
137189 return config ;
@@ -162,6 +214,67 @@ export function generateConfig(
162214 return configPath ;
163215}
164216
217+ /**
218+ * Force regenerate config.yaml with latest settings
219+ * Deletes existing config and creates fresh one with current port
220+ * @returns Path to new config file
221+ */
222+ export function regenerateConfig ( port : number = CLIPROXY_DEFAULT_PORT ) : string {
223+ const configPath = getConfigPath ( ) ;
224+
225+ // Read existing port if config exists (preserve user's port choice)
226+ let effectivePort = port ;
227+ if ( fs . existsSync ( configPath ) ) {
228+ try {
229+ const content = fs . readFileSync ( configPath , 'utf-8' ) ;
230+ const portMatch = content . match ( / ^ p o r t : \s * ( \d + ) / m) ;
231+ if ( portMatch ) {
232+ effectivePort = parseInt ( portMatch [ 1 ] , 10 ) ;
233+ }
234+ } catch {
235+ // Use default port if reading fails
236+ }
237+ // Delete existing config
238+ fs . unlinkSync ( configPath ) ;
239+ }
240+
241+ // Ensure directories exist
242+ fs . mkdirSync ( path . dirname ( configPath ) , { recursive : true } ) ;
243+ fs . mkdirSync ( getAuthDir ( ) , { recursive : true , mode : 0o700 } ) ;
244+
245+ // Generate fresh config
246+ const configContent = generateUnifiedConfigContent ( effectivePort ) ;
247+ fs . writeFileSync ( configPath , configContent , { mode : 0o600 } ) ;
248+
249+ return configPath ;
250+ }
251+
252+ /**
253+ * Check if config needs regeneration (version mismatch)
254+ * @returns true if config should be regenerated
255+ */
256+ export function configNeedsRegeneration ( ) : boolean {
257+ const configPath = getConfigPath ( ) ;
258+ if ( ! fs . existsSync ( configPath ) ) {
259+ return false ; // Will be created on first use
260+ }
261+
262+ try {
263+ const content = fs . readFileSync ( configPath , 'utf-8' ) ;
264+
265+ // Check for version marker
266+ const versionMatch = content . match ( / C C S v ( \d + ) / ) ;
267+ if ( ! versionMatch ) {
268+ return true ; // No version marker = old config
269+ }
270+
271+ const configVersion = parseInt ( versionMatch [ 1 ] , 10 ) ;
272+ return configVersion < CLIPROXY_CONFIG_VERSION ;
273+ } catch {
274+ return true ; // Error reading = regenerate
275+ }
276+ }
277+
165278/**
166279 * Check if config exists for provider
167280 */
0 commit comments