Skip to content

Commit 4038359

Browse files
unknownclaude
authored andcommitted
fix(windows): live output display, hidden CMD windows, back-to-sessions navigation
- Suppress console windows on Windows for all Claude CLI child processes (CREATE_NO_WINDOW via std::os::windows::process::CommandExt), including binary-detection commands and the web-server spawn paths. - Keep the generic and session-scoped event listeners subscribed in parallel instead of tearing down the generic one on session id switch; dedupe messages received on both channels plus the fallback poller by uuid/message id/payload hash. Refresh from on-disk JSONL history after the process completes and poll the live-output buffer as a safety net while a prompt is in flight. - Wire up the existing onBack prop with a visible "Wróć do sesji" button and Alt+ArrowLeft, restoring the originating project's session list via a new projectId field on the tab. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
1 parent 70c16d8 commit 4038359

10 files changed

Lines changed: 524 additions & 248 deletions

File tree

‎src-tauri/src/claude_binary.rs‎

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,11 @@ fn try_which_command() -> Option<ClaudeInstallation> {
214214
fn try_which_command() -> Option<ClaudeInstallation> {
215215
debug!("Trying 'where claude' to find binary...");
216216

217-
match Command::new("where").arg("claude").output() {
217+
let mut cmd = Command::new("where");
218+
cmd.arg("claude");
219+
suppress_console_window_std(&mut cmd);
220+
221+
match cmd.output() {
218222
Ok(output) if output.status.success() => {
219223
let output_str = String::from_utf8_lossy(&output.stdout).trim().to_string();
220224

@@ -481,7 +485,10 @@ fn find_standard_installations() -> Vec<ClaudeInstallation> {
481485
}
482486

483487
// Also check if claude is available in PATH (without full path)
484-
if let Ok(output) = Command::new("claude.exe").arg("--version").output() {
488+
let mut path_check_cmd = Command::new("claude.exe");
489+
path_check_cmd.arg("--version");
490+
suppress_console_window_std(&mut path_check_cmd);
491+
if let Ok(output) = path_check_cmd.output() {
485492
if output.status.success() {
486493
debug!("claude.exe is available in PATH");
487494
let version = extract_version_from_output(&output.stdout);
@@ -500,7 +507,11 @@ fn find_standard_installations() -> Vec<ClaudeInstallation> {
500507

501508
/// Get Claude version by running --version command
502509
fn get_claude_version(path: &str) -> Result<Option<String>, String> {
503-
match Command::new(path).arg("--version").output() {
510+
let mut cmd = Command::new(path);
511+
cmd.arg("--version");
512+
suppress_console_window_std(&mut cmd);
513+
514+
match cmd.output() {
504515
Ok(output) => {
505516
if output.status.success() {
506517
Ok(extract_version_from_output(&output.stdout))
@@ -616,6 +627,43 @@ fn compare_versions(a: &str, b: &str) -> Ordering {
616627
Ordering::Equal
617628
}
618629

630+
/// Windows process creation flag that prevents a console window from being
631+
/// allocated for the child process. Without this, every spawn of the Claude
632+
/// CLI (and any console subprocess it spawns in turn, e.g. an MCP server)
633+
/// flashes a visible CMD window on top of the app.
634+
#[cfg(target_os = "windows")]
635+
const CREATE_NO_WINDOW: u32 = 0x08000000;
636+
637+
/// Configures a tokio [`Command`](tokio::process::Command) to not open a
638+
/// visible console window when spawned on Windows. No-op on other platforms.
639+
/// Does not affect stdout/stderr piping - `Stdio::piped()` is independent of
640+
/// console window allocation.
641+
pub fn suppress_console_window(cmd: &mut tokio::process::Command) {
642+
#[cfg(target_os = "windows")]
643+
{
644+
cmd.creation_flags(CREATE_NO_WINDOW);
645+
}
646+
#[cfg(not(target_os = "windows"))]
647+
{
648+
let _ = cmd;
649+
}
650+
}
651+
652+
/// Same as [`suppress_console_window`] but for a plain `std::process::Command`,
653+
/// used by the short-lived binary-detection commands below (`where`,
654+
/// `--version`) which also run on every prompt via `find_claude_binary`.
655+
fn suppress_console_window_std(cmd: &mut Command) {
656+
#[cfg(target_os = "windows")]
657+
{
658+
use std::os::windows::process::CommandExt;
659+
cmd.creation_flags(CREATE_NO_WINDOW);
660+
}
661+
#[cfg(not(target_os = "windows"))]
662+
{
663+
let _ = cmd;
664+
}
665+
}
666+
619667
/// Helper function to create a Command with proper environment variables
620668
/// This ensures commands like Claude can find Node.js and other dependencies
621669
pub fn create_command_with_env(program: &str) -> Command {
@@ -689,5 +737,7 @@ pub fn create_command_with_env(program: &str) -> Command {
689737
}
690738
}
691739

740+
suppress_console_window_std(&mut cmd);
741+
692742
cmd
693743
}

‎src-tauri/src/commands/agents.rs‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1696,6 +1696,8 @@ fn create_command_with_env(program: &str) -> Command {
16961696
tokio_cmd.env("PATH", "/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin");
16971697
}
16981698

1699+
crate::claude_binary::suppress_console_window(&mut tokio_cmd);
1700+
16991701
tokio_cmd
17001702
}
17011703

‎src-tauri/src/commands/claude.rs‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,8 @@ fn create_command_with_env(program: &str) -> Command {
286286
}
287287
}
288288

289+
crate::claude_binary::suppress_console_window(&mut tokio_cmd);
290+
289291
tokio_cmd
290292
}
291293

‎src-tauri/src/web_server.rs‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,7 @@ async fn execute_claude_command(
497497
cmd.current_dir(&project_path);
498498
cmd.stdout(std::process::Stdio::piped());
499499
cmd.stderr(std::process::Stdio::piped());
500+
crate::claude_binary::suppress_console_window(&mut cmd);
500501

501502
println!(
502503
"[TRACE] Command: {} {:?} (in dir: {})",
@@ -609,6 +610,7 @@ async fn continue_claude_command(
609610
cmd.current_dir(&project_path);
610611
cmd.stdout(std::process::Stdio::piped());
611612
cmd.stderr(std::process::Stdio::piped());
613+
crate::claude_binary::suppress_console_window(&mut cmd);
612614

613615
// Spawn and stream output
614616
let mut child = cmd
@@ -698,6 +700,7 @@ async fn resume_claude_command(
698700
cmd.current_dir(&project_path);
699701
cmd.stdout(std::process::Stdio::piped());
700702
cmd.stderr(std::process::Stdio::piped());
703+
crate::claude_binary::suppress_console_window(&mut cmd);
701704

702705
println!(
703706
"[resume_claude_command] Command: {} {:?} (in dir: {})",

‎src/components/AgentExecution.tsx‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ export interface ClaudeStreamMessage {
6262
type: "system" | "assistant" | "user" | "result";
6363
subtype?: string;
6464
message?: {
65+
id?: string;
6566
content?: any[];
6667
usage?: {
6768
input_tokens: number;

0 commit comments

Comments
 (0)