feat: add built-in upgrade command for self-update (#898)

Adds a new `agent-browser upgrade` command that automatically detects the installation method (npm, Homebrew, or Cargo) and runs the appropriate update command.

**Changes:**
- Added new `upgrade.rs` module with upgrade logic
- Updated `main.rs` to handle the `upgrade` command
- Added upgrade help text in `output.rs`
- Updated README.md and documentation with upgrade instructions
- Updated SKILL.md to mention the upgrade command

**Implementation details:**
- Fetches latest version from npm registry to show version diff
- Auto-detects installation method by checking Homebrew, Cargo paths, and npm global packages
- Provides fallback instructions if installation method cannot be determined
- Uses existing color module for consistent styled output
- Gracefully handles network failures and continues with upgrade

Fixes #895
This commit is contained in:
Chris Tate
2026-03-17 23:29:07 -05:00
committed by GitHub
parent b8a5fc7101
commit 8cfba1752d
6 changed files with 233 additions and 1 deletions
+11
View File
@@ -58,6 +58,16 @@ On Linux, install system dependencies:
agent-browser install --with-deps
```
### Updating
Upgrade to the latest version:
```bash
agent-browser upgrade
```
Detects your installation method (npm, Homebrew, or Cargo) and runs the appropriate update command automatically.
### Requirements
- **Chrome** - Run `agent-browser install` to download Chrome from [Chrome for Testing](https://developer.chrome.com/blog/chrome-for-testing/) (Google's official automation channel). No Playwright or Node.js required for the daemon.
@@ -339,6 +349,7 @@ agent-browser reload # Reload page
```bash
agent-browser install # Download Chrome from Chrome for Testing (Google's official automation channel)
agent-browser install --with-deps # Also install system deps (Linux)
agent-browser upgrade # Upgrade agent-browser to the latest version
```
## Authentication
+8
View File
@@ -7,6 +7,7 @@ mod native;
mod output;
#[cfg(test)]
mod test_utils;
mod upgrade;
mod validation;
use serde_json::json;
@@ -26,6 +27,7 @@ use install::run_install;
use output::{
print_command_help, print_help, print_response_with_opts, print_version, OutputOptions,
};
use upgrade::run_upgrade;
fn serialize_json_value(value: &serde_json::Value) -> String {
serde_json::to_string(value).unwrap_or_else(|_| {
@@ -226,6 +228,12 @@ fn main() {
return;
}
// Handle upgrade separately
if clean.first().map(|s| s.as_str()) == Some("upgrade") {
run_upgrade();
return;
}
// Handle session separately (doesn't need daemon)
if clean.first().map(|s| s.as_str()) == Some("session") {
run_session(&clean, &flags.session, flags.json);
+17
View File
@@ -2266,6 +2266,22 @@ Examples:
"##
}
// === Upgrade ===
"upgrade" => {
r##"
agent-browser upgrade - Upgrade to the latest version
Usage: agent-browser upgrade
Detects the current installation method (npm, Homebrew, or Cargo) and runs
the appropriate update command. Displays the version change on success, or
informs you if you are already on the latest version.
Examples:
agent-browser upgrade
"##
}
// === Connect ===
"connect" => {
r##"
@@ -2572,6 +2588,7 @@ Sessions:
Setup:
install Install browser binaries
install --with-deps Also install system dependencies (Linux)
upgrade Upgrade to the latest version
Snapshot Options:
-i, --interactive Only interactive elements
+186
View File
@@ -0,0 +1,186 @@
use crate::color;
use std::process::{exit, Command, Stdio};
const CURRENT_VERSION: &str = env!("CARGO_PKG_VERSION");
const NPM_REGISTRY_URL: &str = "https://registry.npmjs.org/agent-browser/latest";
enum InstallMethod {
Npm,
Homebrew,
Cargo,
Unknown,
}
async fn fetch_latest_version() -> Result<String, String> {
let resp = reqwest::get(NPM_REGISTRY_URL)
.await
.map_err(|e| format!("Failed to fetch version info: {}", e))?;
let body: serde_json::Value = resp
.json()
.await
.map_err(|e| format!("Failed to parse version info: {}", e))?;
body.get("version")
.and_then(|v| v.as_str())
.map(|s| s.to_string())
.ok_or_else(|| "No version field in registry response".to_string())
}
fn detect_install_method() -> InstallMethod {
// Check Homebrew (available on macOS and Linux)
#[cfg(any(target_os = "macos", target_os = "linux"))]
{
let brew_check = Command::new("brew")
.args(["list", "agent-browser"])
.stdout(Stdio::null())
.stderr(Stdio::null())
.status();
if brew_check.map(|s| s.success()).unwrap_or(false) {
return InstallMethod::Homebrew;
}
}
// Check Cargo installation by executable path
if let Ok(exe) = std::env::current_exe() {
let path_str = exe.to_string_lossy();
if path_str.contains("/.cargo/bin/") || path_str.contains("\\.cargo\\bin\\") {
return InstallMethod::Cargo;
}
}
// Check npm global installation
let npm_check = Command::new("npm")
.args(["list", "-g", "agent-browser", "--depth=0"])
.stdout(Stdio::null())
.stderr(Stdio::null())
.status();
if npm_check.map(|s| s.success()).unwrap_or(false) {
return InstallMethod::Npm;
}
InstallMethod::Unknown
}
fn run_upgrade_command(method: &InstallMethod) -> bool {
match method {
InstallMethod::Npm => {
println!("Running: npm install -g agent-browser@latest");
Command::new("npm")
.args(["install", "-g", "agent-browser@latest"])
.status()
.map(|s| s.success())
.unwrap_or(false)
}
InstallMethod::Homebrew => {
println!("Running: brew upgrade agent-browser");
Command::new("brew")
.args(["upgrade", "agent-browser"])
.status()
.map(|s| s.success())
.unwrap_or(false)
}
InstallMethod::Cargo => {
println!("Running: cargo install agent-browser --force");
Command::new("cargo")
.args(["install", "agent-browser", "--force"])
.status()
.map(|s| s.success())
.unwrap_or(false)
}
InstallMethod::Unknown => false,
}
}
pub fn run_upgrade() {
let current = CURRENT_VERSION;
let rt = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.unwrap_or_else(|e| {
eprintln!(
"{} Failed to create runtime: {}",
color::error_indicator(),
e
);
exit(1);
});
let latest = match rt.block_on(fetch_latest_version()) {
Ok(v) => v,
Err(e) => {
eprintln!(
"{} Could not check latest version: {}",
color::warning_indicator(),
e
);
String::new()
}
};
if !latest.is_empty() && current == latest.as_str() {
println!(
"{} agent-browser is already at the latest version (v{})",
color::success_indicator(),
current
);
return;
}
let method = detect_install_method();
let method_name = match &method {
InstallMethod::Npm => "npm",
InstallMethod::Homebrew => "Homebrew",
InstallMethod::Cargo => "Cargo",
InstallMethod::Unknown => "",
};
if matches!(method, InstallMethod::Unknown) {
eprintln!(
"{} Could not detect installation method.",
color::error_indicator()
);
eprintln!(" To update manually, run one of:");
eprintln!(" npm install -g agent-browser@latest # npm");
eprintln!(" brew upgrade agent-browser # Homebrew");
eprintln!(" cargo install agent-browser --force # Cargo");
exit(1);
}
println!("Detected installation via {}.", method_name);
if !latest.is_empty() {
println!(
"{}",
color::cyan(&format!(
"Upgrading agent-browser... v{} → v{}",
current, latest
))
);
} else {
println!(
"{}",
color::cyan(&format!("Upgrading agent-browser (v{})...", current))
);
}
let success = run_upgrade_command(&method);
if success {
if !latest.is_empty() {
println!(
"{} Done! v{} → v{}",
color::success_indicator(),
current,
latest
);
} else {
println!("{} Done!", color::success_indicator());
}
} else {
eprintln!("{} Upgrade failed.", color::error_indicator());
exit(1);
}
}
+10
View File
@@ -69,6 +69,16 @@ On Linux, install system dependencies:
agent-browser install --with-deps
```
## Updating
Upgrade to the latest version:
```bash
agent-browser upgrade
```
Detects your installation method (npm, Homebrew, or Cargo) and runs the appropriate update command automatically. Displays the version change on success, or informs you if you are already on the latest version.
## Custom browser
Use a custom browser executable instead of bundled Chromium:
+1 -1
View File
@@ -6,7 +6,7 @@ allowed-tools: Bash(npx agent-browser:*), Bash(agent-browser:*)
# Browser Automation with agent-browser
The CLI uses Chrome/Chromium via CDP directly. Install via `npm i -g agent-browser`, `brew install agent-browser`, or `cargo install agent-browser`. Run `agent-browser install` to download Chrome.
The CLI uses Chrome/Chromium via CDP directly. Install via `npm i -g agent-browser`, `brew install agent-browser`, or `cargo install agent-browser`. Run `agent-browser install` to download Chrome. Run `agent-browser upgrade` to update to the latest version.
## Core Workflow