* fix(control-ui): keep the dashboard mounted with a reconnect banner on gateway drops
Once a session is established, a dropped gateway WebSocket no longer
unmounts the dashboard into the login gate. The client's close handler
now reports willRetry (the same fact that drives its reconnect
scheduling), the gateway store derives a `reconnecting` snapshot state
from it (everConnected && willRetry), and the app shell stays mounted
with an amber "Gateway connection lost - reconnecting" banner plus a
Retry now action while the client retries with backoff. The login gate
is reserved for first connects, credential rejections, and manual gate
submissions; event-gap recovery also no longer flashes the gate.
createApplicationGateway moved from bootstrap.ts to gateway-store.ts
with an injectable client factory for direct behavior tests. Adds the
previously unstyled `.callout.warn` variant and a "Connection loss and
reconnect" docs section.
Fixes#100475
* chore(i18n): regenerate control-ui locale bundles for connection banner strings
* chore(control-ui): unbreak CI - add reconnecting to overlays snapshot fixture, regenerate docs map
* chore(i18n): re-sync locale metadata after rebase onto refreshed main locales
* chore(i18n): refresh raw-copy baseline after rebase
* feat(logbook): automatic work journal plugin with a plugin-contributed Control UI tab
Squash of PR #99930 work for rebase onto the Control UI route refactor:
- extensions/logbook: Dayflow-style capture -> observations -> timeline cards
pipeline with SQLite store, node capture commands, standup/ask, retention
- plugin SDK/gateway seam: surface "tab" Control UI descriptors projected
into hello-ok controlUiTabs (scope-filtered, deterministic order)
- Control UI: dynamic plugin tabs with bundled Logbook view
- docs, tests, labeler wiring
* feat(ui): port plugin tabs and Logbook to the route-owned Control UI architecture
- shared /plugin route carries the tab id in the query (?id=<tab>), matching
the router's exact-path contract
- openclaw-plugin-page renders bundled views (Logbook), sandboxed plugin
frames (descriptor path), or the unavailable card
- sidebar renders hello controlUiTabs after each group's static routes
- Logbook view/controller live under ui/src/pages/plugin/
* fix(ui): namespace plugin tabs by pluginId to prevent cross-plugin tab id collisions
* fix(logbook): prefer app capture nodes and rotate off failing nodes
* fix(plugins): reject protocol-relative Control UI tab paths
* fix(logbook): harden automatic journal
* docs(changelog): remove maintainer self-credit
* chore(ui): refresh locale metadata after rebase
* fix(logbook): preserve analysis window boundaries
* fix(logbook): align status privacy and timezone
* fix(ui): stop hidden plugin tab polling
* feat(ui): scroll truncated sidebar session names on hover
Sidebar recent-session labels clip long titles with an ellipsis and there
was no way to read the tail without opening the session. Hovering a row
now animates the label's text-indent to slide the clipped tail into view
(speed-proportional duration, 300ms minimum) and snaps back quickly on
mouse leave. Resting ellipsis rendering is preserved by animating
text-indent instead of transforming an inner wrapper, since text-overflow
draws no ellipsis for atomic inline children. Respects
prefers-reduced-motion.
* fix(ui): harden sidebar session marquee
* feat(control-ui): session grouping with drag & drop and channel categorization
* fix(control-ui): restrict session drag&drop to private session-key payloads
* chore(i18n): translate session grouping strings across control ui locales
* chore(protocol): regenerate swift gateway models for session category
* chore(protocol): regenerate swift gateway models for session category
Restore the maintainer-requested collapsed <details> failure callout that
a parallel session reverted, adapt the e2e expectations, and drop the
PR-side CHANGELOG edit (changelog is release-generation-owned).
Tool calls in Control UI chat rendered as triple-nested cards: activity
group card + tool-shell bubble chrome + gradient summary pill with a
0 8px 22px drop shadow. Collapsed rows now render as flat single-line
rows with ellipsis, the activity group uses a flat header plus a left
rule, and expanded detail keeps soft tinted blocks without card chrome.
Also deletes the dead legacy .chat-tool-card__details/__output CSS and
the unused renderToolCardSidebar path with its never-taken
renderToolDataBlock branches.
Closes#99760
Refactor the Control UI around route-owned page lifecycle and state while preserving existing behavior and design.
Prepared head SHA: bd51b6fa76
Co-authored-by: Shakker <165377636+shakkernerd@users.noreply.github.com>
Reviewed-by: @shakkernerd
* feat: add session thread management
Squash of codex/thread-management (025aefc3ad1) onto origin/main:
pin/archive/rename sessions via sessions.patch, archived-aware
sessions.list, lifecycle fencing, read-only archived chat, SDK +
Swift protocol support, Control UI session management.
* refactor(ui): minimal session rows with hover-revealed management
Chat picker and sidebar recents share session-row primitives: single-line
rows, relative timestamps, rename/archive/pin revealed on hover or focus,
accent pin badge for pinned rows, and an active-run spinner in the trail
slot. Sidebar floats pinned sessions above recency via the shared
comparator and gains archive/pin actions through the unified sessions-view
patch fallback. Archive eligibility is one shared policy
(canArchiveSessionRow); the sidebar/picker active-run tooltip now uses the
real sessionsView.activeRun locale key.
* fix: align session admission with mailbox-era main
Integration fixes after rebasing onto current main: sessions_list mailbox
test expectations learn the archived/pinned row fields and archived:false
list param; gateway agent admission treats a session as deleted only when
both the requested and canonical alias sets miss it (legacy bare-main
stores and exec-approval followups read under different spellings); cron
persist tests keep a consistent store across claim-guarded persist calls;
the ACP abort hook test asserts abort propagation instead of signal
identity; drop dead lifecycle writes flagged by no-useless-assignment and
fix the promise-executor return in the codex compact test.
* fix(qa): align UI e2e and shard fixtures with redesigned session rows
Sidebar session rows are wrapper divs with an inner link now: update the
navigation browser tests and chat-flow Playwright selectors. Seed a real
per-test session store for the auto-fallback admission guard instead of
depending on leftover host files at /tmp/sessions.json. Teach the
test-projects routing fixture about the suites that newly import the
shared temp-dir helper. Document the Codex thread-format contract for
archivedAt/pinnedAt (flag derived from server-stamped timestamp, epoch ms
here vs Codex epoch seconds) at the type and in the session docs.
* test: route auto-fallback suite through temp-dir helper plans
The auto-fallback suite now imports the shared temp-dir helper for its
seeded session store, so the top-level helper routing fixture must list
it in the auto-reply plan.
* feat(gateway): add device.pair.setupCode RPC for connect QR
The OpenClaw mobile/companion app scans a pairing setup code to connect to the gateway, but that code + QR could only be produced by the openclaw qr CLI (ASCII to stdout). Non-terminal clients driving onboarding had no way to display the connect QR.
Add a device.pair.setupCode gateway method that reuses resolvePairingSetupFromConfig + encodePairingSetupCode + renderQrPngDataUrl to return { setupCode, qrDataUrl?, gatewayUrl, auth, urlSource }. The embedded setup code mints a short-lived bootstrap token that hands off broad operator scopes (read/write/approvals/talk.secrets), so the method requires operator.admin (matching the wizard methods a companion already uses) and is not advertised. auth is a label only; the gateway credential is never returned, and an oversized QR is omitted so the response always satisfies the result schema.
Refs #94661.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat(ui): pair mobile devices from Control UI
* docs: refresh generated docs map
* docs: clarify mobile QR auto-connect
* docs: clarify mobile QR auto-connect
* docs: clarify mobile QR auto-connect
---------
Co-authored-by: Barbara Kudiess <76582160+bkudiess@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* refactor(ui): dedupe chat styles and make styles.css import order real
* refactor(ui): dedupe chat tool-row styles into chat files
* refactor(ui): keep light bubble skin after role variants
* refactor(ui): keep light bubble skin after role variants
* refactor(ui): keep light bubble skin after role variants
* fix(a11y): B-1 — raise muted text contrast to ≥4.8:1 WCAG AA
* fix(ui): C-1 — ChatSidePanel joins glass surface language
* feat(mobile): D-1 — hamburger overlay nav below 900px
- Esc key now closes nav drawer (globalKeydownHandler)
- Nav item tap targets bumped to min-height: 44px + padding: 10px 16px
in the ≤1100px drawer breakpoint (was 40px / 0 12px)
- Hamburger toggle + overlay drawer were already wired in app-render.ts;
this completes close-on-Esc and ensures accessible tap targets
* fix(a11y): B-2 — consistent focus-visible states distinct from hover
* fix(a11y): B-3 — lift all sub-12px text to 12px minimum
* fix(a11y): narrow focus and CSS scope
* fix(a11y): finish focus-visible selectors
Keep the Logs page from rendering competing outer page and inner log-stream scrollbars. The Logs route now opts into an explicit content class for desktop fill-height layout, while mobile keeps the single-page scroll behavior with the capped log panel.
Also adds regression coverage for the route class and CSS ownership selectors.
Co-authored-by: Brian potter <brian@potterdigital.com>
Summary:
- The PR adds highlight.js-backed WebChat code-block highlighting, scoped token CSS, regression tests, a type shim, and a direct UI dependency.
- Reproducibility: not applicable. as a bug reproduction; this is a feature addition. The feature gap is source-evident because current main renders code blocks as escaped plaintext without hljs token markup.
Automerge notes:
- No ClawSweeper repair was needed after automerge opt-in.
Validation:
- ClawSweeper review passed for head 7bb95c47ed.
- Required merge gates passed before the squash merge.
Prepared head SHA: 7bb95c47ed
Review: https://github.com/openclaw/openclaw/pull/83569#issuecomment-4476990135
Co-authored-by: zhengzuo0-ai <zheng.zuo0@gmail.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
* feat: show provider quota in control ui overview
* feat: show provider quota in chat header
* fix: recover stale control ui chat runs
* fix: polish control ui quota refresh
Summary:
- Replace the fixed 500px Control UI Logs stream cap with a viewport-responsive max-height plus a 200px floor.
- Keep the offset documented inline and add the changelog entry for #53916.
Verification:
- git diff --check origin/main...HEAD
- git merge-tree --name-only origin/main HEAD
- node assertion confirmed `.log-stream` has `max-height: calc(100vh - 280px)`, `min-height: 200px`, and no `max-height: 500px`
- Source path check confirmed `renderLogs` renders the affected `.log-stream` container
Maintainer note:
- Real behavior proof requirement intentionally overridden by maintainer proof comment: https://github.com/openclaw/openclaw/pull/53916#issuecomment-4455196712
Summary:
- Show compact live/idle/terminal status badges in the Sessions table using existing row status fields.
- Rename the active-minute filter to Updated within and keep Sessions rows single-line across responsive widths.
- Add focused rendering/layout coverage, locale sync, and changelog attribution.
Verification:
- GitHub PR checks green on 5f8994aadc, including Real behavior proof, check, check-additional, checks-node-core, build-artifacts, build-smoke, check-lint, security-fast, security-scm-fast, and security-dependency-audit.
- Local rebase sanity after conflict resolution: git diff --check origin/main...HEAD and pnpm exec oxfmt --check --threads=1 CHANGELOG.md.
Fixes#78307.
Add explicit Control UI feedback for repeated actions: session switches now announce through the chat controls live-status path and flash the active session selector, config actions show inline busy state, and session list empty states distinguish filtered results with a Show all reset. Also refresh generated Control UI locale metadata and fallback markers.
Summary:
- Use sessions.list as the Control UI source of truth for available sessions.
- Hide archived sessions by default and keep the Sessions filter UI explicit, compact, and reversible.
- Preserve session-change behavior, checkpoint details, generated i18n output, and chat/session picker consistency.
Validation:
- pnpm ui:i18n:check
- pnpm test ui/src/styles/components.test.ts ui/src/ui/views/sessions.test.ts ui/src/ui/app-render.helpers.node.test.ts
- pnpm test ui/src/ui/controllers/sessions.test.ts ui/src/ui/app-gateway.sessions.node.test.ts ui/src/ui/views/sessions.test.ts ui/src/styles/components.test.ts ui/src/ui/app-render.helpers.node.test.ts
- pnpm tsgo:test:ui
- Blacksmith Testbox: pnpm check:changed -- <PR paths>
Render the command palette as a native modal dialog with labelled combobox/listbox semantics, stable active-descendant wiring, and guarded close behavior.\n\nValidated with targeted command palette tests and formatter checks.
Introduce a native dialog-backed Control UI modal primitive and migrate the exec approval, gateway URL confirmation, and dreaming restart confirmation prompts to it.
The modal primitive provides aria-modal semantics, shadow-root-local labels/descriptions, focus trapping, safe initial focus, Escape cancellation, and focus restoration while preserving the existing prompt content and decision semantics.
Validation:
- pnpm lint --threads=8
- pnpm --dir ui test src/ui/components/modal-dialog.test.ts src/ui/views/exec-approval.test.ts src/ui/navigation.browser.test.ts
- pnpm test:ui
- pnpm exec oxfmt --check --threads=1 ui/src/ui/components/modal-dialog.ts ui/src/styles/config-quick.test.ts
- git diff --check
CI note: checks-node-core-support-boundary is failing in test/scripts/docker-build-helper.test.ts on an unrelated package-acceptance assertion; the failing files are identical to origin/main and outside this UI-only PR.
## Summary
- render cron job prompts and run summaries through the sanitized markdown pipeline in the Control UI
- keep system-event cron payloads plain and prevent markdown link clicks from triggering row selection
- handle failed runs with missing or empty summaries without duplicating or hiding the error text
## Verification
- pnpm test ui/src/ui/views/cron.test.ts
- pnpm test src/plugins/doctor-contract-registry.test.ts src/plugins/setup-registry.test.ts
- pnpm check:changed
- GitHub CI green on 251f01a3b0
Polish the Control UI markdown preview chrome and sidebar raw-text behavior.
- Add the upgraded preview dialog/sidebar chrome and tighten related CSS coverage.
- Show workspace-relative paths in the markdown preview dialog instead of absolute filesystem paths.
- Preserve raw markdown source for idempotent raw-text toggles.
- Align browser plugin-sdk facade export parity for DEFAULT_BROWSER_ACTION_TIMEOUT_MS.
- Stabilize the gateway update channel test by waiting for the async update runner call.
Validation:
- OPENCLAW_LOCAL_CHECK=0 pnpm test ui/src/ui/views/agents.test.ts ui/src/ui/views/chat.test.ts src/plugins/contracts/plugin-sdk-subpaths.test.ts src/gateway/server.roles-allowlist-update.test.ts
- OPENCLAW_LOCAL_CHECK=0 pnpm check:changed
- GitHub checks green on ebbe96fc88
## Summary
- add browser-local operator identity in Control UI and route user name/avatar rendering through the shared chat/avatar path used by assistant and agent surfaces
- tighten Quick Settings, fallback chip, and mobile chat layout behavior so the personalized UI uses space better and avoids clipped controls
- guard oversized local avatar uploads before FileReader allocation, restore the fallback-chip keyboard focus ring, and add the changelog note for the user-visible Control UI work
## Testing
- pnpm test ui/src/ui/views/config-quick.test.ts ui/src/styles/components.test.ts
- pnpm check:changed