feat(webview): add dev-only browser bridge for standalone Chrome UI - #1593
feat(webview): add dev-only browser bridge for standalone Chrome UI#1593hnbdr wants to merge 1 commit into
Conversation
Runs the Zoo Code interface as the main page of a regular Chrome tab instead of a nested VSCode webview iframe. Inside the iframe the UI shares one DevTools panel with the rest of the window and cannot load DevTools extensions, which makes inspection awkward. As a top-level document the UI gets its own DevTools with installable extensions (React DevTools, etc.), and the extension IPC becomes plain socket.io traffic that can be monitored live in the DevTools network panel as websocket frames. - Add BrowserBridgeServer: a loopback-only socket.io server owned by each ClineProvider, with a virtual webview that keeps the existing WebviewMessage/ExtensionMessage protocol unchanged. - Register a dev-only `zoo-code.openInBrowser` command (activated only with ROO_BROWSER_BRIDGE=1 in Development mode; intentionally not contributed in package.json so end users never see it) that starts the bridge, swaps the real webview for a placeholder with a link, and opens the browser tab. - webview-ui: BrowserBridgeClient in VSCodeAPIWrapper activates when the tab is opened with ?bridgePort=..., plus a dark-theme fallback for --vscode-* CSS variables in standalone browser mode.
|
Important Review skippedAuto reviews are limited based on label configuration. 🏷️ Required labels (at least one) (1)
Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Advanced Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Review statusThanks for contributing. This comment tracks the review sequence and the next action. Current step: Mark the PR ready. Required CI must pass before CodeRabbit starts. Review-state labels are managed by this workflow; do not edit them manually. |
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
Related GitHub Issue
N/A — developer-only tooling; per repo triage, internal DX tooling does not require a pre-existing issue.
Description
Adds an opt-in browser bridge: the Zoo Code UI can run as the main page of a regular Chrome tab instead of a nested VSCode webview iframe.
Why: inside the webview iframe the UI shares one DevTools panel with the rest of the VSCode window and cannot load DevTools extensions, which makes inspection awkward. As a top-level document the UI gets its own DevTools with installable extensions (React DevTools etc.), and the extension IPC becomes plain socket.io traffic that can be monitored live in the Network tab as websocket frames.
How:
src/core/webview/browserBridge.ts—BrowserBridgeServer: a loopback-only (127.0.0.1) socket.io server, owned one-per-ClineProvider. Port0by default so the OS assigns a unique free port per bridge (override withROO_BROWSER_BRIDGE_PORT); the port is passed to the tab as?bridgePort=.... A virtual webview adapter keeps the existingWebviewMessage/ExtensionMessageprotocol unchanged — no protocol forks anywhere.src/activate/registerCommands.ts— registers thezoo-code.openInBrowsercommand only whenROO_BROWSER_BRIDGE=1is set in the extension host env (added to the.vscode/launch.jsondev config) andextensionMode === Development. It is intentionally not contributed inpackage.json, so end users never see a command-palette entry or toolbar button.src/core/webview/ClineProvider.ts—enableBrowserBridge()irreversibly switches a provider to its bridge (re-clicking the command reuses the existing port instead of leaking a second server). The real iframe then renders a static placeholder with a clickable link back to the browser tab, so the two environments never run React simultaneously. The bridge is disposed together with the provider.webview-ui/src/utils/vscode.ts— whenacquireVsCodeApiis absent but?bridgePort=is present,VSCodeAPIWrapperroutes messages over socket.io; inboundextensionMessageevents are re-dispatched throughwindow.postMessageso existing message consumers work unchanged.webview-ui/src/index.css— dark-theme fallback values for the--vscode-*custom properties that VS Code normally injects, so the standalone tab renders sanely.socket.io(extension) /socket.io-client(webview).Reviewer notes:
127.0.0.1only, CORS restricted to local origins, and the whole path is gated behind Development mode + env var.Test Procedure
cd src && npx vitest run core/webview/__tests__/browserBridge.spec.ts activate/__tests__/registerCommands.spec.ts core/webview/__tests__/ClineProvider.spec.ts— covers port allocation, virtual webview message routing, listener single-registration, placeholder rendering, dev-only command registration, bridge reuse/dispose.pnpm lintandpnpm check-typespass (also enforced by pre-commit / pre-push hooks).pnpm install→ run webview dev server (pnpm --dir webview-ui dev) → F5 "Run and Debug → Run Extension" → in the extension host's command palette run Zoo Code: Open in Browser → Chrome openshttp://localhost:5173/?bridgePort=<port>with the full UI as the main page; the sidebar iframe shows a placeholder link; DevTools → Network → WS shows every webview↔extension message pair live.Pre-Submission Checklist
Documentation Updates
Additional Notes
Local run of the changed-code mutation gate (
scripts/stryker-diff.mjs) currently fails to spawn on Windows becausespawnSynccannot execute the.cmdpnpm shims forvitest/stryker(ENOENT) — this is an infrastructure limitation of the gate script on Windows, not a code issue; CI (Linux) should run it normally. Happy to add aStryker disabledirective or focused tests in follow-up commits if the gate flags specific lines.Get in Touch
GitHub: @hnbdr (Discord on request via GitHub/issue thread)