feat: add --block flag to poc-agent read

The --block flag makes poc-agent read block until a complete response
is received (detected by a new user input line starting with '>'),
then exit. This enables smoother three-way conversations where one
instance can wait for the other's complete response without polling.

The implementation:
- Added cmd_read_inner() with block parameter
- Modified socket streaming to detect '>' lines as response boundaries
- Added --block CLI flag to Read subcommand

The --follow flag continues to stream indefinitely.
The --block flag reads one complete response and exits.
Neither flag exits immediately if there's no new output.
This commit is contained in:
Kent Overstreet 2026-03-21 23:39:12 -04:00
parent 8a83f39734
commit a3acf0a681
3 changed files with 19 additions and 6 deletions

View file

@ -62,6 +62,9 @@ pub enum SubCmd {
/// Stream output continuously instead of exiting /// Stream output continuously instead of exiting
#[arg(short, long)] #[arg(short, long)]
follow: bool, follow: bool,
/// Block until a complete response is received, then exit
#[arg(long)]
block: bool,
}, },
/// Send a message to the running agent /// Send a message to the running agent
Write { Write {

View file

@ -83,8 +83,8 @@ async fn main() {
// Subcommands that don't launch the TUI // Subcommands that don't launch the TUI
match &cli.command { match &cli.command {
Some(cli::SubCmd::Read { follow }) => { Some(cli::SubCmd::Read { follow, block }) => {
if let Err(e) = observe::cmd_read(*follow, cli.debug).await { if let Err(e) = observe::cmd_read_inner(*follow, *block, cli.debug).await {
eprintln!("{:#}", e); eprintln!("{:#}", e);
std::process::exit(1); std::process::exit(1);
} }

View file

@ -69,6 +69,11 @@ fn cursor_path() -> PathBuf { session_dir().join("read-cursor") }
/// Print new output since last read. With -f, also stream live from socket. /// Print new output since last read. With -f, also stream live from socket.
pub async fn cmd_read(follow: bool, debug: bool) -> anyhow::Result<()> { pub async fn cmd_read(follow: bool, debug: bool) -> anyhow::Result<()> {
cmd_read_inner(follow, false, debug).await
}
/// Print new output since last read. With -f, stream live. With block, wait for one response.
pub async fn cmd_read_inner(follow: bool, block: bool, debug: bool) -> anyhow::Result<()> {
use std::io::{Read, Seek, SeekFrom, Write}; use std::io::{Read, Seek, SeekFrom, Write};
let log = log_path(); let log = log_path();
@ -91,20 +96,20 @@ pub async fn cmd_read(follow: bool, debug: bool) -> anyhow::Result<()> {
f.read_to_string(&mut buf)?; f.read_to_string(&mut buf)?;
print!("{}", buf); print!("{}", buf);
let _ = std::io::stdout().flush(); let _ = std::io::stdout().flush();
} else if !follow { } else if !follow && !block {
println!("(nothing new)"); println!("(nothing new)");
} }
let _ = std::fs::write(&cursor, len.to_string()); let _ = std::fs::write(&cursor, len.to_string());
} else if !follow { } else if !follow && !block {
println!("(no log yet — is poc-agent running?)"); println!("(no log yet — is poc-agent running?)");
return Ok(()); return Ok(());
} }
if !follow { if !follow && !block {
return Ok(()); return Ok(());
} }
// -f: connect to socket for live output // -f or --block: connect to socket for live output
let sock = socket_path(); let sock = socket_path();
let stream = UnixStream::connect(&sock).await let stream = UnixStream::connect(&sock).await
.map_err(|e| anyhow::anyhow!( .map_err(|e| anyhow::anyhow!(
@ -122,6 +127,11 @@ pub async fn cmd_read(follow: bool, debug: bool) -> anyhow::Result<()> {
Ok(_) => { Ok(_) => {
print!("{}", line); print!("{}", line);
let _ = std::io::stdout().lock().flush(); let _ = std::io::stdout().lock().flush();
// In blocking mode, stop when we see a new user input (line starting with ">")
if block && line.trim_start().starts_with('>') {
break;
}
} }
Err(_) => break, Err(_) => break,
} }