From a0bd0c2f0fef0212530db55bd1b70e3212a97e6a Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 8 Mar 2026 17:41:40 -0500 Subject: [PATCH] Add webview support for Electron apps in native mode (#671) * Add webview support for Electron apps in native mode Fixes #580 * Fix cargo fmt violations in actions.rs and browser.rs Co-Authored-By: Claude Opus 4.6 * Revert unrelated refactors, keep only webview support changes - Restore is_none_or (was changed to map_or unnecessarily) - Restore single-if WebDriver check (was split into nested ifs) - Restore simple needs_relaunch logic (was expanded into 4 branches) - Restore find_frame signature (unused selector param was added) - Restore flat download handler condition (was nested unnecessarily) - Restore wait_or_kill and graceful close() to preserve cookie flushing --------- Co-authored-by: ctate <366502+ctate@users.noreply.github.com> Co-authored-by: Claude Opus 4.6 --- cli/src/native/actions.rs | 6 +++++- cli/src/native/browser.rs | 10 +++++++++- skills/electron/SKILL.md | 25 +++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/cli/src/native/actions.rs b/cli/src/native/actions.rs index 77d5b73..573974f 100644 --- a/cli/src/native/actions.rs +++ b/cli/src/native/actions.rs @@ -167,7 +167,8 @@ impl DaemonState { if let Ok(te) = serde_json::from_value::(event.params.clone()) { - if te.target_info.target_type == "page" + if (te.target_info.target_type == "page" + || te.target_info.target_type == "webview") && !te.target_info.url.is_empty() { let already_tracked = self @@ -443,6 +444,7 @@ pub async fn execute_command(cmd: &Value, state: &mut DaemonState) -> Value { session_id: attach.session_id, url: te.target_info.url.clone(), title: te.target_info.title.clone(), + target_type: te.target_info.target_type.clone(), }); } } @@ -2468,6 +2470,7 @@ async fn handle_recording_start(cmd: &Value, state: &mut DaemonState) -> Result< session_id: new_session_id.clone(), url: nav_url.clone(), title: String::new(), + target_type: "page".to_string(), }); // Navigate to URL @@ -4057,6 +4060,7 @@ async fn handle_window_new(cmd: &Value, state: &mut DaemonState) -> Result = result .target_infos .into_iter() - .filter(|t| t.target_type == "page" && !t.url.is_empty()) + .filter(|t| { + (t.target_type == "page" || t.target_type == "webview") && !t.url.is_empty() + }) .collect(); if page_targets.is_empty() { @@ -348,6 +351,7 @@ impl BrowserManager { session_id: attach_result.session_id.clone(), url: "about:blank".to_string(), title: String::new(), + target_type: "page".to_string(), }); self.active_page_index = 0; self.enable_domains(&attach_result.session_id).await?; @@ -370,6 +374,7 @@ impl BrowserManager { session_id: attach_result.session_id.clone(), url: target.url.clone(), title: target.title.clone(), + target_type: target.target_type.clone(), }); } @@ -664,6 +669,7 @@ impl BrowserManager { session_id: attach_result.session_id.clone(), url: "about:blank".to_string(), title: String::new(), + target_type: "page".to_string(), }); self.active_page_index = 0; self.enable_domains(&attach_result.session_id).await?; @@ -696,6 +702,7 @@ impl BrowserManager { "index": i, "title": p.title, "url": p.url, + "type": p.target_type, "active": i == self.active_page_index, }) }) @@ -736,6 +743,7 @@ impl BrowserManager { session_id: attach.session_id, url: target_url.to_string(), title: String::new(), + target_type: "page".to_string(), }); self.active_page_index = index; diff --git a/skills/electron/SKILL.md b/skills/electron/SKILL.md index 8de5718..4931da6 100644 --- a/skills/electron/SKILL.md +++ b/skills/electron/SKILL.md @@ -102,6 +102,31 @@ agent-browser tab 2 agent-browser tab --url "*settings*" ``` +## Webview Support + +Electron `` elements are automatically discovered and can be controlled like regular pages. When using `--native` mode, webviews appear as separate targets in the tab list with `type: "webview"`: + +```bash +# Connect in native mode +agent-browser --native connect 9222 + +# List targets -- webviews appear alongside pages +agent-browser tab +# Example output: +# 0: [page] Slack - Main Window https://app.slack.com/ +# 1: [webview] Embedded Content https://example.com/widget + +# Switch to a webview +agent-browser tab 1 + +# Interact with the webview normally +agent-browser snapshot -i +agent-browser click @e3 +agent-browser screenshot webview.png +``` + +**Note:** Webview support requires `--native` mode (raw CDP). The Playwright-based mode does not support webview targets. + ## Common Patterns ### Inspect and Navigate an App