From f0606ba703e4836ec2d0a8ac7b8fecac2172a2e8 Mon Sep 17 00:00:00 2001 From: sanil-23 Date: Tue, 12 May 2026 00:37:30 +0530 Subject: [PATCH] fix(windows): silence conhost flashes from core-side spawns (#731/#1338 follow-up) (#1498) Co-authored-by: Claude Opus 4.7 (1M context) --- src/openhuman/doctor/core.rs | 36 +++++++++------- src/openhuman/local_ai/device.rs | 14 ++++--- src/openhuman/local_ai/install.rs | 1 + src/openhuman/local_ai/mod.rs | 1 + src/openhuman/local_ai/process_util.rs | 40 ++++++++++++++++++ .../local_ai/service/ollama_admin.rs | 42 +++++++++---------- src/openhuman/node_runtime/resolver.rs | 14 ++++--- src/openhuman/service/common.rs | 16 +++++++ src/openhuman/service/windows.rs | 2 + 9 files changed, 121 insertions(+), 45 deletions(-) create mode 100644 src/openhuman/local_ai/process_util.rs diff --git a/src/openhuman/doctor/core.rs b/src/openhuman/doctor/core.rs index 455b12eab..100108a87 100644 --- a/src/openhuman/doctor/core.rs +++ b/src/openhuman/doctor/core.rs @@ -509,17 +509,20 @@ fn available_disk_space_mb_windows(path: &Path) -> Option { // PowerShell is ubiquitous on supported Windows; `Get-PSDrive` needs no admin // and returns free bytes as a single integer line. let script = format!("(Get-PSDrive -Name {letter} -ErrorAction Stop).Free"); - let output = std::process::Command::new("powershell") - .args([ - "-NoProfile", - "-NonInteractive", - "-ExecutionPolicy", - "Bypass", - "-Command", - &script, - ]) - .output() - .ok()?; + let mut cmd = std::process::Command::new("powershell"); + cmd.args([ + "-NoProfile", + "-NonInteractive", + "-ExecutionPolicy", + "Bypass", + "-Command", + &script, + ]); + { + use std::os::windows::process::CommandExt; + cmd.creation_flags(0x0800_0000); // CREATE_NO_WINDOW + } + let output = cmd.output().ok()?; if !output.status.success() { return None; } @@ -729,12 +732,17 @@ fn check_command_available( cat: &'static str, items: &mut Vec, ) { - match std::process::Command::new(cmd) + let mut child_cmd = std::process::Command::new(cmd); + child_cmd .args(args) .stdout(std::process::Stdio::piped()) - .stderr(std::process::Stdio::piped()) - .output() + .stderr(std::process::Stdio::piped()); + #[cfg(windows)] { + use std::os::windows::process::CommandExt; + child_cmd.creation_flags(0x0800_0000); // CREATE_NO_WINDOW + } + match child_cmd.output() { Ok(output) if output.status.success() => { let version = String::from_utf8_lossy(&output.stdout) .lines() diff --git a/src/openhuman/local_ai/device.rs b/src/openhuman/local_ai/device.rs index 371a6fa0c..b4ef9e58a 100644 --- a/src/openhuman/local_ai/device.rs +++ b/src/openhuman/local_ai/device.rs @@ -99,12 +99,16 @@ fn detect_gpu(cpu_brand: &str, os_name: &str) -> (bool, Option) { /// Probe for an NVIDIA GPU by running `nvidia-smi --query-gpu=name --format=csv,noheader`. /// Returns `Some("NVIDIA (CUDA)")` on success, `None` if nvidia-smi is not available. fn probe_nvidia_smi() -> Option { - let output = std::process::Command::new("nvidia-smi") - .args(["--query-gpu=name", "--format=csv,noheader"]) + let mut cmd = std::process::Command::new("nvidia-smi"); + cmd.args(["--query-gpu=name", "--format=csv,noheader"]) .stdout(std::process::Stdio::piped()) - .stderr(std::process::Stdio::null()) - .output() - .ok()?; + .stderr(std::process::Stdio::null()); + #[cfg(windows)] + { + use std::os::windows::process::CommandExt; + cmd.creation_flags(0x0800_0000); // CREATE_NO_WINDOW + } + let output = cmd.output().ok()?; if !output.status.success() { return None; diff --git a/src/openhuman/local_ai/install.rs b/src/openhuman/local_ai/install.rs index 53fad43fe..72c1f9396 100644 --- a/src/openhuman/local_ai/install.rs +++ b/src/openhuman/local_ai/install.rs @@ -37,6 +37,7 @@ fn build_install_command(install_dir: &Path) -> Result { log::debug!( "[local_ai] spawned `ollama serve` from {}", @@ -170,14 +172,12 @@ impl LocalAiService { } async fn command_works(&self, command: &Path) -> bool { - tokio::process::Command::new(command) - .arg("--version") + let mut cmd = tokio::process::Command::new(command); + cmd.arg("--version") .stdout(std::process::Stdio::null()) - .stderr(std::process::Stdio::null()) - .status() - .await - .map(|s| s.success()) - .unwrap_or(false) + .stderr(std::process::Stdio::null()); + apply_no_window(&mut cmd); + cmd.status().await.map(|s| s.success()).unwrap_or(false) } async fn download_and_install_ollama(&self, config: &Config) -> Result<(), String> { @@ -895,12 +895,12 @@ impl LocalAiService { } #[cfg(windows)] { - let _ = tokio::process::Command::new("taskkill") - .args(["/F", "/IM", "ollama.exe"]) + let mut cmd = tokio::process::Command::new("taskkill"); + cmd.args(["/F", "/IM", "ollama.exe"]) .stdout(std::process::Stdio::null()) - .stderr(std::process::Stdio::null()) - .status() - .await; + .stderr(std::process::Stdio::null()); + apply_no_window(&mut cmd); + let _ = cmd.status().await; tokio::time::sleep(std::time::Duration::from_millis(500)).await; } } diff --git a/src/openhuman/node_runtime/resolver.rs b/src/openhuman/node_runtime/resolver.rs index 19fe1bff4..a800c54ae 100644 --- a/src/openhuman/node_runtime/resolver.rs +++ b/src/openhuman/node_runtime/resolver.rs @@ -208,13 +208,17 @@ fn probe_subcommand_version(path: &std::path::Path, label: &str) -> Option String { .replace('\'', "'") } +/// Suppress conhost allocation for Windows command spawns. Without this, +/// every `schtasks /Query` polled by service status checks flashes a +/// console — visible to users (#1475 follow-up to #731 + #1338). +#[cfg(windows)] +fn no_window(cmd: &mut Command) { + use std::os::windows::process::CommandExt; + cmd.creation_flags(0x0800_0000); // CREATE_NO_WINDOW +} + +#[cfg(not(windows))] +fn no_window(_cmd: &mut Command) {} + pub(crate) fn run_checked(cmd: &mut Command) -> Result<()> { + no_window(cmd); let status = cmd.status()?; if !status.success() { anyhow::bail!("command failed with status {status}"); @@ -111,6 +124,7 @@ pub(crate) fn run_checked(cmd: &mut Command) -> Result<()> { } pub(crate) fn run_capture(cmd: &mut Command) -> Result { + no_window(cmd); let output = cmd.output()?; if !output.status.success() { anyhow::bail!("command failed with status {}", output.status); @@ -120,6 +134,7 @@ pub(crate) fn run_capture(cmd: &mut Command) -> Result { } pub(crate) fn run_best_effort(cmd: &mut Command) { + no_window(cmd); match cmd.stdout(Stdio::null()).stderr(Stdio::null()).status() { Ok(status) => { if !status.success() { @@ -133,6 +148,7 @@ pub(crate) fn run_best_effort(cmd: &mut Command) { } pub(crate) fn run_check_silent(cmd: &mut Command) -> bool { + no_window(cmd); cmd.stdout(Stdio::null()) .stderr(Stdio::null()) .status() diff --git a/src/openhuman/service/windows.rs b/src/openhuman/service/windows.rs index 01490233f..50974641d 100644 --- a/src/openhuman/service/windows.rs +++ b/src/openhuman/service/windows.rs @@ -131,8 +131,10 @@ pub(crate) fn uninstall(config: &Config) -> Result { } fn is_task_exists_windows(task_name: &str) -> Result { + use std::os::windows::process::CommandExt; let result = Command::new("schtasks") .args(["/Query", "/TN", task_name]) + .creation_flags(0x0800_0000) // CREATE_NO_WINDOW .output(); match result {