mirror of
https://github.com/farcasclaudiu/openclaw.git
synced 2026-06-28 17:01:53 +03:00
refactor: clarify restoreTerminalState stdin resume option
This commit is contained in:
@@ -47,7 +47,7 @@ describe("runInteractiveOnboarding", () => {
|
|||||||
|
|
||||||
expect(runtime.exit).toHaveBeenCalledWith(1);
|
expect(runtime.exit).toHaveBeenCalledWith(1);
|
||||||
expect(mocks.restoreTerminalState).toHaveBeenCalledWith("onboarding finish", {
|
expect(mocks.restoreTerminalState).toHaveBeenCalledWith("onboarding finish", {
|
||||||
resumeStdin: false,
|
resumeStdinIfPaused: false,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ describe("runInteractiveOnboarding", () => {
|
|||||||
|
|
||||||
expect(runtime.exit).not.toHaveBeenCalled();
|
expect(runtime.exit).not.toHaveBeenCalled();
|
||||||
expect(mocks.restoreTerminalState).toHaveBeenCalledWith("onboarding finish", {
|
expect(mocks.restoreTerminalState).toHaveBeenCalledWith("onboarding finish", {
|
||||||
resumeStdin: false,
|
resumeStdinIfPaused: false,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ describe("runInteractiveOnboarding", () => {
|
|||||||
|
|
||||||
expect(mocks.runOnboardingWizard).toHaveBeenCalledOnce();
|
expect(mocks.runOnboardingWizard).toHaveBeenCalledOnce();
|
||||||
expect(mocks.restoreTerminalState).toHaveBeenCalledWith("onboarding finish", {
|
expect(mocks.restoreTerminalState).toHaveBeenCalledWith("onboarding finish", {
|
||||||
resumeStdin: false,
|
resumeStdinIfPaused: false,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -60,7 +60,7 @@ describe("runInteractiveOnboarding", () => {
|
|||||||
|
|
||||||
expect(runtime.exit).toHaveBeenCalledWith(1);
|
expect(runtime.exit).toHaveBeenCalledWith(1);
|
||||||
expect(mocks.restoreTerminalState).toHaveBeenCalledWith("onboarding finish", {
|
expect(mocks.restoreTerminalState).toHaveBeenCalledWith("onboarding finish", {
|
||||||
resumeStdin: false,
|
resumeStdinIfPaused: false,
|
||||||
});
|
});
|
||||||
const restoreOrder =
|
const restoreOrder =
|
||||||
mocks.restoreTerminalState.mock.invocationCallOrder[0] ?? Number.MAX_SAFE_INTEGER;
|
mocks.restoreTerminalState.mock.invocationCallOrder[0] ?? Number.MAX_SAFE_INTEGER;
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ export async function runInteractiveOnboarding(
|
|||||||
throw err;
|
throw err;
|
||||||
} finally {
|
} finally {
|
||||||
// Keep stdin paused so non-daemon runs can exit cleanly (e.g. Docker setup).
|
// Keep stdin paused so non-daemon runs can exit cleanly (e.g. Docker setup).
|
||||||
restoreTerminalState("onboarding finish", { resumeStdin: false });
|
restoreTerminalState("onboarding finish", { resumeStdinIfPaused: false });
|
||||||
if (exitCode !== null) {
|
if (exitCode !== null) {
|
||||||
runtime.exit(exitCode);
|
runtime.exit(exitCode);
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -31,7 +31,7 @@ export const defaultRuntime: RuntimeEnv = {
|
|||||||
console.error(...args);
|
console.error(...args);
|
||||||
},
|
},
|
||||||
exit: (code) => {
|
exit: (code) => {
|
||||||
restoreTerminalState("runtime exit", { resumeStdin: false });
|
restoreTerminalState("runtime exit", { resumeStdinIfPaused: false });
|
||||||
process.exit(code);
|
process.exit(code);
|
||||||
throw new Error("unreachable"); // satisfies tests when mocked
|
throw new Error("unreachable"); // satisfies tests when mocked
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -58,9 +58,26 @@ describe("restoreTerminalState", () => {
|
|||||||
(process.stdin as { resume?: () => void }).resume = resume;
|
(process.stdin as { resume?: () => void }).resume = resume;
|
||||||
(process.stdin as { isPaused?: () => boolean }).isPaused = isPaused;
|
(process.stdin as { isPaused?: () => boolean }).isPaused = isPaused;
|
||||||
|
|
||||||
restoreTerminalState("test", { resumeStdin: true });
|
restoreTerminalState("test", { resumeStdinIfPaused: true });
|
||||||
|
|
||||||
expect(setRawMode).toHaveBeenCalledWith(false);
|
expect(setRawMode).toHaveBeenCalledWith(false);
|
||||||
expect(resume).toHaveBeenCalledOnce();
|
expect(resume).toHaveBeenCalledOnce();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("does not touch stdin when stdin is not a TTY", () => {
|
||||||
|
const setRawMode = vi.fn();
|
||||||
|
const resume = vi.fn();
|
||||||
|
const isPaused = vi.fn(() => true);
|
||||||
|
|
||||||
|
Object.defineProperty(process.stdin, "isTTY", { value: false, 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", { resumeStdinIfPaused: true });
|
||||||
|
|
||||||
|
expect(setRawMode).not.toHaveBeenCalled();
|
||||||
|
expect(resume).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
+10
-1
@@ -10,6 +10,13 @@ type RestoreTerminalStateOptions = {
|
|||||||
* Default: false (safer for "cleanup then exit" call sites).
|
* Default: false (safer for "cleanup then exit" call sites).
|
||||||
*/
|
*/
|
||||||
resumeStdin?: boolean;
|
resumeStdin?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alias for resumeStdin. Prefer this name to make the behavior explicit.
|
||||||
|
*
|
||||||
|
* Default: false.
|
||||||
|
*/
|
||||||
|
resumeStdinIfPaused?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
function reportRestoreFailure(scope: string, err: unknown, reason?: string): void {
|
function reportRestoreFailure(scope: string, err: unknown, reason?: string): void {
|
||||||
@@ -26,7 +33,9 @@ export function restoreTerminalState(
|
|||||||
reason?: string,
|
reason?: string,
|
||||||
options: RestoreTerminalStateOptions = {},
|
options: RestoreTerminalStateOptions = {},
|
||||||
): void {
|
): void {
|
||||||
const resumeStdin = options.resumeStdin ?? false;
|
// Docker TTY note: resuming stdin can keep a container process alive even
|
||||||
|
// after the wizard is "done" (stdin_open: true), making installers appear hung.
|
||||||
|
const resumeStdin = options.resumeStdinIfPaused ?? options.resumeStdin ?? false;
|
||||||
try {
|
try {
|
||||||
clearActiveProgressLine();
|
clearActiveProgressLine();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|||||||
@@ -329,7 +329,7 @@ export async function finalizeOnboardingWizard(
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (hatchChoice === "tui") {
|
if (hatchChoice === "tui") {
|
||||||
restoreTerminalState("pre-onboarding tui", { resumeStdin: true });
|
restoreTerminalState("pre-onboarding tui", { resumeStdinIfPaused: true });
|
||||||
await runTui({
|
await runTui({
|
||||||
url: links.wsUrl,
|
url: links.wsUrl,
|
||||||
token: settings.authMode === "token" ? settings.gatewayToken : undefined,
|
token: settings.authMode === "token" ? settings.gatewayToken : undefined,
|
||||||
|
|||||||
Reference in New Issue
Block a user