name: hd-ui-mac description: > macOS platform companion to hd-ui — the Apple-specific half of DRIVING HD's UI. Every menu/dialog/panel id, the GET /ui/actions → POST /ui/invoke contract, and registerUiAction live in hd-ui (adom/hd-bootstrap); THIS skill carries only what's macOS-specific: HD's webview is WKWebView with NO Chrome DevTools Protocol, so the legacy CDP .click() path is dead — you drive the UI via the platform-agnostic command bus (hd-ui-command → /ui/_result) and the backend invoke_ui_action RPC (e.g. dom.measure resolves a selector's rect WITHOUT CDP). Mirror of hd-ui-windows (raw CDP clicking, hd-cdp.js, WebView2 CDP). Trigger words — drive HD UI macos, WKWebView, no CDP, dom.measure, hd-ui-command, invoke_ui_action, ui/invoke macos, click HD menu mac, open dialog mac.

hd-ui (macOS) — driving the UI without CDP

This is the macOS half of hd-ui. The window layout, the menu/dialog catalog, the list of action ids, and the whole GET /ui/actionsPOST /ui/invoke workflow are host-agnostic and live in the generic hd-ui skill — read that first. This skill only covers what changes on a Mac: how clicks reach the webview when there is no CDP.

The macOS reality — WKWebView has no CDP

On macOS HD's webview is WKWebView, which exposes no Chrome DevTools Protocol port. The Windows lineage drove the UI by CDP .click() on CSS selectors (hd-cdp.js → WebView2's CDP). None of that works here — there's no port to attach to (the same limitation that makes /eval effectively fire-and-forget on macOS). So on macOS the command bus isn't merely preferred, it's the only way to operate HD's UI. For an element that isn't on the bus yet, register it (a 2-line registerUiAction(...) — see hd-ui) rather than reaching for a selector click; there is nothing to click through.

How the bus crosses to WKWebView — hd-ui-command/ui/_result

POST /ui/invoke {id} is platform-agnostic precisely because it does not depend on CDP. The backend (src-tauri/crates/hd-control/src/lib.rs, invoke_ui_action) emits a Tauri event hd-ui-command {id, args, request_id}; the frontend dispatcher runs the registered handler and reports back via POST /ui/_result {request_id, ok, value}. The call blocks until that result lands (or the timeout fires). This is the identical round-trip on every host — but on macOS it's load-bearing, since it's the substitute for the CDP path Windows still has.

dom.measure — resolve a selector's rect without CDP

The one place the Windows path leaned on CDP that macOS had to re-plumb is geometry. Where Windows cropped a region screenshot server-side via CDP Page.captureScreenshot with a clip, macOS can't — so the capture path calls invoke_ui_action(app, "dom.measure", {selector}, 3000) to ask the frontend for the element's rect, then screencaptures the webview content area and crops the PNG to that rect (hd-control/src/lib.rs ~5193). dom.measure returns {left, top, width, height, viewport:{width,height}} in CSS px. It's a normal bus action — the macOS analog of CDP's Runtime.evaluate for "where is this element," reusable by any caller that needs a selector's geometry without CDP.

NOT here (lives in the Windows companion)

Raw CDP .click() driving, the node C:\Users\…\hd-cdp.js snippets, the WebView2 CDP port, and the CSS-selector-click playbook are the Windows UI path — see hd-ui-windows. On macOS that machinery does not exist; drive everything through the command bus (/ui/actions/ui/invoke) and register anything that's missing.