@@ -23,7 +23,8 @@ import {
2323 isCLIProxyInstalled ,
2424 getCLIProxyPath ,
2525} from '../cliproxy' ;
26- import { getAllAuthStatus , getOAuthConfig } from '../cliproxy/auth-handler' ;
26+ import { getAllAuthStatus , getOAuthConfig , triggerOAuth } from '../cliproxy/auth-handler' ;
27+ import { getProviderAccounts } from '../cliproxy/account-manager' ;
2728import { CLIPROXY_FALLBACK_VERSION } from '../cliproxy/platform-detector' ;
2829import { CLIPROXY_PROFILES , CLIProxyProfileName } from '../auth/profile-detector' ;
2930import { getCcsDir , getConfigPath , loadConfig } from '../utils/config-manager' ;
@@ -53,6 +54,7 @@ interface CliproxyProfileArgs {
5354 name ?: string ;
5455 provider ?: CLIProxyProfileName ;
5556 model ?: string ;
57+ account ?: string ;
5658 force ?: boolean ;
5759 yes ?: boolean ;
5860}
@@ -70,6 +72,8 @@ function parseProfileArgs(args: string[]): CliproxyProfileArgs {
7072 result . provider = args [ ++ i ] as CLIProxyProfileName ;
7173 } else if ( arg === '--model' && args [ i + 1 ] ) {
7274 result . model = args [ ++ i ] ;
75+ } else if ( arg === '--account' && args [ i + 1 ] ) {
76+ result . account = args [ ++ i ] ;
7377 } else if ( arg === '--force' ) {
7478 result . force = true ;
7579 } else if ( arg === '--yes' || arg === '-y' ) {
@@ -136,7 +140,8 @@ function cliproxyVariantExists(name: string): boolean {
136140function createCliproxySettingsFile (
137141 name : string ,
138142 provider : CLIProxyProfileName ,
139- model : string
143+ model : string ,
144+ _account ?: string
140145) : string {
141146 const ccsDir = getCcsDir ( ) ;
142147 const settingsPath = path . join ( ccsDir , `${ provider } -${ name } .settings.json` ) ;
@@ -170,7 +175,8 @@ function createCliproxySettingsFile(
170175function addCliproxyVariant (
171176 name : string ,
172177 provider : CLIProxyProfileName ,
173- settingsPath : string
178+ settingsPath : string ,
179+ account ?: string
174180) : void {
175181 const configPath = getConfigPath ( ) ;
176182
@@ -189,10 +195,16 @@ function addCliproxyVariant(
189195
190196 // Use relative path with ~ for portability
191197 const relativePath = `~/.ccs/${ path . basename ( settingsPath ) } ` ;
192- config . cliproxy [ name ] = {
198+
199+ // Build variant config with optional account
200+ const variantConfig : { provider : string ; settings : string ; account ?: string } = {
193201 provider,
194202 settings : relativePath ,
195203 } ;
204+ if ( account ) {
205+ variantConfig . account = account ;
206+ }
207+ config . cliproxy [ name ] = variantConfig ;
196208
197209 // Write config atomically
198210 const tempPath = configPath + '.tmp' ;
@@ -290,6 +302,103 @@ async function handleCreate(args: string[]): Promise<void> {
290302 process . exit ( 1 ) ;
291303 }
292304
305+ // Step 2.5: Account selection
306+ let account = parsedArgs . account ;
307+ const providerAccounts = getProviderAccounts ( provider as CLIProxyProvider ) ;
308+
309+ if ( ! account ) {
310+ if ( providerAccounts . length === 0 ) {
311+ // No accounts - prompt to authenticate first
312+ console . log ( '' ) ;
313+ console . log ( warn ( `No accounts authenticated for ${ provider } ` ) ) ;
314+ console . log ( '' ) ;
315+
316+ const shouldAuth = await InteractivePrompt . confirm ( `Authenticate with ${ provider } now?` , {
317+ default : true ,
318+ } ) ;
319+
320+ if ( ! shouldAuth ) {
321+ console . log ( '' ) ;
322+ console . log ( info ( 'Run authentication first:' ) ) ;
323+ console . log ( ` ${ color ( `ccs ${ provider } --auth` , 'command' ) } ` ) ;
324+ process . exit ( 0 ) ;
325+ }
326+
327+ // Trigger OAuth inline
328+ console . log ( '' ) ;
329+ const newAccount = await triggerOAuth ( provider as CLIProxyProvider , {
330+ add : true ,
331+ verbose : args . includes ( '--verbose' ) ,
332+ } ) ;
333+
334+ if ( ! newAccount ) {
335+ console . log ( fail ( 'Authentication failed' ) ) ;
336+ process . exit ( 1 ) ;
337+ }
338+
339+ account = newAccount . id ;
340+ console . log ( '' ) ;
341+ console . log ( ok ( `Authenticated as ${ newAccount . email || newAccount . id } ` ) ) ;
342+ } else if ( providerAccounts . length === 1 ) {
343+ // Single account - auto-select
344+ account = providerAccounts [ 0 ] . id ;
345+ } else {
346+ // Multiple accounts - show selector with "Add new" option
347+ const ADD_NEW_ID = '__add_new__' ;
348+
349+ const accountOptions = [
350+ ...providerAccounts . map ( ( acc ) => ( {
351+ id : acc . id ,
352+ label : `${ acc . email || acc . id } ${ acc . isDefault ? ' (default)' : '' } ` ,
353+ } ) ) ,
354+ {
355+ id : ADD_NEW_ID ,
356+ label : color ( '[+ Add new account...]' , 'info' ) ,
357+ } ,
358+ ] ;
359+
360+ const defaultIdx = providerAccounts . findIndex ( ( a ) => a . isDefault ) ;
361+
362+ const selectedAccount = await InteractivePrompt . selectFromList (
363+ 'Select account:' ,
364+ accountOptions ,
365+ { defaultIndex : defaultIdx >= 0 ? defaultIdx : 0 }
366+ ) ;
367+
368+ if ( selectedAccount === ADD_NEW_ID ) {
369+ // Add new account inline
370+ console . log ( '' ) ;
371+ const newAccount = await triggerOAuth ( provider as CLIProxyProvider , {
372+ add : true ,
373+ verbose : args . includes ( '--verbose' ) ,
374+ } ) ;
375+
376+ if ( ! newAccount ) {
377+ console . log ( fail ( 'Authentication failed' ) ) ;
378+ process . exit ( 1 ) ;
379+ }
380+
381+ account = newAccount . id ;
382+ console . log ( '' ) ;
383+ console . log ( ok ( `Authenticated as ${ newAccount . email || newAccount . id } ` ) ) ;
384+ } else {
385+ account = selectedAccount ;
386+ }
387+ }
388+ } else {
389+ // Validate provided account exists
390+ const exists = providerAccounts . find ( ( a ) => a . id === account ) ;
391+ if ( ! exists ) {
392+ console . log ( fail ( `Account '${ account } ' not found for ${ provider } ` ) ) ;
393+ console . log ( '' ) ;
394+ console . log ( 'Available accounts:' ) ;
395+ providerAccounts . forEach ( ( a ) => {
396+ console . log ( ` - ${ a . email || a . id } ${ a . isDefault ? ' (default)' : '' } ` ) ;
397+ } ) ;
398+ process . exit ( 1 ) ;
399+ }
400+ }
401+
293402 // Step 3: Model selection
294403 let model = parsedArgs . model ;
295404 if ( ! model ) {
@@ -323,15 +432,16 @@ async function handleCreate(args: string[]): Promise<void> {
323432 console . log ( info ( 'Creating CLIProxy variant...' ) ) ;
324433
325434 try {
326- const settingsPath = createCliproxySettingsFile ( name , provider , model ) ;
327- addCliproxyVariant ( name , provider , settingsPath ) ;
435+ const settingsPath = createCliproxySettingsFile ( name , provider , model , account ) ;
436+ addCliproxyVariant ( name , provider , settingsPath , account ) ;
328437
329438 console . log ( '' ) ;
330439 console . log (
331440 infoBox (
332441 `Variant: ${ name } \n` +
333442 `Provider: ${ provider } \n` +
334443 `Model: ${ model } \n` +
444+ ( account ? `Account: ${ account } \n` : '' ) +
335445 `Settings: ~/.ccs/${ path . basename ( settingsPath ) } ` ,
336446 'CLIProxy Variant Created'
337447 )
@@ -551,6 +661,7 @@ async function showHelp(): Promise<void> {
551661 const createOpts : [ string , string ] [ ] = [
552662 [ '--provider <name>' , 'Provider (gemini, codex, agy, qwen)' ] ,
553663 [ '--model <model>' , 'Model name' ] ,
664+ [ '--account <id>' , 'Account ID (email or default)' ] ,
554665 [ '--force' , 'Overwrite existing variant' ] ,
555666 [ '--yes, -y' , 'Skip confirmation prompts' ] ,
556667 ] ;
0 commit comments