diff --git a/src/core/webview/ClineProvider.ts b/src/core/webview/ClineProvider.ts
index 657e4a9ab6..3e8ed51668 100644
--- a/src/core/webview/ClineProvider.ts
+++ b/src/core/webview/ClineProvider.ts
@@ -1262,6 +1262,10 @@ export class ClineProvider implements vscode.WebviewViewProvider {
await this.updateGlobalState("browserViewportSize", browserViewportSize)
await this.postStateToWebview()
break
+ case "remoteBrowserHost":
+ await this.updateGlobalState("remoteBrowserHost", message.text)
+ await this.postStateToWebview()
+ break
case "fuzzyMatchThreshold":
await this.updateGlobalState("fuzzyMatchThreshold", message.value)
await this.postStateToWebview()
@@ -2188,6 +2192,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
soundVolume,
browserViewportSize,
screenshotQuality,
+ remoteBrowserHost,
preferredLanguage,
writeDelayMs,
terminalOutputLimit,
@@ -2246,6 +2251,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
soundVolume: soundVolume ?? 0.5,
browserViewportSize: browserViewportSize ?? "900x600",
screenshotQuality: screenshotQuality ?? 75,
+ remoteBrowserHost,
preferredLanguage: preferredLanguage ?? "English",
writeDelayMs: writeDelayMs ?? 1000,
terminalOutputLimit: terminalOutputLimit ?? TERMINAL_OUTPUT_LIMIT,
@@ -2399,6 +2405,7 @@ export class ClineProvider implements vscode.WebviewViewProvider {
soundVolume: stateValues.soundVolume,
browserViewportSize: stateValues.browserViewportSize ?? "900x600",
screenshotQuality: stateValues.screenshotQuality ?? 75,
+ remoteBrowserHost: stateValues.remoteBrowserHost,
fuzzyMatchThreshold: stateValues.fuzzyMatchThreshold ?? 1.0,
writeDelayMs: stateValues.writeDelayMs ?? 1000,
terminalOutputLimit: stateValues.terminalOutputLimit ?? TERMINAL_OUTPUT_LIMIT,
diff --git a/src/services/browser/BrowserSession.ts b/src/services/browser/BrowserSession.ts
index bed0332244..6fe25ddf5b 100644
--- a/src/services/browser/BrowserSession.ts
+++ b/src/services/browser/BrowserSession.ts
@@ -1,11 +1,12 @@
import * as vscode from "vscode"
import * as fs from "fs/promises"
import * as path from "path"
-import { Browser, Page, ScreenshotOptions, TimeoutError, launch } from "puppeteer-core"
+import { Browser, Page, ScreenshotOptions, TimeoutError, launch, connect } from "puppeteer-core"
// @ts-ignore
import PCR from "puppeteer-chromium-resolver"
import pWaitFor from "p-wait-for"
import delay from "delay"
+import axios from "axios"
import { fileExistsAtPath } from "../../utils/fs"
import { BrowserActionResult } from "../../shared/ExtensionMessage"
@@ -52,6 +53,41 @@ export class BrowserSession {
await this.closeBrowser() // this may happen when the model launches a browser again after having used it already before
}
+ const remoteBrowserHost = this.context.globalState.get("remoteBrowserHost") as string | undefined
+
+ if (remoteBrowserHost) {
+ console.log(`Attempting to connect to remote browser at ${remoteBrowserHost}`)
+ try {
+ // Fetch the WebSocket endpoint from the Chrome DevTools Protocol
+ const versionUrl = `${remoteBrowserHost.replace(/\/$/, "")}/json/version`
+ console.log(`Fetching WebSocket endpoint from ${versionUrl}`)
+
+ const response = await axios.get(versionUrl)
+ const browserWSEndpoint = response.data.webSocketDebuggerUrl
+
+ if (!browserWSEndpoint) {
+ throw new Error("Could not find webSocketDebuggerUrl in the response")
+ }
+
+ console.log(`Found WebSocket endpoint: ${browserWSEndpoint}`)
+
+ this.browser = await connect({
+ browserWSEndpoint,
+ defaultViewport: (() => {
+ const size =
+ (this.context.globalState.get("browserViewportSize") as string | undefined) || "900x600"
+ const [width, height] = size.split("x").map(Number)
+ return { width, height }
+ })(),
+ })
+ this.page = await this.browser?.newPage()
+ return
+ } catch (error) {
+ console.error(`Failed to connect to remote browser: ${error}`)
+ // Fall back to local browser if remote connection fails
+ }
+ }
+
const stats = await this.ensureChromiumExists()
this.browser = await stats.puppeteer.launch({
args: [
@@ -72,7 +108,14 @@ export class BrowserSession {
async closeBrowser(): Promise
+ Connect to a remote Chrome browser by providing the DevTools Protocol host address. + Roo will automatically fetch the WebSocket endpoint from this address. If provided, + Roo will use this browser instead of launching a local one. Leave empty to use the + built-in browser. +
+