Fix piped stdin support, auto-enable print mode

When stdin is piped (not a TTY), read the content and treat it as the
first message. Since interactive mode requires a TTY for keyboard input,
print mode is automatically enabled.

- echo foo | pi -> equivalent to pi -p foo
- echo foo | pi -p -> equivalent to pi -p foo
- RPC mode unaffected (uses stdin for JSON-RPC)

fixes #708
This commit is contained in:
Mario Zechner 2026-01-16 03:18:56 +01:00
parent c08801e4c5
commit c50bfec01b
2 changed files with 36 additions and 0 deletions

View file

@ -30,6 +30,29 @@ import { runMigrations, showDeprecationWarnings } from "./migrations.js";
import { InteractiveMode, runPrintMode, runRpcMode } from "./modes/index.js";
import { initTheme, stopThemeWatcher } from "./modes/interactive/theme/theme.js";
/**
* Read all content from piped stdin.
* Returns undefined if stdin is a TTY (interactive terminal).
*/
async function readPipedStdin(): Promise<string | undefined> {
// If stdin is a TTY, we're running interactively - don't read stdin
if (process.stdin.isTTY) {
return undefined;
}
return new Promise((resolve) => {
let data = "";
process.stdin.setEncoding("utf8");
process.stdin.on("data", (chunk) => {
data += chunk;
});
process.stdin.on("end", () => {
resolve(data.trim() || undefined);
});
process.stdin.resume();
});
}
async function prepareInitialMessage(
parsed: Args,
autoResizeImages: boolean,
@ -310,6 +333,18 @@ export async function main(args: string[]) {
return;
}
// Read piped stdin content (if any) - skip for RPC mode which uses stdin for JSON-RPC
if (parsed.mode !== "rpc") {
const stdinContent = await readPipedStdin();
if (stdinContent !== undefined) {
// Force print mode since interactive mode requires a TTY for keyboard input
parsed.print = true;
// Prepend stdin content to messages
parsed.messages.unshift(stdinContent);
}
time("readPipedStdin");
}
if (parsed.export) {
try {
const outputPath = parsed.messages.length > 0 ? parsed.messages[0] : undefined;