aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-07-17 16:03:47 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-07-17 16:03:47 +0300
commita723dc8852f761b65b2f4cd25e958bf656278074 (patch)
tree02267b4519d918d67a2e3019164394f92d488c26 /src
parent8d2af4e046c2a95dfc54aafd6f88da12389d76e8 (diff)
fix(windows): prevent remaining subprocess console flashes
refs #1468
Diffstat (limited to 'src')
-rw-r--r--src/cli/plugin.rs4
-rw-r--r--src/integration/version.rs2
-rw-r--r--src/platform/mod.rs4
-rw-r--r--src/platform/windows.rs20
-rw-r--r--src/sound.rs6
-rw-r--r--src/worktree.rs10
6 files changed, 33 insertions, 13 deletions
diff --git a/src/cli/plugin.rs b/src/cli/plugin.rs
index 68cf0282..32447d1b 100644
--- a/src/cli/plugin.rs
+++ b/src/cli/plugin.rs
@@ -849,7 +849,7 @@ fn git_checkout(
}
fn run_git<const N: usize>(cwd: Option<&Path>, args: [&str; N]) -> std::io::Result<()> {
- let mut command = Command::new("git");
+ let mut command = crate::noninteractive_process::command("git");
command.args(args);
if let Some(cwd) = cwd {
command.current_dir(cwd);
@@ -865,7 +865,7 @@ fn run_git<const N: usize>(cwd: Option<&Path>, args: [&str; N]) -> std::io::Resu
}
fn git_output<const N: usize>(cwd: &Path, args: [&str; N]) -> std::io::Result<String> {
- let output = Command::new("git")
+ let output = crate::noninteractive_process::command("git")
.args(args)
.current_dir(cwd)
.stdin(Stdio::null())
diff --git a/src/integration/version.rs b/src/integration/version.rs
index c9c2af8d..648b86ae 100644
--- a/src/integration/version.rs
+++ b/src/integration/version.rs
@@ -47,7 +47,7 @@ pub(crate) fn enforce_agent_version(
requirement: &AgentVersionRequirement,
) -> io::Result<Option<String>> {
let probe = format!("{} {}", requirement.binary, requirement.args.join(" "));
- let output = match std::process::Command::new(requirement.binary)
+ let output = match crate::noninteractive_process::command(requirement.binary)
.args(requirement.args)
.output()
{
diff --git a/src/platform/mod.rs b/src/platform/mod.rs
index 42b9e128..82a6704d 100644
--- a/src/platform/mod.rs
+++ b/src/platform/mod.rs
@@ -26,7 +26,9 @@ pub enum Signal {
}
pub(crate) fn detached_custom_command_process(command: &str) -> std::process::Command {
- detached_custom_command_process_platform(command)
+ let mut process = detached_custom_command_process_platform(command);
+ configure_background_command(&mut process);
+ process
}
pub(crate) fn pane_custom_command_pty_builder(command: &str) -> portable_pty::CommandBuilder {
diff --git a/src/platform/windows.rs b/src/platform/windows.rs
index 46c75141..5b0d647f 100644
--- a/src/platform/windows.rs
+++ b/src/platform/windows.rs
@@ -671,7 +671,7 @@ mod tests {
const CONSOLE_TEST_CHILD_ENV: &str = "HERDR_TEST_CONSOLE_CHILD_MODE";
#[test]
- fn background_and_server_daemon_commands_do_not_have_consoles() {
+ fn windows_background_and_server_daemon_commands_do_not_have_consoles() {
if let Some(mode) = std::env::var_os(CONSOLE_TEST_CHILD_ENV) {
assert!(
unsafe { GetConsoleWindow() }.is_null(),
@@ -696,7 +696,7 @@ mod tests {
for (mode, configure) in configurations {
let mut child = Command::new(&test_exe);
child
- .arg("background_and_server_daemon_commands_do_not_have_consoles")
+ .arg("windows_background_and_server_daemon_commands_do_not_have_consoles")
.env(CONSOLE_TEST_CHILD_ENV, mode)
.stdin(Stdio::null())
.stdout(Stdio::null())
@@ -710,6 +710,22 @@ mod tests {
);
}
+ let command = format!(
+ r#""{}" windows_background_and_server_daemon_commands_do_not_have_consoles"#,
+ test_exe.display()
+ );
+ let status = crate::platform::detached_custom_command_process(&command)
+ .env(CONSOLE_TEST_CHILD_ENV, "detached custom command descendant")
+ .stdin(Stdio::null())
+ .stdout(Stdio::null())
+ .stderr(Stdio::null())
+ .status()
+ .expect("spawn detached custom command test child");
+ assert!(
+ status.success(),
+ "detached custom command descendant opened or inherited a console"
+ );
+
if allocated_console {
unsafe {
FreeConsole();
diff --git a/src/sound.rs b/src/sound.rs
index ef45ccc7..7925069c 100644
--- a/src/sound.rs
+++ b/src/sound.rs
@@ -6,7 +6,9 @@
use std::io::Write;
use std::path::{Path, PathBuf};
-use std::process::{Command, Output};
+#[cfg(not(windows))]
+use std::process::Command;
+use std::process::Output;
use std::sync::atomic::{AtomicU64, Ordering};
use tracing::warn;
@@ -142,7 +144,7 @@ if (-not $script:done) { throw 'sound playback timed out' }
#[cfg(windows)]
fn run_windows_player(path: &Path) -> Result<Output, String> {
- Command::new("powershell.exe")
+ crate::noninteractive_process::command("powershell.exe")
.args([
"-NoLogo",
"-NoProfile",
diff --git a/src/worktree.rs b/src/worktree.rs
index 33b03d56..0bb091d7 100644
--- a/src/worktree.rs
+++ b/src/worktree.rs
@@ -199,7 +199,7 @@ pub(crate) fn worktree_dirty_remove_message(path: &Path) -> String {
#[cfg(any(windows, test))]
pub(crate) fn checkout_has_dirty_files(path: &Path) -> Result<bool, String> {
let path_arg = path.display().to_string();
- let output = std::process::Command::new("git")
+ let output = crate::noninteractive_process::command("git")
.args([
"-C",
&path_arg,
@@ -265,7 +265,7 @@ pub(crate) fn build_worktree_add_existing_branch_command(
}
pub(crate) fn local_branch_exists(repo_root: &Path, branch: &str) -> Result<bool, String> {
- let output = std::process::Command::new("git")
+ let output = crate::noninteractive_process::command("git")
.arg("-C")
.arg(repo_root)
.args(["show-ref", "--verify", "--quiet"])
@@ -306,7 +306,7 @@ pub(crate) fn run_worktree_add_command(
}
pub(crate) fn run_worktree_command(command: &WorktreeCommand) -> Result<(), String> {
- let output = std::process::Command::new(&command.program)
+ let output = crate::noninteractive_process::command(&command.program)
.args(&command.args)
.output()
.map_err(|err| err.to_string())?;
@@ -375,7 +375,7 @@ fn leftover_worktree_checkout_matches_repo(repo_root: &Path, path: &Path) -> boo
}
fn git_common_worktrees_dir(repo_root: &Path) -> Option<PathBuf> {
- let output = std::process::Command::new("git")
+ let output = crate::noninteractive_process::command("git")
.arg("-C")
.arg(repo_root)
.args(["rev-parse", "--git-common-dir"])
@@ -471,7 +471,7 @@ pub(crate) fn parse_worktree_list_porcelain(output: &str) -> Vec<ExistingWorktre
}
pub(crate) fn list_existing_worktrees(repo_root: &Path) -> Result<Vec<ExistingWorktree>, String> {
- let output = std::process::Command::new("git")
+ let output = crate::noninteractive_process::command("git")
.arg("-C")
.arg(repo_root)
.args(["worktree", "list", "--porcelain"])