Explain that daemon set-password needs a terminal when stdin is piped (#5358)

* Explain that daemon set-password needs a terminal when stdin is piped

The password prompt only resolves on a keypress from a terminal. With
stdin piped or redirected it never settled, so Node exited 13 with an
unsettled top-level await warning and no message. The command now fails
with PASSWORD_TTY_REQUIRED and points at PASEO_PASSWORD.

Closes #5350

* Assert the set-password terminal error message

---------

Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
This commit is contained in:
paseo-bot[bot]
2026-09-25 06:54:28 +02:00
committed by GitHub
parent 5c9f767d51
commit bf4dc22c2f
2 changed files with 34 additions and 1 deletions
@@ -57,6 +57,17 @@ function createCommandError(code: string, message: string, details?: string): Co
return { code, message, ...(details ? { details } : {}) };
}
function terminalPasswordPrompt(): PromptPassword {
if (!process.stdin.isTTY) {
throw createCommandError(
"PASSWORD_TTY_REQUIRED",
"paseo daemon set-password needs a terminal to read the password",
"Run it in an interactive terminal, or set PASEO_PASSWORD in the daemon's environment instead.",
);
}
return (message) => passwordPrompt({ message });
}
async function promptForPassword(promptPassword: PromptPassword): Promise<string> {
const first = await promptPassword("New daemon password");
if (isCancel(first)) {
@@ -112,7 +123,7 @@ export async function runSetPasswordCommand(
const promptPassword =
typeof options.promptPassword === "function"
? (options.promptPassword as PromptPassword)
: (message: string) => passwordPrompt({ message });
: terminalPasswordPrompt();
const newPassword = await promptForPassword(promptPassword);
const result = await setDaemonPasswordInConfig(newPassword, {
home: options.daemonTarget.kind === "instance" ? options.daemonTarget.home : undefined,