mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-27 12:56:01 -06:00
a4c01c1a77
* feat(ui): save appearance preferences per user profile When a Control UI connection is bound to an authenticated user profile (trusted-proxy, Tailscale, GitHub identity), theme, theme mode, and accent become per-profile: stored in the existing user_preferences KV store via users.prefs.set, overriding gateway-wide ui.prefs, with live cross-device updates over a new additive users.prefs.changed event scoped to the same merged profile. Restore default deletes only the profile key and falls back to the gateway-wide value. talk.config projects the caller's profile accent for native clients. Profile-less connections (token/password/none auth) keep the existing gateway-config behavior byte-identically. Release-note context: on multi-person gateways appearance choices are now personal and follow you across devices; an admin restyling their own UI no longer reskins the whole team. * chore(protocol): allowlist users.prefs.changed for mobile clients iOS and Android resolve the profile accent through talk.config on connect and config refresh; live per-profile appearance push on natives is a named follow-up. * chore(protocol): regenerate Swift/Kotlin models for users.prefs.changed * fix(ui): honor explicit defaults and identity switches for profile appearance Addresses the three ClawSweeper review findings: - resetValue for profile-bound appearance keys is the deletion fallback (gateway value), so an explicit product-default selection persists as a profile write instead of being misclassified as a reset. - An identity switch between two known scopes forces a full appearance reconcile and clears appearance keys the returning identity never set, so a shared browser cannot keep the previous profile's look (boot keeps the last-seen shortcut). - talk.config joins the profile-dependent dispatch gate so a pending GitHub identity sync completes before the profile accent is projected; token clients pass through untouched. * chore(ui): satisfy assertion-safety ratchet and docs formatting * refactor(ui): extract server-prefs storage primitives server-prefs.ts crossed the 700-line cap after the review fixes; the stateless localStorage persistence primitives move to server-prefs-storage.ts (no behavior change). Shrink-prunes the assertion-safety baseline for the moved casts. * fix(ui): keep imported custom themes out of profile storage Custom palettes are browser-local by contract, so a profile must never carry theme=custom to a browser that cannot render it. The wire contract drops custom from the storable theme values (readers self-heal any stored value), a profile-bound custom selection stays retained browser-local (including the offline-queued path), and the exhaustive theme test now encodes the exception.