Commit Graph

3179 Commits

Author SHA1 Message Date
Peter Steinberger
fa77fe10d5 chore: migrate active GPT-5.5 references to GPT-5.6 (#104452)
* chore(models): migrate active GPT-5.5 references

* test(workboard): expect GPT-5.6 Sol default

* chore: keep release notes in PR body

* test(models): align picker fixtures with Sol default

* test: update PDF default model expectation

* test(qa): migrate thinking smoke to Luna

* test(gateway): align mock catalog with Sol default

* ci: retrigger exact-head PR checks

* test(gateway): document default catalog invariant
2026-07-11 06:30:57 -07:00
Peter Steinberger
05aecc1d6f feat: show Codex transcripts in the sidebar (#104437)
* feat: show Codex transcripts in sidebar

* fix: clear Codex sidebar on Gateway switch

* chore: leave release notes to release workflow

* chore: refresh native i18n inventory

* fix: satisfy macOS Codex node lint

* fix: refresh native localization inventory

* docs: refresh documentation map

* chore: refresh UI locale metadata
2026-07-11 05:39:29 -07:00
Peter Steinberger
5325c4a786 feat(ui): redesign queued-message list as compact composer-width rows (#104445) 2026-07-11 04:59:14 -07:00
Peter Steinberger
9523a52871 fix(ui): stop sidebar session sections from painting over each other in short windows (#104447) 2026-07-11 04:57:15 -07:00
Peter Steinberger
6c415c44c9 refactor(ui): style the new-session draft as the chat composer shell (#104448)
* refactor(ui): style new-session draft as the chat composer shell

* fix(ui): guard new-session Enter send against IME keyCode 229
2026-07-11 04:55:53 -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
fe608a8dcb fix(ui): give sidebar build chip breathing room from the status dot (#104411) 2026-07-11 03:56:15 -07:00
Peter Steinberger
4fc147105b fix(ui): delay scrolling truncated session titles (#104392)
* fix(ui): delay session title hover scroll

* chore: keep release notes out of PR
2026-07-11 03:36:49 -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
saju01
cbc84767bd fix(exec-approval): stop misattributing Allow Always unavailability to policy (#97740)
* fix(exec-approval): stop misattributing Allow Always unavailability to policy

Allow Always is dropped both when policy ask=always AND when a command is
non-persistable (e.g. shell redirect `2>&1` -> one-shot), but the prompt always
claimed 'effective approval policy requires approval every time'. That's
misleading for the non-persistable case (#97069). Reword to reason-neutral
'Allow Always is unavailable for this command.' across all approval surfaces,
update en + 20 locale bundles, refresh i18n meta, and the matching tests.

Closes #97069

* fix(exec-approval): stop misattributing Allow Always unavailability to policy

* test(ui): await exec approval render updates

* chore(ui): sync approval i18n metadata

---------

Co-authored-by: saju01 <saju01@users.noreply.github.com>
Co-authored-by: openclaw-clownfish[bot] <280122609+openclaw-clownfish[bot]@users.noreply.github.com>
Co-authored-by: Vincent Koc <25068+vincentkoc@users.noreply.github.com>
2026-07-11 18:09:51 +08:00
Peter Steinberger
6268eeef15 test: wire Control UI suite into CI, fix its broken tests, drop dead harness surface (#104361)
* test: wire Control UI suite into CI, fix its broken tests, drop dead harness surface

- fix 7 Control UI tests broken on main: module-mock factories are unreliable
  under isolate:false shared workers; use RealtimeTalkSession prototype spies
  and real jsdom storage instead (chat-realtime, chat-pull-requests)
- add gated checks-ui CI job (runUiTests changed-scope output): chromium
  provisioning, lint:ui:no-raw-window-open, pnpm --dir ui test; ~30s on a
  4vcpu runner, runs only when ui-affecting paths change
- add weekly node22-compat workflow exercising the supported lower Node bound
  with the same command set as the dispatch-only ci.yml job
- delete the unreachable channels entry in EXTENSION_TEST_CONFIG_ROUTES and
  the never-populated extensionRoutedChannelTestFiles override machinery
  (born empty in 2ccb5cff22); resolved globs are provably identical
- guard run-vitest.mjs hardcoded path maps with existence tests so renames
  cannot silently drop extended stall watchdogs
- remove unenforced coverage thresholds; test:coverage is informational, docs
  updated (reference/test, help/testing, plugins/sdk-testing)

Closes #104321

* test: pin OPENCLAW_CI_RUN_UI_TESTS in the manifest env expectation

* test(ui): capture the realtime start spy instead of referencing the unbound prototype method

* test(ui): raise ui vitest timeouts for real-browser layout tests on small CI runners
2026-07-11 03:04:11 -07:00
Peter Steinberger
aeab8e7faf fix(ui): hide group submenu separator when New group is the only entry (#104370) 2026-07-11 03:02:02 -07:00
Peter Steinberger
0e1e077f4f feat(control-ui): show build identity chip in sidebar footer (#104350) 2026-07-11 02:42:01 -07:00
Vincent Koc
8e2ddd60ad fix(ci): sync Control UI raw-copy baseline (#104352) 2026-07-11 17:39:00 +08:00
Peter Steinberger
c48cbabfc1 fix(control-ui): ignore foreign side results over a live pending card and collapse carried drafts 2026-07-11 02:20:08 -07:00
Peter Steinberger
c071fcfeb6 fix(control-ui): harden BTW selection popup lifecycle from review feedback 2026-07-11 02:20:08 -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
b5db7d7d04 fix(ui): give workspace rail summary chips top padding (#104331) 2026-07-11 02:06:51 -07:00
Peter Steinberger
e8cbc62e3e chore(ui): remove dead .sidebar-new-session styles (#104296) 2026-07-11 01:48:40 -07:00
Peter Steinberger
88c563b241 fix: address update-card review findings (channel normalization, hidden-nav affordance, prerelease pinning, policy-aware bridge) (#104316)
* fix(mac): prerelease-exact launch resolution and policy-aware update ownership

* fix(ui): keep update affordance when nav is hidden and fall back on native decline

* chore(i18n): sync native inventory
2026-07-11 01:44:26 -07:00
Peter Steinberger
236d1b2484 feat(control-ui): selection popup with More details and Ask in side chat via /btw (#104205)
* feat(control-ui): add chat selection popup with More details and Ask in side chat

* fix(control-ui): keep BTW pending card visible and clear it on resultless terminal runs

* fix(control-ui): route failed BTW runs to an error side-result card and ignore stale side results

* fix(control-ui): correlate BTW pending cards by pre-generated run id and suppress superseded runs

* fix(control-ui): retire abandoned BTW runs so late side events never reach the transcript

* chore(docs): regenerate docs map for btw selection-popup section; fix selection-popup test lint
2026-07-11 01:42:17 -07:00
Peter Steinberger
c59d07b9a8 fix(ui): auto-recover Control UI panels from stale hashed-chunk imports after gateway updates (#104305) 2026-07-11 01:12:16 -07:00
Peter Steinberger
7bf80dc2c6 chore(tooling): enforce formatting and refresh TypeScript checks (#104239)
* chore(tooling): enforce current formatter and refresh checks

* chore(tooling): keep release changelog formatter-owned

* chore(tooling): retain compatible Node type surface

* ci: enforce formatting for docs-only changes

* ci: isolate docs formatter check

* chore(tooling): apply updated lint and format rules

* chore(tooling): satisfy updated switch lint

* style(ui): apply Linux formatter layout

* test(doctor): match quiet local audio contribution

* test(doctor): assert quiet output only

* test(doctor): follow restored information contract
2026-07-11 01:09:51 -07:00
Peter Steinberger
81ce206ee8 improve(control-ui): move dev branch badge to its own footer strip (#104300)
The sidebar footer icon row got crowded with the inline branch label.
The dev-checkout branch now renders on a slim tinted strip above the
icon bar with a git-branch icon, keeping the full name readable and
the footer controls uncluttered.
2026-07-11 01:05:15 -07:00
Peter Steinberger
ebc848deec feat: sidebar update card (web + macOS) with app-first mac update flow and Sparkle beta track (#104171)
* feat: sidebar update card (web + macOS) with app-first mac update flow and Sparkle beta track

Squashed from claude/update-notification-display-c6cfb9 after semantic merge
with #104178 (channel-aware CLI installs). See PR #104171 body for details.

* chore(i18n): resync generated inventories after rebase

* chore(i18n): resync locale metadata after rebase
2026-07-11 00:34:10 -07:00
Peter Steinberger
7da12cbbe5 feat(ui): sweep a text wave across the active tool row while it runs (#104266) 2026-07-11 00:28:33 -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
5b451b5d1c fix(ui): floating chat rail toggles overlap message bubbles and block window dragging (#104247)
* fix(ui): move floating chat rail toggles into a single top row inside a titlebar band

The workspace and background-tasks openers stacked vertically over the
chat thread and covered the first message. They now sit side by side in
one 28px row, the thread reserves a ~44-52px top inset that keeps them
clear of bubbles, and empty band background starts a native window drag
in the macOS app (same beginNativeWindowDrag contract as pane headers).
Split panes keep their compact inset since the pane header already owns
the top row.

* test(ui): own the titlebar-band drag in native-window-drag and cover it with tests

Moves the top-inset drag logic from an inline chat-thread closure to
beginNativeWindowDragFromTopInset next to its sibling handler, and adds
jsdom regression tests for in-band background presses, below-band
presses, and presses on scrolled-under content.
2026-07-11 00:21:31 -07:00
Peter Steinberger
34a8472274 fix(ui): tone down hover/click control shadows; show dev build identity in status tooltip (#104215)
* fix(ui): tone down hover/click control shadows via theme tokens

* feat(ui): show dev build identity in gateway status tooltip
2026-07-11 00:13:36 -07:00
Peter Steinberger
f94a7dc183 feat(codex): supervise native Codex sessions (#104045)
* feat(codex): add native session supervision

* fix(codex): harden supervision integration

* fix(codex): preserve locked harness ownership

* fix(codex): fence native session archive

* fix(codex): revalidate archive binding ownership

* feat(codex): integrate supervision runtime

* feat(sessions): preserve harness-owned execution

* feat(sessions): persist harness ownership invariants

* feat(gateway): enforce harness-owned sessions

* feat(setup): enable detected Codex supervision

* feat(mac): expose supervised Codex sessions

* feat(ui): make Codex sessions actionable

* docs(codex): document session supervision

* test(codex): cover integration ownership

* chore(i18n): refresh supervision inventories

* fix(setup): finalize Codex activation atomically

* test(codex): narrow binding store update

* fix(sessions): preserve legacy model locks

* test(macos): serialize Codex catalog fixtures

* fix(sessions): preserve legacy lock admission

* chore(i18n): reconcile supervision metadata

* test(sessions): mark legacy lock fixture

* fix(macos): drain final Codex catalog frame

* docs: leave supervision note to release

* style(macos): satisfy Codex catalog type length

* chore: record session accessor seam owners

* fix(macos): honor configured Codex supervision

* fix(codex): preserve harness-owned model locks

* fix(codex): satisfy supervision lint gates

* chore(i18n): refresh native supervision inventory

* fix(codex): align supervision validation contracts

* fix(codex): close supervision boundary gaps

* fix(codex): preserve supervision activation contracts

* fix(codex): dispose standalone supervision runtime

* fix(codex): pin supervised source connection

* fix(plugins): bind delegated runs to exact session target

* fix(codex): scope supervised sessions to configured agents

* fix(codex): fingerprint effective supervision home

* fix(codex): normalize supervision plugin policy

* fix(codex): keep supervised bindings stable across upgrades

* fix(codex): guard all supervised binding connections

* fix(codex): preserve catalog filters and pending CAS identity

* fix(codex): preserve supervision identity for diagnostics

* fix(codex): bind uncertain commits to supervision connection

* fix(codex): satisfy supervision type boundaries

* fix(macos): reconcile current main validation

* fix(codex): handle absent runtime config in supervision

* fix(doctor): own local audio acceleration check

* fix(codex): satisfy integration lint gates

* fix(codex): satisfy lifecycle safety guards
2026-07-11 00:12:08 -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
10820e9c03 fix(ui): resolve global-alias session kinds for chat avatar mode (#104155)
* fix(ui): resolve global-alias session kinds for chat avatar mode

* fix(ui): borrow only the session kind from alias-matched global rows

* fix(ui): gate the global-row kind fallback on configured global scope

* fix(ui): classify global-scope aliases without requiring a listed row
2026-07-10 22:40:35 -07:00
Peter Steinberger
1a7827c020 fix(ui): suppress tooltips that repeat fully visible trigger text (#104193)
Hovering a model row in the chat model picker showed a tooltip that just
echoed the row's own label. The shared openclaw-tooltip now skips opens
whose content is already fully visible inside the trigger, while keeping
the full-text tooltip for clipped/ellipsized labels.
2026-07-10 22:40:17 -07:00
Peter Steinberger
cb64117416 feat: session menu adds Open PR, Open in editor, and numbered group shortcuts (#104154)
* feat(ui): add Open PR, Open in editor, and numbered group shortcuts to the session menu

* fix(ui): lift session menu to popover top layer and use shadow tokens
2026-07-10 22:17:18 -07:00
Peter Steinberger
e0862e609a feat(ui): hide chat avatars in direct sessions (#104092)
* feat(ui): hide chat avatars in direct sessions

* fix(ui): classify direct threads from full history, not the render window

* fix(ui): classify direct threads by canonical session kind

* fix(ui): match session metadata across equivalent alias keys in the chat thread

* fix(ui): classify unmatched chat sessions by canonical key shape

* fix(ui): keep avatars in global sessions that can aggregate group senders

* docs(ui): note global-alias limitation on chat avatar classification
2026-07-10 20:00:44 -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
add44b19f1 improve(ui): replace background tasks rail chips with a quiet status line (#104074) 2026-07-10 19:33:06 -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
0ca8237905 fix(ui): keep raw ids out of sidebar session rows and stop WebKit section overlap (#104062) 2026-07-10 19:14:51 -07:00
Peter Steinberger
b7156ce688 fix(macos): drag the window from split-view pane headers (#104048)
* fix(macos): drag the window from split-view pane headers

In the macOS app, split-screen pane header rows (session title strip) now
start a native window drag instead of selecting the title text. The Control
UI posts an openclawWindowDrag script message on mousedown over passive
header chrome; the dashboard window validates the trusted main-frame source
and the in-flight left-mouse press before calling NSWindow.performDrag.
Pane headers are chrome, so they are also no longer text-selectable.

* refactor(macos): move the dashboard failure page out of the window controller

SwiftLint type_body_length: the drag-message handler pushed
DashboardWindowController past 800 lines; the failure-page HTML is
presentation-only and now lives in DashboardFailurePage.
2026-07-10 19:07:04 -07:00
Peter Steinberger
67e1d43911 fix(ui): preserve UTF-16 workshop previews (#104047) 2026-07-10 18:45:04 -07:00
Peter Steinberger
c34ada31c5 feat(ui): hover-revealed chat message meta with relative timestamps (#104035)
* feat(ui): hover-revealed chat message meta with relative timestamps

* fix(ui): derive relative chat timestamps from the injected clock

* fix(ui): date far-future chat timestamps instead of clamping to just now

* fix(ui): invalidate memoized chat thread on relative-time ticks

* fix(ui): keep relative-time ticks out of the chat live region
2026-07-10 18:30:01 -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
e07ad4b05b fix(ui): draw resize dividers as a thin line instead of a filled gutter bar (#104013) 2026-07-11 01:45:07 +01:00
Peter Steinberger
ee7c2c1455 feat(ui): render assistant replies as a flat text stream in web chat (#104016) 2026-07-11 01:43:37 +01:00
Peter Steinberger
62d10f7b84 improve(ui): drag sidebar group headers to reorder custom groups (#103997)
* improve(ui): drag sidebar group headers to reorder custom groups

* test(ui): repair sidebar group e2e for the gateway-owned catalog
2026-07-11 01:39:47 +01:00