diff --git a/app/src-tauri/src/commands/project_commands.rs b/app/src-tauri/src/commands/project_commands.rs index a7c881a..6dec327 100644 --- a/app/src-tauri/src/commands/project_commands.rs +++ b/app/src-tauri/src/commands/project_commands.rs @@ -102,9 +102,37 @@ pub async fn start_project_container( // Check for existing container let container_id = if let Some(existing_id) = docker::find_existing_container(&project).await? { - // Start existing container - docker::start_container(&existing_id).await?; - existing_id + // Check if docker socket mount matches the current project setting. + // If the user toggled "Allow container spawning" after the container was + // created, we need to recreate the container for the mount change to take + // effect. + let has_socket = docker::container_has_docker_socket(&existing_id).await.unwrap_or(false); + if has_socket != project.allow_docker_access { + log::info!( + "Docker socket mismatch (container has_socket={}, project wants={}), recreating container", + has_socket, project.allow_docker_access + ); + // Safe to remove and recreate: the claude config named volume is + // keyed by project ID (not container ID) so it persists across + // container recreation. Bind mounts (workspace, SSH, AWS) are + // host paths and are unaffected. + let _ = docker::stop_container(&existing_id).await; + docker::remove_container(&existing_id).await?; + let new_id = docker::create_container( + &project, + api_key.as_deref(), + &docker_socket, + &image_name, + aws_config_path.as_deref(), + &settings.global_aws, + ).await?; + docker::start_container(&new_id).await?; + new_id + } else { + // Start existing container as-is + docker::start_container(&existing_id).await?; + existing_id + } } else { // Create new container let new_id = docker::create_container( diff --git a/app/src-tauri/src/docker/container.rs b/app/src-tauri/src/docker/container.rs index f8d6c5c..e63cfbc 100644 --- a/app/src-tauri/src/docker/container.rs +++ b/app/src-tauri/src/docker/container.rs @@ -288,6 +288,27 @@ pub async fn remove_container(container_id: &str) -> Result<(), String> { .map_err(|e| format!("Failed to remove container: {}", e)) } +/// Check whether an existing container has docker socket mounted. +pub async fn container_has_docker_socket(container_id: &str) -> Result { + let docker = get_docker()?; + let info = docker + .inspect_container(container_id, None) + .await + .map_err(|e| format!("Failed to inspect container: {}", e))?; + + let has_socket = info + .host_config + .and_then(|hc| hc.mounts) + .map(|mounts| { + mounts.iter().any(|m| { + m.target.as_deref() == Some("/var/run/docker.sock") + }) + }) + .unwrap_or(false); + + Ok(has_socket) +} + pub async fn get_container_info(project: &Project) -> Result, String> { if let Some(ref container_id) = project.container_id { let docker = get_docker()?;