* 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>
* feat(ui): rename, delete, and toggle sidebar session groups
Sidebar group headers gain a kebab + right-click menu with Rename group,
New group, and Delete group. Rename/delete enumerate every member session
(active + archived, across agents) via unbounded sessions.list queries and
patch category per session; delete keeps sessions and moves them to
Ungrouped. Stored-but-empty groups render as sections, and the sidebar
sort popover gains a persisted Group by toggle (Custom groups / None).
* test(ui): capture sidebar group management UI proof shots
* fix(ui): page session-group enumeration past the gateway's 100-row default
sessions.list caps an absent limit at SESSIONS_LIST_DEFAULT_LIMIT (100), so
the rename/delete member enumeration now walks nextOffset pages explicitly;
a silent cap would strand members in the old group on stores >100 sessions.
* chore(i18n): restore fallback-key tracking for new sidebar group strings after rebase
* chore(i18n): translate new sidebar group strings across locales
* fix(control-ui): make long /btw side results scrollable
The BTW side-result card in Control UI expanded to the full height of its
content on desktop, so answers taller than the viewport couldn't be read.
Constrain the result body with a max-height and overflow:auto so it scrolls
in place, while keeping the existing mobile overlay behavior intact.
- Add max-height/min(55vh,480px), overflow:auto, and overscroll-behavior:contain
to .chat-side-result__body for non-mobile viewports.
- Reset those rules inside the mobile media query so the whole card still
scrolls as a fixed overlay.
- Add a lightweight browser test that verifies the body is scrollable on
desktop and the mobile overlay still scrolls as a whole.
* test(ui): consolidate side-result scroll coverage
* chore: keep release notes in PR metadata
* test(ui): verify side-result scroll interactions
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Translate chat.composer.realtimeTalkRequiresMicrophone across all
locales; it shipped as a recorded English fallback with the chat
composer redesign and broke the control-ui-i18n CI gate on main.
* feat(ui): redesign sessions page into roster table with details drawer
* fix(ui): decouple sessions drawer expansion from deep-link query narrowing; update mobile column hiding for new roster
* fix(ui): reload open session drawer when a session gains compaction checkpoints
* feat(ui): link file paths in chat and add workspace file viewer sidebar
Auto-detect file paths in chat markdown (plain paths, path:line, inline
code, explicit/absolute links) and render them as clickable links that
open a dedicated file viewer sidebar with line numbers, highlight.js
syntax highlighting, scroll-to-line, in-file search, reveal-in-rail,
open-in-editor, and copy actions. Workspace rail browser entries are
now previewable even when the transcript never touched them;
sessions.files.get serves any file inside the workspace root with the
existing containment, symlink/hardlink, and size guards.
Closes#100615
* feat(ui): linkify file paths in sidebar markdown and fix file-view gutter width
Markdown rendered in the chat detail sidebar now gets the same clickable
file links as chat messages, opening files via the panel's own click
delegation. File viewer gutter uses a fixed per-file digit width so
short lines no longer indent their code past longer ones.
* fix(ui): keep browser-entry active highlight and narrow file content for editor open
loadWorkspace no longer clears the rail active marker for browser-only
entries, so Show in Files keeps the revealed file highlighted after the
forced reload. openInEditor narrows the sidebar content kind before use,
fixing the tsgo type error.
* chore(ui): fix lint findings in file viewer helpers
* fix(ui): harden workspace file previews
* fix(ui): wire file previews through chat panes
* fix(ui): preserve workspace file targets
* fix(ui): preserve workspace file targets
* feat(ui): declutter the sidebar — pinned/chats groups, stable ordering, palette session search, titlebar brand in macOS app
- Sessions split into Pinned and Chats groups; pins are exempt from the
nine-row recency cap and the open session highlights in place instead of
hoisting to the top, so clicking a row no longer reshuffles the list.
- The command palette (Cmd+K) is the single search: it queries sessions
across agents server-side and lists matching chats next to nav commands;
the sidebar session-picker popover and its magnifier are removed, and the
topbar search pill shrinks to an icon button.
- The sidebar brand row is gone: web keeps the breadcrumb wordmark, and the
macOS app shows a compact brand mark in the native titlebar strip next to
the traffic lights (CSS-gated on the injected openclaw-native-macos class).
- The agent filter dropdown becomes a compact scope chip in the Chats group
header; the welcome badge drops its duplicate claw logo.
- Footer collapses to one icon row (status dot, settings, docs, pairing,
mobile theme switch); default pinned nav routes are now Overview-only and
the Recent-collapse preference is retired.
* test(ui): keep sidebar hover-reveal proof before the stability click; refresh locale metadata
Clicking the row leaves :focus-within on it, which keeps the management
actions visible; the hidden-actions assertion must run first.
* test(ui): archive an idle session in the sidebar e2e; assert running rows stay archive-disabled
* fix(ui): drop stale and hidden rows from palette session search
Invalidate the in-flight search and clear results on every query change so a
late-resolving previous-query request cannot leave stale rows selectable, and
run results through getVisibleSessionRows so archived/global/unknown/cron/
subagent rows stay hidden like the sidebar list. Codex review findings.
* fix(ui): over-fetch palette session search so hidden rows cannot starve visible matches
Exclude global/unknown rows server-side and fetch a full 50-row page before
applying the sidebar's hidden-row filter, keeping the 10-row display cap.
Codex review finding.
* chore(i18n): refresh sidebar locale metadata after rebase
* fix(ui): bound command palette session search
* docs: defer release notes to release generation
Gateway (additive, no protocol version bump): SessionEntry gains
lastReadAt/markedUnreadAt/lastActivityAt; session rows expose a derived
unread flag (explicit mark, or last read before latest activity; never-read
sessions stay read so upgrades do not light up). lastActivityAt is stamped
in the canonical post-run store update - user, channel, and cron runs count
as activity; heartbeat, internal-event, and preserved-state runs do not.
sessions.patch gains unread; sessions.create gains fork (transcript fork
from parentSessionKey under the parent lifecycle lock, refusing active,
concurrently-changed, and oversized parents, cross-agent aware).
Web sidebar: Pinned/custom-group/Ungrouped sections, unread dots, kebab and
right-click context menu (pin, mark unread/read, rename, fork, move to group,
archive, delete guarded for agent main sessions and active runs), mark-read
on view with loop-safe re-acknowledgement and failure retry; sessions page
gets unread + fork actions and shared custom-group helpers.
iOS Command Center: grouped sections, unread/pin indicators, Show Archived
gated on per-entry state, full context menu with rename/new-group alerts and
delete confirmation, current-session preview guarantee, read-episode
re-acknowledgement; new patch/delete/fork transport calls; Swift protocol
models regenerated.
Android SessionsScreen: grouped headers, unread/pin indicators, Archived
filter gated on per-entry state, long-press menu with the full control set,
agent-scoped forks, explicit label/category clears from session events,
main-session fallback when archiving/deleting the open chat, read-episode
re-acknowledgement with failure retry.
Closes#100739
Adds an additive worktree flag to sessions.create so any new chat can run in an
isolated managed worktree of the agent's git workspace, with the branch checked
out and .worktreeinclude provisioning applied. The session's spawnedCwd points at
the matching subdirectory inside the worktree so chat runs, CLI, and the file
browser execute there. agents.list gains workspaceGit (workspace or an ancestor
is a git checkout) to gate the affordance; web sidebar, iOS, and Android expose a
New-Chat-in-worktree action. Uses the method's operator.write scope, but the
.openclaw/worktree-setup.sh step runs only for operator.admin callers since it
executes repo code. Deleting the session, or leaving via a plain New Chat, clears
the cwd and lossless-removes the worktree; idle GC treats recent session activity
as worktree activity so an active session's checkout is never swept.
Live-verified end-to-end on a real gateway; follow-up to #100535 (issue #100534).
Nav routes (Overview, Workboard, Agents, More) now render first and stay
pinned; the session list owns the remaining sidebar height and scrolls
internally instead of being capped at min(42vh, 400px). Mobile drawer
matches the pinned-nav layout.