feat: add screenshot output config, clipboard CLI commands, and fix wait --text native path (#749)
* feat: add screenshot output config, clipboard CLI commands, and fix wait --text native path
## Summary
- Add `--screenshot-dir`, `--screenshot-quality`, and `--screenshot-format` CLI flags (with corresponding `AGENT_BROWSER_SCREENSHOT_DIR`, `AGENT_BROWSER_SCREENSHOT_QUALITY`, `AGENT_BROWSER_SCREENSHOT_FORMAT` env vars) so users can configure where and how screenshots are saved without specifying a full path every time
- Add `clipboard read`, `clipboard write <text>`, `clipboard copy`, and `clipboard paste` CLI commands, exposing the existing protocol-level clipboard handlers that were previously only accessible via JSON-RPC
- Fix `wait --text` in native mode: the CLI was emitting `selector: "text=..."` (a Playwright-style locator) which native's `querySelector` can't handle. Now emits a `text` field that correctly hits the native `wait_for_text` polling path
- Add native clipboard `copy` and `paste` support via CDP `Input.dispatchKeyEvent`, and a `write` operation to the Node.js handler
* fix: resolve CI failures in Rust formatting and TypeScript typecheck
Use string-based page.evaluate for clipboard writeText to avoid
referencing `navigator` in Node.js compilation context. Run cargo fmt
to fix formatting in commands.rs and screenshot.rs.
* fix: clipboard write captures full multi-word text
Use rest[1..].join(" ") instead of rest.get(1) so unquoted multi-word
input like `clipboard write hello world` sends the full string rather
than silently dropping everything after the first word.
* improvements
* fixes
* improvements
* improvements
This commit is contained in:
@@ -43,6 +43,9 @@ pub struct Config {
|
||||
pub confirm_interactive: Option<bool>,
|
||||
pub native: Option<bool>,
|
||||
pub engine: Option<String>,
|
||||
pub screenshot_dir: Option<String>,
|
||||
pub screenshot_quality: Option<u32>,
|
||||
pub screenshot_format: Option<String>,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
@@ -86,6 +89,9 @@ impl Config {
|
||||
confirm_interactive: other.confirm_interactive.or(self.confirm_interactive),
|
||||
native: other.native.or(self.native),
|
||||
engine: other.engine.or(self.engine),
|
||||
screenshot_dir: other.screenshot_dir.or(self.screenshot_dir),
|
||||
screenshot_quality: other.screenshot_quality.or(self.screenshot_quality),
|
||||
screenshot_format: other.screenshot_format.or(self.screenshot_format),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -161,6 +167,9 @@ fn extract_config_path(args: &[String]) -> Option<Option<String>> {
|
||||
"--action-policy",
|
||||
"--confirm-actions",
|
||||
"--engine",
|
||||
"--screenshot-dir",
|
||||
"--screenshot-quality",
|
||||
"--screenshot-format",
|
||||
];
|
||||
let mut i = 0;
|
||||
while i < args.len() {
|
||||
@@ -240,6 +249,9 @@ pub struct Flags {
|
||||
pub confirm_interactive: bool,
|
||||
pub native: bool,
|
||||
pub engine: Option<String>,
|
||||
pub screenshot_dir: Option<String>,
|
||||
pub screenshot_quality: Option<u32>,
|
||||
pub screenshot_format: Option<String>,
|
||||
|
||||
// Track which launch-time options were explicitly passed via CLI
|
||||
// (as opposed to being set only via environment variables)
|
||||
@@ -347,6 +359,17 @@ pub fn parse_flags(args: &[String]) -> Flags {
|
||||
|| config.confirm_interactive.unwrap_or(false),
|
||||
native: env_var_is_truthy("AGENT_BROWSER_NATIVE") || config.native.unwrap_or(false),
|
||||
engine: env::var("AGENT_BROWSER_ENGINE").ok().or(config.engine),
|
||||
screenshot_dir: env::var("AGENT_BROWSER_SCREENSHOT_DIR")
|
||||
.ok()
|
||||
.or(config.screenshot_dir),
|
||||
screenshot_quality: env::var("AGENT_BROWSER_SCREENSHOT_QUALITY")
|
||||
.ok()
|
||||
.and_then(|s| s.parse().ok())
|
||||
.or(config.screenshot_quality),
|
||||
screenshot_format: env::var("AGENT_BROWSER_SCREENSHOT_FORMAT")
|
||||
.ok()
|
||||
.or(config.screenshot_format)
|
||||
.filter(|s| s == "png" || s == "jpeg"),
|
||||
cli_executable_path: false,
|
||||
cli_extensions: false,
|
||||
cli_profile: false,
|
||||
@@ -586,6 +609,42 @@ pub fn parse_flags(args: &[String]) -> Flags {
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
"--screenshot-dir" => {
|
||||
if let Some(s) = args.get(i + 1) {
|
||||
flags.screenshot_dir = Some(s.clone());
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
"--screenshot-quality" => {
|
||||
if let Some(s) = args.get(i + 1) {
|
||||
if let Ok(n) = s.parse::<u32>() {
|
||||
if n <= 100 {
|
||||
flags.screenshot_quality = Some(n);
|
||||
} else {
|
||||
eprintln!(
|
||||
"{} --screenshot-quality must be 0-100, got {}",
|
||||
color::warning_indicator(),
|
||||
n
|
||||
);
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
"--screenshot-format" => {
|
||||
if let Some(s) = args.get(i + 1) {
|
||||
if s == "png" || s == "jpeg" {
|
||||
flags.screenshot_format = Some(s.clone());
|
||||
} else {
|
||||
eprintln!(
|
||||
"{} --screenshot-format must be png or jpeg, got '{}'",
|
||||
color::warning_indicator(),
|
||||
s
|
||||
);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
"--config" => {
|
||||
// Already handled by load_config(); skip the value
|
||||
i += 1;
|
||||
@@ -640,6 +699,9 @@ pub fn clean_args(args: &[String]) -> Vec<String> {
|
||||
"--confirm-actions",
|
||||
"--config",
|
||||
"--engine",
|
||||
"--screenshot-dir",
|
||||
"--screenshot-quality",
|
||||
"--screenshot-format",
|
||||
];
|
||||
|
||||
let mut i = 0;
|
||||
|
||||
Reference in New Issue
Block a user