From c96c65baa52a16e4d7e6a8a5de2e5f059256f57a Mon Sep 17 00:00:00 2001 From: Ryan Vogel <89211796+R44VC0RP@users.noreply.github.com> Date: Sat, 5 Sep 2026 12:39:06 -0400 Subject: [PATCH 1/2] Support simultaneous browser profiles with pinned sessions Replace the single-extension relay restriction with isolated per-profile runtimes, persistent installation identities and labels, and explicit CLI/MCP selection. Keep target and RPC IDs, reconnect cleanup, recording, and session ownership isolated so accounts cannot be silently switched. Migrate legacy sessions only using exact target evidence or explicit targetless selection; preserve all profile catalogs on shutdown. Verified typecheck, CLI/extension builds, all existing suite cases with failed/affected groups rerun after fixes, and added collision, migration, disconnect, and persistence cases. Live Helium checks ran parallel executes in the original and Rebase Accounts profiles with separate page titles/state, rejected ambiguous and conflicting selectors, and recovered the Rebase label after relay restart. Full browser smoke suite not run. Record transient profile-specific reconnect waiting as a follow-up. Preserve pre-existing documentation edits and untracked todos. --- AGENTS.md | 7 +- CONTEXT.md | 7 + PLAN.md | 35 +- extension/manifest.json | 4 +- extension/src/background.ts | 54 ++- skills/browser-control/SKILL.md | 37 +- src/cli.ts | 70 ++- src/doctor.ts | 2 +- src/http-api.ts | 227 +++++++--- src/mcp.ts | 25 +- src/protocol.ts | 1 + src/relay-client.ts | 14 +- src/relay-schema.ts | 28 ++ src/relay-types.ts | 2 + src/relay.ts | 584 +++++++++++++++++-------- src/session-catalog.ts | 2 + src/session-manager.ts | 114 ++++- test/doctor.test.ts | 2 +- test/http-api.test.ts | 43 +- test/relay-extension-handshake.test.ts | 147 ++++++- test/relay-session-persistence.test.ts | 275 +++++++++++- 21 files changed, 1353 insertions(+), 327 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 14882fa..5573e1b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -97,8 +97,9 @@ local Node relay. sandbox before releasing its execute permit, preventing a non-settling prompt action from mutating the page later. Cancel the waiter if WAIT presentation or action startup fails. -- `TargetRegistry` is the sole production live target-ownership authority. - Session state keeps one durable default-target identity and owner. Adoption reserves, +- Each browser profile has an isolated `TargetRegistry`, the sole live + target-ownership authority for that profile. Session state keeps one durable + profile ID, default-target identity, and owner. Adoption reserves, commits, or rolls back registry ownership transactionally and reconciles CDP visibility, grouping, and page status for every changed target. - Same-tab root target generations are explicit replacements, never map @@ -260,7 +261,7 @@ browser-control skill - Load `extension/dist` as the unpacked extension. - The relay listens on `127.0.0.1:19989` by default. -- Current shim version is `0.0.24` and extension protocol version is `2`. +- Current shim version is `0.0.25` and extension protocol version is `2`. - Store and npm versions may differ while their extension protocol versions remain compatible. - The source and unpacked-build manifest carries the public key for stable id `eibhgjafffkigblngnhafgbcipofaeon`. Store packaging must strip that key so the diff --git a/CONTEXT.md b/CONTEXT.md index 9de3683..dfc8608 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -32,6 +32,13 @@ The user's already-running Chromium-family browser with the Browser Control extension installed. _Avoid_: Chrome-only, managed browser +**Browser Profile**: +One extension installation, identified by a persistent locally generated profile +ID. Each profile has isolated live transport, targets, and sessions within the +same daemon. An optional user-chosen label is not a detected account identity. +Browser profiles are distinct from secret profiles used for captured credentials. +_Avoid_: Browser Control session, secret profile, Google account + **Local Driver Daemon**: The persistent Node process that owns Playwright execution, Browser Control sessions, target ownership, cross-process serialization, artifacts, and the diff --git a/PLAN.md b/PLAN.md index d41616f..9bf0040 100644 --- a/PLAN.md +++ b/PLAN.md @@ -242,15 +242,32 @@ require a new extension capture protocol and permission model. ## Session And Tab Model -A relay serves one browser/profile connection at a time. The first compatible -OPEN connection keeps ownership through inventory reconciliation and normal -operation; another connection is rejected with close code 4004 instead of -destroying existing targets, handoffs, or pending commands. Contention starts a -bounded websocket liveness probe so a dead incumbent cannot hold ownership -indefinitely. Genuine disconnect/reconnect still rebuilds the inventory. -`status` and `doctor` report rejected connection attempts, not a browser count. -This does not add simultaneous multi-browser routing or persistent browser -selection: switching requires disconnecting the incumbent extension. +A relay serves multiple browser/profile connections simultaneously. Each extension +installation stores a random profile ID locally and announces it in `hello`. +Connections, RPCs, target registries, CDP clients, handoffs, and recording state +are isolated per profile, including when Chrome tab/session IDs collide. +Sessions persist their profile ID in the shared catalog and never fall back to +another profile when their own disconnects. New sessions require `--profile` +(or MCP `profileId`) when selection is ambiguous. `profile list` discovers IDs; +`profile name