diff --git a/packages/desktop/src-tauri/Cargo.lock b/packages/desktop/src-tauri/Cargo.lock index c8575a759..f9516350e 100644 --- a/packages/desktop/src-tauri/Cargo.lock +++ b/packages/desktop/src-tauri/Cargo.lock @@ -3136,6 +3136,7 @@ dependencies = [ "tracing-subscriber", "uuid", "webkit2gtk", + "windows 0.62.2", ] [[package]] diff --git a/packages/desktop/src-tauri/Cargo.toml b/packages/desktop/src-tauri/Cargo.toml index a5539645d..e98b8965c 100644 --- a/packages/desktop/src-tauri/Cargo.toml +++ b/packages/desktop/src-tauri/Cargo.toml @@ -54,6 +54,9 @@ chrono = "0.4" tokio-stream = { version = "0.1.18", features = ["sync"] } process-wrap = { version = "9.0.3", features = ["tokio1"] } +[target.'cfg(windows)'.dependencies] +windows = { version = "0.62", features = ["Win32_System_Threading"] } + [target.'cfg(target_os = "linux")'.dependencies] gtk = "0.18.2" webkit2gtk = "=2.0.2" diff --git a/packages/desktop/src-tauri/src/cli.rs b/packages/desktop/src-tauri/src/cli.rs index cad942acb..130958bf7 100644 --- a/packages/desktop/src-tauri/src/cli.rs +++ b/packages/desktop/src-tauri/src/cli.rs @@ -3,7 +3,7 @@ use process_wrap::tokio::CommandWrap; #[cfg(unix)] use process_wrap::tokio::ProcessGroup; #[cfg(windows)] -use process_wrap::tokio::{JobObject, KillOnDrop}; +use process_wrap::tokio::{CommandWrapper, JobObject, KillOnDrop}; #[cfg(unix)] use std::os::unix::process::ExitStatusExt; use std::sync::Arc; @@ -18,9 +18,24 @@ use tokio::{ }; use tokio_stream::wrappers::ReceiverStream; use tracing::Instrument; +#[cfg(windows)] +use windows::Win32::System::Threading::{CREATE_NO_WINDOW, CREATE_SUSPENDED}; use crate::server::get_wsl_config; +#[cfg(windows)] +#[derive(Clone, Copy, Debug)] +// Keep this as a custom wrapper instead of process_wrap::CreationFlags. +// JobObject pre_spawn rewrites creation flags, so this must run after it. +struct WinCreationFlags; + +#[cfg(windows)] +impl CommandWrapper for WinCreationFlags { + fn pre_spawn(&mut self, command: &mut Command, _core: &CommandWrap) -> std::io::Result<()> { + command.creation_flags((CREATE_NO_WINDOW | CREATE_SUSPENDED).0); + Ok(()) + } +} const CLI_INSTALL_DIR: &str = ".opencode/bin"; const CLI_BINARY_NAME: &str = "opencode"; @@ -203,7 +218,7 @@ fn get_user_shell() -> String { } fn is_wsl_enabled(_app: &tauri::AppHandle) -> bool { - get_wsl_config(_app.clone()).is_ok_and(|v| v.enabled) + get_wsl_config(_app.clone()).is_ok_and(|v| v.enabled) } fn shell_escape(input: &str) -> String { @@ -318,9 +333,6 @@ pub fn spawn_command( cmd.stderr(Stdio::piped()); cmd.stdin(Stdio::null()); - #[cfg(windows)] - cmd.creation_flags(0x0800_0000); - let mut wrap = CommandWrap::from(cmd); #[cfg(unix)] @@ -330,7 +342,7 @@ pub fn spawn_command( #[cfg(windows)] { - wrap.wrap(JobObject).wrap(KillOnDrop); + wrap.wrap(JobObject).wrap(WinCreationFlags).wrap(KillOnDrop); } let mut child = wrap.spawn()?;