@@ -102,178 +102,223 @@ export const AuthLoginCommand = cmd({
102102 prompts . outro ( "Done" )
103103 return
104104 }
105- await ModelsDev . refresh ( ) . catch ( ( ) => { } )
106- const providers = await ModelsDev . get ( )
107- const priority : Record < string , number > = {
108- opencode : 0 ,
109- anthropic : 1 ,
110- "github-copilot" : 2 ,
111- openai : 3 ,
112- google : 4 ,
113- openrouter : 5 ,
114- vercel : 6 ,
115- }
116- let provider = await prompts . autocomplete ( {
117- message : "Select provider" ,
118- maxItems : 8 ,
119- options : [
120- ...pipe (
121- providers ,
122- values ( ) ,
123- sortBy (
124- ( x ) => priority [ x . id ] ?? 99 ,
125- ( x ) => x . name ?? x . id ,
126- ) ,
127- map ( ( x ) => ( {
128- label : x . name ,
129- value : x . id ,
130- hint : priority [ x . id ] <= 1 ? "recommended" : undefined ,
131- } ) ) ,
105+ await ModelsDev . refresh ( ) . catch ( ( ) => { } )
106+ const providers = await ModelsDev . get ( )
107+ const priority : Record < string , number > = {
108+ opencode : 0 ,
109+ anthropic : 1 ,
110+ "github-copilot" : 2 ,
111+ openai : 3 ,
112+ google : 4 ,
113+ openrouter : 5 ,
114+ vercel : 6 ,
115+ }
116+ let provider = await prompts . autocomplete ( {
117+ message : "Select provider" ,
118+ maxItems : 8 ,
119+ options : [
120+ ...pipe (
121+ providers ,
122+ values ( ) ,
123+ sortBy (
124+ ( x ) => priority [ x . id ] ?? 99 ,
125+ ( x ) => x . name ?? x . id ,
132126 ) ,
133- {
134- value : "other" ,
135- label : "Other" ,
136- } ,
137- ] ,
138- } )
127+ map ( ( x ) => ( {
128+ label : x . name ,
129+ value : x . id ,
130+ hint : priority [ x . id ] <= 1 ? "recommended" : undefined ,
131+ } ) ) ,
132+ ) ,
133+ {
134+ value : "other" ,
135+ label : "Other" ,
136+ } ,
137+ ] ,
138+ } )
139139
140- if ( prompts . isCancel ( provider ) ) throw new UI . CancelledError ( )
140+ if ( prompts . isCancel ( provider ) ) throw new UI . CancelledError ( )
141141
142- const plugin = await Plugin . list ( ) . then ( ( x ) => x . find ( ( x ) => x . auth ?. provider === provider ) )
143- if ( plugin && plugin . auth ) {
144- let index = 0
145- if ( plugin . auth . methods . length > 1 ) {
146- const method = await prompts . select ( {
147- message : "Login method" ,
148- options : [
149- ...plugin . auth . methods . map ( ( x , index ) => ( {
150- label : x . label ,
151- value : index . toString ( ) ,
152- } ) ) ,
153- ] ,
154- } )
155- if ( prompts . isCancel ( method ) ) throw new UI . CancelledError ( )
156- index = parseInt ( method )
157- }
158- const method = plugin . auth . methods [ index ]
159- if ( method . type === "oauth" ) {
160- await new Promise ( ( resolve ) => setTimeout ( resolve , 10 ) )
161- const authorize = await method . authorize ( )
142+ const plugin = await Plugin . list ( ) . then ( ( x ) => x . find ( ( x ) => x . auth ?. provider === provider ) )
143+ if ( plugin && plugin . auth ) {
144+ let index = 0
145+ if ( plugin . auth . methods . length > 1 ) {
146+ const method = await prompts . select ( {
147+ message : "Login method" ,
148+ options : [
149+ ...plugin . auth . methods . map ( ( x , index ) => ( {
150+ label : x . label ,
151+ value : index . toString ( ) ,
152+ } ) ) ,
153+ ] ,
154+ } )
155+ if ( prompts . isCancel ( method ) ) throw new UI . CancelledError ( )
156+ index = parseInt ( method )
157+ }
158+ const method = plugin . auth . methods [ index ]
162159
163- if ( authorize . url ) {
164- prompts . log . info ( "Go to: " + authorize . url )
160+ // Handle prompts for all auth types
161+ await new Promise ( ( resolve ) => setTimeout ( resolve , 10 ) )
162+ const inputs : Record < string , string > = { }
163+ if ( method . prompts ) {
164+ for ( const prompt of method . prompts ) {
165+ if ( prompt . condition && ! prompt . condition ( inputs ) ) {
166+ continue
165167 }
168+ if ( prompt . type === "select" ) {
169+ const value = await prompts . select ( {
170+ message : prompt . message ,
171+ options : prompt . options ,
172+ } )
173+ if ( prompts . isCancel ( value ) ) throw new UI . CancelledError ( )
174+ inputs [ prompt . key ] = value
175+ } else {
176+ const value = await prompts . text ( {
177+ message : prompt . message ,
178+ placeholder : prompt . placeholder ,
179+ validate : prompt . validate ? ( v ) => prompt . validate ! ( v ?? "" ) : undefined ,
180+ } )
181+ if ( prompts . isCancel ( value ) ) throw new UI . CancelledError ( )
182+ inputs [ prompt . key ] = value
183+ }
184+ }
185+ }
166186
167- if ( authorize . method === "auto" ) {
168- if ( authorize . instructions ) {
169- prompts . log . info ( authorize . instructions )
170- }
171- const spinner = prompts . spinner ( )
172- spinner . start ( "Waiting for authorization..." )
173- const result = await authorize . callback ( )
174- if ( result . type === "failed" ) {
175- spinner . stop ( "Failed to authorize" , 1 )
187+ if ( method . type === "oauth" ) {
188+ const authorize = await method . authorize ( inputs )
189+
190+ if ( authorize . url ) {
191+ prompts . log . info ( "Go to: " + authorize . url )
192+ }
193+
194+ if ( authorize . method === "auto" ) {
195+ if ( authorize . instructions ) {
196+ prompts . log . info ( authorize . instructions )
197+ }
198+ const spinner = prompts . spinner ( )
199+ spinner . start ( "Waiting for authorization..." )
200+ const result = await authorize . callback ( )
201+ if ( result . type === "failed" ) {
202+ spinner . stop ( "Failed to authorize" , 1 )
203+ }
204+ if ( result . type === "success" ) {
205+ const saveProvider = result . provider ?? provider
206+ if ( "refresh" in result ) {
207+ const { type : _ , provider : __ , refresh, access, expires, ...extraFields } = result
208+ await Auth . set ( saveProvider , {
209+ type : "oauth" ,
210+ refresh,
211+ access,
212+ expires,
213+ ...extraFields ,
214+ } )
176215 }
177- if ( result . type === "success" ) {
178- if ( "refresh" in result ) {
179- await Auth . set ( provider , {
180- type : "oauth" ,
181- refresh : result . refresh ,
182- access : result . access ,
183- expires : result . expires ,
184- } )
185- }
186- if ( "key" in result ) {
187- await Auth . set ( provider , {
188- type : "api" ,
189- key : result . key ,
190- } )
191- }
192- spinner . stop ( "Login successful" )
216+ if ( "key" in result ) {
217+ await Auth . set ( saveProvider , {
218+ type : "api" ,
219+ key : result . key ,
220+ } )
193221 }
222+ spinner . stop ( "Login successful" )
194223 }
224+ }
195225
196- if ( authorize . method === "code" ) {
197- const code = await prompts . text ( {
198- message : "Paste the authorization code here: " ,
199- validate : ( x ) => ( x && x . length > 0 ? undefined : "Required" ) ,
200- } )
201- if ( prompts . isCancel ( code ) ) throw new UI . CancelledError ( )
202- const result = await authorize . callback ( code )
203- if ( result . type === "failed" ) {
204- prompts . log . error ( "Failed to authorize" )
226+ if ( authorize . method === "code" ) {
227+ const code = await prompts . text ( {
228+ message : "Paste the authorization code here: " ,
229+ validate : ( x ) => ( x && x . length > 0 ? undefined : "Required" ) ,
230+ } )
231+ if ( prompts . isCancel ( code ) ) throw new UI . CancelledError ( )
232+ const result = await authorize . callback ( code )
233+ if ( result . type === "failed" ) {
234+ prompts . log . error ( "Failed to authorize" )
235+ }
236+ if ( result . type === "success" ) {
237+ const saveProvider = result . provider ?? provider
238+ if ( "refresh" in result ) {
239+ const { type : _ , provider : __ , refresh, access, expires, ...extraFields } = result
240+ await Auth . set ( saveProvider , {
241+ type : "oauth" ,
242+ refresh,
243+ access,
244+ expires,
245+ ...extraFields ,
246+ } )
205247 }
206- if ( result . type === "success" ) {
207- if ( "refresh" in result ) {
208- await Auth . set ( provider , {
209- type : "oauth" ,
210- refresh : result . refresh ,
211- access : result . access ,
212- expires : result . expires ,
213- } )
214- }
215- if ( "key" in result ) {
216- await Auth . set ( provider , {
217- type : "api" ,
218- key : result . key ,
219- } )
220- }
221- prompts . log . success ( "Login successful" )
248+ if ( "key" in result ) {
249+ await Auth . set ( saveProvider , {
250+ type : "api" ,
251+ key : result . key ,
252+ } )
222253 }
254+ prompts . log . success ( "Login successful" )
223255 }
224- prompts . outro ( "Done" )
225- return
226256 }
227- }
228257
229- if ( provider === "other" ) {
230- provider = await prompts . text ( {
231- message : "Enter provider id" ,
232- validate : ( x ) => ( x && x . match ( / ^ [ 0 - 9 a - z - ] + $ / ) ? undefined : "a-z, 0-9 and hyphens only" ) ,
233- } )
234- if ( prompts . isCancel ( provider ) ) throw new UI . CancelledError ( )
235- provider = provider . replace ( / ^ @ a i - s d k \/ / , "" )
236- if ( prompts . isCancel ( provider ) ) throw new UI . CancelledError ( )
237- prompts . log . warn (
238- `This only stores a credential for ${ provider } - you will need configure it in opencode.json, check the docs for examples.` ,
239- )
240- }
241-
242- if ( provider === "amazon-bedrock" ) {
243- prompts . log . info (
244- "Amazon bedrock can be configured with standard AWS environment variables like AWS_BEARER_TOKEN_BEDROCK, AWS_PROFILE or AWS_ACCESS_KEY_ID" ,
245- )
246- prompts . outro ( "Done" )
247- return
248- }
249-
250- if ( provider === "google-vertex" ) {
251- prompts . log . info (
252- "Google Cloud Vertex AI uses Application Default Credentials. Set GOOGLE_APPLICATION_CREDENTIALS or run 'gcloud auth application-default login'. Optionally set GOOGLE_CLOUD_PROJECT and GOOGLE_CLOUD_LOCATION (or VERTEX_LOCATION)" ,
253- )
254258 prompts . outro ( "Done" )
255259 return
256260 }
257261
258- if ( provider === "opencode" ) {
259- prompts . log . info ( "Create an api key at https://opencode.ai/auth" )
260- }
261-
262- if ( provider === "vercel" ) {
263- prompts . log . info ( "You can create an api key at https://vercel.link/ai-gateway-token" )
262+ if ( method . type === "api" ) {
263+ if ( method . authorize ) {
264+ const result = await method . authorize ( inputs )
265+ if ( result . type === "failed" ) {
266+ prompts . log . error ( "Failed to authorize" )
267+ }
268+ if ( result . type === "success" ) {
269+ const saveProvider = result . provider ?? provider
270+ await Auth . set ( saveProvider , {
271+ type : "api" ,
272+ key : result . key ,
273+ } )
274+ prompts . log . success ( "Login successful" )
275+ }
276+ prompts . outro ( "Done" )
277+ return
278+ }
264279 }
280+ }
265281
266- const key = await prompts . password ( {
267- message : "Enter your API key" ,
268- validate : ( x ) => ( x && x . length > 0 ? undefined : "Required" ) ,
269- } )
270- if ( prompts . isCancel ( key ) ) throw new UI . CancelledError ( )
271- await Auth . set ( provider , {
272- type : "api" ,
273- key,
282+ if ( provider === "other" ) {
283+ provider = await prompts . text ( {
284+ message : "Enter provider id" ,
285+ validate : ( x ) => ( x && x . match ( / ^ [ 0 - 9 a - z - ] + $ / ) ? undefined : "a-z, 0-9 and hyphens only" ) ,
274286 } )
287+ if ( prompts . isCancel ( provider ) ) throw new UI . CancelledError ( )
288+ provider = provider . replace ( / ^ @ a i - s d k \/ / , "" )
289+ if ( prompts . isCancel ( provider ) ) throw new UI . CancelledError ( )
290+ prompts . log . warn (
291+ `This only stores a credential for ${ provider } - you will need configure it in opencode.json, check the docs for examples.` ,
292+ )
293+ }
275294
295+ if ( provider === "amazon-bedrock" ) {
296+ prompts . log . info (
297+ "Amazon bedrock can be configured with standard AWS environment variables like AWS_BEARER_TOKEN_BEDROCK, AWS_PROFILE or AWS_ACCESS_KEY_ID" ,
298+ )
276299 prompts . outro ( "Done" )
300+ return
301+ }
302+
303+ if ( provider === "opencode" ) {
304+ prompts . log . info ( "Create an api key at https://opencode.ai/auth" )
305+ }
306+
307+ if ( provider === "vercel" ) {
308+ prompts . log . info ( "You can create an api key at https://vercel.link/ai-gateway-token" )
309+ }
310+
311+ const key = await prompts . password ( {
312+ message : "Enter your API key" ,
313+ validate : ( x ) => ( x && x . length > 0 ? undefined : "Required" ) ,
314+ } )
315+ if ( prompts . isCancel ( key ) ) throw new UI . CancelledError ( )
316+ await Auth . set ( provider , {
317+ type : "api" ,
318+ key,
319+ } )
320+
321+ prompts . outro ( "Done" )
277322 } ,
278323 } )
279324 } ,
0 commit comments