diff --git a/proto/browser.proto b/proto/browser.proto index 95cb52bb9e..cf7d0efda9 100644 --- a/proto/browser.proto +++ b/proto/browser.proto @@ -6,10 +6,17 @@ import "common.proto"; service BrowserService { rpc getBrowserConnectionInfo(EmptyRequest) returns (BrowserConnectionInfo); + rpc testBrowserConnection(StringRequest) returns (BrowserConnection); } message BrowserConnectionInfo { bool is_connected = 1; bool is_remote = 2; - string host = 3; // Optional, may be empty + optional string host = 3; +} + +message BrowserConnection { + bool success = 1; + string message = 2; + optional string endpoint = 3; } diff --git a/proto/common.proto b/proto/common.proto index dac0eca42b..34e935871e 100644 --- a/proto/common.proto +++ b/proto/common.proto @@ -11,3 +11,30 @@ message EmptyRequest { message Empty { } + +message StringRequest { + Metadata metadata = 1; + string value = 2; +} + +message String { + string value = 1; +} + +message Int64Request { + Metadata metadata = 1; + int64 value = 2; +} + +message Int64 { + int64 value = 1; +} + +message BytesRequest { + Metadata metadata = 1; + bytes value = 2; +} + +message Bytes { + bytes value = 1; +} diff --git a/src/core/controller/browser/methods.ts b/src/core/controller/browser/methods.ts index a9404319af..1c09be2952 100644 --- a/src/core/controller/browser/methods.ts +++ b/src/core/controller/browser/methods.ts @@ -4,9 +4,11 @@ // Import all method implementations import { registerMethod } from "./index" import { getBrowserConnectionInfo } from "./getBrowserConnectionInfo" +import { testBrowserConnection } from "./testBrowserConnection" // Register all browser service methods export function registerAllMethods(): void { // Register each method with the registry registerMethod("getBrowserConnectionInfo", getBrowserConnectionInfo) + registerMethod("testBrowserConnection", testBrowserConnection) } diff --git a/src/core/controller/browser/testBrowserConnection.ts b/src/core/controller/browser/testBrowserConnection.ts new file mode 100644 index 0000000000..ee76262721 --- /dev/null +++ b/src/core/controller/browser/testBrowserConnection.ts @@ -0,0 +1,63 @@ +import { BrowserConnection } from "../../../shared/proto/browser" +import { StringRequest } from "../../../shared/proto/common" +import { Controller } from "../index" +import { getAllExtensionState } from "../../storage/state" +import { BrowserSession } from "../../../services/browser/BrowserSession" +import { discoverChromeInstances } from "../../../services/browser/BrowserDiscovery" + +/** + * Test connection to a browser instance + * @param controller The controller instance + * @param request The request message + * @returns The browser connection result + */ +export async function testBrowserConnection(controller: Controller, request: StringRequest): Promise { + try { + const { browserSettings } = await getAllExtensionState(controller.context) + const browserSession = new BrowserSession(controller.context, browserSettings) + const text = request.value || "" + + // If no text is provided, try auto-discovery + if (!text) { + try { + const discoveredHost = await discoverChromeInstances() + if (discoveredHost) { + // Test the connection to the discovered host + const result = await browserSession.testConnection(discoveredHost) + return { + success: result.success, + message: `Auto-discovered and tested connection to Chrome at ${discoveredHost}: ${result.message}`, + endpoint: result.endpoint || "", + } + } else { + return { + success: false, + message: + "No Chrome instances found on the network. Make sure Chrome is running with remote debugging enabled (--remote-debugging-port=9222).", + endpoint: "", + } + } + } catch (error) { + return { + success: false, + message: `Error during auto-discovery: ${error instanceof Error ? error.message : String(error)}`, + endpoint: "", + } + } + } else { + // Test the provided URL + const result = await browserSession.testConnection(text) + return { + success: result.success, + message: result.message, + endpoint: result.endpoint || "", + } + } + } catch (error) { + return { + success: false, + message: `Error testing connection: ${error instanceof Error ? error.message : String(error)}`, + endpoint: "", + } + } +} diff --git a/src/core/controller/index.ts b/src/core/controller/index.ts index 0492467180..065c91e872 100644 --- a/src/core/controller/index.ts +++ b/src/core/controller/index.ts @@ -311,58 +311,6 @@ export class Controller { await this.postStateToWebview() } break - case "testBrowserConnection": - try { - const { browserSettings } = await getAllExtensionState(this.context) - const browserSession = new BrowserSession(this.context, browserSettings) - // If no text is provided, try auto-discovery - if (!message.text) { - try { - const discoveredHost = await discoverChromeInstances() - if (discoveredHost) { - // Test the connection to the discovered host - const result = await browserSession.testConnection(discoveredHost) - // Send the result back to the webview - await this.postMessageToWebview({ - type: "browserConnectionResult", - success: result.success, - text: `Auto-discovered and tested connection to Chrome at ${discoveredHost}: ${result.message}`, - endpoint: result.endpoint, - }) - } else { - await this.postMessageToWebview({ - type: "browserConnectionResult", - success: false, - text: "No Chrome instances found on the network. Make sure Chrome is running with remote debugging enabled (--remote-debugging-port=9222).", - }) - } - } catch (error) { - await this.postMessageToWebview({ - type: "browserConnectionResult", - success: false, - text: `Error during auto-discovery: ${error instanceof Error ? error.message : String(error)}`, - }) - } - } else { - // Test the provided URL - const result = await browserSession.testConnection(message.text) - - // Send the result back to the webview - await this.postMessageToWebview({ - type: "browserConnectionResult", - success: result.success, - text: result.message, - endpoint: result.endpoint, - }) - } - } catch (error) { - await this.postMessageToWebview({ - type: "browserConnectionResult", - success: false, - text: `Error testing connection: ${error instanceof Error ? error.message : String(error)}`, - }) - } - break case "discoverBrowser": try { const discoveredHost = await discoverChromeInstances() diff --git a/src/shared/WebviewMessage.ts b/src/shared/WebviewMessage.ts index e6d4051181..c74cf81096 100644 --- a/src/shared/WebviewMessage.ts +++ b/src/shared/WebviewMessage.ts @@ -40,8 +40,6 @@ export interface WebviewMessage { | "autoApprovalSettings" | "browserSettings" | "discoverBrowser" - | "testBrowserConnection" - | "browserConnectionResult" | "browserRelaunchResult" | "togglePlanActMode" | "checkpointDiff" diff --git a/src/shared/proto/browser.ts b/src/shared/proto/browser.ts index 0f8774fad8..0f4d02c448 100644 --- a/src/shared/proto/browser.ts +++ b/src/shared/proto/browser.ts @@ -6,19 +6,24 @@ /* eslint-disable */ import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire" -import { EmptyRequest } from "./common" +import { EmptyRequest, StringRequest } from "./common" export const protobufPackage = "cline" export interface BrowserConnectionInfo { isConnected: boolean isRemote: boolean - /** Optional, may be empty */ - host: string + host?: string | undefined +} + +export interface BrowserConnection { + success: boolean + message: string + endpoint?: string | undefined } function createBaseBrowserConnectionInfo(): BrowserConnectionInfo { - return { isConnected: false, isRemote: false, host: "" } + return { isConnected: false, isRemote: false, host: undefined } } export const BrowserConnectionInfo: MessageFns = { @@ -29,7 +34,7 @@ export const BrowserConnectionInfo: MessageFns = { if (message.isRemote !== false) { writer.uint32(16).bool(message.isRemote) } - if (message.host !== "") { + if (message.host !== undefined) { writer.uint32(26).string(message.host) } return writer @@ -79,7 +84,7 @@ export const BrowserConnectionInfo: MessageFns = { return { isConnected: isSet(object.isConnected) ? globalThis.Boolean(object.isConnected) : false, isRemote: isSet(object.isRemote) ? globalThis.Boolean(object.isRemote) : false, - host: isSet(object.host) ? globalThis.String(object.host) : "", + host: isSet(object.host) ? globalThis.String(object.host) : undefined, } }, @@ -91,7 +96,7 @@ export const BrowserConnectionInfo: MessageFns = { if (message.isRemote !== false) { obj.isRemote = message.isRemote } - if (message.host !== "") { + if (message.host !== undefined) { obj.host = message.host } return obj @@ -104,7 +109,99 @@ export const BrowserConnectionInfo: MessageFns = { const message = createBaseBrowserConnectionInfo() message.isConnected = object.isConnected ?? false message.isRemote = object.isRemote ?? false - message.host = object.host ?? "" + message.host = object.host ?? undefined + return message + }, +} + +function createBaseBrowserConnection(): BrowserConnection { + return { success: false, message: "", endpoint: undefined } +} + +export const BrowserConnection: MessageFns = { + encode(message: BrowserConnection, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { + if (message.success !== false) { + writer.uint32(8).bool(message.success) + } + if (message.message !== "") { + writer.uint32(18).string(message.message) + } + if (message.endpoint !== undefined) { + writer.uint32(26).string(message.endpoint) + } + return writer + }, + + decode(input: BinaryReader | Uint8Array, length?: number): BrowserConnection { + const reader = input instanceof BinaryReader ? input : new BinaryReader(input) + let end = length === undefined ? reader.len : reader.pos + length + const message = createBaseBrowserConnection() + while (reader.pos < end) { + const tag = reader.uint32() + switch (tag >>> 3) { + case 1: { + if (tag !== 8) { + break + } + + message.success = reader.bool() + continue + } + case 2: { + if (tag !== 18) { + break + } + + message.message = reader.string() + continue + } + case 3: { + if (tag !== 26) { + break + } + + message.endpoint = reader.string() + continue + } + } + if ((tag & 7) === 4 || tag === 0) { + break + } + reader.skip(tag & 7) + } + return message + }, + + fromJSON(object: any): BrowserConnection { + return { + success: isSet(object.success) ? globalThis.Boolean(object.success) : false, + message: isSet(object.message) ? globalThis.String(object.message) : "", + endpoint: isSet(object.endpoint) ? globalThis.String(object.endpoint) : undefined, + } + }, + + toJSON(message: BrowserConnection): unknown { + const obj: any = {} + if (message.success !== false) { + obj.success = message.success + } + if (message.message !== "") { + obj.message = message.message + } + if (message.endpoint !== undefined) { + obj.endpoint = message.endpoint + } + return obj + }, + + create, I>>(base?: I): BrowserConnection { + return BrowserConnection.fromPartial(base ?? ({} as any)) + }, + fromPartial, I>>(object: I): BrowserConnection { + const message = createBaseBrowserConnection() + message.success = object.success ?? false + message.message = object.message ?? "" + message.endpoint = object.endpoint ?? undefined return message }, } @@ -122,6 +219,14 @@ export const BrowserServiceDefinition = { responseStream: false, options: {}, }, + testBrowserConnection: { + name: "testBrowserConnection", + requestType: StringRequest, + requestStream: false, + responseType: BrowserConnection, + responseStream: false, + options: {}, + }, }, } as const diff --git a/src/shared/proto/common.ts b/src/shared/proto/common.ts index 28cede67dc..48699ef4ec 100644 --- a/src/shared/proto/common.ts +++ b/src/shared/proto/common.ts @@ -17,6 +17,33 @@ export interface EmptyRequest { export interface Empty {} +export interface StringRequest { + metadata?: Metadata | undefined + value: string +} + +export interface String { + value: string +} + +export interface Int64Request { + metadata?: Metadata | undefined + value: number +} + +export interface Int64 { + value: number +} + +export interface BytesRequest { + metadata?: Metadata | undefined + value: Buffer +} + +export interface Bytes { + value: Buffer +} + function createBaseMetadata(): Metadata { return {} } @@ -162,6 +189,419 @@ export const Empty: MessageFns = { }, } +function createBaseStringRequest(): StringRequest { + return { metadata: undefined, value: "" } +} + +export const StringRequest: MessageFns = { + encode(message: StringRequest, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { + if (message.metadata !== undefined) { + Metadata.encode(message.metadata, writer.uint32(10).fork()).join() + } + if (message.value !== "") { + writer.uint32(18).string(message.value) + } + return writer + }, + + decode(input: BinaryReader | Uint8Array, length?: number): StringRequest { + const reader = input instanceof BinaryReader ? input : new BinaryReader(input) + let end = length === undefined ? reader.len : reader.pos + length + const message = createBaseStringRequest() + while (reader.pos < end) { + const tag = reader.uint32() + switch (tag >>> 3) { + case 1: { + if (tag !== 10) { + break + } + + message.metadata = Metadata.decode(reader, reader.uint32()) + continue + } + case 2: { + if (tag !== 18) { + break + } + + message.value = reader.string() + continue + } + } + if ((tag & 7) === 4 || tag === 0) { + break + } + reader.skip(tag & 7) + } + return message + }, + + fromJSON(object: any): StringRequest { + return { + metadata: isSet(object.metadata) ? Metadata.fromJSON(object.metadata) : undefined, + value: isSet(object.value) ? globalThis.String(object.value) : "", + } + }, + + toJSON(message: StringRequest): unknown { + const obj: any = {} + if (message.metadata !== undefined) { + obj.metadata = Metadata.toJSON(message.metadata) + } + if (message.value !== "") { + obj.value = message.value + } + return obj + }, + + create, I>>(base?: I): StringRequest { + return StringRequest.fromPartial(base ?? ({} as any)) + }, + fromPartial, I>>(object: I): StringRequest { + const message = createBaseStringRequest() + message.metadata = + object.metadata !== undefined && object.metadata !== null ? Metadata.fromPartial(object.metadata) : undefined + message.value = object.value ?? "" + return message + }, +} + +function createBaseString(): String { + return { value: "" } +} + +export const String: MessageFns = { + encode(message: String, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { + if (message.value !== "") { + writer.uint32(10).string(message.value) + } + return writer + }, + + decode(input: BinaryReader | Uint8Array, length?: number): String { + const reader = input instanceof BinaryReader ? input : new BinaryReader(input) + let end = length === undefined ? reader.len : reader.pos + length + const message = createBaseString() + while (reader.pos < end) { + const tag = reader.uint32() + switch (tag >>> 3) { + case 1: { + if (tag !== 10) { + break + } + + message.value = reader.string() + continue + } + } + if ((tag & 7) === 4 || tag === 0) { + break + } + reader.skip(tag & 7) + } + return message + }, + + fromJSON(object: any): String { + return { value: isSet(object.value) ? globalThis.String(object.value) : "" } + }, + + toJSON(message: String): unknown { + const obj: any = {} + if (message.value !== "") { + obj.value = message.value + } + return obj + }, + + create, I>>(base?: I): String { + return String.fromPartial(base ?? ({} as any)) + }, + fromPartial, I>>(object: I): String { + const message = createBaseString() + message.value = object.value ?? "" + return message + }, +} + +function createBaseInt64Request(): Int64Request { + return { metadata: undefined, value: 0 } +} + +export const Int64Request: MessageFns = { + encode(message: Int64Request, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { + if (message.metadata !== undefined) { + Metadata.encode(message.metadata, writer.uint32(10).fork()).join() + } + if (message.value !== 0) { + writer.uint32(16).int64(message.value) + } + return writer + }, + + decode(input: BinaryReader | Uint8Array, length?: number): Int64Request { + const reader = input instanceof BinaryReader ? input : new BinaryReader(input) + let end = length === undefined ? reader.len : reader.pos + length + const message = createBaseInt64Request() + while (reader.pos < end) { + const tag = reader.uint32() + switch (tag >>> 3) { + case 1: { + if (tag !== 10) { + break + } + + message.metadata = Metadata.decode(reader, reader.uint32()) + continue + } + case 2: { + if (tag !== 16) { + break + } + + message.value = longToNumber(reader.int64()) + continue + } + } + if ((tag & 7) === 4 || tag === 0) { + break + } + reader.skip(tag & 7) + } + return message + }, + + fromJSON(object: any): Int64Request { + return { + metadata: isSet(object.metadata) ? Metadata.fromJSON(object.metadata) : undefined, + value: isSet(object.value) ? globalThis.Number(object.value) : 0, + } + }, + + toJSON(message: Int64Request): unknown { + const obj: any = {} + if (message.metadata !== undefined) { + obj.metadata = Metadata.toJSON(message.metadata) + } + if (message.value !== 0) { + obj.value = Math.round(message.value) + } + return obj + }, + + create, I>>(base?: I): Int64Request { + return Int64Request.fromPartial(base ?? ({} as any)) + }, + fromPartial, I>>(object: I): Int64Request { + const message = createBaseInt64Request() + message.metadata = + object.metadata !== undefined && object.metadata !== null ? Metadata.fromPartial(object.metadata) : undefined + message.value = object.value ?? 0 + return message + }, +} + +function createBaseInt64(): Int64 { + return { value: 0 } +} + +export const Int64: MessageFns = { + encode(message: Int64, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { + if (message.value !== 0) { + writer.uint32(8).int64(message.value) + } + return writer + }, + + decode(input: BinaryReader | Uint8Array, length?: number): Int64 { + const reader = input instanceof BinaryReader ? input : new BinaryReader(input) + let end = length === undefined ? reader.len : reader.pos + length + const message = createBaseInt64() + while (reader.pos < end) { + const tag = reader.uint32() + switch (tag >>> 3) { + case 1: { + if (tag !== 8) { + break + } + + message.value = longToNumber(reader.int64()) + continue + } + } + if ((tag & 7) === 4 || tag === 0) { + break + } + reader.skip(tag & 7) + } + return message + }, + + fromJSON(object: any): Int64 { + return { value: isSet(object.value) ? globalThis.Number(object.value) : 0 } + }, + + toJSON(message: Int64): unknown { + const obj: any = {} + if (message.value !== 0) { + obj.value = Math.round(message.value) + } + return obj + }, + + create, I>>(base?: I): Int64 { + return Int64.fromPartial(base ?? ({} as any)) + }, + fromPartial, I>>(object: I): Int64 { + const message = createBaseInt64() + message.value = object.value ?? 0 + return message + }, +} + +function createBaseBytesRequest(): BytesRequest { + return { metadata: undefined, value: Buffer.alloc(0) } +} + +export const BytesRequest: MessageFns = { + encode(message: BytesRequest, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { + if (message.metadata !== undefined) { + Metadata.encode(message.metadata, writer.uint32(10).fork()).join() + } + if (message.value.length !== 0) { + writer.uint32(18).bytes(message.value) + } + return writer + }, + + decode(input: BinaryReader | Uint8Array, length?: number): BytesRequest { + const reader = input instanceof BinaryReader ? input : new BinaryReader(input) + let end = length === undefined ? reader.len : reader.pos + length + const message = createBaseBytesRequest() + while (reader.pos < end) { + const tag = reader.uint32() + switch (tag >>> 3) { + case 1: { + if (tag !== 10) { + break + } + + message.metadata = Metadata.decode(reader, reader.uint32()) + continue + } + case 2: { + if (tag !== 18) { + break + } + + message.value = Buffer.from(reader.bytes()) + continue + } + } + if ((tag & 7) === 4 || tag === 0) { + break + } + reader.skip(tag & 7) + } + return message + }, + + fromJSON(object: any): BytesRequest { + return { + metadata: isSet(object.metadata) ? Metadata.fromJSON(object.metadata) : undefined, + value: isSet(object.value) ? Buffer.from(bytesFromBase64(object.value)) : Buffer.alloc(0), + } + }, + + toJSON(message: BytesRequest): unknown { + const obj: any = {} + if (message.metadata !== undefined) { + obj.metadata = Metadata.toJSON(message.metadata) + } + if (message.value.length !== 0) { + obj.value = base64FromBytes(message.value) + } + return obj + }, + + create, I>>(base?: I): BytesRequest { + return BytesRequest.fromPartial(base ?? ({} as any)) + }, + fromPartial, I>>(object: I): BytesRequest { + const message = createBaseBytesRequest() + message.metadata = + object.metadata !== undefined && object.metadata !== null ? Metadata.fromPartial(object.metadata) : undefined + message.value = object.value ?? Buffer.alloc(0) + return message + }, +} + +function createBaseBytes(): Bytes { + return { value: Buffer.alloc(0) } +} + +export const Bytes: MessageFns = { + encode(message: Bytes, writer: BinaryWriter = new BinaryWriter()): BinaryWriter { + if (message.value.length !== 0) { + writer.uint32(10).bytes(message.value) + } + return writer + }, + + decode(input: BinaryReader | Uint8Array, length?: number): Bytes { + const reader = input instanceof BinaryReader ? input : new BinaryReader(input) + let end = length === undefined ? reader.len : reader.pos + length + const message = createBaseBytes() + while (reader.pos < end) { + const tag = reader.uint32() + switch (tag >>> 3) { + case 1: { + if (tag !== 10) { + break + } + + message.value = Buffer.from(reader.bytes()) + continue + } + } + if ((tag & 7) === 4 || tag === 0) { + break + } + reader.skip(tag & 7) + } + return message + }, + + fromJSON(object: any): Bytes { + return { value: isSet(object.value) ? Buffer.from(bytesFromBase64(object.value)) : Buffer.alloc(0) } + }, + + toJSON(message: Bytes): unknown { + const obj: any = {} + if (message.value.length !== 0) { + obj.value = base64FromBytes(message.value) + } + return obj + }, + + create, I>>(base?: I): Bytes { + return Bytes.fromPartial(base ?? ({} as any)) + }, + fromPartial, I>>(object: I): Bytes { + const message = createBaseBytes() + message.value = object.value ?? Buffer.alloc(0) + return message + }, +} + +function bytesFromBase64(b64: string): Uint8Array { + return Uint8Array.from(globalThis.Buffer.from(b64, "base64")) +} + +function base64FromBytes(arr: Uint8Array): string { + return globalThis.Buffer.from(arr).toString("base64") +} + type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined export type DeepPartial = T extends Builtin @@ -179,6 +619,17 @@ export type Exact = P extends Builtin ? P : P & { [K in keyof P]: Exact } & { [K in Exclude>]: never } +function longToNumber(int64: { toString(): string }): number { + const num = globalThis.Number(int64.toString()) + if (num > globalThis.Number.MAX_SAFE_INTEGER) { + throw new globalThis.Error("Value is larger than Number.MAX_SAFE_INTEGER") + } + if (num < globalThis.Number.MIN_SAFE_INTEGER) { + throw new globalThis.Error("Value is smaller than Number.MIN_SAFE_INTEGER") + } + return num +} + function isSet(value: any): boolean { return value !== null && value !== undefined } diff --git a/webview-ui/src/components/settings/BrowserSettingsSection.tsx b/webview-ui/src/components/settings/BrowserSettingsSection.tsx index 848e004f5c..3ff72ffe7f 100644 --- a/webview-ui/src/components/settings/BrowserSettingsSection.tsx +++ b/webview-ui/src/components/settings/BrowserSettingsSection.tsx @@ -5,6 +5,7 @@ import { BROWSER_VIEWPORT_PRESETS } from "../../../../src/shared/BrowserSettings import { useExtensionState } from "../../context/ExtensionStateContext" import { vscode } from "../../utils/vscode" import styled from "styled-components" +import { BrowserServiceClient } from "../../services/grpc-client" const ConnectionStatusIndicator = ({ isChecking, @@ -93,10 +94,24 @@ export const BrowserSettingsSection: React.FC = () => { if (browserSettings.remoteBrowserEnabled) { setIsCheckingConnection(true) setConnectionStatus(null) - vscode.postMessage({ - type: browserSettings.remoteBrowserHost ? "testBrowserConnection" : "discoverBrowser", - text: browserSettings.remoteBrowserHost, - }) + if (browserSettings.remoteBrowserHost) { + // Use gRPC for testBrowserConnection + BrowserServiceClient.testBrowserConnection({ value: browserSettings.remoteBrowserHost }) + .then((result) => { + setConnectionStatus(result.success) + setIsCheckingConnection(false) + }) + .catch((error) => { + console.error("Error testing browser connection:", error) + setConnectionStatus(false) + setIsCheckingConnection(false) + }) + } else { + // Use old message passing for discoverBrowser (not yet migrated) + vscode.postMessage({ + type: "discoverBrowser", + }) + } } }, 1000), [browserSettings.remoteBrowserEnabled, browserSettings.remoteBrowserHost], @@ -153,10 +168,22 @@ export const BrowserSettingsSection: React.FC = () => { const checkConnectionOnce = useCallback(() => { // Don't show the spinner for every check to avoid UI flicker // We'll rely on the response to update the connectionStatus - vscode.postMessage({ - type: browserSettings.remoteBrowserHost ? "testBrowserConnection" : "discoverBrowser", - text: browserSettings.remoteBrowserHost, - }) + if (browserSettings.remoteBrowserHost) { + // Use gRPC for testBrowserConnection + BrowserServiceClient.testBrowserConnection({ value: browserSettings.remoteBrowserHost }) + .then((result) => { + setConnectionStatus(result.success) + }) + .catch((error) => { + console.error("Error testing browser connection:", error) + setConnectionStatus(false) + }) + } else { + // Use old message passing for discoverBrowser (not yet migrated) + vscode.postMessage({ + type: "discoverBrowser", + }) + } }, [browserSettings.remoteBrowserHost]) // Setup continuous polling for connection status when remote browser is enabled diff --git a/webview-ui/src/services/grpc-client.ts b/webview-ui/src/services/grpc-client.ts index 49c004c360..f7d3041b45 100644 --- a/webview-ui/src/services/grpc-client.ts +++ b/webview-ui/src/services/grpc-client.ts @@ -58,10 +58,21 @@ function createGrpcClient(service: T): GrpcClientType window.addEventListener("message", handleResponse) - let encodedRequest = "{}" - if (Object.keys(request).length !== 0) { + let encodedRequest = {} + + // Handle different types of requests + if (request === null || request === undefined) { + // Empty request + encodedRequest = {} + } else if (typeof request.toJSON === "function") { + // Proper protobuf object encodedRequest = request.toJSON() - console.log("[DEBUG] request is", request, encodedRequest) + } else if (typeof request === "object") { + // Plain JavaScript object + encodedRequest = { ...request } + } else { + // Fallback + encodedRequest = { value: request } } // Send the request