1- import { autocomplete , intro , outro , spinner } from "@clack/prompts"
1+ import { intro , outro , spinner } from "@clack/prompts"
22import { Effect , Option } from "effect"
3- import type { IntegrationInfo } from "@opencode/client"
43import { Commands } from "../../commands"
54import { Runtime } from "../../../framework/runtime"
6- import { handlePromptErrors , prompt , requireInteractive } from "../../../ui/prompt"
7- import { createClient , loadIntegrations , location , request , resolveIntegration } from "./shared"
5+ import { handlePromptErrors , requireInteractive } from "../../../ui/prompt"
6+ import { createClient , loadIntegrations , location , request } from "./shared"
7+ import { chooseCredential , chooseIntegration } from "./account"
88
99export default Runtime . handler (
1010 Commands . commands . auth . commands . logout ,
1111 Effect . fn ( "cli.auth.logout" ) ( ( input ) =>
1212 logout ( {
1313 target : Option . getOrUndefined ( input . target ) ,
14+ credential : Option . getOrUndefined ( input . credential ) ,
1415 server : Option . getOrUndefined ( input . server ) ,
1516 standalone : input . standalone ,
1617 } ) . pipe ( handlePromptErrors ) ,
@@ -19,65 +20,24 @@ export default Runtime.handler(
1920
2021const logout = Effect . fn ( "cli.auth.logout.run" ) ( function * ( input : {
2122 target ?: string
23+ credential ?: string
2224 server ?: string
2325 standalone : boolean
2426} ) {
2527 if ( ! input . target )
2628 yield * requireInteractive ( "Pass an integration ID or name when running without an interactive terminal" )
27- intro ( "Remove credential" )
29+ if ( ! input . credential )
30+ yield * requireInteractive ( "Pass a credential ID or label when running without an interactive terminal" )
31+ intro ( "Log out of an account" )
2832 const client = yield * createClient ( { server : input . server , standalone : input . standalone } )
2933 const integrations = yield * loadIntegrations ( client )
3034 const integration = yield * chooseIntegration ( integrations , input . target )
31- const credentials = integration . connections . filter ( ( connection ) => connection . type === "credential" )
32- if ( credentials . length === 0 ) {
33- const environment = integration . connections
34- . filter ( ( connection ) => connection . type === "env" )
35- . map ( ( connection ) => connection . name )
36- if ( environment . length ) {
37- yield * Effect . fail (
38- new Error (
39- `${ integration . name } is authenticated through ${ environment . join ( ", " ) } ; unset the environment variable to disconnect` ,
40- ) ,
41- )
42- }
43- yield * Effect . fail ( new Error ( `No stored credentials for ${ integration . name } ` ) )
44- }
35+ const credentialID = yield * chooseCredential ( integration , "log out" , input . credential )
4536 const progress = spinner ( )
4637 progress . start ( "Removing credential..." )
47- yield * Effect . forEach (
48- credentials ,
49- ( connection ) =>
50- request ( ( signal ) => client . credential . remove ( { credentialID : connection . id , location } , { signal } ) ) ,
51- { concurrency : "unbounded" , discard : true } ,
52- ) . pipe (
53- Effect . tap ( ( ) => Effect . sync ( ( ) => progress . stop ( `Disconnected from ${ integration . name } ` ) ) ) ,
38+ yield * request ( ( signal ) => client . credential . remove ( { credentialID, location } , { signal } ) ) . pipe (
39+ Effect . tap ( ( ) => Effect . sync ( ( ) => progress . stop ( `Removed account from ${ integration . name } ` ) ) ) ,
5440 Effect . tapCause ( ( ) => Effect . sync ( ( ) => progress . stop ( "Failed to remove credential" , 1 ) ) ) ,
5541 )
5642 outro ( "Done" )
5743} )
58-
59- const chooseIntegration = Effect . fn ( "cli.auth.logout.integration" ) ( function * (
60- integrations : IntegrationInfo [ ] ,
61- target ?: string ,
62- ) {
63- if ( target ) return yield * resolveIntegration ( integrations , target )
64- const configured = integrations . filter ( ( integration ) =>
65- integration . connections . some ( ( connection ) => connection . type === "credential" ) ,
66- )
67- if ( configured . length === 0 ) return yield * Effect . fail ( new Error ( "No stored credentials found" ) )
68- const id = yield * prompt < string > ( ( ) =>
69- autocomplete ( {
70- message : "Select integration" ,
71- maxItems : 8 ,
72- options : configured . map ( ( integration ) => ( {
73- value : integration . id ,
74- label : integration . name ,
75- hint : integration . connections
76- . filter ( ( connection ) => connection . type === "credential" )
77- . map ( ( connection ) => connection . label )
78- . join ( ", " ) ,
79- } ) ) ,
80- } ) ,
81- )
82- return yield * resolveIntegration ( configured , id )
83- } )
0 commit comments