From 0dc36f2cff7e2ac445506fabad48dfc84f039124 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Mon, 2 Feb 2026 20:29:43 -0600 Subject: [PATCH] Add --stdin flag for eval command (#348) Adds --stdin flag to read JavaScript from stdin, enabling heredoc usage for multiline scripts without shell escaping issues. --- .changeset/stdin-eval.md | 5 +++ README.md | 2 +- cli/src/commands.rs | 42 ++++++++++++++------- cli/src/output.rs | 7 ++++ skills/agent-browser/references/commands.md | 11 +++++- 5 files changed, 50 insertions(+), 17 deletions(-) create mode 100644 .changeset/stdin-eval.md diff --git a/.changeset/stdin-eval.md b/.changeset/stdin-eval.md new file mode 100644 index 0000000..6e5c36b --- /dev/null +++ b/.changeset/stdin-eval.md @@ -0,0 +1,5 @@ +--- +"agent-browser": patch +--- + +Add --stdin flag for eval command to read JavaScript from stdin, enabling heredoc usage for multiline scripts diff --git a/README.md b/README.md index 23a0606..b82e79f 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ agent-browser upload # Upload files agent-browser screenshot [path] # Take screenshot (--full for full page, saves to a temporary directory if no path) agent-browser pdf # Save as PDF agent-browser snapshot # Accessibility tree with refs (best for AI) -agent-browser eval # Run JavaScript +agent-browser eval # Run JavaScript (-b for base64, --stdin for piped input) agent-browser connect # Connect to browser via CDP agent-browser close # Close browser (aliases: quit, exit) ``` diff --git a/cli/src/commands.rs b/cli/src/commands.rs index f4fa483..26f466f 100644 --- a/cli/src/commands.rs +++ b/cli/src/commands.rs @@ -1,5 +1,6 @@ use base64::{engine::general_purpose::STANDARD, Engine}; use serde_json::{json, Value}; +use std::io::{self, BufRead}; use crate::flags::Flags; @@ -419,24 +420,37 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result { - let (is_base64, script_parts): (bool, &[&str]) = + // Check for flags: -b/--base64 or --stdin + let (is_base64, is_stdin, script_parts): (bool, bool, &[&str]) = if rest.first() == Some(&"-b") || rest.first() == Some(&"--base64") { - (true, &rest[1..]) + (true, false, &rest[1..]) + } else if rest.first() == Some(&"--stdin") { + (false, true, &rest[1..]) } else { - (false, rest.as_slice()) + (false, false, rest.as_slice()) }; - let raw_script = script_parts.join(" "); - let script = if is_base64 { - let decoded = STANDARD.decode(&raw_script).map_err(|_| ParseError::InvalidValue { - message: "Invalid base64 encoding".to_string(), - usage: "eval -b ", - })?; - String::from_utf8(decoded).map_err(|_| ParseError::InvalidValue { - message: "Base64 decoded to invalid UTF-8".to_string(), - usage: "eval -b ", - })? + + let script = if is_stdin { + // Read script from stdin + let stdin = io::stdin(); + let lines: Vec = stdin.lock().lines() + .map(|l| l.unwrap_or_default()) + .collect(); + lines.join("\n") } else { - raw_script + let raw_script = script_parts.join(" "); + if is_base64 { + let decoded = STANDARD.decode(&raw_script).map_err(|_| ParseError::InvalidValue { + message: "Invalid base64 encoding".to_string(), + usage: "eval -b ", + })?; + String::from_utf8(decoded).map_err(|_| ParseError::InvalidValue { + message: "Base64 decoded to invalid UTF-8".to_string(), + usage: "eval -b ", + })? + } else { + raw_script + } }; Ok(json!({ "id": id, "action": "evaluate", "script": script })) } diff --git a/cli/src/output.rs b/cli/src/output.rs index 07e035f..7388e2a 100644 --- a/cli/src/output.rs +++ b/cli/src/output.rs @@ -885,6 +885,7 @@ Executes JavaScript code in the browser context and returns the result. Options: -b, --base64 Decode script from base64 (avoids shell escaping issues) + --stdin Read script from stdin (useful for heredocs/multiline) Global Options: --json Output as JSON @@ -895,6 +896,12 @@ Examples: agent-browser eval "window.location.href" agent-browser eval "document.querySelectorAll('a').length" agent-browser eval -b "ZG9jdW1lbnQudGl0bGU=" + + # Read from stdin with heredoc + cat <<'EOF' | agent-browser eval --stdin + const links = document.querySelectorAll('a'); + links.length; + EOF "## } diff --git a/skills/agent-browser/references/commands.md b/skills/agent-browser/references/commands.md index 6ac2084..8744acc 100644 --- a/skills/agent-browser/references/commands.md +++ b/skills/agent-browser/references/commands.md @@ -189,14 +189,21 @@ agent-browser dialog dismiss # Dismiss dialog ```bash agent-browser eval "document.title" # Simple expressions only -agent-browser eval -b "" # Any JavaScript (recommended) +agent-browser eval -b "" # Any JavaScript (base64 encoded) +agent-browser eval --stdin # Read script from stdin ``` -Use `-b`/`--base64` for reliable execution. Shell escaping with nested quotes and special characters is error-prone. +Use `-b`/`--base64` or `--stdin` for reliable execution. Shell escaping with nested quotes and special characters is error-prone. ```bash # Base64 encode your script, then: agent-browser eval -b "ZG9jdW1lbnQucXVlcnlTZWxlY3RvcignW3NyYyo9Il9uZXh0Il0nKQ==" + +# Or use stdin with heredoc for multiline scripts: +cat <<'EOF' | agent-browser eval --stdin +const links = document.querySelectorAll('a'); +Array.from(links).map(a => a.href); +EOF ``` ## State Management