fix: Docker installation keeps hanging on MacOS (#12972)

* Onboarding: avoid stdin resume after wizard finish

* Changelog: remove Docker hang entry from PR

* Terminal: make stdin resume behavior explicit at call sites

* CI: rerun format check

* Onboarding: restore terminal before cancel exit

* test(onboard): align restoreTerminalState expectation

* chore(format): align onboarding restore test with updated oxfmt config

* chore(format): enforce updated oxfmt on restore test

* chore(format): apply updated oxfmt spacing to restore test

* fix: avoid stdin resume after onboarding (#12972) (thanks @vincentkoc)

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
This commit is contained in:
Vincent Koc
2026-02-14 10:46:07 -08:00
committed by GitHub
parent cab0abf52a
commit a042b32d2f
8 changed files with 129 additions and 9 deletions

View File

@@ -30,7 +30,7 @@ describe("restoreTerminalState", () => {
(process.stdin as { isPaused?: () => boolean }).isPaused = originalIsPaused;
});
it("does not resume paused stdin while restoring raw mode", () => {
it("does not resume paused stdin by default", () => {
const setRawMode = vi.fn();
const resume = vi.fn();
const isPaused = vi.fn(() => true);
@@ -46,4 +46,21 @@ describe("restoreTerminalState", () => {
expect(setRawMode).toHaveBeenCalledWith(false);
expect(resume).not.toHaveBeenCalled();
});
it("resumes paused stdin when resumeStdin is true", () => {
const setRawMode = vi.fn();
const resume = vi.fn();
const isPaused = vi.fn(() => true);
Object.defineProperty(process.stdin, "isTTY", { value: true, configurable: true });
Object.defineProperty(process.stdout, "isTTY", { value: false, configurable: true });
(process.stdin as { setRawMode?: (mode: boolean) => void }).setRawMode = setRawMode;
(process.stdin as { resume?: () => void }).resume = resume;
(process.stdin as { isPaused?: () => boolean }).isPaused = isPaused;
restoreTerminalState("test", { resumeStdin: true });
expect(setRawMode).toHaveBeenCalledWith(false);
expect(resume).toHaveBeenCalledOnce();
});
});

View File

@@ -2,6 +2,16 @@ import { clearActiveProgressLine } from "./progress-line.js";
const RESET_SEQUENCE = "\x1b[0m\x1b[?25h\x1b[?1000l\x1b[?1002l\x1b[?1003l\x1b[?1006l\x1b[?2004l";
type RestoreTerminalStateOptions = {
/**
* Resumes paused stdin after restoring terminal mode.
* Keep this off when the process should exit immediately after cleanup.
*
* Default: false (safer for "cleanup then exit" call sites).
*/
resumeStdin?: boolean;
};
function reportRestoreFailure(scope: string, err: unknown, reason?: string): void {
const suffix = reason ? ` (${reason})` : "";
const message = `[terminal] restore ${scope} failed${suffix}: ${String(err)}`;
@@ -12,7 +22,11 @@ function reportRestoreFailure(scope: string, err: unknown, reason?: string): voi
}
}
export function restoreTerminalState(reason?: string): void {
export function restoreTerminalState(
reason?: string,
options: RestoreTerminalStateOptions = {},
): void {
const resumeStdin = options.resumeStdin ?? false;
try {
clearActiveProgressLine();
} catch (err) {
@@ -26,6 +40,13 @@ export function restoreTerminalState(reason?: string): void {
} catch (err) {
reportRestoreFailure("raw mode", err, reason);
}
if (resumeStdin && typeof stdin.isPaused === "function" && stdin.isPaused()) {
try {
stdin.resume();
} catch (err) {
reportRestoreFailure("stdin resume", err, reason);
}
}
}
if (process.stdout.isTTY) {