11import {
2+ AUTH_MODES ,
23 BailianError ,
4+ CODING_PLAN_REGIONS ,
35 ExitCode ,
6+ TOKEN_PLAN_REGIONS ,
47 chatEndpoint ,
58 defineCommand ,
69 getConfigPath ,
@@ -9,12 +12,16 @@ import {
912 readConfigFile ,
1013 requestJson ,
1114 writeConfigFile ,
15+ type AuthMode ,
16+ type CodingPlanRegion ,
1217 type Config ,
1318 type GlobalFlags ,
19+ type TokenPlanRegion ,
1420} from "bailian-cli-core" ;
1521import { printQuickStart } from "../../output/banner.ts" ;
1622import { emitBare } from "../../output/output.ts" ;
1723import { promptConfirm } from "../../output/prompt.ts" ;
24+ import { interactiveAuthSetup } from "../../utils/auth-wizard.ts" ;
1825import { printCurrentCommandHelp } from "../../utils/command-help.ts" ;
1926import { resolveConsoleOrigin , runConsoleLogin } from "./login-console.ts" ;
2027
@@ -39,11 +46,26 @@ function canRetry(err: unknown): boolean {
3946 return false ;
4047}
4148
42- async function validateKeyAndPersist ( config : Config , key : string ) : Promise < void > {
49+ async function validateKeyAndPersist (
50+ config : Config ,
51+ key : string ,
52+ mode : AuthMode ,
53+ codingPlanRegion : CodingPlanRegion ,
54+ tokenPlanRegion : TokenPlanRegion ,
55+ ) : Promise < void > {
4356 process . stderr . write ( "Testing key... " ) ;
44- const testConfig = { ...config , apiKey : key } ;
57+ const testConfig : Config = {
58+ ...config ,
59+ activeAuthMode : mode ,
60+ apiKey : undefined ,
61+ fileApiKey : mode === "standard-api-key" ? key : undefined ,
62+ codingPlanApiKey : mode === "coding-plan" ? key : config . codingPlanApiKey ,
63+ codingPlanRegion,
64+ tokenPlanApiKey : mode === "token-plan" ? key : config . tokenPlanApiKey ,
65+ tokenPlanRegion,
66+ } ;
4567 const requestOpts = {
46- url : chatEndpoint ( testConfig . baseUrl ) ,
68+ url : chatEndpoint ( testConfig ) ,
4769 method : "POST" ,
4870 timeout : Math . min ( config . timeout , 30 ) ,
4971 body : {
@@ -64,7 +86,6 @@ async function validateKeyAndPersist(config: Config, key: string): Promise<void>
6486 cause : err ,
6587 } ) ;
6688 }
67- // retry delay: 500ms, 1000ms, 2000ms
6889 const delayMs = RETRY_DELAY_BASE_MS * 2 ** ( attempt - 1 ) ;
6990 await new Promise ( ( resolve ) => setTimeout ( resolve , delayMs ) ) ;
7091 }
@@ -73,25 +94,49 @@ async function validateKeyAndPersist(config: Config, key: string): Promise<void>
7394 process . stderr . write ( "Valid\n" ) ;
7495
7596 const existing = readConfigFile ( ) as Record < string , unknown > ;
76- existing . api_key = key ;
97+ existing . active_auth_mode = mode ;
98+ if ( mode === "standard-api-key" ) existing . api_key = key ;
99+ if ( mode === "coding-plan" ) {
100+ existing . coding_plan_api_key = key ;
101+ existing . coding_plan_region = codingPlanRegion ;
102+ }
103+ if ( mode === "token-plan" ) {
104+ existing . token_plan_api_key = key ;
105+ existing . token_plan_region = tokenPlanRegion ;
106+ }
77107 await writeConfigFile ( existing ) ;
108+ process . stderr . write ( `Active auth mode set to ${ mode } \n` ) ;
78109 process . stderr . write ( `Saved to ${ getConfigPath ( ) } \n` ) ;
79110}
80111
81112export default defineCommand ( {
82113 name : "auth login" ,
83- description : "Authenticate with API key or console browser login (credentials can coexist) " ,
84- usage : "bl auth login --api-key <key> | bl auth login --console" ,
114+ description : "Authenticate with API key, console browser login, or interactive wizard " ,
115+ usage : "bl auth login --mode <mode> -- api-key <key> | bl auth login --console" ,
85116 options : [
86- { flag : "--api-key <key>" , description : "DashScope API key to store" } ,
117+ {
118+ flag : "--mode <mode>" ,
119+ description : "Auth mode: standard-api-key, coding-plan, token-plan" ,
120+ } ,
121+ { flag : "--api-key <key>" , description : "API key for the selected auth mode" } ,
122+ { flag : "--coding-plan-api-key <key>" , description : "Coding Plan API key (sets mode)" } ,
123+ { flag : "--coding-plan-region <region>" , description : "Coding Plan region: cn, intl" } ,
124+ { flag : "--token-plan-api-key <key>" , description : "Token Plan API key (sets mode)" } ,
125+ { flag : "--token-plan-region <region>" , description : "Token Plan region: cn, intl" } ,
87126 {
88127 flag : "--console" ,
89128 description : "Sign in via browser; opens the console login URL in your default browser" ,
90129 type : "boolean" ,
91130 } ,
92131 ] ,
93- examples : [ "bl auth login --api-key sk-xxxxx" , "bl auth login --console" ] ,
132+ examples : [
133+ "bl auth login --api-key sk-xxxxx" ,
134+ "bl auth login --mode coding-plan --api-key sk-sp-xxxxx" ,
135+ "bl auth login --token-plan-api-key sk-xxxxx --token-plan-region intl" ,
136+ "bl auth login --console" ,
137+ ] ,
94138 async run ( config : Config , flags : GlobalFlags ) {
139+ // Console login branch (cli-specific)
95140 if ( flags . console ) {
96141 if ( config . dryRun ) {
97142 emitBare (
@@ -102,11 +147,32 @@ export default defineCommand({
102147 const hasApiKey = ! ! ( config . apiKey || config . fileApiKey ) ;
103148 await runConsoleLogin ( resolveConsoleOrigin ( ) , {
104149 needApiKey : ! hasApiKey ,
105- onApiKey : ( key ) => validateKeyAndPersist ( config , key ) ,
150+ onApiKey : ( key ) =>
151+ validateKeyAndPersist (
152+ config ,
153+ key ,
154+ "standard-api-key" ,
155+ config . codingPlanRegion ,
156+ config . tokenPlanRegion ,
157+ ) ,
106158 } ) ;
107159 return ;
108160 }
109161
162+ const hasFlags = ! ! (
163+ flags . mode ||
164+ flags . apiKey ||
165+ flags . codingPlanApiKey ||
166+ flags . tokenPlanApiKey ||
167+ flags . codingPlanRegion ||
168+ flags . tokenPlanRegion
169+ ) ;
170+
171+ let mode : AuthMode ;
172+ let key : string | undefined ;
173+ let codingPlanRegion : CodingPlanRegion ;
174+ let tokenPlanRegion : TokenPlanRegion ;
175+
110176 const envKey = process . env . DASHSCOPE_API_KEY ;
111177 if ( envKey && ! flags . apiKey ) {
112178 const maskedEnvKey = maskToken ( envKey ) ;
@@ -119,22 +185,93 @@ export default defineCommand({
119185 process . stdout . write ( "Login skipped. Using environment variables.\n" ) ;
120186 process . exit ( 0 ) ;
121187 }
122- } else {
188+ } else if ( hasFlags ) {
123189 process . stderr . write ( `Warning: DASHSCOPE_API_KEY is already set in environment.\n` ) ;
124190 }
125191 }
126192
127- const key = ( flags . apiKey as string ) || config . apiKey ;
193+ if ( ! hasFlags && isInteractive ( { nonInteractive : config . nonInteractive } ) ) {
194+ const result = await interactiveAuthSetup ( config ) ;
195+ mode = result . mode ;
196+ key = result . key ;
197+ codingPlanRegion = result . codingPlanRegion ?? config . codingPlanRegion ;
198+ tokenPlanRegion = result . tokenPlanRegion ?? config . tokenPlanRegion ;
199+ } else {
200+ const explicitMode = flags . mode as string | undefined ;
201+ mode = resolveLoginMode ( explicitMode , flags ) ;
202+ key =
203+ ( flags . apiKey as string | undefined ) ||
204+ ( flags . codingPlanApiKey as string | undefined ) ||
205+ ( flags . tokenPlanApiKey as string | undefined ) ||
206+ ( mode === "standard-api-key" ? config . apiKey : undefined ) ;
207+ codingPlanRegion = resolveCodingPlanRegion ( flags , config ) ;
208+ tokenPlanRegion = resolveTokenPlanRegion ( flags , config ) ;
209+ }
210+
128211 if ( ! key ) {
129- printCurrentCommandHelp ( process . stderr ) ;
130- process . exit ( 0 ) ;
212+ if ( ! hasFlags ) {
213+ printCurrentCommandHelp ( process . stderr ) ;
214+ process . exit ( 0 ) ;
215+ }
216+ throw new BailianError (
217+ "--api-key is required." ,
218+ ExitCode . USAGE ,
219+ "bl auth login --mode <mode> --api-key <key>" ,
220+ ) ;
221+ }
222+
223+ if ( mode === "coding-plan" && ! key . startsWith ( "sk-sp-" ) ) {
224+ throw new BailianError (
225+ 'Invalid API key. Coding Plan API keys start with "sk-sp-".' ,
226+ ExitCode . USAGE ,
227+ ) ;
131228 }
132229
133230 if ( ! config . dryRun ) {
134- await validateKeyAndPersist ( config , key ) ;
231+ await validateKeyAndPersist ( config , key , mode , codingPlanRegion , tokenPlanRegion ) ;
135232 printQuickStart ( ) ;
136233 } else {
137- emitBare ( " Would validate and save API key." ) ;
234+ emitBare ( ` Would validate and save ${ mode } API key.` ) ;
138235 }
139236 } ,
140237} ) ;
238+
239+ function resolveLoginMode ( explicitMode : string | undefined , flags : GlobalFlags ) : AuthMode {
240+ if ( explicitMode ) {
241+ if ( ! AUTH_MODES . has ( explicitMode ) ) {
242+ throw new BailianError (
243+ `Invalid auth mode "${ explicitMode } ".` ,
244+ ExitCode . USAGE ,
245+ "Valid modes: standard-api-key, coding-plan, token-plan" ,
246+ ) ;
247+ }
248+ return explicitMode as AuthMode ;
249+ }
250+ if ( flags . codingPlanApiKey ) return "coding-plan" ;
251+ if ( flags . tokenPlanApiKey ) return "token-plan" ;
252+ return "standard-api-key" ;
253+ }
254+
255+ function resolveCodingPlanRegion ( flags : GlobalFlags , config : Config ) : CodingPlanRegion {
256+ const region = ( flags . codingPlanRegion as string | undefined ) || config . codingPlanRegion ;
257+ if ( ! CODING_PLAN_REGIONS . has ( region ) ) {
258+ throw new BailianError (
259+ `Invalid Coding Plan region "${ region } ".` ,
260+ ExitCode . USAGE ,
261+ "Valid Coding Plan regions: cn, intl" ,
262+ ) ;
263+ }
264+ return region as CodingPlanRegion ;
265+ }
266+
267+ function resolveTokenPlanRegion ( flags : GlobalFlags , config : Config ) : TokenPlanRegion {
268+ const region = ( flags . tokenPlanRegion as string | undefined ) || config . tokenPlanRegion ;
269+ if ( ! TOKEN_PLAN_REGIONS . has ( region ) ) {
270+ throw new BailianError (
271+ `Invalid Token Plan region "${ region } ".` ,
272+ ExitCode . USAGE ,
273+ "Valid Token Plan regions: cn, intl" ,
274+ ) ;
275+ }
276+ return region as TokenPlanRegion ;
277+ }
0 commit comments