Avoid Windows libuv assertions on CLI errors

Merged
FE
3mo ago
+72-25

Summary

  • replace forced process.exit calls in the shared CLI error path with exitCode plus a private control-flow error
  • let the command guard absorb already-reported exits without printing twice
  • preserve immediate command abortion and exit status 1 while allowing Node to drain active handles safely

Verification

  • npm run typecheck
  • 16 util tests, including a regression assertion that die never calls process.exit
  • npm run build
  • 50 Windows local-error runs with a fresh detached update check each time
  • 20 Windows API-error runs with a fresh detached update check each time

Windows regression

Expected API failures could race process.exit against the detached update-check child and abort in src\win\async.c with UV_HANDLE_CLOSING. All 70 stress runs now exited cleanly with code 1 and no assertion or leaked CliExit stack.


Summary by cubic

Replaces forced process.exit calls in the CLI error path with exitCode plus a private control-flow error, so Windows no longer races the detached update-check child and hits libuv assertions (UV_HANDLE_CLOSING). The command guard absorbs the new CliExit error, preventing duplicate error output. Errors still print to stderr and exit with status 1.

Verification

  • Runs typecheck, build, and 16 util tests, including a regression assertion that die never calls process.exit.
  • 70 stress runs on Windows with fresh detached update checks exited cleanly with code 1, no assertions or leaked stacks.
  • Tests now restore process.exitCode in finally blocks and scope stderr/stdout spies per test.