Compare commits

..
4 Commits
Author SHA1 Message Date
leeguooooo d8f484eded fix(tabs): gate the about:blank cleanup to the relay only
CI / Version Sync Check (push) Has been cancelled
CI / Rust (push) Has been cancelled
CI / Rust (macos-latest - aarch64-apple-darwin) (push) Has been cancelled
CI / Rust (macos-latest - x86_64-apple-darwin) (push) Has been cancelled
CI / Rust (windows-latest - x86_64-pc-windows-msvc) (push) Has been cancelled
Release binaries / Build macOS ARM64 (push) Has been cancelled
Release binaries / Build macOS x64 (push) Has been cancelled
Release binaries / Build Linux ARM64 (push) Has been cancelled
Release binaries / Build Linux musl ARM64 (push) Has been cancelled
Release binaries / Build Linux musl x64 (push) Has been cancelled
Release binaries / Build Linux x64 (push) Has been cancelled
Release binaries / Build Windows x64 (push) Has been cancelled
CI / Native E2E Tests (push) Has been cancelled
CI / Windows Integration Test (push) Has been cancelled
CI / Global Install (macos-latest) (push) Has been cancelled
CI / Global Install (ubuntu-latest) (push) Has been cancelled
CI / Global Install (windows-latest) (push) Has been cancelled
Release binaries / Attach binaries to GitHub Release (push) Has been cancelled
The previous commit closed the leftover about:blank on ANY connection — but on a
launched browser the initial about:blank is the browser's own first tab, not
daemon scratch, so it must stay. Broke e2e_tab_ids_not_reused (launched). Gate
the cleanup on agent_group().is_some() (relay only), where the about:blank is a
tab WE created. e2e_tab_ids_not_reused passes; relay scratch-blank close intact.
2026-06-19 14:32:49 +09:00
leeguooooo 1eb40eabd5 fix(tabs): close the leftover initial about:blank when a real tab opens
A fresh session's daemon creates an about:blank scratch tab on connect; a
subsequent `tab new <url>` then opened the work tab beside it, so every session's
tab group showed a stray 'about:blank' next to the real page (e.g. about:blank +
ChatGPT). tab_new now closes any OWNED, still-blank tab once a real (non-blank)
tab exists, and re-pins the new tab. Verified live: `tab new <url>` on a fresh
session leaves only the work tab. 870 tests pass.
2026-06-19 14:06:42 +09:00
leeguooooo 601404ba72 feat(session): session stop <name> + session prune + lifecycle docs (#48)
Release binaries / Build macOS ARM64 (push) Has been cancelled
Release binaries / Build macOS x64 (push) Has been cancelled
Release binaries / Build Linux ARM64 (push) Has been cancelled
Release binaries / Build Linux musl ARM64 (push) Has been cancelled
Release binaries / Build Linux musl x64 (push) Has been cancelled
Release binaries / Build Linux x64 (push) Has been cancelled
Release binaries / Build Windows x64 (push) Has been cancelled
Release binaries / Attach binaries to GitHub Release (push) Has been cancelled
Explicit daemon reclamation to go with the v1.5.25 idle auto-shutdown:
- `session stop [name]` — stop one session daemon (default: current), graceful
  (SIGTERM → the daemon's shutdown runs close(), tidying the tabs it created).
- `session prune` — stop ALL session daemons now (clears the pile of idle
  daemons left after an automation/debug round; they respawn clean on next use).
  The __nm-host relay isn't a tracked session daemon, so the live-Chrome
  connection survives.
- --help Sessions section now documents the daemon lifecycle: spawn → 10-min idle
  auto-shutdown (AGENT_BROWSER_IDLE_TIMEOUT_MS / 0 to disable) → keep / stop / prune.

Closes #48. Verified live: session stop reclaimed a test daemon. 870 tests pass.
2026-06-18 14:44:35 +09:00
leeguooooo fd10766762 chore(ext): pack ab-connect 0.4.12 zip + crx (ABExt.ungroupTab for keep) 2026-06-18 12:16:14 +09:00
8 changed files with 96 additions and 3 deletions
+1 -1
View File
@@ -290,7 +290,7 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
[[package]]
name = "chrome-use"
version = "1.5.25"
version = "1.5.27"
dependencies = [
"aes",
"aes-gcm",
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "chrome-use"
version = "1.5.25"
version = "1.5.27"
edition = "2021"
description = "Fast browser automation CLI for AI agents"
license = "Apache-2.0"
+43
View File
@@ -305,6 +305,49 @@ fn run_session(args: &[String], session: &str, json_mode: bool) {
}
}
}
// Stop a specific session daemon (issue #48). Graceful: kill_stale_daemon
// sends SIGTERM first, so the daemon's shutdown handler runs `close()` and
// tidies the tabs IT created (its tab group) before exiting.
Some("stop") => {
let target = args.get(2).map(|s| s.as_str()).unwrap_or(session);
connection::kill_stale_daemon(target);
if json_mode {
print_json_value(json!({ "success": true, "data": { "stopped": target } }));
} else {
println!(
"{} stopped session daemon: {}",
color::success_indicator(),
target
);
}
}
// Reclaim ALL session daemons now (issue #48) — for clearing the pile of
// idle daemons left after a round of automation/debugging without waiting
// for the idle timeout. Each is stopped gracefully (closes its own tabs);
// they respawn clean on next use. The `__nm-host` relay is not a tracked
// session daemon, so the extension/live-Chrome connection survives.
Some("prune") => {
let sessions: Vec<String> = walk_daemons()
.sessions
.into_iter()
.map(|s| s.name)
.collect();
for s in &sessions {
connection::kill_stale_daemon(s);
}
if json_mode {
print_json_value(json!({ "success": true, "data": { "pruned": sessions } }));
} else if sessions.is_empty() {
println!("No session daemons to prune");
} else {
println!(
"{} pruned {} session daemon(s): {}",
color::success_indicator(),
sessions.len(),
sessions.join(", ")
);
}
}
None | Some(_) => {
// Just show current session
if json_mode {
+40
View File
@@ -2070,6 +2070,46 @@ impl BrowserManager {
self.active_page_index = index;
self.pin_active_target();
// Close the daemon's leftover initial `about:blank` scratch tab once this
// real tab exists, so the session's tab group isn't left showing a stray
// blank page beside the work tab (every group otherwise carried one). Only
// on the RELAY — there the about:blank is a tab WE created as scratch; on a
// launched browser the initial about:blank is the browser's own first tab,
// which we must not close. Only when opening a real url, OWNED, still-blank.
if target_url != "about:blank" && self.agent_group().is_some() {
if let Some(new_tid) = self.pages.get(index).map(|p| p.target_id.clone()) {
let blanks: Vec<String> = self
.pages
.iter()
.filter(|p| {
p.target_id != new_tid
&& self.created_targets.contains(&p.target_id)
&& (p.url == "about:blank" || p.url.is_empty())
})
.map(|p| p.target_id.clone())
.collect();
for tid in blanks {
let _ = self
.client
.send_command_typed::<_, Value>(
"Target.closeTarget",
&CloseTargetParams {
target_id: tid.clone(),
},
None,
)
.await;
self.created_targets.remove(&tid);
self.remove_page_by_target_id(&tid);
}
// Removing earlier pages shifts indices — re-pin the new tab.
if let Some(i) = self.pages.iter().position(|p| p.target_id == new_tid) {
self.active_page_index = i;
self.pin_active_target();
}
}
}
Ok(json!({
"tabId": format_tab_id(tab_id),
"label": label,
+10
View File
@@ -3455,11 +3455,21 @@ Confirmation:
Sessions:
session Show current session name
session list List active sessions
session stop [name] Stop one session daemon (default: current) — graceful,
closes the tabs it created
session prune Stop ALL session daemons now (closes their tabs; they
respawn clean on next use). For clearing idle daemons.
sessions List running session daemons (alias of daemon status)
daemon status List running session daemons (+ relay state)
daemon restart Kill all session daemons; keeps the extension relay
up. Clears stale/cross-leaked state after an upgrade.
Lifecycle: each --session <name> spawns a background daemon that drives that
session's tabs. A daemon auto-shuts-down after 10 min idle (no commands) —
AGENT_BROWSER_IDLE_TIMEOUT_MS overrides, 0 disables — and on shutdown closes
the scratch tabs IT created (its tab group). Use `keep` to leave a tab for the
user (exempt from auto-close), `session stop/prune` to reclaim now.
Chat (AI):
chat <message> Send a natural language instruction (single-shot)
chat Start interactive chat (REPL mode when stdin is a TTY)
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "chrome-use",
"version": "1.5.25",
"version": "1.5.27",
"description": "chrome-use — drive your real, logged-in Chrome from any AI agent, stealth by default",
"type": "module",
"packageManager": "pnpm@11.1.3",