This document describes the current IDE <-> Web UI communication mechanism used by:
hosts/jetbrains-pluginhosts/vscode-pluginpackages/opencode/webguiThis replaces the older CEF/JSQuery/router injection approach and avoids VSCode-specific postMessage tunnels for ideBridge traffic.
cefQuery_* bindings, no JS injection ordering sensitivityvscode.env.asExternalUri(...)All messages are JSON objects.
Common fields:
type: stringpayload?: anytimestamp?: numberRequest/response:
id: stringreplyTo: string matching the request idok: boolean and optional error: stringExample request:
{ "id": "abc123", "type": "openFile", "payload": { "path": "/p/file.ts", "line": 42 }, "timestamp": 1731390000000 }
Example response:
{ "replyTo": "abc123", "ok": true, "timestamp": 1731390000100 }
The IDE host runs a small HTTP server bound to 127.0.0.1 on an ephemeral port and creates a per-webview session.
Session identifiers:
sessionId: random UUID used in the URL pathtoken: random UUID used as a query parameter for authBase URL shape:
http://127.0.0.1:{port}/idebridge/{sessionId}
Endpoints:
GET {baseUrl}/events?token=...
text/event-stream)event: message with data: <json>: ping) to prevent proxy/tunnel timeoutsPOST {baseUrl}/send?token=...
204 on success, 401 if token mismatch, 400 on malformed bodyNotes:
Access-Control-Allow-Origin: *) because the token is unguessable and scoped per session.Cache-Control: no-cache, no-transform and X-Accel-Buffering: no to reduce buffering by proxies.File: packages/opencode/webgui/src/lib/ideBridge.ts
The UI reads two query params from window.location.search:
ideBridge: base URL (string)ideBridgeToken: tokenBehavior:
ideBridge.init() opens an EventSource to {ideBridge}/events?token=...fetch(POST {ideBridge}/send?token=...)id/replyTo to implement Promise-based RPCIf params are missing, ideBridge.isInstalled() is false and requests are rejected.
Server + routing:
hosts/jetbrains-plugin/src/main/kotlin/paviko/opencode/ui/IdeBridge.kt
HttpServer on 127.0.0.1:0createSession(project)), maps Project -> sessionIdopenFile, openUrl, reloadPathURL wiring:
hosts/jetbrains-plugin/src/main/kotlin/paviko/opencode/ui/ChatToolWindowFactory.kt
ideBridge and ideBridgeToken to the UI URLHost -> UI updates:
IdeBridge.send(project, type, payload) (session is looked up automatically)Server + routing:
hosts/vscode-plugin/src/ui/IdeBridgeServer.ts
127.0.0.1:0createSession(handlers))openFile, openUrl, reloadPath)Remote-SSH support:
hosts/vscode-plugin/src/ui/WebviewController.ts
vscode.env.asExternalUri(...) for both:Host -> UI updates:
CommunicationBridge can route ideBridge-type host messages via the bridge server once setBridgeSession(...) is called.Web UI -> host (handled by both hosts):
openFile payload: { path: string, line?: number }openUrl payload: { url: string }reloadPath payload: { path: string, operation?: "write" | "edit" | "apply_patch" }Host -> Web UI (sent by hosts):
insertPaths payload: { paths: string[] }pastePath payload: { path: string }updateOpenedFiles payload: { openedFiles: string[], currentFile?: string | null }UI never connects:
ideBridge= and ideBridgeToken=Requests never resolve:
{ replyTo: <id>, ok: true|false } over SSERemote-SSH drops the connection:
: ping frames)asExternalUri is applied to the bridge URL in VSCode