Skip to content

Fix Windows console-window flash on browser/runtime auto-launch#471

Merged
richard-devbot merged 3 commits into
mainfrom
fix-windowshide-browser-launch
Jul 26, 2026
Merged

Fix Windows console-window flash on browser/runtime auto-launch#471
richard-devbot merged 3 commits into
mainfrom
fix-windowshide-browser-launch

Conversation

@richard-devbot

Copy link
Copy Markdown
Owner

Summary

  • Fixes Windows: browser/runtime auto-launch briefly flashes a visible console window #470 — on Windows, every browser auto-launch (Business Hub SessionStart, rstack-agents hub, Pi session-start) and the Docker/Podman doctor --start-runtime engine auto-start briefly flash a visible cmd.exe console window.
  • Root cause: spawn(cmd, args, { shell: true }) on win32 runs through cmd.exe /c ...; child_process.spawn defaults windowsHide to false, so that intermediate console-subsystem process is visible for a split second before it hands off and exits.
  • Same copy-pasted openBrowser/openUrl helper existed in three files (src/hooks/auto-launch.js, src/observability/dashboard/server.js, src/integrations/pi/rstack-sdlc.ts), plus the same gap in startContainerRuntime (src/core/harness/sandbox.js), which spawns cmd.exe/podman.exe directly on win32.
  • Fix: windowsHide: true on all four spawn calls. win32-only option — no behavior change on macOS/Linux, and no change to what actually launches (browser/engine still start identically), only the transient console window is suppressed.

Test plan

  • npm run lint — clean on the four touched files
  • npm run typecheck — 0 errors
  • npx tsx --test tests/integrations-init.test.js tests/sandbox-doctor-452.test.js tests/sandbox-execution-452.test.js tests/harness-observability.test.js — same 54 pass / 1 pre-existing unrelated fail (Windows path-separator flake in sandbox-execution-452.test.js, confirmed present identically without this change via git stash)
  • Live-reproduced the flash on this Windows machine via the Business Hub SessionStart hook before the fix; not re-verifiable live post-fix within this session (SessionStart only fires once per session), but the root cause (missing windowsHide) and fix are directly confirmed against Node's documented child_process.spawn behavior

Add windowsHide:true to every spawn() that launches a browser via
cmd.exe (shell:true on win32) or starts the Docker/Podman engine.
Without it, Node's spawn defaults windowsHide to false, so the
intermediate console-subsystem process briefly flashes a visible
window before handing off. win32-only option, no behavior change
elsewhere.
@strix-security

strix-security Bot commented Jul 26, 2026

Copy link
Copy Markdown

Strix Security Review

No security issues found.

Updated for e700489.


Reviewed by Strix
Re-run review · Configure security review settings

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@richard-devbot, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 46 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: a8d64f73-d64e-46a3-a26e-4614794bb2b8

📥 Commits

Reviewing files that changed from the base of the PR and between 03f8d5d and 179947f.

📒 Files selected for processing (5)
  • src/core/harness/sandbox.js
  • src/hooks/auto-launch.js
  • src/integrations/pi/rstack-sdlc.ts
  • src/observability/dashboard/server.js
  • tests/windows-console-flash-470.test.js
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-windowshide-browser-launch

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Hide Windows console flash when auto-launching browser/runtime

🐞 Bug fix 🕐 20-40 Minutes

Grey Divider

AI Description

• Suppress transient cmd.exe/podman console windows during auto-launch on Windows.
• Add windowsHide: true to browser URL launchers and container runtime auto-start.
• Keep behavior unchanged on macOS/Linux; only affects win32 process windowing.
Diagram

