Skip to content

Commit b6d5765

Browse files
committed
feat: for codex exec, if PROMPT is not specified, read from stdin if not a TTY
1 parent e207f20 commit b6d5765

File tree

2 files changed

+40
-2
lines changed

2 files changed

+40
-2
lines changed

codex-rs/exec/src/cli.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,10 @@ pub struct Cli {
4545
#[arg(long = "output-last-message")]
4646
pub last_message_file: Option<PathBuf>,
4747

48-
/// Initial instructions for the agent.
49-
pub prompt: String,
48+
/// Initial instructions for the agent. If not provided as an argument (or
49+
/// if `-` is used), instructions are read from stdin.
50+
#[arg(value_name = "PROMPT")]
51+
pub prompt: Option<String>,
5052
}
5153

5254
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, ValueEnum)]

codex-rs/exec/src/lib.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ mod cli;
22
mod event_processor;
33

44
use std::io::IsTerminal;
5+
use std::io::Read;
56
use std::path::Path;
67
use std::path::PathBuf;
78
use std::sync::Arc;
@@ -40,6 +41,41 @@ pub async fn run_main(cli: Cli, codex_linux_sandbox_exe: Option<PathBuf>) -> any
4041
config_overrides,
4142
} = cli;
4243

44+
// Determine the prompt based on CLI arg and/or stdin.
45+
let prompt = match prompt {
46+
Some(p) if p != "-" => p,
47+
// Either `-` was passed or no positional arg.
48+
maybe_dash => {
49+
// When no arg (None) **and** stdin is a TTY, bail out early – unless the
50+
// user explicitly forced reading via `-`.
51+
let force_stdin = matches!(maybe_dash.as_deref(), Some("-"));
52+
53+
if std::io::stdin().is_terminal() && !force_stdin {
54+
eprintln!(
55+
"No prompt provided. Either specify one as an argument or pipe the prompt into stdin."
56+
);
57+
std::process::exit(1);
58+
}
59+
60+
// Ensure the user knows we are waiting on stdin, as they may
61+
// have gotten into this state by mistake. If so, and they are not
62+
// writing to stdin, Codex will hang indefinitely, so this should
63+
// help them debug in that case.
64+
if !force_stdin {
65+
eprintln!("Reading prompt from stdin...");
66+
}
67+
let mut buffer = String::new();
68+
if let Err(e) = std::io::stdin().read_to_string(&mut buffer) {
69+
eprintln!("Failed to read prompt from stdin: {e}");
70+
std::process::exit(1);
71+
} else if buffer.trim().is_empty() {
72+
eprintln!("No prompt provided via stdin.");
73+
std::process::exit(1);
74+
}
75+
buffer
76+
}
77+
};
78+
4379
let (stdout_with_ansi, stderr_with_ansi) = match color {
4480
cli::Color::Always => (true, true),
4581
cli::Color::Never => (false, false),

0 commit comments

Comments
 (0)