Skip to content

Commit ca386d2

Browse files
committed
fix(windows): prevent terminal flashing during WSL detection and execution
- Add CREATE_NO_WINDOW flag (0x08000000) to all WSL commands - Create wsl_command() helper function that sets the flag automatically - Apply flag to WSL detection in claude_binary.rs (distro listing, claude path finding) - Apply flag to WSL detection in shell_environment.rs (distro detection, claude check) - Apply flag to actual Claude execution via WSL in commands/claude.rs - Apply flag to Git Bash execution as well This prevents the console window from briefly appearing when: 1. Auto-detecting Claude installations in WSL distributions 2. Running Claude commands through WSL 3. Running Claude commands through Git Bash
1 parent 31d446c commit ca386d2

File tree

3 files changed

+54
-11
lines changed

3 files changed

+54
-11
lines changed

src-tauri/src/claude_binary.rs

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,19 @@ use anyhow::Result;
22
use log::{debug, error, info, warn};
33
use serde::{Deserialize, Serialize};
44
use std::cmp::Ordering;
5+
#[cfg(windows)]
6+
use std::os::windows::process::CommandExt;
57
/// Shared module for detecting Claude Code binary installations
68
/// Supports NVM installations, aliased paths, and version-based selection
79
use std::path::PathBuf;
810
use std::process::Command;
911
use tauri::Manager;
1012

