Skip to content

fix: close child stdin so pnpm PowerShell shim doesn't deadlock on Windows#66

Closed
fengmk2 wants to merge 2 commits intomainfrom
debug/windows-alpha-hang
Closed

fix: close child stdin so pnpm PowerShell shim doesn't deadlock on Windows#66
fengmk2 wants to merge 2 commits intomainfrom
debug/windows-alpha-hang

Conversation

@fengmk2
Copy link
Copy Markdown
Member

@fengmk2 fengmk2 commented May 7, 2026

Summary

@actions/exec leaves child stdin open by default. pnpm's pnpm.ps1 shim takes the $MyInvocation.ExpectingInput branch when stdin is a pipe and drains $input until EOF before invoking node. With stdin inherited from the runner and never closed, that drain blocks forever — pwsh.exe running pnpm.ps1 stays alive but no node child is ever spawned, and the job times out silently.

Fix: pass input: Buffer.alloc(0) to exec so the child sees immediate EOF on stdin and the shim falls through to spawn node.

Repro & evidence

Failing run before fix: https://github.com/voidzero-dev/setup-vp/actions/runs/24870325083/job/74809705560test (windows-latest, alpha) hangs 5+ minutes after Setting up VITE+... then is canceled. windows-latest, latest finishes in ~13s on the same install path.

A short-lived diagnostic commit (replaced by this fix) added a heartbeat that snapshotted descendants of the pwsh PID every 30s. It showed:

pid=6264 cmd.exe   :: cmd /c "set CI=true && vp.exe install"
pid=5828 vp.exe    :: vp.exe install
pid=6656 pwsh.exe  :: pwsh -File ...\pnpm\10.33.0\pnpm\bin\pnpm.ps1 install

Same tree across three consecutive heartbeats, never spawning a node child — the pnpm shim is alive but blocked on draining stdin before it ever invokes node.

Test plan

  • test (windows-latest, alpha) runs to completion on this PR (previously hung).
  • Other matrix jobs still pass — empty stdin is safe on bash too (the inner curl | bash pipe is independent of the outer bash's stdin).
  • Local vp test passes (115/115).

fengmk2 added 2 commits May 7, 2026 20:13
Wrap pwsh invocation with timestamped stage markers and a 30s
descendant-process heartbeat (via Start-ThreadJob) so a silent hang
inside install.ps1 (e.g. pnpm install during `vp install`) is visible
in CI logs instead of timing out blind.

Driven by hangs on test (windows-latest, alpha) where the job hits 5+
minutes of silence after install.ps1 prints "Setting up VITE+..." and
gets canceled.
@actions/exec leaves child stdin open by default. pnpm's pnpm.ps1 shim
takes the `$MyInvocation.ExpectingInput` branch when stdin is a pipe
and drains $input until EOF before invoking node. With our stdin
inherited and never closed, that drain blocks forever — pwsh.exe
running pnpm.ps1 stays alive but no node child is ever spawned, and
the job times out silently.

Pass an empty Buffer as input so the child sees immediate EOF on
stdin and the shim falls through to spawn node.

Repro: setup-vp@latest with version: alpha on windows-latest hangs 5+
minutes after `Setting up VITE+...`. Heartbeat tracing on the
diagnostic commit (reverted in this commit) showed pnpm.ps1 alive
without a node descendant.
@fengmk2 fengmk2 marked this pull request as ready for review May 7, 2026 12:37
Copilot AI review requested due to automatic review settings May 7, 2026 12:37
@fengmk2 fengmk2 changed the title debug: trace Windows install.ps1 stages to diagnose alpha hang fix: close child stdin so pnpm PowerShell shim doesn't deadlock on Windows May 7, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR modifies the GitHub Action’s Vite+ installer invocation to avoid a Windows-specific hang by explicitly closing stdin for the child process.

Changes:

  • Pass input: Buffer.alloc(0) to @actions/exec so the spawned pwsh (and currently also bash) process sees EOF on stdin.
  • Regenerate dist/index.mjs to include the compiled change.

Reviewed changes

Copilot reviewed 1 out of 2 changed files in this pull request and generated 1 comment.

File Description
src/install-viteplus.ts Adds exec options to close stdin (empty input) during install to prevent PowerShell/pnpm shim deadlock.
dist/index.mjs Updates the bundled output to reflect the new exec option.
Comments suppressed due to low confidence (1)

src/install-viteplus.ts:68

  • input: Buffer.alloc(0) is currently applied to both the Windows pwsh path and the non-Windows bash path, but the rationale in the comment is Windows/pnpm-specific. Consider scoping the stdin-closing behavior to process.platform === "win32" (or adding a short note explaining why it’s safe/desirable on non-Windows too) to avoid unnecessarily changing install.sh execution semantics.
  // Close child stdin (empty input) so pnpm's PowerShell shim doesn't deadlock.
  // The shim's `$MyInvocation.ExpectingInput` branch drains $input until EOF
  // before invoking node; if we leave stdin open, that drain never returns and
  // pnpm install hangs forever — observed on Windows alpha runs with
  // vite-plus@0.1.21-alpha.2 (pwsh.exe -File pnpm.ps1 alive, no node child).
  const options = { env, ignoreReturnCode: true, input: Buffer.alloc(0) };
  if (process.platform === "win32") {
    return exec(
      "pwsh",
      ["-Command", `& ([scriptblock]::Create((irm ${INSTALL_URL_PS1})))`],
      options,
    );
  }
  return exec("bash", ["-c", `curl -fsSL ${INSTALL_URL_SH} | bash`], options);

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/install-viteplus.ts
Comment on lines +55 to +60
// Close child stdin (empty input) so pnpm's PowerShell shim doesn't deadlock.
// The shim's `$MyInvocation.ExpectingInput` branch drains $input until EOF
// before invoking node; if we leave stdin open, that drain never returns and
// pnpm install hangs forever — observed on Windows alpha runs with
// vite-plus@0.1.21-alpha.2 (pwsh.exe -File pnpm.ps1 alive, no node child).
const options = { env, ignoreReturnCode: true, input: Buffer.alloc(0) };
@fengmk2 fengmk2 closed this May 7, 2026
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.

2 participants