From 9b1f98b966e851c802c11029c944a97dde006a43 Mon Sep 17 00:00:00 2001 From: leeguooooo Date: Wed, 10 Jun 2026 15:12:34 +0900 Subject: [PATCH] fix: polish two Hermes follow-up cosmetics (invalid-selector wording, empty url glob) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - invalid CSS selector now errors "Invalid selector '': " instead of the misleading "Element not found" — the coordinate path (resolve_by_selector) now also inspects exception_details, matching resolve_element_object_id. - `wait --url ""` is rejected at parse time ("needs a non-empty pattern") rather than silently matching any URL. Unit test added. Not changed: verb-less `find role X` defaulting to a click. That default is a deliberate, tested decision (test_find_role_default_subaction_click_when_no_action); changing it to locate-and-report is a design choice left to the maintainer. --- cli/Cargo.lock | 2 +- cli/Cargo.toml | 2 +- cli/src/commands.rs | 17 +++++++++++++++++ cli/src/native/element.rs | 6 ++++++ package.json | 2 +- 5 files changed, 26 insertions(+), 3 deletions(-) diff --git a/cli/Cargo.lock b/cli/Cargo.lock index 79d6f92..871edd9 100644 --- a/cli/Cargo.lock +++ b/cli/Cargo.lock @@ -45,7 +45,7 @@ dependencies = [ [[package]] name = "agent-browser-stealth" -version = "0.27.0-fork.32" +version = "0.27.0-fork.33" dependencies = [ "aes-gcm", "async-trait", diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 6f33fca..e1516f3 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "agent-browser-stealth" -version = "0.27.0-fork.32" +version = "0.27.0-fork.33" edition = "2021" description = "Fast browser automation CLI for AI agents" license = "Apache-2.0" diff --git a/cli/src/commands.rs b/cli/src/commands.rs index 86fe8ac..efdd06d 100644 --- a/cli/src/commands.rs +++ b/cli/src/commands.rs @@ -548,6 +548,14 @@ fn parse_command_inner(args: &[String], flags: &Flags) -> Result", })?; + if url.is_empty() { + return Err(ParseError::InvalidValue { + message: "wait --url needs a non-empty pattern (an empty pattern would \ + match any URL)." + .to_string(), + usage: "wait --url ", + }); + } let mut cmd = json!({ "id": id, "action": "waitforurl", "url": url }); // Parse --timeout (without it the default applies — and a // non-matching pattern would otherwise wait the full default). @@ -3811,6 +3819,15 @@ mod tests { assert_eq!(cmd["url"], "**/dashboard"); } + #[test] + fn test_wait_url_empty_pattern_rejected() { + // An empty pattern would match any URL — reject it rather than silently + // always-match. (Build argv directly: split_whitespace can't yield "".) + let argv = vec!["wait".to_string(), "--url".to_string(), String::new()]; + let err = parse_command(&argv, &default_flags()); + assert!(err.is_err(), "empty --url pattern should be rejected"); + } + #[test] fn test_wait_url_with_timeout() { // --timeout must be parsed for the --url path; without it a non-matching diff --git a/cli/src/native/element.rs b/cli/src/native/element.rs index 4aec670..4e3eaef 100644 --- a/cli/src/native/element.rs +++ b/cli/src/native/element.rs @@ -845,6 +845,12 @@ async fn resolve_by_selector( ) .await?; + // A syntactically-invalid CSS selector makes querySelector throw — surface + // that as "invalid selector" rather than a misleading "element not found". + if let Some(ex) = result.exception_details { + return Err(format!("Invalid selector '{}': {}", selector, ex.text)); + } + let val = result.result.value.unwrap_or(Value::Null); let x = val.get("x").and_then(|v| v.as_f64()); let y = val.get("y").and_then(|v| v.as_f64()); diff --git a/package.json b/package.json index 72798d1..a39bd03 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "agent-browser-stealth", - "version": "0.27.0-fork.32", + "version": "0.27.0-fork.33", "description": "Browser automation CLI for AI agents — stealth fork with anti-detection", "type": "module", "packageManager": "pnpm@11.1.3",