feat(ui): add SPA-side support for WebView2 native bridge#69633
feat(ui): add SPA-side support for WebView2 native bridge#69633AlexAlves87 wants to merge 1 commit intoopenclaw:mainfrom
Conversation
cb0f814 to
54b3d31
Compare
|
Codex review: keeping this open for maintainer follow-up; there is still a little grit to resolve. Keep this PR open. Current main still has no Control UI SPA-side WebView2 bridge or lifecycle wiring, while the draft PR adds a focused bridge module, app hookup, and tests for the draft-text and ready handshake surface. The linked Windows host-side bridge has merged in openclaw-windows-node#192, so this remains a live implementation candidate rather than obsolete cleanup. Best possible solution: Keep this PR open for normal maintainer review while it is draft. The best path is to review the focused Control UI bridge, confirm the merged Windows host bridge with a WebView2 smoke, keep the runtime validation and lifecycle cleanup tests, and land it if maintainers accept SPA-side WebView2 support. What I checked:
Likely related people:
Remaining risk / open question:
Codex review notes: model gpt-5.5, reasoning high; reviewed against fd2625a16252. |
Adds app-native-bridge.ts and wires it into OpenClawApp lifecycle.
Surface (minimal, parity-aligned with openclaw-windows-node#159):
- inbound: draft-text { payload: { text: string } }
- outbound: ready handshake
Implementation:
- NativeBridgeHost requires only handleChatDraftChange(next).
recording-start/stop and voice-start/stop excluded — no handler or
UI surface today, and recording follows the parity decision in
openclaw-windows-node#159.
- handleNativeMessage validates event.data as unknown: guards object,
type string, and payload.text string; malformed messages are silently
ignored.
- draft-text routes through handleChatDraftChange so native-injected
text resets input-history navigation state, same as a user edit.
- initNativeBridge called in connectedCallback; cleanup in
disconnectedCallback via private nativeBridgeCleanup field.
Tests (15):
- isWebView2 present/absent
- sendToNative posts message, no-op outside WebView2
- ready handshake sent on init, listener registered first
- no-op outside WebView2
- draft-text happy path calls handleChatDraftChange
- draft-text with missing payload, non-string text — ignored
- unknown types, null, primitives, missing type — ignored
- cleanup removes listener; post-cleanup messages ignored
- integration: draft-text resets active history navigation state
Native side: openclaw-windows-node#192 (c7630fa).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
7be00dd to
2aefa11
Compare
Summary
Wires the WebView2 bridge into the SPA lifecycle with a minimal, parity-aligned surface.
app-native-bridge.ts— reducesNativeBridgeMessagetodraft-text(inbound) andready(outbound handshake). Removesrecording-start/stopandvoice-start/stop, since there is no corresponding SPA handler or UI surface today, and recording follows the parity decision inopenclaw-windows-node#159.NativeBridgeHostnow requires onlyhandleChatDraftChange(next).app.ts— importsinitNativeBridge, calls it inconnectedCallback, and cleans it up indisconnectedCallback.draft-textgoes throughhandleChatDraftChangeso native-injected text resets input-history navigation the same way a real user edit does.Context
The native side landed in
openclaw-windows-node#192(c7630fa) with origin validation, dispatcher marshaling, closed-window guards, sanitized logging, and payload JSON validation. This PR closes the SPA side of that minimal bridge surface.Test plan
{"type":"draft-text","payload":{"text":"hello"}}→ chat input updates and input-history navigation resetsinitNativeBridgeno-ops without errors