# v0.4.0 - Self-managing connections: takeover + idle self-cleanup

## TL;DR
Bridge sessions now clean up after themselves. Calling `connect_host_network` while a bridge is already active performs a **takeover** - the new tunnel is established and verified first, then the old one is torn down in one sweep. And the remote `npx @luutuankiet/firefox-bridge` process now **auto-exits after 30 minutes with no live connections** (`--idle-timeout <min>`, `0` disables). A hard **4-hour lifetime cap** (`--max-lifetime <min>`) backstops it - even a held-open keep-alive connection can't keep the process (and its DHT bandwidth) alive forever. No orphaned tunnels, no zombie npx processes.

## Why
These tools live behind agents and MCP - the human operating the stack can't call `disconnect_host_network` by hand. v0.3.0's "one bridge at a time" rule meant a forgotten session hard-blocked the next one, and a forgotten bridge process idled forever on the remote host. Both ends now self-manage their lifecycle.

## Highlights
| Capability | Detail |
|---|---|
| Takeover on connect | With a bridge active, `connect_host_network` probes + starts the NEW tunnel first, repoints Firefox, then closes the old client. A failed takeover leaves the existing bridge fully intact - the browser is never left without a working tunnel. |
| Baseline preserved across takeovers | The proxy-pref baseline captured before the FIRST bridge is carried forward. Takeover never records bridge prefs as "user settings", so the final `disconnect_host_network` restores the true originals. |
| Idle self-cleanup | The bridge process counts live streams; after `--idle-timeout` minutes at zero (default 30, env `FIREFOX_BRIDGE_IDLE_TIMEOUT`) it logs and exits 0. Armed at listen time, so a bridge nobody ever connects to also cleans itself up. |
| Hard lifetime cap | Independent of activity: the process always exits after `--max-lifetime` minutes (default 240 = 4h, env `FIREFOX_BRIDGE_MAX_LIFETIME`, `0` disables). Bounds network/bandwidth usage even when an idle-but-open connection defeats the idle timer. |
| Concurrency guard kept | Two simultaneous connect calls still can't race - the in-flight sentinel remains; only the "already active" hard error is gone. |

## Files changed
- `src/tools/bridge.ts` - takeover flow in `connect_host_network` + updated tool description
- `packages/firefox-bridge/src/server.js` - live-stream tracking + idle timer (armed at listen, re-armed when last stream closes, cleared on close) + hard lifetime timer
- `packages/firefox-bridge/src/cli.js` - `--idle-timeout` + `--max-lifetime` flags / env vars / banner + help text
- New tests: `packages/firefox-bridge/test/idle.mjs` + `test/lifetime.mjs` - spawn the CLI with 3s timers, assert unattended exit 0
