Add heartbeat event and daemon browser-liveness reaper

Introduce a `system.heartbeat` protocol event and use it as a
liveness signal on the daemon side.

- Track `last_seen` per connected browser, bumped on every inbound
  WS frame (tool response, event, ping/pong, or heartbeat).
- Add a reaper task that drops any browser silent past a 60s window
  and purges its sessions, mirroring the WS disconnect cleanup. This
  releases half-open connections left behind when the OS resumes from
  sleep and kills the service worker without delivering a close frame,
  so the daemon no longer pins a phantom "connected" browser and can
  idle-exit normally.
- Wire the reaper into both the foreground daemon and the test/embed
  entry point, aborting it on shutdown.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
drakezhang
2026-07-22 12:16:56 +08:00
co-authored by Cursor
parent ccf3c32140
commit 5e91178e03
8 changed files with 161 additions and 2 deletions
@@ -51,6 +51,7 @@ fn fake_client(id: &str, label: &str, connected_at_ms: i64) -> Arc<BrowserClient
generation: next_browser_generation(),
connected_at_ms,
version_skew: false,
last_seen: Mutex::new(std::time::Instant::now()),
})
}
+1
View File
@@ -242,6 +242,7 @@ async fn status_surfaces_version_skew_for_skewed_browser() {
generation: bsk::daemon::browsers::next_browser_generation(),
connected_at_ms: 0,
version_skew: true,
last_seen: Mutex::new(std::time::Instant::now()),
});
state.browsers.insert(client);