* fix(ui): keep clampText/truncateText surrogate-safe at emoji boundaries
clampText and truncateText in format.ts used String.prototype.slice(0, N)
to truncate user-visible text. When the truncation boundary falls inside
a UTF-16 surrogate pair (emoji, CJK extended, etc.), the resulting
string contains a dangling surrogate that browsers render as U+FFFD (�).
Replace .slice(0, ...) with truncateUtf16Safe(...) which skips past
incomplete surrogate pairs so the truncation point always falls on a
code-point boundary.
Affected UI surfaces: markdown rendering, command descriptions, skill
summaries, exec-approval rules, tool-stream output previews.
Add surrogate-safe truncation test cases for both functions using a
real emoji at the exact truncation boundary.
* test(ui): tighten UTF-16 truncation coverage
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix: keep emoji intact at remaining text truncation boundaries
Replace .slice(0, N) with truncateUtf16Safe() in five remaining
user-visible text truncation sites that were missed by earlier
UTF-16 safety sweeps:
- restart.ts: restart reason text (2 sites)
- chat-composer.ts: reply target text preview
- chat-thread.ts: thread text preview + message text extraction
All sites truncate user-generated content where emoji or other
supplementary-plane characters could produce lone surrogates.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: complete UTF-16-safe restart and chat boundaries
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
First connects backed by stored auth (URL/session token, password, or an
approved device token) now paint a small wiggling OpenClaw mark (delayed
fade-in, reduced-motion aware) until the hello resolves. The login gate
still owns credential-less first opens, rejected credentials, and manual
gate submissions.
Closes#101847
The idle Talk mic button used a full-strength accent ring that visually
competed with the recording (stop) state. Mute the idle ring to 40%
accent and ramp hover to 70% so idle -> hover -> recording escalates.
Formatting proof: oxfmt --check clean on ui/src/styles/chat/layout.css
on Testbox tbx_01kwyvx4pbdmb3yhjff6gvzvny (worktree has no node_modules,
so the format hook cannot run).
* fix(gateway): support native Windows exec approvals
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
* chore: defer changelog entry to release
* test: use tracked approvals temp directories
---------
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
Related: #101647
## What Problem This Solves
Removes stale Control UI test mocks that modeled helper exports no longer exposed by the chat display module.
## Why This Change Was Made
The chat message tests no longer reach the display module, so their mock was removed. The chat view tests retain only the fallback asset mock and exercise the canonical avatar helpers directly.
## User Impact
No user-visible behavior change. Tests now reflect the current module ownership without duplicating avatar logic.
## Evidence
- Focused Testbox run: 2 files, 209 tests passed.
- Testbox: `tbx_01kwyatxdvb64ncvbn9ertg6fa`
- Actions run: https://github.com/openclaw/openclaw/actions/runs/28868305075
- `git diff --check`: passed.
- Codex autoreview: no actionable findings.
* feat(ui): redesign dashboard chrome with tiny top bar and sidebar search
Move the sidebar toggle to the top bar as a macOS-style panel button
(collapse on desktop, drawer on tablet/mobile), move search into a
sidebar field that opens the command palette, and move the color-mode
toggle into the sidebar footer. Shrink the top bar to 44px, make the
terminal toggle a quiet ghost button, and drop the shadow plate behind
the macOS titlebar brand mark so the transparent mascot renders bare.
Adds the missing common.colorModeOption i18n key (theme buttons were
announcing the raw key) and removes the dead theme-orb styles.
* fix(ui): translate common.colorModeOption across locale bundles
The i18n sync initially recorded English fallbacks for the new key,
which the ships-no-recorded-English-fallbacks gate rejects. Regenerated
with a real translation provider; all 20 locales now carry translated
values (fallbacks=0).
* refactor(ui): unify the topbar sidebar toggle into one button
One button drives both modes: rail collapse on desktop and the
slide-over drawer at the ≤1100px breakpoint, decided via matchMedia
(with the legacy addListener fallback used elsewhere in bootstrap).
Replaces the previous pair of CSS-swapped buttons.
* ci(mantis): add web ui chat proof lane
* ci(mantis): tighten web ui proof candidate parsing
* ci: tighten Mantis Web UI proof lane
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>