graph TD
  A["src/hooks/auto-launch.js"] --> S(["spawn()/spawnImpl"]) --> W{{"win32 console process"}} --> T["Browser / Engine"]
  B["src/observability/dashboard/server.js"] --> S
  C["src/integrations/pi/rstack-sdlc.ts"] --> S
  D["src/core/harness/sandbox.js"] --> S
  subgraph Legend
    direction LR
    _mod["Module"] ~~~ _call(["Process spawn"]) ~~~ _win{{"Windows console"}}
  end
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Centralize URL-opening into one shared helper
  • ➕ Eliminates copy/paste variants across 3 modules
  • ➕ Ensures future launch behavior (including Windows options) stays consistent
  • ➕ Makes it easier to add tests around launch behavior
  • ➖ Requires a small refactor and follow-up touchpoints across call sites
  • ➖ May be out-of-scope for a focused bug fix
2. Use a dedicated cross-platform library (e.g., npm `open`)
  • ➕ Offloads OS quirks and command selection to a maintained dependency
  • ➕ Typically reduces custom platform branching
  • ➖ Introduces/expands dependency surface area
  • ➖ Still may require Windows-specific flags depending on implementation
3. Avoid `shell: true` on Windows by launching via explorer/Start-Process
  • ➕ Reduces reliance on cmd.exe indirection (cmd /c start ...)
  • ➕ Potentially fewer quoting/escaping edge cases
  • ➖ Higher behavior-change risk (differences in default browser resolution / argument handling)
  • ➖ More platform-specific code paths to maintain

Recommendation: The PR’s approach (adding windowsHide: true to the existing spawn calls) is the best minimal-risk fix for #470: it directly addresses the Windows console flash without changing command selection or launch semantics. Consider a follow-up to centralize the duplicated browser-launch helper to prevent the same omission from reappearing.

Files changed (4) +29 / -4

Bug fix (4) +29 / -4
sandbox.jsHide console window when auto-starting Docker/Podman engine +4/-1

Hide console window when auto-starting Docker/Podman engine

• Adds 'windowsHide: true' to the runtime start spawn call to suppress transient console flashes on Windows. Includes inline documentation clarifying why this is win32-specific and harmless elsewhere.

src/core/harness/sandbox.js

auto-launch.jsSuppress cmd.exe flash during Windows browser auto-launch +9/-1

Suppress cmd.exe flash during Windows browser auto-launch

• Expands the spawn options used for URL launching to include 'windowsHide: true'. Documents the Windows 'shell: true' → 'cmd.exe /c start' behavior that caused the visible flash.

src/hooks/auto-launch.js

rstack-sdlc.tsHide Windows console window for Pi integration URL launches +8/-1

Hide Windows console window for Pi integration URL launches

• Adds 'windowsHide: true' to the 'openUrl' spawn call while preserving detached/shell behavior. Keeps the existing best-effort error handling and unref semantics.

src/integrations/pi/rstack-sdlc.ts

server.jsPrevent cmd.exe window flash when opening the dashboard in a browser +8/-1

Prevent cmd.exe window flash when opening the dashboard in a browser

• Updates the dashboard server’s 'openBrowser' helper to pass 'windowsHide: true' alongside 'shell: win32'. Adds comments explaining the intermediate cmd.exe window that is being suppressed.

src/observability/dashboard/server.js

@qodo-code-review

qodo-code-review Bot commented Jul 26, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📜 Skill insights (1)

Context used
✅ Compliance rules (platform): 300 rules
✅ Skills: 17 invoked
  code-review-pr
  claude-api
  documentation-writing
  pptx
  docx
  performance-monitoring
  security-compliance
  cso
  plan-eng-review
  design-review
  prompt-engineering
  mcp-builder
  qa-testing
  code-patterns
  xlsx
  security-owasp
  testing-qa

Grey Divider


Remediation recommended

1. No tests for windowsHide ✗ Dismissed 📘 Rule violation ▣ Testability
Description
This PR changes runtime behavior by adding windowsHide: true to multiple spawn() calls, but the
changeset shows no corresponding automated test additions/updates. This violates the requirement
that behavior modifications include tests in the same changeset, increasing regression risk
(especially on win32-specific paths).
Code

src/core/harness/sandbox.js[R117-120]

