From b2c4aa0004dfe4b2f61041dc34b97d491847c9ba Mon Sep 17 00:00:00 2001 From: leeguooooo Date: Fri, 12 Jun 2026 01:34:15 +0900 Subject: [PATCH] fix(observability): stamp page URL on screenshot/network; enable capture on --clear (issue #8) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Field report #8: in extension-relay sessions, reads (eval/screenshot/network) could silently run against whatever tab drifted into focus, with no signal, and network capture was intermittently empty. - #8.1: screenshot and `network requests` now print `screenshot @ ` / `network @ ` to stderr (mirrors the existing `eval @ `), and the responses carry `origin`. A read against the wrong/drifted tab — and the "0 captured" vs "wrong page" ambiguity — is now obvious. - #8.3: `network requests --clear` now enables Network capture immediately instead of lazily on the next read, so requests fired between `--clear` and the following read are tracked (fixes the "No requests captured" on first try, works on retry" race). Extracted enable_request_tracking helper. - #8.2: the daemon version-mismatch restart notice now spells out that in-memory context (active tab, refs, captured requests) is reset and tells the user to re-open the target URL if the next read looks blank/wrong. Verified on a launched browser: coordinate clicks land, screenshot/network stamps appear, and a fetch after --clear is captured on the first read. --- cli/src/connection.rs | 5 +++- cli/src/native/actions.rs | 55 ++++++++++++++++++++++++++++++--------- cli/src/output.rs | 18 +++++++++++++ 3 files changed, 65 insertions(+), 13 deletions(-) diff --git a/cli/src/connection.rs b/cli/src/connection.rs index 07e5805..828735e 100644 --- a/cli/src/connection.rs +++ b/cli/src/connection.rs @@ -625,7 +625,10 @@ pub fn ensure_daemon(session: &str, opts: &DaemonOptions) -> Result Result, filter: &str) -> bool { false } +async fn enable_request_tracking(state: &mut DaemonState) { + if state.request_tracking { + return; + } + state.request_tracking = true; + if let Some(ref mgr) = state.browser { + if let Ok(session_id) = mgr.active_session_id() { + let _ = mgr + .client + .send_command_no_params("Network.enable", Some(session_id)) + .await; + } + } +} + async fn handle_requests(cmd: &Value, state: &mut DaemonState) -> Result { if cmd.get("clear").and_then(|v| v.as_bool()).unwrap_or(false) { state.tracked_requests.clear(); + // Enable Network capture NOW, on `--clear`, not lazily on the next read. + // `--clear` is the canonical "start capturing fresh" call, so requests + // fired between it and the following `requests` read must be tracked. + // Lazy-enabling only on read missed exactly those → intermittent + // "No requests captured" on the first try, fine on retry (issue #8.3). + enable_request_tracking(state).await; return Ok(json!({ "cleared": true })); } - if !state.request_tracking { - state.request_tracking = true; - if let Some(ref mgr) = state.browser { - if let Ok(session_id) = mgr.active_session_id() { - let _ = mgr - .client - .send_command_no_params("Network.enable", Some(session_id)) - .await; - } - } - } + enable_request_tracking(state).await; + // Current page URL, so a `requests` read on a drifted/wrong tab is obvious + // and "0 captured" can't be confused with "wrong page" (issues #8.1/#8.3). + let origin = match state.browser.as_ref() { + Some(mgr) => mgr.get_url().await.ok().filter(|u| !u.is_empty()), + None => None, + }; let filter = cmd.get("filter").and_then(|v| v.as_str()); let type_filter = cmd.get("type").and_then(|v| v.as_str()); @@ -7967,7 +7991,14 @@ async fn handle_requests(cmd: &Value, state: &mut DaemonState) -> Result Result { diff --git a/cli/src/output.rs b/cli/src/output.rs index 7ee2909..9ce40c8 100644 --- a/cli/src/output.rs +++ b/cli/src/output.rs @@ -595,6 +595,15 @@ pub fn print_response_with_opts(resp: &Response, action: Option<&str>, opts: &Ou } // Network requests if let Some(requests) = data.get("requests").and_then(|v| v.as_array()) { + // Stamp the page these requests were read from, mirroring `eval @ url`, + // so a read against a drifted/wrong tab is obvious (issue #8.1). + if let Some(o) = data + .get("origin") + .and_then(|v| v.as_str()) + .filter(|o| !o.is_empty()) + { + eprintln!("network @ {o}"); + } if requests.is_empty() { println!("No requests captured"); } else { @@ -798,6 +807,15 @@ pub fn print_response_with_opts(resp: &Response, action: Option<&str>, opts: &Ou color::success_indicator(), color::green(path) ); + // Stamp which page was captured (mirrors `eval @ url`) so a + // screenshot of the wrong/drifted tab is obvious (issue #8.1). + if let Some(o) = data + .get("origin") + .and_then(|v| v.as_str()) + .filter(|o| !o.is_empty()) + { + eprintln!("screenshot @ {o}"); + } if let Some(annotations) = data.get("annotations").and_then(|v| v.as_array()) { // Cap the printed legend on dense pages (it can be // hundreds of lines and flood the terminal). The image