@@ -343,7 +343,14 @@ pub struct LsArgs {
343343#[ derive( Debug , Args ) ]
344344pub struct DestroyArgs {
345345 /// Session identifier (UUID or session name)
346- pub session : String ,
346+ #[ arg( required_unless_present = "all" , conflicts_with = "all" ) ]
347+ pub session : Option < String > ,
348+ /// Destroy all sessions
349+ #[ arg( long) ]
350+ pub all : bool ,
351+ /// Skip confirmation when destroying all sessions
352+ #[ arg( long, short, requires = "all" ) ]
353+ pub force : bool ,
347354}
348355
349356#[ derive( Debug , Args ) ]
@@ -601,6 +608,19 @@ fn confirm(question: &str) -> Result<bool, anyhow::Error> {
601608 || trimmed. eq_ignore_ascii_case ( "yes" ) )
602609}
603610
611+ /// Prompt for confirmation, defaulting to no.
612+ fn confirm_default_no ( question : & str ) -> Result < bool , anyhow:: Error > {
613+ eprint ! ( "{question} [y/N] " ) ;
614+ std:: io:: stderr ( ) . flush ( ) . ok ( ) ;
615+
616+ let mut input = String :: new ( ) ;
617+ std:: io:: stdin ( )
618+ . read_line ( & mut input)
619+ . context ( "reading stdin" ) ?;
620+ let trimmed = input. trim ( ) ;
621+ Ok ( trimmed. eq_ignore_ascii_case ( "y" ) || trimmed. eq_ignore_ascii_case ( "yes" ) )
622+ }
623+
604624/// List sessions via the `ListSessions` RPC.
605625pub async fn cmd_ls ( global : & GlobalArgs , args : LsArgs ) -> Result < ( ) , anyhow:: Error > {
606626 ensure_daemon ( global) ?;
@@ -1267,20 +1287,80 @@ pub async fn cmd_destroy(global: &GlobalArgs, args: DestroyArgs) -> Result<(), a
12671287
12681288 let mut client = connect_daemon ( global) . await ?;
12691289
1290+ if args. all {
1291+ return destroy_all_sessions ( & mut client, args. force ) . await ;
1292+ }
1293+
1294+ let session = args
1295+ . session
1296+ . as_deref ( )
1297+ . context ( "a session or --all is required" ) ?;
1298+ let record = resolve_session ( & mut client, session) . await ?;
1299+
1300+ destroy_session ( & mut client, record. id , record. name . as_deref ( ) ) . await
1301+ }
1302+
1303+ async fn destroy_all_sessions (
1304+ client : & mut client:: Client ,
1305+ force : bool ,
1306+ ) -> Result < ( ) , anyhow:: Error > {
1307+ use minimald_rpc:: ListSessions ;
1308+
1309+ let sessions = client
1310+ . oneshot_rpc :: < ListSessions > ( ( ) )
1311+ . await
1312+ . context ( "ListSessions RPC failed" ) ?
1313+ . sessions ;
1314+
1315+ if sessions. is_empty ( ) {
1316+ println ! ( "No active sessions." ) ;
1317+ return Ok ( ( ) ) ;
1318+ }
1319+
1320+ if !force {
1321+ if !std:: io:: stdin ( ) . is_terminal ( ) {
1322+ bail ! ( "refusing to destroy all sessions without confirmation; pass --force" )
1323+ }
1324+ if !confirm_default_no ( & format ! ( "Destroy all {} sessions?" , sessions. len( ) ) ) ? {
1325+ println ! ( "Aborted." ) ;
1326+ return Ok ( ( ) ) ;
1327+ }
1328+ }
1329+
1330+ let session_count = sessions. len ( ) ;
1331+ let mut failures = 0 ;
1332+ for session in sessions {
1333+ if let Err ( error) = destroy_session ( client, session. id , session. name . as_deref ( ) ) . await {
1334+ failures += 1 ;
1335+ eprintln ! (
1336+ "Failed to destroy session {} ({}): {error:#}" ,
1337+ session. id,
1338+ session. name. as_deref( ) . unwrap_or( "-" )
1339+ ) ;
1340+ }
1341+ }
1342+
1343+ if failures > 0 {
1344+ bail ! ( "failed to destroy {failures} of {session_count} sessions" )
1345+ }
1346+
1347+ Ok ( ( ) )
1348+ }
1349+
1350+ async fn destroy_session (
1351+ client : & mut client:: Client ,
1352+ id : sessions:: SessionId ,
1353+ name : Option < & str > ,
1354+ ) -> Result < ( ) , anyhow:: Error > {
12701355 use minimald_rpc:: { DestroySession , DestroySessionRequest } ;
1271- let record = resolve_session ( & mut client, & args. session ) . await ?;
12721356
12731357 let resp = client
1274- . oneshot_rpc :: < DestroySession > ( DestroySessionRequest { id : record . id } )
1358+ . oneshot_rpc :: < DestroySession > ( DestroySessionRequest { id } )
12751359 . await
12761360 . context ( "DestroySession RPC failed" ) ?;
12771361
12781362 if resp. ok ( ) . is_some ( ) {
1279- println ! (
1280- "Destroyed session {} ({})" ,
1281- record. id,
1282- record. name. as_deref( ) . unwrap_or( "-" )
1283- ) ;
1363+ println ! ( "Destroyed session {} ({})" , id, name. unwrap_or( "-" ) ) ;
12841364 } else {
12851365 bail ! ( "DestroySession returned an error from the daemon" ) ;
12861366 }
0 commit comments