diff --git a/crates/openshell-bootstrap/src/lib.rs b/crates/openshell-bootstrap/src/lib.rs index 9098fd4a..93898675 100644 --- a/crates/openshell-bootstrap/src/lib.rs +++ b/crates/openshell-bootstrap/src/lib.rs @@ -48,10 +48,10 @@ pub use crate::docker::{ DockerPreflight, ExistingGatewayInfo, check_docker_available, create_ssh_docker_client, }; pub use crate::metadata::{ - GatewayMetadata, clear_active_gateway, extract_host_from_ssh_destination, get_gateway_metadata, - list_gateways, load_active_gateway, load_gateway_metadata, load_last_sandbox, - remove_gateway_metadata, resolve_ssh_hostname, save_active_gateway, save_last_sandbox, - store_gateway_metadata, + GatewayMetadata, clear_active_gateway, clear_last_sandbox_if_matches, + extract_host_from_ssh_destination, get_gateway_metadata, list_gateways, load_active_gateway, + load_gateway_metadata, load_last_sandbox, remove_gateway_metadata, resolve_ssh_hostname, + save_active_gateway, save_last_sandbox, store_gateway_metadata, }; /// Options for remote SSH deployment. diff --git a/crates/openshell-bootstrap/src/metadata.rs b/crates/openshell-bootstrap/src/metadata.rs index bd49ba8c..15f79c08 100644 --- a/crates/openshell-bootstrap/src/metadata.rs +++ b/crates/openshell-bootstrap/src/metadata.rs @@ -271,6 +271,20 @@ pub fn load_last_sandbox(gateway: &str) -> Option { if name.is_empty() { None } else { Some(name) } } +/// Clear the last-used sandbox record for a gateway if it matches the given name. +/// +/// This should be called after a sandbox is deleted so that subsequent commands +/// don't try to connect to a sandbox that no longer exists. +pub fn clear_last_sandbox_if_matches(gateway: &str, sandbox: &str) { + if let Some(current) = load_last_sandbox(gateway) { + if current == sandbox { + if let Ok(path) = last_sandbox_path(gateway) { + let _ = std::fs::remove_file(path); + } + } + } +} + /// List all gateways that have stored metadata. /// /// Scans `$XDG_CONFIG_HOME/openshell/gateways/` for subdirectories containing diff --git a/crates/openshell-cli/src/main.rs b/crates/openshell-cli/src/main.rs index 3799b392..5de31c79 100644 --- a/crates/openshell-cli/src/main.rs +++ b/crates/openshell-cli/src/main.rs @@ -2268,7 +2268,7 @@ async fn main() -> Result<()> { run::sandbox_list(endpoint, limit, offset, ids, names, &tls).await?; } SandboxCommands::Delete { names, all } => { - run::sandbox_delete(endpoint, &names, all, &tls).await?; + run::sandbox_delete(endpoint, &names, all, &tls, &ctx.name).await?; } SandboxCommands::Connect { name, editor } => { let name = resolve_sandbox_name(name, &ctx.name)?; diff --git a/crates/openshell-cli/src/run.rs b/crates/openshell-cli/src/run.rs index a4331ee5..e32eec2a 100644 --- a/crates/openshell-cli/src/run.rs +++ b/crates/openshell-cli/src/run.rs @@ -16,10 +16,10 @@ use hyper_util::{client::legacy::Client, rt::TokioExecutor}; use indicatif::{MultiProgress, ProgressBar, ProgressStyle}; use miette::{IntoDiagnostic, Result, WrapErr, miette}; use openshell_bootstrap::{ - DeployOptions, GatewayMetadata, RemoteOptions, clear_active_gateway, container_name, - extract_host_from_ssh_destination, get_gateway_metadata, list_gateways, load_active_gateway, - remove_gateway_metadata, resolve_ssh_hostname, save_active_gateway, save_last_sandbox, - store_gateway_metadata, + DeployOptions, GatewayMetadata, RemoteOptions, clear_active_gateway, + clear_last_sandbox_if_matches, container_name, extract_host_from_ssh_destination, + get_gateway_metadata, list_gateways, load_active_gateway, remove_gateway_metadata, + resolve_ssh_hostname, save_active_gateway, save_last_sandbox, store_gateway_metadata, }; use openshell_core::proto::{ ApproveAllDraftChunksRequest, ApproveDraftChunkRequest, ClearDraftChunksRequest, @@ -1904,13 +1904,14 @@ async fn finalize_sandbox_create_session( persist: bool, session_result: Result<()>, tls: &TlsOptions, + gateway: &str, ) -> Result<()> { if persist { return session_result; } let names = [sandbox_name.to_string()]; - if let Err(err) = sandbox_delete(server, &names, false, tls).await { + if let Err(err) = sandbox_delete(server, &names, false, tls, gateway).await { if session_result.is_ok() { return Err(err); } @@ -2380,6 +2381,7 @@ pub async fn sandbox_create( persist, connect_result, &effective_tls, + gateway_name, ) .await; } @@ -2415,6 +2417,7 @@ pub async fn sandbox_create( persist, exec_result, &effective_tls, + gateway_name, ) .await } @@ -2824,6 +2827,7 @@ pub async fn sandbox_delete( names: &[String], all: bool, tls: &TlsOptions, + gateway: &str, ) -> Result<()> { let mut client = grpc_client(server, tls).await?; @@ -2864,6 +2868,7 @@ pub async fn sandbox_delete( let deleted = response.into_inner().deleted; if deleted { + clear_last_sandbox_if_matches(gateway, name); println!("{} Deleted sandbox {name}", "✓".green().bold()); } else { println!("{} Sandbox {name} not found", "!".yellow());