From 62e7229b4738505cc0d29ceca04e6e2716093f33 Mon Sep 17 00:00:00 2001 From: leeguooooo Date: Sat, 13 Jun 2026 23:41:16 +0900 Subject: [PATCH] feat(version): extension reports its version; doctor shows all-component coherence MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The upgrade story spanned four parts (CLI, daemon, extension, skill) with no single view and — worst — the extension was a total black box: nothing reported which build was live, so a user could sit on a stale extension with zero signal. - ext (0.4.7): on connect the extension sends a `hello` with chrome.runtime.getManifest().version; the native-messaging host records it to a `relay-ext-version` sidecar (next to relay-cdp-url, removed on exit). - build.rs embeds the shipped extension version (AB_CONNECT_VERSION, read from the ext manifest at compile time) so the CLI knows what extension it expects. - `chrome-use doctor` gains a Versions section: CLI (vs the cached latest from the background update check), extension (connected version vs the bundled expected — warns + tells you to reload it in Chrome if behind), and skill (bundled, version- locked; `skills add` copies may be stale). Daemon coherence was already covered. So 'which of the four parts is on what version, and what needs upgrading' is now one command. Verified: doctor warns on a simulated old extension and passes on a current one; gracefully shows 'not connected / predates reporting' when the host hasn't learned a version yet. --- cli/build.rs | 18 ++++++ cli/src/connect.rs | 32 ++++++++++ cli/src/doctor/mod.rs | 2 + cli/src/doctor/versions.rs | 89 ++++++++++++++++++++++++++++ cli/src/upgrade.rs | 21 +++++++ extensions/ab-connect.crx | Bin 31733 -> 31865 bytes extensions/ab-connect.zip | Bin 31149 -> 31289 bytes extensions/ab-connect/background.js | 6 ++ extensions/ab-connect/manifest.json | 2 +- 9 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 cli/src/doctor/versions.rs diff --git a/cli/build.rs b/cli/build.rs index 7bc9cf1..ddf1660 100644 --- a/cli/build.rs +++ b/cli/build.rs @@ -3,6 +3,23 @@ use std::env; use std::fs; use std::path::Path; +/// Embed the version of the `ab-connect` extension this CLI ships alongside, so +/// `doctor` can tell a connected extension "you're older than what this CLI +/// expects, update it." Read from the extension manifest at build time so it +/// stays in sync with whatever extension version is in the same checkout/release +/// (the ext is on its own 0.4.x line, separate from the CLI version). Falls back +/// to "unknown" if the manifest can't be read. +fn embed_extension_version() { + let manifest = Path::new("../extensions/ab-connect/manifest.json"); + println!("cargo:rerun-if-changed=../extensions/ab-connect/manifest.json"); + let version = fs::read_to_string(manifest) + .ok() + .and_then(|s| serde_json::from_str::(&s).ok()) + .and_then(|v| v.get("version").and_then(|x| x.as_str()).map(String::from)) + .unwrap_or_else(|| "unknown".to_string()); + println!("cargo:rustc-env=AB_CONNECT_VERSION={}", version); +} + /// Ensure `packages/dashboard/out/` exists so `rust-embed` doesn't fail during /// Rust-only dev builds where the dashboard hasn't been built. The placeholder /// `index.html` is only written when the directory is completely absent. @@ -20,6 +37,7 @@ fn ensure_dashboard_dir() { fn main() { ensure_dashboard_dir(); + embed_extension_version(); let protocol_dir = Path::new("cdp-protocol"); let out_dir = env::var("OUT_DIR").unwrap(); diff --git a/cli/src/connect.rs b/cli/src/connect.rs index caab913..6504bc9 100644 --- a/cli/src/connect.rs +++ b/cli/src/connect.rs @@ -449,6 +449,28 @@ pub fn relay_url() -> Option { } } +/// Sidecar recording the connected extension's version, written by the host when +/// it receives the extension's `hello` (sibling of `relay-cdp-url`). Lets +/// `doctor` surface which extension build is live without a CDP round-trip. +fn relay_ext_version_path() -> PathBuf { + relay_url_path().with_file_name("relay-ext-version") +} + +/// Version of the connected `ab-connect` extension, if the host learned it from +/// the extension's `hello`. `None` when no extension has connected since the +/// host started, or the extension predates version reporting. +pub fn relay_ext_version() -> Option { + let s = std::fs::read_to_string(relay_ext_version_path()) + .ok()? + .trim() + .to_string(); + if s.is_empty() { + None + } else { + Some(s) + } +} + /// Hidden `__nm-host` mode: launched by Chrome for the ab-connect extension. /// /// Bridges the extension (native-messaging stdio, envelope protocol) to a local @@ -570,6 +592,15 @@ async fn nm_host_main() { Ok(v) => v, Err(_) => continue, }; + // Extension version handshake: record it next to the relay URL so + // `doctor` can report which extension build is live (and whether it's + // behind). Best-effort; the message carries no CDP payload. + if v.get("method").and_then(|m| m.as_str()) == Some("hello") { + if let Some(ver) = v.get("version").and_then(|x| x.as_str()) { + let _ = std::fs::write(relay_ext_version_path(), ver); + } + continue; + } let outs = { let mut s = state.lock().await; s.handle_ext_message(&v, "") @@ -602,6 +633,7 @@ async fn nm_host_main() { } nm_log("[nm-host] stdin EOF — Chrome closed the port"); let _ = std::fs::remove_file(relay_url_path()); + let _ = std::fs::remove_file(relay_ext_version_path()); } #[allow(clippy::too_many_arguments)] diff --git a/cli/src/doctor/mod.rs b/cli/src/doctor/mod.rs index 51c4484..64a3faa 100644 --- a/cli/src/doctor/mod.rs +++ b/cli/src/doctor/mod.rs @@ -18,6 +18,7 @@ mod launch; mod network; mod providers; mod security; +mod versions; use serde_json::{json, Value}; @@ -97,6 +98,7 @@ pub fn run_doctor(opts: DoctorOptions) -> i32 { let mut fixed: Vec = Vec::new(); environment::check(&mut checks); + versions::check(&mut checks); chrome::check(&mut checks); daemon::check(&mut checks); config::check(&mut checks); diff --git a/cli/src/doctor/versions.rs b/cli/src/doctor/versions.rs new file mode 100644 index 0000000..24f04d2 --- /dev/null +++ b/cli/src/doctor/versions.rs @@ -0,0 +1,89 @@ +//! Version-coherence checks across all four moving parts: the CLI binary, the +//! per-session daemons (covered by `daemon.rs`), the connected `ab-connect` +//! extension, and the bundled skill. The extension was previously a black box — +//! nothing reported which build was live — so a user could sit on an old +//! extension with no signal. The extension now reports its version over the +//! relay (`hello`), the host records it, and this surfaces it in one place. + +use super::{Check, Status}; +use crate::{connect, upgrade}; + +pub(super) fn check(checks: &mut Vec) { + let category = "Versions"; + let cli_version = env!("CARGO_PKG_VERSION"); + + // CLI — compare against the latest seen by the background update check. + match upgrade::cached_latest_version() { + Some(latest) if upgrade::version_is_newer(&latest, cli_version) => { + checks.push( + Check::new( + "versions.cli", + category, + Status::Warn, + format!("CLI {cli_version} (newer available: {latest})"), + ) + .with_fix("chrome-use upgrade".to_string()), + ); + } + _ => { + checks.push(Check::new( + "versions.cli", + category, + Status::Pass, + format!("CLI {cli_version}"), + )); + } + } + + // Extension — the build this CLI shipped alongside (embedded at compile time + // from the extension manifest) is what we expect to be running. + let expected_ext = env!("AB_CONNECT_VERSION"); + match connect::relay_ext_version() { + Some(ext) if upgrade::version_is_newer(expected_ext, &ext) => { + checks.push( + Check::new( + "versions.extension", + category, + Status::Warn, + format!("extension {ext} is behind the bundled {expected_ext}"), + ) + .with_fix( + "update ab-connect in Chrome: chrome://extensions \u{2192} reload \ + (or wait for the Web Store auto-update)" + .to_string(), + ), + ); + } + Some(ext) => { + checks.push(Check::new( + "versions.extension", + category, + Status::Pass, + format!("extension {ext}"), + )); + } + None => { + checks.push(Check::new( + "versions.extension", + category, + Status::Info, + format!( + "extension not connected (or it predates version reporting — \ + expected {expected_ext})" + ), + )); + } + } + + // Skill — ships inside the same release artifact as the binary, so it's + // version-locked here. Copies made elsewhere via `skills add` aren't. + checks.push(Check::new( + "versions.skill", + category, + Status::Info, + format!( + "skills bundled with this CLI ({cli_version}); copies made via `skills add` \ + elsewhere may be stale — re-run to refresh" + ), + )); +} diff --git a/cli/src/upgrade.rs b/cli/src/upgrade.rs index 8f29466..293ed3c 100644 --- a/cli/src/upgrade.rs +++ b/cli/src/upgrade.rs @@ -52,6 +52,27 @@ fn is_newer(latest: &str, current: &str) -> bool { matches!((parse_version(latest), parse_version(current)), (Some(l), Some(c)) if l > c) } +/// Public semver-ish comparison (`latest` strictly newer than `current`), so +/// `doctor` can flag a stale extension/CLI without re-implementing parsing. +pub fn version_is_newer(latest: &str, current: &str) -> bool { + is_newer(latest, current) +} + +/// The latest CLI version recorded by the background update check, if any. +/// `doctor` uses it to show "a newer chrome-use is available" without a network +/// call (the `__update-check` worker refreshes the cache out of band). +pub fn cached_latest_version() -> Option { + std::fs::read_to_string(update_cache_path()) + .ok() + .and_then(|s| serde_json::from_str::(&s).ok()) + .and_then(|j| { + j.get("latest") + .and_then(|v| v.as_str()) + .map(|s| s.to_string()) + }) + .filter(|s| !s.is_empty()) +} + /// Hidden `__update-check` subcommand: fetch the latest release tag and cache it. /// Spawned detached by [`maybe_notify_update`] so the network call never blocks a /// real command. Uses `curl` (no extra deps, matches `upgrade`). diff --git a/extensions/ab-connect.crx b/extensions/ab-connect.crx index 08b5b32a823929ffbc6a7418d5570583349b1f50..598d59f3958ac50c1f8473fe5ef3e87ed915cb8c 100644 GIT binary patch delta 7144 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 delta 7166 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ÐXkps&0oqQqWWIc6n9W~P6 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