+    // windowsHide suppresses the console window a freshly-spawned console
+    // subsystem process (cmd.exe on win32's docker path, podman.exe) would
+    // otherwise briefly flash — harmless elsewhere, since only win32 honors it.
+    const child = spawnImpl(startCmd.cmd, startCmd.args, { stdio: 'ignore', windowsHide: true });
Relevance

⭐⭐⭐ High

Team has accepted behavior+tests expectation in similar harness changes; likely request tests here
too.

PR-#153

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
Compliance ID 1587034 requires tests to be included alongside behavior changes. The cited lines show
new/changed spawn() invocations that now pass windowsHide: true (observable behavior change on
Windows), but no test changes are present in the provided PR diff.

Rule 1587034: Require tests in the same changeset as behavior modifications
src/core/harness/sandbox.js[117-120]
src/hooks/auto-launch.js[52-65]
src/integrations/pi/rstack-sdlc.ts[97-112]
src/observability/dashboard/server.js[124-135]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The PR changes executable behavior (adds `windowsHide: true` to several `spawn()` calls) but does not include any automated tests that exercise or assert the updated behavior.

## Issue Context
Compliance requires that non-trivial behavior changes (including bug fixes) ship with tests in the same changeset.

## Fix Focus Areas
- src/core/harness/sandbox.js[95-134]
- src/hooks/auto-launch.js[52-65]
- src/integrations/pi/rstack-sdlc.ts[97-112]
- src/observability/dashboard/server.js[124-139]
- tests/windows-hide-spawn.test.js[1-200]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Duplicated openBrowser/openUrl spawn logic 📜 Skill insight ⚙ Maintainability
Description
The PR repeats near-identical spawn(..., { shell: win32, windowsHide: true, ... }) browser-launch
logic (and explanatory comments) across multiple files, increasing maintenance overhead and drift
risk. This violates the DRY compliance requirement to refactor duplicated logic into a shared
helper/module.
Code

src/hooks/auto-launch.js[R56-64]

+    // On win32 this runs through `cmd.exe /c start <url>` (shell: true); without
+    // windowsHide, that intermediate cmd.exe briefly flashes a visible console
+    // window before handing off to the actual browser process.
+    spawn(cmd, [url], {
+      stdio: 'ignore',
+      detached: true,
+      shell: process.platform === 'win32',
+      windowsHide: true,
+    }).unref();
Relevance

⭐⭐ Medium

DRY refactor across files is subjective; no close precedent found enforcing helper extraction for
this pattern.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 1399536 requires refactoring duplicated logic. The diff shows the same browser
auto-launch spawn invocation pattern (and the same win32 windowsHide rationale) implemented in
multiple files rather than a shared helper.

src/hooks/auto-launch.js[56-64]
src/observability/dashboard/server.js[128-135]
src/integrations/pi/rstack-sdlc.ts[102-109]
Skill: plan-eng-review

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The same `openBrowser`/`openUrl` spawn configuration (including `shell: process.platform === 'win32'` and `windowsHide: true`) is duplicated across multiple files, which makes future changes error-prone and inconsistent.

## Issue Context
This PR already touches all copies of the helper, which is a good opportunity to consolidate into a single shared utility (e.g., `src/utils/open-browser.{js,ts}`) and import it where needed.

## Fix Focus Areas
- src/hooks/auto-launch.js[56-64]
- src/observability/dashboard/server.js[128-135]
- src/integrations/pi/rstack-sdlc.ts[102-109]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Qodo Logo

Comment thread src/hooks/auto-launch.js
Comment on lines +56 to +64
// On win32 this runs through `cmd.exe /c start <url>` (shell: true); without
// windowsHide, that intermediate cmd.exe briefly flashes a visible console
// window before handing off to the actual browser process.
spawn(cmd, [url], {
stdio: 'ignore',
detached: true,
shell: process.platform === 'win32',
windowsHide: true,
}).unref();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remediation recommended

1. Duplicated openbrowser/openurl spawn logic 📜 Skill insight ⚙ Maintainability

