feat: JCEF shared chat webview — pixel-identical chat UI in JetBrains and VS Code#70
Open
matze4u wants to merge 6 commits into
Open
feat: JCEF shared chat webview — pixel-identical chat UI in JetBrains and VS Code#70matze4u wants to merge 6 commits into
matze4u wants to merge 6 commits into
Conversation
Replace the direct acquireVsCodeApi() coupling with a HostBridge interface (post + onMessage). VS Code impl wraps postMessage/window events; the JCEF impl speaks window.__e4uJcefPost (outbound) and window.__e4uHostMessage (inbound) for the JetBrains host. Bootstrap detects the host at runtime; 8 unit tests lock both bridges. Part of road-to-jcef-chat-parity Phase 1 (council fork 3A, ADR-055).
scripts/build-jcef-html.mjs bundles chat-app.ts (same esbuild settings as the VS Code webview) and inlines it into the chat-html-jcef.ts shell — theme CSS inline, </script-escaped bundle, Kotlin-side placeholders for the JBCefJSQuery bridge hook and the IDE-theme variable block. Output lands in clients/jetbrains/src/main/resources/webview/chat.html (gitignored build artifact, wired into pnpm run build); gradle check never depends on it. Council forks 1A + 2A (codex + gemini, 2 rounds): webview source stays in clients/vscode; loadHTML() with the inlined bundle beats a custom scheme handler for a self-contained ~27 KiB document. ADR-055.
JcefChatPanel hosts the shared webview document in a JBCefBrowser:
JBCefJSQuery bridge in (ready/send/stop/toggle-mode dispatched onto the
controller — pick-model/halt-answer/attach stay no-ops, exact parity
with the VS Code ChatController), SnapshotJson pushes field-for-field
ChatModelSnapshot JSON out (queued until the webview's ready), and
ThemeCssExporter maps the active LaF onto the --vscode-* variable set
with live LafManagerListener re-injection. JCEF-unsupported runtimes or
a missing bundle degrade to a notice panel.
Swing chat renderer retired in the same change (council fork 4A,
unanimous): ChatPanel, ChatMessageRenderer, SimpleMarkdownRenderer and
the ui/ component set are deleted; Theme.kt (exporter source) and
CostFooterFormatter (statusbar) stay. Contract locked by 9 SnapshotJson
+ 4 ThemeCssExporter tests; ./gradlew check green.
road-to-jcef-chat-parity Phases 0/2/3 + 4, ADR-055.
Gotcha worth keeping: kotlinx JsonObjectBuilder.put returns the
PREVIOUS value for the key (Map semantics) — never chain it with
?.let { put(...) } ?: put(key, JsonNull).
ADR-055 records the four council-decided forks (source location, loadHTML loading, JBCefJSQuery bridge, Swing retirement) + index row. road-to-jcef-chat-parity lands fully processed: 22 done, 3 deferred (runIde focus/smoke + theme screenshots — need a human IDE session), 1 cancelled (host-side attach wiring — no-op on both hosts today, kept in road-to-mvp-ui-finish). Dashboard updated by hand (regen script not installed in this environment). Client READMEs document the shared webview contract.
… 055 rows in numeric order)
JCEF (Chromium) ships no default webview stylesheet, unlike VS Code — buttons/selects fell back to UA fonts and chrome, scrollbars to the chunky Chromium bars, and the model-select popup to the UA white list. Add a form-control inherit reset, styled ::-webkit-scrollbar (VS Code scrollbarSlider vars with translucent fallbacks), dark option colors, and hover/focus states for the model pill. Switch .e4u-pill:hover to background-color so the select's arrow gradient survives hover. Shared CSS — both hosts render the same fixes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Ports the JetBrains chat tool window from Swing to JCEF and makes the VS Code webview bundle the single chat UI for both IDEs — pixel-identical chat in PhpStorm and VS Code, one UI codebase.
Roadmap:
agents/roadmaps/road-to-jcef-chat-parity.md(fully processed: 22 done / 3 deferred / 1 cancelled) · ADR-055.How
host-bridge.ts— the webview is now host-agnostic:acquireVsCodeApi().postMessageunder VS Code,window.__e4uJcefPost/window.__e4uHostMessageunder JCEF. ZerovscodeAPI imports left insrc/webview/.build-jcef-html.mjs—pnpm run buildadditionally emits a self-containedchat.html(theme CSS + chat-app bundle inlined) intoclients/jetbrains/src/main/resources/webview/(gitignored build artifact).gradle checknever needs the Node build — missing bundle degrades to a notice panel.JcefChatPanel.kt—JBCefBrowser.loadHTML()+JBCefJSQuerybridge;SnapshotJson.ktserializes the Kotlin model field-for-field to the TSChatModelSnapshotshape (snapshot pushes queue until the webview postsready).ThemeCssExporter.kt— maps the active IDE LaF onto the--vscode-*variable settheme.tsconsumes; live re-injection on theme switch (LafManagerListener), no reload.ChatPanel,ChatMessageRenderer,SimpleMarkdownRenderer,ui/{Chip,Composer,Header,IconButton,ModePill,ModelPill,RoundedPanel,WelcomeCard,WrapLayout}deleted.Theme.kt(exporter source) andCostFooterFormatter(statusbar) stay. Statusbar widgets and the sidecar protocol are untouched.Council
codex + gemini, 2 rounds (round 2 tiebreak converged unanimous): webview source stays in
clients/vscode(1A) ·loadHTML()with inlined bundle over a custom scheme handler (2A) ·JBCefJSQuery+ HostBridge (3A) · delete Swing now, notice-panel fallback (4A).Verification
task cigreen (lint, format, build, typecheck, test — incl. 8 new host-bridge tests)../gradlew checkgreen (32 tests — 9 SnapshotJson contract tests, 4 ThemeCssExporter tests; detekt + ktlint clean).[~]in the roadmap):runIdesmoke (send → stream → stop), keyboard focus / Cmd+Enter inside JCEF, theme screenshots Darcula / Light / high-contrast.Notes for review
chat-model.ts(locked bySnapshotJsonTest).pick-model/halt-answer/attachremain host-side no-ops on BOTH hosts (exact parity withchat-controller.ts); wiring them is tracked in road-to-mvp-ui-finish / v1.0.JsonObjectBuilder.putreturns the previous value (Map semantics) — caught by a failing contract test during this run.