13+
/// Windows constant for CREATE_NO_WINDOW flag
14+
/// This prevents console windows from flashing when running background commands
15+
#[cfg(windows)]
16+
const CREATE_NO_WINDOW: u32 = 0x08000000;
17+
1118
/// Type of Claude installation
1219
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
1320
pub enum InstallationType {
@@ -552,11 +559,19 @@ fn find_wsl_installations() -> Vec<ClaudeInstallation> {
552559
installations
553560
}
554561

562+
/// Creates a WSL command with CREATE_NO_WINDOW flag to prevent terminal flashing
563+
#[cfg(windows)]
564+
fn wsl_command() -> Command {
565+
let mut cmd = Command::new("wsl");
566+
cmd.creation_flags(CREATE_NO_WINDOW);
567+
cmd
568+
}
569+
555570
/// Get list of WSL distributions
556571
#[cfg(windows)]
557572
fn get_wsl_distributions() -> Result<Vec<String>, String> {
558573
// Run: wsl -l -q (quiet mode, just names)
559-
let output = Command::new("wsl")
574+
let output = wsl_command()
560575
.args(["-l", "-q"])
561576
.output()
562577
.map_err(|e| format!("Failed to run wsl -l -q: {}", e))?;
@@ -594,7 +609,7 @@ fn get_wsl_distributions() -> Result<Vec<String>, String> {
594609
#[cfg(windows)]
595610
fn find_claude_in_wsl(distro: &str) -> Option<String> {
596611
// Try 'which claude' in the WSL distribution
597-
let output = Command::new("wsl")
612+
let output = wsl_command()
598613
.args(["-d", distro, "--", "which", "claude"])
599614
.output()
600615
.ok()?;
@@ -615,7 +630,7 @@ fn find_claude_in_wsl(distro: &str) -> Option<String> {
615630
let nvm_base = format!("{}/.nvm/versions/node", home);
616631

617632
// List node versions and check for claude
618-
let output = Command::new("wsl")
633+
let output = wsl_command()
619634
.args(["-d", distro, "--", "ls", "-1", &nvm_base])
620635
.output();
621636

@@ -627,7 +642,7 @@ fn find_claude_in_wsl(distro: &str) -> Option<String> {
627642
if !version.is_empty() {
628643
let claude_path = format!("{}/{}/bin/claude", nvm_base, version);
629644
// Check if claude exists at this path
630-
let check = Command::new("wsl")
645+
let check = wsl_command()
631646
.args(["-d", distro, "--", "test", "-f", &claude_path])
632647
.output();
633648

@@ -643,7 +658,7 @@ fn find_claude_in_wsl(distro: &str) -> Option<String> {
643658

644659
// Check ~/.local/bin/claude
645660
let local_claude = format!("{}/.local/bin/claude", home);
646-
let check = Command::new("wsl")
661+
let check = wsl_command()
647662
.args(["-d", distro, "--", "test", "-f", &local_claude])
648663
.output();
649664

@@ -656,7 +671,7 @@ fn find_claude_in_wsl(distro: &str) -> Option<String> {
656671

657672
// Check common system paths
658673
for path in common_paths {
659-
let check = Command::new("wsl")
674+
let check = wsl_command()
660675
.args(["-d", distro, "--", "test", "-f", path])
661676
.output();
662677

@@ -673,7 +688,7 @@ fn find_claude_in_wsl(distro: &str) -> Option<String> {
673688
/// Get home directory in WSL
674689
#[cfg(windows)]
675690
fn get_wsl_home_dir(distro: &str) -> Option<String> {
676-
let output = Command::new("wsl")
691+
let output = wsl_command()
677692
.args(["-d", distro, "--", "echo", "$HOME"])
678693
.output()
679694
.ok()?;
@@ -691,7 +706,7 @@ fn get_wsl_home_dir(distro: &str) -> Option<String> {
691706
/// Get Claude version in WSL
692707
#[cfg(windows)]
693708
fn get_claude_version_in_wsl(distro: &str, claude_path: &str) -> Option<String> {
694-
let output = Command::new("wsl")
709+
let output = wsl_command()
695710
.args(["-d", distro, "--", claude_path, "--version"])
696711
.output()
697712
.ok()?;

src-tauri/src/commands/claude.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,14 @@ use tokio::sync::Mutex;
1313
#[cfg(windows)]
1414
use crate::shell_environment::{create_wsl_command, ShellConfig, ShellEnvironment};
1515

16+
#[cfg(windows)]
17+
use std::os::windows::process::CommandExt;
18+
19+
/// Windows constant for CREATE_NO_WINDOW flag
20+
/// This prevents console windows from flashing when running background commands
21+
#[cfg(windows)]
22+
const CREATE_NO_WINDOW: u32 = 0x08000000;
23+
1624
/// Global state to track current Claude process
1725
pub struct ClaudeProcessState {
1826
pub current_process: Arc<Mutex<Option<Child>>>,
@@ -398,6 +406,8 @@ fn create_system_command_with_shell(
398406
tokio_cmd.arg(arg);
399407
}
400408

409+
// Set CREATE_NO_WINDOW to prevent terminal flashing
410+
tokio_cmd.creation_flags(CREATE_NO_WINDOW);
401411
tokio_cmd.stdout(Stdio::piped()).stderr(Stdio::piped());
402412

403413
tokio_cmd
@@ -434,6 +444,8 @@ fn create_system_command_with_shell(
434444
);
435445

436446
cmd.args(["-lc", &bash_command]);
447+
// Set CREATE_NO_WINDOW to prevent terminal flashing
448+
cmd.creation_flags(CREATE_NO_WINDOW);
437449
cmd.stdout(Stdio::piped()).stderr(Stdio::piped());
438450

439451
cmd

src-tauri/src/shell_environment.rs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,23 @@
1111
1212
use log::{debug, info, warn};
1313
use serde::{Deserialize, Serialize};
14+
#[cfg(windows)]
15+
use std::os::windows::process::CommandExt;
1416
use std::process::Command;
1517

18+
/// Windows constant for CREATE_NO_WINDOW flag
19+
/// This prevents console windows from flashing when running background commands
20+
#[cfg(windows)]
21+
const CREATE_NO_WINDOW: u32 = 0x08000000;
22+
23+
/// Creates a WSL command with CREATE_NO_WINDOW flag to prevent terminal flashing
24+
#[cfg(windows)]
25+
fn wsl_command() -> Command {
26+
let mut cmd = Command::new("wsl");
27+
cmd.creation_flags(CREATE_NO_WINDOW);
28+
cmd
29+
}
30+
1631
/// Available shell environments for Claude execution
1732
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
1833
#[serde(rename_all = "lowercase")]
@@ -101,7 +116,7 @@ fn detect_wsl_distributions() -> Vec<WslDistribution> {
101116
let mut distributions = Vec::new();
102117

103118
// Run `wsl --list --verbose` to get distributions
104-
match Command::new("wsl").args(["--list", "--verbose"]).output() {
119+
match wsl_command().args(["--list", "--verbose"]).output() {
105120
Ok(output) if output.status.success() => {
106121
// WSL outputs UTF-16LE on Windows, need to handle that
107122
let stdout = String::from_utf8_lossy(&output.stdout);
@@ -220,7 +235,7 @@ fn detect_git_bash() -> Option<String> {
220235
pub fn check_claude_in_wsl(distro: Option<&str>) -> Option<String> {
221236
debug!("Checking for Claude in WSL (distro: {:?})...", distro);
222237

223-
let mut cmd = Command::new("wsl");
238+
let mut cmd = wsl_command();
224239

225240
if let Some(d) = distro {
226241
cmd.args(["-d", d]);
@@ -282,14 +297,15 @@ pub fn windows_to_wsl_path(path: &str) -> String {
282297
}
283298

284299
/// Create a command that runs through WSL
300+
/// Uses CREATE_NO_WINDOW flag to prevent terminal flashing
285301
#[cfg(windows)]
286302
pub fn create_wsl_command(
287303
distro: Option<&str>,
288304
claude_path: &str,
289305
args: &[String],
290306
working_dir: &str,
291307
) -> Command {
292-
let mut cmd = Command::new("wsl");
308+
let mut cmd = wsl_command();
293309

294310
// Specify distribution if provided
295311
if let Some(d) = distro {

0 commit comments

Comments
 (0)