The PR repeats near-identical spawn(..., { shell: win32, windowsHide: true, ... }) browser-launch
logic (and explanatory comments) across multiple files, increasing maintenance overhead and drift
risk. This violates the DRY compliance requirement to refactor duplicated logic into a shared
helper/module.
Agent Prompt
## Issue description
The same `openBrowser`/`openUrl` spawn configuration (including `shell: process.platform === 'win32'` and `windowsHide: true`) is duplicated across multiple files, which makes future changes error-prone and inconsistent.

## Issue Context
This PR already touches all copies of the helper, which is a good opportunity to consolidate into a single shared utility (e.g., `src/utils/open-browser.{js,ts}`) and import it where needed.

## Fix Focus Areas
- src/hooks/auto-launch.js[56-64]
- src/observability/dashboard/server.js[128-135]
- src/integrations/pi/rstack-sdlc.ts[102-109]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed — exported openBrowser (auto-launch.js) / openUrl (rstack-sdlc.ts) with an injectable platform/spawnImpl (mirrors sandbox.js's existing spawnImpl convention), and added tests/windows-console-flash-470.test.js pinning windowsHide:true + per-platform shell selection for both, plus sandbox.js's startContainerRuntime. dashboard/server.js's identical copy is covered by code-review parity rather than a direct import test — that module calls server.listen() unguarded at the top level (pre-existing, out of scope here), so importing it for the export would start a real HTTP server as a side effect.

Comment thread src/core/harness/sandbox.js
Qodo flagged that the windowsHide:true change shipped with no tests.
Export openBrowser (auto-launch.js, dashboard/server.js) and openUrl
(rstack-sdlc.ts) with an injectable platform/spawnImpl (mirrors
sandbox.js's existing spawnImpl convention) so the fix is testable
without actually spawning a browser. Pins windowsHide:true + shell
selection per-platform for auto-launch.js, rstack-sdlc.ts, and
sandbox.js's startContainerRuntime.

dashboard/server.js's identical openBrowser copy isn't covered by a
direct import test: that module calls server.listen() unguarded at
the top level (pre-existing, out of scope here), so importing it for
the export would start a real HTTP server as a side effect. Covered
by code-review parity with the other two call sites instead.
@richard-devbot

Copy link
Copy Markdown
Owner Author

Qodo Fix Summary — Round 1

Reviewed and addressed Qodo review issues:

✅ Fixed Issues

  • No tests for windowsHide (Review recommended) - exported openBrowser/openUrl with an injectable platform/spawnImpl (mirrors sandbox.js's existing convention) and added tests/windows-console-flash-470.test.js pinning windowsHide:true + per-platform shell selection across auto-launch.js, rstack-sdlc.ts, and sandbox.js's startContainerRuntime.

⏭️ Deferred Issues

  • Duplicated openBrowser/openUrl spawn logic (Review recommended, Medium relevance) - the refactor spans a .ts file and two ESM .js files; this repo's tsconfig.json doesn't enable allowJs, so a shared .js helper wouldn't type-check from the .ts side without a broader config change. Deferring the consolidation to a dedicated follow-up rather than risking a build regression in this focused bugfix PR.

Qodo
Generated by Qodo PR Resolver skill

openUrl (rstack-sdlc.ts) intentionally early-returns when
process.env.CI is set, to avoid popping a browser during automated
runs. GitHub Actions always sets CI=true, so the two openUrl tests
added in the last commit never actually reached spawnImpl there,
while passing locally (CI unset) — caught by PR #471's real CI run,
not by local verification.

Clear process.env.CI for the duration of those two tests (restored
after) so they exercise the real spawn path in CI too, and add a
dedicated test pinning the CI no-op behavior itself so it stays
covered rather than just being an env quirk the other tests dodge.
Verified locally both with and without CI=true set.
@richard-devbot
richard-devbot merged commit cce8808 into main Jul 26, 2026
8 of 9 checks passed
@richard-devbot
richard-devbot deleted the fix-windowshide-browser-launch branch July 26, 2026 11:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Windows: browser/runtime auto-launch briefly flashes a visible console window

2 participants