Commit Graph

298 Commits

Author SHA1 Message Date
Peter Steinberger
0ae3de7c6f fix(ui): dock the chat background-tasks rail to the bottom of narrow panes (#104107)
The tasks rail (from #104010) only rendered as a right-docked 230-280px
column and vanished with its toggles below a 1120px viewport, so narrow
split-view panes got a crushed thread and compact windows lost access
to background tasks entirely — the same bug class #104033 fixed for the
workspace rail and detail panel.

The rail now follows the pane's measured width: it presents as a
full-width bottom strip (sections side by side like the workspace
rail's bottom dock) when the pane is too narrow for a side column, and
the workspace rail keeps first claim on the side slot when only one
column fits. Side-docked rails, not bottom strips, now count against
the width available to the chat + detail split.

Proof: check:changed + 212 focused tests green on Testbox at this exact
content; codex autoreview clean; chromium+webkit visual verification at
seven window widths plus split view with zero geometry overlaps.
Landed with maintainer CI override.

Closes #104091
2026-07-11 13:40:08 -07:00
Peter Steinberger
c48ed95533 feat(ui): merge Instances into a unified Devices page (#104561)
* chore(i18n): regenerate locale bundles for Devices rename

* chore(i18n): regenerate locale bundles for Devices rename

* chore(i18n): sync locale metadata for Devices rename

* fix(gateway): stop tracking ephemeral control-plane clients in presence

* feat(ui): merge Instances into a unified Devices page

* docs: point Instances references at the unified Devices page

* chore(i18n): reconcile locale metadata after rebase

* fix(gateway): keep test-mode clients tracked in presence; refresh docs map
2026-07-11 13:36:07 -07:00
Shakker
cc07451a57 docs: document centered chat layout 2026-07-11 20:33:52 +01:00
Peter Steinberger
96f0983a85 fix(onboarding): skip setup for configured gateways and require inference first (#102883)
* fix(crestodian): keep onboarding RPCs restart-safe

* fix(profiles): isolate approval state migrations

* fix(crestodian): bypass configured gateway setup

* test(crestodian): type onboarding mocks

* fix(onboarding): require inference before Crestodian

* fix(onboarding): enforce verified inference handoff

* fix(macos): reset setup on gateway endpoint edits

* chore(i18n): refresh native source inventory

* fix(gateway): keep socket on request cancellation

* test(packaging): require workspace templates

* fix(onboarding): bind setup to verified inference

* fix(onboarding): align inference gate contracts

* fix(crestodian): classify concurrent policy rejection

* test(crestodian): expect registry restoration

* fix(onboarding): bind setup to configured gateways

* fix(codex): preserve startup phase deadlines

* test(crestodian): match fail-closed policy ordering

* test(onboarding): assert bound gateway handoff

* fix(codex): bind runtime resolution to spawn cwd

* test(crestodian): assert policy rejection order

* fix(cli): preserve gateway routing across restarts

* fix(macos): fail closed during gateway edits

* test(macos): cover gateway route generation races

* chore: keep release notes out of onboarding PR

* fix(ci): refresh onboarding generated checks

* style(swift): align gateway channel formatting

* fix(ci): refresh plugin SDK surface budgets

* fix(ci): resync native string inventory

* refactor(swift): split gateway channel support

* test(doctor): isolate plugin compatibility registry

* test(macos): isolate gateway onboarding fixtures

* test(macos): assert gateway lease health ordering

* fix(codex): reconcile computer-use startup changes
2026-07-11 10:25:14 -07:00
Peter Steinberger
d5fe0c5e73 feat(ui): multi-select sessions in the sidebar with batch menu actions (#104416)
* feat(ui): multi-select sessions in the sidebar with batch menu actions

* chore(i18n): sync locale bundles for sidebar multi-select strings

* docs(control-ui): document sidebar session multi-select and batch menu
2026-07-11 04:38:05 -07:00
Peter Steinberger
0af8467137 feat(workspaces): add agent-composable Workspaces (#104139)
* feat(dashboard): modular dashboard — workspace store, Workspaces tab, sandboxed custom widgets

Squashes openclaw/openclaw#101094 + #101097 + #101098 onto current main and
applies the maintainer review fixes to the backend control plane.

Co-authored-by: 100yenadmin <239388517+100yenadmin@users.noreply.github.com>

* fix(dashboard): UI review fixes — grid, error boundary, embed sandbox, locale

* fix(dashboard): make the CLI and agent broadcasts actually reachable

Three defects only a live run surfaces, all invisible to the unit suites:

- The plugin claimed the CLI command name `dashboard`, which core already owns
  (it opens the Control UI). A plugin CLI group that overlaps a core command is
  dropped at registration behind a `logger.debug`, so the entire CLI face was
  unreachable while `cli.test.ts` kept passing against its own Commander
  program. Renamed to `openclaw workspaces`, matching the tab it drives.

- The manifest never declared `activation.onCommands`, so the CLI root resolved
  to no owning plugin even once the name was free.

- `dashboard.widget.approve` needs `operator.approvals`; the CLI asked for
  `operator.write` on every call. It now requests the approvals scope only for
  the approve call, matching `operator-approvals-client.ts`.

Also: agent tools resolved their broadcast from the plugin runtime's
gateway-request scope, an AsyncLocalStorage set only around gateway RPCs and
plugin HTTP routes. An agent turn started from a channel, cron, or heartbeat
therefore wrote the document without emitting `plugin.dashboard.changed`, so an
open Control UI never saw the edit — the feature's headline promise. The gateway
broadcast is server-lifetime, so the plugin now remembers it in a single slot and
agent tools fall back to it.

* docs(web): document dashboard workspaces, provenance, and the custom-widget sandbox

* fix(dashboard): agent-tool ergonomics + close two approval-boundary gaps

From a source-blind agent driving the dashboard_* tools with nothing but their
schemas, and from a Codex review of the hardening delta.

- dashboard_widget_update could never succeed. It passed its whole parameter
  record to the patch reader, whose allowlist rejects the very `tab`/`id` keys
  the tool's own schema marks required, so every call died on
  "unexpected param: tab". Its test only ran Value.Check against the schema and
  never executed the tool.
- dashboard_data_read surfaced an `rpc` binding as a thrown error, though its
  description promised `binding_client_resolved`. It now returns that as a
  result the model can act on.
- Valid widget kinds and the rpc allowlist were undiscoverable: a model saw only
  "builtin:<name> or custom:<name>" and "Allowlisted gateway read method", then
  brute-forced ~40 calls against errors that named no alternatives. Both schemas
  and both validator errors now enumerate them, and the kind description says
  what each builtin renders and which binding id it reads. widget_move documents
  that grid and toTab are exclusive; widget_scaffold says an operator must
  approve, because no agent tool can.
- workspace.replace could mint a pending registry entry for a name that was
  never scaffolded. An operator could then approve a widget whose code did not
  exist yet, and the agent could write it afterwards. Registry entries now come
  from dashboard_widget_scaffold and nowhere else, and approve refuses a name
  with no manifest on disk.
- dashboard.widget.approve answered with the whole workspace document, so a
  connection holding only operator.approvals could read it through the approvals
  door. It now returns the registry entry it changed.

* fix(dashboard): approval pins the code it approves

Codex review found the scaffold-before-approval gate still nameable rather than
binding: approve only proved that widget.json parsed, and the Control UI loaded a
hardcoded index.html rather than the manifest's entrypoint. An agent could
scaffold a widget, win approval on an innocuous or absent entrypoint, then write
the real payload afterwards — code appearing after the human said yes.

Approval now hashes every servable file in the widget directory and stores the
digests on the registry entry, refusing a manifest whose declared entrypoint is
missing. The asset route re-hashes each file it reads and 404s anything that does
not match, so a file edited or added after approval never reaches a browser. The
Control UI loads the manifest's entrypoint, which is the file that was hashed.

The content-type allowlist moves to manifest.ts so the set of files approval
hashes and the set the route can serve cannot drift apart.

Proof, against a running gateway: scaffold -> 404, approve -> 200, rewrite
index.html -> 404, add late.js -> 404.

* fix(dashboard): parse the approved manifest from the bytes that were hashed

Codex found a TOCTOU in the approval path: it loaded and validated widget.json,
then walked the directory again to compute the digests. An agent could swap
widget.json between the two reads, so the operator validated one entrypoint while
the digest froze — and the Control UI later mounted — a different one.

snapshotApprovedWidget now reads the widget directory once: it hashes every
servable file, parses the manifest out of the same widget.json bytes it hashed,
and requires the declared entrypoint to be among them.

Proof, against a running gateway: approve -> index.html 200; rewrite widget.json
to point at evil.html and drop evil.html in -> both 404.

* fix(dashboard): cap approval asset reads; bound the grid fallback search

Two findings from the fourth Codex pass.

Approval hashes agent-authored files that are untrusted until it runs, and read
each one into memory with no size check — dropping one huge .png into a scaffold
directory would stall or OOM the gateway during approve. Sizes are now checked
before the read, with a 2 MB per-file and 8 MB total cap.

nearestFreeSlot searched one band below the lowest occupied row, so a crowded
layout near the bottom could return y=500 as the closest free slot: a placement
the store rejects, which the UI applies optimistically and then snaps back. The
search now stops at the last row a widget of that height can legally occupy.

* fix(dashboard): refuse oversized widget assets before reading them

Approved widget files stay writable and the asset route is unauthenticated, so
swapping an approved small file for a very large one made every GET buffer the
whole file before the digest check rejected it. The route now refuses anything
past the same per-file cap approval enforces, on the stat it already performs.

* fix(dashboard): enforce widget approval boundaries

* docs(changelog): note modular dashboard workspaces

* fix(dashboard): enforce static custom-widget data boundary

* fix(dashboard): satisfy UI lint

* test(dashboard): avoid legacy proto access

* feat(dashboard): make plugin opt-in

* docs(dashboard): refresh workspaces map

* refactor(workspaces): standardize plugin naming

* fix(workspaces): make widget prompt sends idempotent

* docs(workspaces): fix internal path references

* test(workspaces): make prompt assertion lint-safe

* test(workspaces): type prompt request mock

* fix(workspaces): harden approval and binding boundaries

* test(workspaces): complete stale binding client mock

* fix(workspaces): harden widget file boundaries

* fix(workspaces): scope custom widget capabilities

* fix(workspaces): align approval provenance

* fix(workspaces): close branch contract gaps

* test(workspaces): complete builtin context fixtures

* fix(workspaces): aggregate overview usage

* chore(workspaces): defer release note

* chore(workspaces): refresh i18n metadata

---------

Co-authored-by: 100yenadmin <239388517+100yenadmin@users.noreply.github.com>
2026-07-11 03:30:23 -07:00
Peter Steinberger
df16372af3 fix(macos): host the dashboard sidebar toggle beside back/forward in the titlebar (#104380)
* fix(macos): host the dashboard sidebar toggle beside back/forward in the titlebar

The Control UI's floating sidebar-expand button rendered as a bordered web
control crowding the traffic lights in the dashboard window. The toggle now
lives as a native borderless button in the leading titlebar accessory ahead
of back/forward (Safari ordering) and bridges to the web UI via the
openclaw:native-toggle-sidebar event; the injected chrome script advertises
the capability with an openclaw-native-nav class so the web control retires
itself visually while staying keyboard/screen-reader reachable.

* docs: note the macOS app's native titlebar sidebar toggle in the Control UI guide
2026-07-11 03:19:33 -07:00
Peter Steinberger
adb05e72dc improve(control-ui): move the split-view opener into the top-right toggle cluster (#104341)
* improve(control-ui): move split-view opener into the top-right floating toggle cluster

* test(control-ui): anchor split-view opener e2e assertions to the floating toggle cluster
2026-07-11 02:18:58 -07:00
Peter Steinberger
c16bd0df8d feat(control-ui): show non-main gateway checkout branch in sidebar footer (#104262)
Source-checkout (non-release) gateways now report their git branch in the
Control UI bootstrap config; the sidebar footer renders it in red next to
the connection dot. Package installs, main/master, and detached HEAD never
show it.
2026-07-11 00:25:43 -07:00
Peter Steinberger
ae2c6117d3 feat(ui): full-page New session screen with gateway folder browser (#104238)
* feat(gateway): add admin-only fs.listDir host directory listing

* feat(ui): replace new-session dialog with full-page /new screen and folder browser

* fix(ui): drop unnecessary template literal in new-session page

* refactor(ui): rename request token locals for review-bundle hygiene

* fix(ui): preserve typed draft on agent hydration and clear stale folder listings

* fix(ui): gate new-session submit on agent hydration and keep live folder edits

* test(ui): use exact textbox selector in new-session e2e

* test(ui): deep-link new-session e2e so agents.list override supplies workspace

* chore(i18n): translate new-session strings and refresh native inventory

* chore(i18n): reconcile locale metadata after rebase
2026-07-11 00:10:48 -07:00
Peter Steinberger
1d72c0f423 feat(ui): session diff panel showing a session checkout's changes in chat (#104184)
Adds a git-backed session diff panel to the Control UI, complementing the existing PR status chips.

New sessions.diff gateway method (operator.read): resolves the session checkout and returns structured per-file diffs (status, renames, +/- counts, capped unified patch) of branch + uncommitted + untracked work against the default-branch merge base. Hardened against git textconv execution and hardlinked out-of-tree content leaks; handles repos before their first commit via the empty-tree base.

Control UI renders a "Changes" panel in the chat detail sidebar with collapsible per-file diffs, hunk-gap markers, stat chips, and untracked/binary badges, gated on gateway method advertisement. Schemas additive (Swift models regenerated), 20 locales translated.

Closes #104182
2026-07-10 23:57:55 -07:00
Peter Steinberger
04865fe44b feat(ui): gateway browser panel with annotate-to-prompt and element inspect in the web Control UI (#104012)
* feat(ui): add gateway browser panel with annotate and inspect modes

* chore(i18n): translate browser panel strings

* fix(ui): address browser panel review findings (stable tab handles, stale view guard, inspect click suppression)

* fix(ui): make the browser panel reload button reload the remote page

* fix(ui): tile the browser dock against the terminal dock and re-probe evaluate per connection

* fix(ui): label page-reported prompt text as untrusted and accept host:port URL entries

* fix(ui): sanitize inspected selector fragments in the annotation prompt

* fix(i18n): retranslate annotation prompt keys so the page-reported provenance label survives localization

* docs: regenerate docs map for the browser panel section

* chore(i18n): reconcile locale bundles with latest main after rebase

* style(ui): format chat-pane imports after rebase

* chore(i18n): refresh locale metadata after rebase
2026-07-10 19:54:47 -07:00
Peter Steinberger
0074005682 feat(ui): add Model Providers settings page with auth, quota, and cost per provider (#104061) 2026-07-10 19:31:41 -07:00
Peter Steinberger
e6671d9de0 fix(ui): adapt chat workspace rail and detail panel to narrow panes (#104033)
The workspace rail and message detail panel keyed layout off viewport
media queries, so narrow split-view panes and compact windows got
crushed side-by-side columns, and below 1120px the rail was
display:none with no way to reach workspace files.

Chat panes now measure their own width with a ResizeObserver: under
800px the rail presents as the existing bottom-dock strip (side-dock
controls hide), and when the chat + detail split has under 680px the
detail panel stacks below the thread with a horizontal resize divider.
The phone full-screen detail takeover is unchanged. Bottom-strip path
and summary rows no longer flex-shrink into clipped text.

Closes #104023
2026-07-10 19:18:35 -07:00
Peter Steinberger
7b5854bee8 feat(webui): reintroduce opt-in AI purpose titles for tool calls (#103989)
* feat(webui): reintroduce opt-in AI purpose titles for tool calls

Restores the chat.toolTitles path removed in #103821, gated behind the new
gateway.controlUi.toolTitles opt-in (default false) so tool rendering stays
fully deterministic with no background model calls unless an operator enables
it. Disabled gateways answer { titles: {}, disabled: true } without loading
the completion runtime, and clients stop asking for the session.

When enabled, titles use canonical utility-model routing: an explicit
utilityModel (operator-chosen provider, like every utility task), else the
session provider's declared small-model default, honoring per-session model
overrides and auth profiles; utilityModel "" disables titles and malformed
refs fail closed — never the primary model. Tool inputs are redacted with the
tools-mode redactor before cache keys or prompts, caller ids are bounded and
never reach the model, and results cache in the per-agent SQLite
cache_entries so repeat views never re-bill.

Also completes two crestodian model-input mock factories that leaked into
sibling tests under shared-registry CI shards.

Fixes #103987

* fix(webui): redact tool-title inputs before truncation
2026-07-10 19:18:02 -07:00
Peter Steinberger
46692355c9 feat(ui): add a background tasks pane to chat panes (#104010)
* feat(ui): add background tasks rail to chat panes

* chore(i18n): sync control-ui locale bundles

* fix(ui): match gateway owner-key task scoping and hide tasks rail on narrow viewports

* chore(i18n): translate background tasks rail strings
2026-07-10 17:56:25 -07:00
Peter Steinberger
6d39ec5152 feat(ui): collapse session PR chips and add a CI monitoring popover (#103853)
* feat(ui): collapse session PR chips and add a CI monitoring popover

* chore(i18n): translate session PR chip strings

* docs(gateway): note Control UI contract shapes ship in lockstep

* chore(i18n): regenerate locale bundles after rebase
2026-07-11 00:37:06 +01:00
Shakker
e6ae79360c feat: open Settings with Shift-Command-Comma (#103870)
Open Settings from anywhere in the Control UI with Shift-Command-Comma while preserving browser-owned Command-Comma and existing shortcuts.

Prepared head SHA: 769a4fec5f
Co-authored-by: shakkernerd <165377636+shakkernerd@users.noreply.github.com>
Reviewed-by: @shakkernerd
2026-07-10 19:13:44 +01:00
Peter Steinberger
fd2a2411b9 feat(ui): sessions sidebar redesign with agent sections, smart groups, and draft sessions (#103498)
* feat(ui): sessions sidebar redesign with agent sections, smart groups, and draft sessions

- agents become collapsible top-level sidebar sections; expanding an agent
  browses its sessions without navigating, replacing the hidden scope select
- built-in smart groups: one section per channel (rows keep their chat
  titles), a Work section for worktree/exec-node sessions with a
  repo/branch/node subtitle, custom groups, and Chats
- session names never show raw keys or peer ids; DM fallbacks shorten ids,
  dashboard sessions read 'New session', unnamed work sessions read as
  their checkout
- one + opens the new-session draft dialog: agent, exec host (paired
  system.run nodes), folder, worktree toggle with base-branch picker
  (worktrees.branches) and optional name; the first message creates the
  session and starts the run in one sessions.create call
- custom group catalog/order moves to the gateway (sessions.groups.*) with
  a one-time localStorage migration; rename/delete update members
  server-side instead of client-side paging

Part of #103431

* fix(ui): resolve dragged sessions across browsed agent sections

Dropping a row dragged out of a non-active agent section now finds the
session in the per-agent row cache instead of only the active scope, so
the category patch is applied instead of silently doing nothing.

Part of #103431

* fix(ui): propagate group catalog changes to open clients

sessions.groups.put/rename/delete now always broadcast a groups-change
event, and the session capability reloads the gateway-owned catalog when
one arrives, so another browser's group create/reorder/rename/delete no
longer leaves this client on a stale snapshot for the rest of the
connection.

Part of #103431

* docs: restore new session dialog section after rebase

* fix(ui): translate new sidebar/session strings and refresh docs map

Real locale translations for the new-session dialog and sidebar keys
(the fallback gate requires zero recorded English fallbacks), plus the
regenerated docs map for the new Control UI section.

Part of #103431

* fix(ui): repair locale metadata after rebase conflict resolution

* fix(ui): merge mainline locale keys with the sidebar redesign strings

* fix(ui): refresh raw-copy baseline for mainline tool-card strings

* fix(ui): reconcile generated locale artifacts after rebase
2026-07-10 18:54:44 +01:00
Peter Steinberger
188535b097 fix(ui): queue chat input while reconnecting (#102781)
* fix(ui): queue chat input while reconnecting

* test(ui): strengthen offline reconnect proof

* chore: follow release-only changelog policy

* fix(ui): harden offline queue replay

* fix(ui): harden offline replay recovery
2026-07-10 18:37:46 +01:00
Peter Steinberger
5aea34ad8c fix(webui): keep tool activity paired without model calls (#103821)
* fix(webui): make tool activity rendering deterministic

* fix(protocol): remove stale tool-title models

* fix(i18n): translate tool activity labels

* fix(i18n): translate tool activity labels
2026-07-10 18:21:08 +01:00
Peter Steinberger
fc2afc83da feat(webui): redesign tool-call rendering with inline diffs, group summaries, and cheap-model purpose titles (#103748)
Kind-aware tool rows (terminal-style commands with wrapper stripping and
display highlighting, file edits with inline numbered diffs and diffstat,
write previews, key-value args), aggregate group summaries with live run
status, and a new batched chat.toolTitles gateway RPC that titles complex
calls via the configured utilityModel or the OpenAI Luna default (gated to
OpenAI-primary agents, cached in the per-agent SQLite cache_entries).

Also fixes two transcript pairing bugs: result blocks now inherit call
id/name/details at merge time, and results pair with any open call in the
current tool run so parallel calls render as single rows.

Fixes #103554
2026-07-10 17:26:22 +01:00
Peter Steinberger
2d54be31ba feat(ui): detect session pull requests and pin status chips above the chat composer (#103600) 2026-07-10 16:23:28 +01:00
Peter Steinberger
401f278f11 feat: add Control UI plugin management (#103176)
* feat(ui): add plugin catalog management

* feat(gateway): add plugins.uninstall and richer plugin catalog metadata

Adds a plugins.uninstall gateway method (operator.admin, control-plane write)
backed by a lock-guarded uninstallManagedPlugin that mirrors the CLI flow:
config cleanup, install-record removal, managed file deletion, and registry
refresh. Bundled plugins stay disable-only. Catalog entries now carry a
manifest-derived category and a removable flag; ClawHub search results expose
download counts and verification tiers.

* feat(ui): redesign plugins page with inventory, store shelves, and cover art

Rebuilds /settings/plugins around three tabs: Installed (category-grouped
inventory with overview stats, state filters, uninstall for external plugins,
and inline MCP server management through the shared config seam), Discover
(featured/official shelves plus one-click MCP connectors and curated ClawHub
searches), and ClawHub (search with download counts and verification badges).
Every catalog entry renders bundled cover art or a deterministic gradient
monogram tile - no more empty boxes. Artwork generated with Codex CLI, shipped
as 512px WebP under ui/public/plugin-art.

* chore(ui): regenerate locale bundles for plugins manager strings

* docs: describe plugins manager tabs, uninstall, and MCP connectors

* fix(plugins): human catalog labels and un-pinned hosted fallback ids

listManagedPlugins now prefers manifest names over registry package-name
backfill, falls back to channel catalog labels and blurbs, and stops pinning
expectedPluginId when a hosted feed entry only exposes its package name
(which rejected every legitimate install of that package). Found via live
gateway testing against ClawHub.

* fix(ui): send minimal RFC 7396 merge patches for MCP server edits

config.patch merges rather than replaces, so key removal needs an explicit
null; sending the full config back made MCP server removal a no-op. Found
via live gateway testing.

* fix(ui): write explicit MCP transports for URL servers

The MCP runtime defaults URL-only servers to SSE, so streamable HTTP
endpoints saved by the add form or connector templates would fail at
connect time. Connector templates now declare their transport and the
add form infers streamable-http unless the URL follows the /sse
convention. Flagged by autoreview against the transport resolver.

* test(ui): wait for deferred plugin requests before resolving in e2e

* feat(ui): plugins detail view, action menus, and unified ClawHub search

Reworks the plugins page from PR #103176 feedback: merges the ClawHub tab into
Discover (typing searches ClawHub inline and appends a quiet From ClawHub
section, with Browse ClawHub demoted to a header text link), makes every row and
store card open a plugin detail overlay (hero art, primary enable/install
action, metadata table), and replaces enable/disable switches with a state chip
plus an overflow menu (Enable/Disable, Remove for external plugins, View
details) matching the ChatGPT-store install+menu pattern. MCP rows use the same
menu; refresh is now icon-only.

* chore(ui): regenerate locale bundles for plugins UI iteration

* feat(ui): vetted, grouped connector catalog for the plugins store

Expands Connect your world to 28 connectors organized into use-case shelves
(Work & productivity, Coding & infrastructure, Home & media, Everyday life).
Every entry passed a three-stage subagent review: official-docs verification
plus live endpoint probes for MCP servers, ClawHub result-quality and
malware/typosquat screening for curated searches, and an adversarial pass
that dynamically registered OAuth clients to prove one-click viability.

That review removed Figma (registration allowlisted, 403) and Atlassian
(OAuth issuer-mismatch bug upstream), downgraded GitHub to PAT-based setup
(no dynamic client registration upstream), fixed Linear (/sse retired) and
Home Assistant (/api/mcp, streamable HTTP) endpoints, retargeted poisoned or
dead searches (youtube, finance, hue dropped; calendar -> google calendar;
stocks replaces finance), and added Todoist, Airtable, Canva, Stripe,
Context7, DeepWiki, Hugging Face one-click MCP servers plus Jira, PDF,
transcription, Kubernetes, Reddit, maps, translation, and notes searches.
Keyless servers get a ready-to-use success message; new cover art included.

* chore(ui): regenerate locale bundles for connector groups

* fix(plugins): suppress hosted catalog rows once their package is installed

Hosted feed entries without a declared runtime id fall back to their package
name as catalog id, which never matches the installed runtime id, so the
Discover shelf kept offering an already-installed package. Installed package
names now also suppress official rows. Flagged by autoreview.

* fix(plugins): pin declared runtime ids and surface connector errors in place

The runtime-id pin now keys off explicitly declared catalog ids (plugin,
channel, or provider) instead of string-comparing against the package name,
so declared ids that equal their package name stay enforced while entry-id
fallbacks stay unpinned. Connector add failures on Discover now render on the
triggering card instead of the Installed tab's MCP section. Both flagged by
autoreview; regression tests included.

* feat(ui): full inventory artwork, pulse header, and two-column plugin list

Every bundled plugin now ships distinctive cover art (113 new Codex CLI
illustrations; 172 total, ~2.1MB WebP), so inventory rows and detail views
never fall back to monogram tiles. The four stat cards give way to a compact
inventory pulse: a segmented enabled/disabled/issues meter whose legend and
counts live inside the filter chips. Inventory, MCP, and search rows flow
into two columns when the panel is wide enough.

* chore(ui): regenerate locale bundles for pulse header

* fix(ui): omit stdio args from the MCP server row target

Stdio MCP args routinely carry tokens, and the inventory is visible to
read-only operators; mirror the config page and show only the command.
Flagged by autoreview; regression test included.

* fix(merge): point crestodian setup at relocated plugin commit/refresh modules

* fix(merge): add bootstrapToken to plugins page test gateway harness

* fix(plugins): name catalog install-action branches so Swift emits the union

* fix(ui): satisfy strict lint on plugins page form parsing and mocks

* chore(build): regen docs map, raise plugin-sdk declaration budget for new protocol surface

* fix(ui): type the plugins page patch mock with its real call signature
2026-07-10 11:56:44 +01:00
Peter Steinberger
ecfea21eeb feat(webchat,cli): the lobster notices things (#103573)
The resident pauses its fidgeting and turns to watch passers cross the
ledge. After a droop it tidies up with a little broom. On lobster days
(shared day hash with the CLI banner cousin, now in src/shared) it wears
a sailor cap unless the seed already rolled headwear. The Dreams sleeper
half-opens one eye when pressed.
2026-07-10 10:25:08 +01:00
Peter Steinberger
9ecb2f3a84 feat(ui): restore sidebar chrome, delete the pane workspace strip, compact native narrow header (#103561)
* feat(ui): restore sidebar chrome and remove the pane workspace strip

Reverse course from #103426 on the app chrome: the left sidebar owns
brand, pinned navigation + More, New session, sessions, and the footer
(status dot, Settings, Docs, pairing, theme) again, and the desktop
topbar is gone. What stays from that PR: the dockable workspace rail
(right/bottom, drag or button), the in-flow split-pane headers, and
Cmd+B now hides the sidebar entirely (no 78px icon rail) with a
floating expand control.

The real target of the original request: the vertical icon strip at
each pane's right edge is deleted. A collapsed workspace rail renders
nothing; the toggle (with a changed-file badge) lives in the split-pane
header next to split/close, or floats at the top-right in single-pane
chat. Shift+Cmd+B still toggles.

Narrow native macOS windows (e.g. the in-app link browser splitting
the window) previously stacked 50px of injected titlebar padding on
top of the 58px drawer row; the web CSS now folds that into one
compact 58px row beside the traffic lights, with selectors that
outrank the rules shipped Mac apps inject.

* chore(ui): regenerate locale bundles and docs map for sidebar restore

* fix(ui): bind showPaneHeader explicitly on the classic single pane

* chore(ui): reconcile locale metadata after rebase onto lobster wild cards
2026-07-10 09:35:14 +01:00
Peter Steinberger
4a4a32a5de feat(cli,webchat): lobster wild cards — a CLI cousin, moving day, and opt-in sounds (#103412)
* feat(cli,webchat): lobster wild cards - a CLI cousin, moving day, and opt-in sounds

The openclaw banner gains a rare day-seeded ASCII lobster (rich TTYs,
random tagline mode, never CI). The web pet notices gateway upgrades and
arrives carrying a bindle for one load. A new default-off Lobster sounds
quick setting adds tiny WebAudio chirps on pokes and pets. The lobster
docs page learns about petting, sounds, and this batch's field notes.

* chore(webchat): regenerate keyless raw-copy i18n baseline after rebase
2026-07-10 08:49:27 +01:00
Peter Steinberger
4a72a6cb2f feat(ui): move app chrome into a topbar and dock the session workspace rail (#103426)
* feat(ui): move app chrome into a topbar and dock the session workspace rail

The desktop shell now uses a slim topbar for brand, primary navigation
(Chat + pinned routes + More menu), command-palette search, pairing,
theme, and Settings; the left column slims down to a sessions-only
panel (Cmd+B hides it entirely — the 78px icon rail is gone). Split
view drops the fixed geometry-mirroring toolbar for in-flow per-pane
headers. The session workspace rail can dock right or bottom inside
its pane — drag its header between edges or use the dock button — and
the collapsed strip's file glyph is now a real button (it used to be a
dead, button-looking span) with a changed-file count badge. The Mac
app's injected chrome CSS slims down accordingly; its drag-region
geometry is unchanged and the topbar brand strip stays passive under
it.

* chore(ui): regenerate locale bundles for topbar and workspace dock strings

* fix(ui): keep the native macOS drawer clear of the titlebar overlay

The narrow-width slide-over drawer sits fixed at the window top, over
the AppKit traffic lights and drag regions. The old Mac-app-injected
CSS padded .sidebar-shell for this; that rule moved web-side for the
desktop topbar, so restore drawer clearance here for both the app
drawer and the in-drawer settings sidebar.

* chore(ui): translate topbar and workspace dock strings; regen docs map
2026-07-10 07:32:57 +01:00
Ayaan Zaidi
e6a9a5d182 docs(web): document Docker host-networking requirement for the Telegram Mini App 2026-07-10 07:53:37 +05:30
Ayaan Zaidi
b2ee68780c docs(web): document Telegram dashboard entry 2026-07-10 07:53:37 +05:30
Peter Steinberger
2c622e19de docs(web): the Lobster gets its own page (#103175)
A fun field guide for the Control UI lobster: what it is, when it
visits, how to interact (hover names, pokes, right-click shoo), the
Appearance toggle, the Lobsterdex, reduced-motion and privacy notes.
Deliberately teases rather than documents the rare variants, events,
and the anniversary. Registered in the Web interfaces nav group and the
generated docs map.
2026-07-10 02:48:21 +01:00
Peter Steinberger
fe2486247b feat(ui): add settings sidebar search (#103138)
* feat(ui): add settings sidebar search

* chore: keep release notes in PR body

* fix(i18n): translate settings search labels
2026-07-10 00:08:13 +01:00
Shakker
fc107382b9 docs: document session workspace shortcut 2026-07-09 19:30:37 +01:00
Peter Steinberger
b80062be3a improve(ui): drop the redundant desktop top bar and add back/forward navigation to the macOS app (#102808)
* feat(ui): drop the desktop top bar in favor of sidebar navigation

The Control UI top bar only rendered the OpenClaw › agent › page breadcrumb
on desktop, duplicating the sidebar. Desktop now renders no topbar row; the
row returns solely as the chat split toolbar's backdrop. Narrow viewports
keep the header (drawer toggle, brand, command-palette search) and now show
the brand across the whole drawer range. Routing already uses pushState, so
browser back/forward traverses navigation.

* feat(macos): add back/forward controls to the dashboard window

Native titlebar buttons next to the traffic lights drive WKWebView history,
which carries the Control UI's pushState navigation; enabled state tracks
canGoBack/canGoForward via KVO and trackpad swipe gestures are enabled too.
Back/forward traversals to entries from a replaced gateway endpoint cancel
silently instead of opening a dead URL in the system browser.

* fix(macos): keep the dashboard drag strip off the web content column

With the desktop topbar row removed, the 28px mid-window drag region sat on
top of the content column (chat thread has no top padding) and swallowed
clicks as window drags. Shrink it to a 12px edge strip; the sidebar region
over the reserved native-chrome padding stays the primary drag surface.
2026-07-09 15:46:59 +01:00
Peter Steinberger
8985598302 fix(gateway): stop paired-device duplication and redesign the Nodes page (#102810)
* fix(gateway): prune superseded silent device pairings on auto-approve

* feat(ui): unified nodes & devices inventory with dedupe and cleanup

* docs: nodes page inventory + silent pairing supersede cleanup

* refactor(gateway): run silent-pairing prune after approval broadcast

* fix(ui): surface node list errors on the nodes inventory card

* fix(gateway): restrict pairing auto-prune to same-host silent approvals

* fix(gateway): report live device connections and guard pairing prune races

* docs(ui): document bulk-cleanup name-collision tradeoff

* fix(gateway): avoid map-spread when marking live device connections

* docs: regenerate docs map
2026-07-09 15:40:30 +01:00
Peter Steinberger
2f013382a0 feat(ui): add settings profile page with lifetime token stats, streaks, and activity heatmap (#102842)
* feat(ui): add settings profile i18n strings and regenerated locale bundles

* feat(ui): add settings profile page with token stats, streak heatmap, and top tools

* chore(ui): record intentional OpenClaw brand string in raw-copy baseline
2026-07-09 15:03:12 +01:00
Peter Steinberger
fdd19e3017 feat(ui): merge the voice level meter into the stop-voice pill and disambiguate the stop controls (#102786)
* feat(ui): merge voice level meter into the stop-voice pill and disambiguate stop controls

* docs(web): describe the live voice pill control in Talk mode

* test(ui): capture dark-mode voice control proof in talk e2e

* fix(ui): keep the live voice pill wide at phone widths

* fix(ui): show the stop glyph instead of a fake listening meter when a talk session errors

* test(ui): assemble the mock talk client secret so scanners do not flag it
2026-07-09 13:55:56 +01:00
Peter Steinberger
3ccf2a0739 feat: render inline web chat widgets via capability-gated show_widget tool (#101840)
Adds client-capability-gated tool availability: gateway clients declare
capabilities at connect (new inline-widgets cap), chat.send stamps them into
the run context, and every tool assembly path (embedded runner, queued
followups, Codex app-server harness, plugin-only construction plans) drops
tools whose requiredClientCaps the originating client did not declare. The
Canvas plugin ships the first such tool, show_widget: agents pass SVG or an
HTML fragment plus a title; the plugin hosts it as a bounded, retention-scoped
Canvas document and returns the existing canvas preview handle, which web chat
renders as a sandboxed iframe fitted to the widget's reported content height.
Widget frames never get allow-same-origin (per-preview sandbox ceiling,
including the sidebar path) and the Canvas host serves widget documents with a
CSP sandbox header so direct navigation runs in an opaque origin. Verified
live end-to-end on a Testbox with gpt-5.5 (screenshots on the PR). CLI-backed
model backends do not carry client caps yet and stay fail-closed (#102577).

Closes #101790
2026-07-09 12:29:50 +01:00
Peter Steinberger
7abf1c7f85 improve(ui): calmer sessions roster with dot status and drawer-level runtime (#102664)
Feedback pass on the sessions redesign: status pills become a plain colored
dot + label (green pulse for live, green dot with neutral label for done,
muted idle, red failed) in both the roster and the drawer hero, and the
Runtime column moves out of the table into the row drawer as Runtime (agent
runtime) plus Run duration. Runtime stays searchable. Responsive breakpoints
reflow for the 7-column roster and the actions column shrinks to the chevron
and row menu that landed in #102564.

Closes #102654
2026-07-09 12:13:19 +01:00
Peter Steinberger
ecc2cffad8 improve(ui): keep sidebar sessions inline and draggable (#102558)
* feat(ui): add drag-managed sidebar session groups

* chore: keep release notes in PR body
2026-07-09 09:40:53 +01:00
Peter Steinberger
5c3c5c0ee4 feat(ui): redesign sessions page with overview tiles, kind avatars, and context meters (#102523)
The Control UI sessions roster now leads with operator telemetry: overview
tiles (sessions / live / unread / tokens), per-kind row avatars with a live-run
dot, compact token values with context-usage meters (ok/warn/danger at
65%/85%), initial-load skeleton rows, and icon-led empty states. Stale token
snapshots render as ~approximations with a neutral meter and never drive
warning tones, matching the chat composer convention; the overview token sum
counts only known snapshots (~ when partial, n/a when none). Label chips
ellipsize instead of overflowing sticky columns; <=500px drops the avatar to
preserve the key column budget.

Closes #102517
2026-07-09 09:19:03 +01:00
Peter Steinberger
9566aded5c fix(openai): correct Realtime auth and transcription secrets (#102518)
* fix(openai): correct Realtime auth and transcription secrets

* chore: leave release notes to release automation
2026-07-09 08:55:31 +01:00
Peter Steinberger
ea4e005008 fix(ui): unify split-view controls in one toolbar row (#102492)
* fix(ui): unify split-view toolbar

* chore: remove release-owned changelog entry
2026-07-09 08:17:35 +01:00
Peter Steinberger
5533d979d4 feat: add follow-up task suggestions (#102422)
* feat(tools): add follow-up task suggestions

* chore: leave changelog to release flow

* fix(tools): add task suggestion display metadata

* fix(tools): update task suggestion display snapshot

* docs: format task suggestion tool table

* test(gateway): expect compaction worktree workspace

* test(gateway): preserve configured compaction workspace

* fix(ui): translate task suggestions
2026-07-09 06:30:01 +01:00
Peter Steinberger
6235344006 fix(ui): stop flashing the login gate on dashboard load when credentials are stored (#101849)
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
2026-07-07 19:40:30 +01:00
Peter Steinberger
21f251220f feat(ui): redesign gateway connection-lost banner as floating pill (#101812) 2026-07-07 19:00:29 +01:00
Peter Steinberger
5a234d61fa feat(ui): redesign dashboard chrome with tiny top bar and sidebar search (#101497)
* 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.
2026-07-07 10:57:45 +01:00
Peter Steinberger
6a5726b808 feat(control-ui): drag sessions into split view with animated drop preview (#101191)
* feat(control-ui): drag sessions into split view with animated drop preview

* fix(i18n): translate split drop labels and pending upstream strings
2026-07-07 03:30:46 +01:00
Peter Steinberger
5157446a2c feat(ui): rename, delete, and toggle sidebar session groups (#101117)
* 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
2026-07-07 00:54:36 +01:00
Peter Steinberger
92cfceac09 feat(ui): select Talk microphone inputs (#101100) 2026-07-06 19:39:58 +01:00