Commit Graph

56 Commits

Author SHA1 Message Date
Simon-XYDT
bb16ca50d6 fix(identity): keep bounded identity values UTF-16 safe (#103034)
* fix(identity): keep bounded values UTF-16 safe

Co-authored-by: simon-w <weng.qimeng@xydigit.com>

* test(identity): cover reachable surrogate boundary

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-09 21:27:01 +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
428c68a3c7 feat: show provider plan usage (5h/weekly/credits) in the chat context popover, keep API cost for API billing (#102784)
* feat(usage): route claude-cli to Anthropic plan usage with plan label and billing

* feat(webchat): redesign context popover with plan-usage bars and API-cost gating

* fix(usage): match plan usage across CLI provider aliases and source plan label from synced auth profile

* docs(plugins): document plan metadata on usage auth token

* chore(usage): document provider-level billing attribution limits, fix overview test types

* fix(webchat): avoid map-spread in quota group collection

* test(webchat): deflake subscription popover reset fixture
2026-07-09 15:36:13 +01:00
Peter Steinberger
f9bafcc240 feat(ui): show agent avatars in the agents page selector (#102817)
Replace the native <select> on the Agents page with an accessible custom
listbox dropdown (openclaw-agent-select) that renders each agent's avatar
image, identity emoji, or initial. Local /avatar/<id> routes are fetched
with the bearer credential and rendered as cached blob URLs when gateway
token auth is active, matching the chat-avatar contract.

Refs #102792, #57067
2026-07-09 14:55:25 +01:00
Peter Steinberger
deb7faf7b0 refactor(ui): harden Lit lifecycle boundaries (#102745)
* refactor(ui): harden Lit lifecycle boundaries

* fix(ui): clear ChatPage subscriptions before teardown

* test(ui): satisfy lifecycle lint gates

* chore: defer Lit lifecycle release note

* fix(ui): sync raw-copy baseline

* test(ui): avoid order-sensitive Sessions mock

---------

Co-authored-by: Peter Steinberger <peter@steipete.me>
2026-07-09 05:28:52 -07:00
Vincent Koc
aaf5ddd832 refactor(ui): localize internal declarations (#102793) 2026-07-09 05:16:06 -07:00
Peter Steinberger
8d6c54f513 improve(ui): remove the Context Profile presets card from Quick Settings (#102748)
* fix(control-ui): remove the Context Profile presets card from Quick Settings

* fix(control-ui): regenerate i18n raw-copy baseline after Gateway Host card rebase
2026-07-09 12:50:50 +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
bcc4517d99 test(ui): align sidebar ordering coverage (#102660) 2026-07-09 11:37:09 +01:00
maweibin
9bf212765f fix(ui): keep workboard capture text truncation UTF-16 safe (#102544)
* fix(ui): keep workboard capture text truncation UTF-16 safe

Replace raw .slice(0, N - 3) with truncateUtf16Safe in
clampSessionCaptureText and clampSessionCaptureTitle to prevent
lone surrogates when emoji cross the truncation boundary.

Completes the UTF-16 hardening started in #101685, which added the
import but only covered buildCardSessionLabel.

* test(ui): cover workboard UTF-16 boundaries

* docs(changelog): note Workboard UTF-16 fix

* docs(changelog): leave release notes to release flow

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-09 10:42:34 +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
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
zw-xysk
57db713ff7 fix(ui): keep clampText/truncateText surrogate-safe at emoji boundaries (#102225)
* fix(ui): keep clampText/truncateText surrogate-safe at emoji boundaries

clampText and truncateText in format.ts used String.prototype.slice(0, N)
to truncate user-visible text. When the truncation boundary falls inside
a UTF-16 surrogate pair (emoji, CJK extended, etc.), the resulting
string contains a dangling surrogate that browsers render as U+FFFD (�).

Replace .slice(0, ...) with truncateUtf16Safe(...) which skips past
incomplete surrogate pairs so the truncation point always falls on a
code-point boundary.

Affected UI surfaces: markdown rendering, command descriptions, skill
summaries, exec-approval rules, tool-stream output previews.

Add surrogate-safe truncation test cases for both functions using a
real emoji at the exact truncation boundary.

* test(ui): tighten UTF-16 truncation coverage

---------

Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-09 04:46:36 +01:00
Vincent Koc
9dbb1ed3d2 refactor(deadcode): localize control ui declarations (#101894) 2026-07-07 15:34:09 -07: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
Vincent Koc
3d206140f3 refactor: localize internal implementation constants (#101758) 2026-07-07 08:34:13 -07:00
Peter Steinberger
87fe266c5e fix: preserve emoji at remaining bounded-text edges (#101711)
* fix: keep remaining text bounds UTF-16 safe

Co-authored-by: ben.li <li.yang6@xydigit.com>
Co-authored-by: 0668001336 <wang.lizhang@xydigit.com>
Co-authored-by: Alix-007 <li.long15@xydigit.com>

* docs: credit bounded Unicode fixes

* test: update UTF-16 browser import boundary

* chore: leave Unicode note to release changelog

---------

Co-authored-by: ben.li <li.yang6@xydigit.com>
Co-authored-by: 0668001336 <wang.lizhang@xydigit.com>
Co-authored-by: Alix-007 <li.long15@xydigit.com>
2026-07-07 15:48:21 +01:00
Vincent Koc
c8d95da14c refactor: localize file-private exports (#101701) 2026-07-07 06:57:19 -07:00
Peter Steinberger
a7faec8ca1 fix(gateway): support native Windows exec approvals (#101669)
* fix(gateway): support native Windows exec approvals

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>

* chore: defer changelog entry to release

* test: use tracked approvals temp directories

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
2026-07-07 14:50:59 +01:00
Peter Steinberger
176fee5d07 fix: prevent garbled emoji at remaining text limits (#101685)
* fix: keep remaining bounded text UTF-16 safe

Co-authored-by: 0668000787 <ma.weibin@xydigit.com>
Co-authored-by: ben.li <li.yang6@xydigit.com>
Co-authored-by: 廖石荣 0668000909 <liao.shirong@xydigit.com>
Co-authored-by: 陈志强0668000989 <chen.zhiqiang1@xydigit.com>

* test: use tracked prompt template fixture

---------

Co-authored-by: 0668000787 <ma.weibin@xydigit.com>
Co-authored-by: ben.li <li.yang6@xydigit.com>
Co-authored-by: 廖石荣 0668000909 <liao.shirong@xydigit.com>
Co-authored-by: 陈志强0668000989 <chen.zhiqiang1@xydigit.com>
2026-07-07 14:49:15 +01:00
Vincent Koc
60f0749b7f refactor(ui): remove duplicate helper paths (#101647) 2026-07-07 05:21:29 -07:00
Vincent Koc
2ba622ca30 refactor(ui): trim unused control UI helpers (#101632) 2026-07-07 04:55:28 -07:00
Vincent Koc
7e995cbf2b refactor(ui): remove stale helper exports (#101549) 2026-07-07 02:49:42 -07:00
Jason (Json)
521bf99f17 fix(ui): clear stale sidebar run state after chat final (#101293)
Merged via squash.

Prepared head SHA: 32a33eb4cd
Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com>
Reviewed-by: @fuller-stack-dev
2026-07-07 01:04:00 -06:00
Jason (Json)
e024eacf17 fix(ui): preserve login across same-origin gateways (#101352)
* fix(ui): scope device auth by gateway

* fix(ui): migrate legacy device auth storage

* test(ui): cover gateway device-token isolation
2026-07-07 00:51:19 -06:00
Vincent Koc
835e6a7532 refactor(ui): localize unused module exports (#101339) 2026-07-06 21:20:18 -07:00
Vincent Koc
62e5d4406d refactor(ui): remove unused module exports (#101262) 2026-07-06 20:20:06 -07: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
Jvle
f309c6054b fix(ui): preserve chat scroll when copying code (#100807)
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-07 03:22:14 +01:00
Vincent Koc
775ef966c3 refactor(deadcode): localize internal type aliases (#101243) 2026-07-06 17:57:32 -07:00
Vincent Koc
9d86728795 refactor(ui): localize internal type exports (#101165) 2026-07-06 17:28:31 -07: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
Jason (Json)
17d3c2eb0a feat(ui): redesign chat composer controls (#100461)
* feat(ui): redesign chat composer controls

* fix(ui): preserve scoped chat model catalogs

* fix(ui): honor configured default agent in chat commands

* fix(ui): align composer translations and tests

* test(ui): expect cached chat commands

* fix(ui): inset composer attachment previews

* fix(ui): add attachment preview top padding

* fix(ui): preserve composer layout after main merge

* fix(ui): keep abort available during voice input

* fix(ui): merge duplicate model provider groups

* feat(ui): finalize chat composer redesign

* fix(ui): refine composer layout and scroll indicators

* fix(ui): align composer with chat column

* fix(ui): restore composer max width

* fix(ui): match composer Codex width

* fix(ui): stabilize chat composer controls

* docs: refresh generated map

* fix(ui): discard rejected model drafts

* fix(ui): clear chat composer CI gates

* test(ui): await rejected model rollback

* fix(ui): address chat composer review findings

* fix(ui): preserve default provider ordering

* fix(ui): stage model picker changes until save

* fix(ui): scope model picker drafts to chat context

* fix(ui): align composer drafts and message actions

* fix(ui): preserve reasoning rendering

* feat(ui): refine chat composer interactions

* fix(ui): repair chat composer CI checks

* fix(ui): repair chat composer integration checks

* fix(ui): translate chat composer labels

* fix(ui): restore mobile camera action

* test(ui): target visible attachment control

* test(ui): locate attachment disclosure directly

* fix(ui): preserve composer control ordering

* test(ui): track current composer controls

* fix(ui): honor terminal active-run state

* fix(ui): guard command metadata ownership

* fix(ui): stage agent model defaults

* fix(ui): preserve chat settings and scroll signals

* fix(ui): reconcile merged chat controls

* fix(ui): localize Talk composer options

* test(ui): infer chat control props

* fix(ui): refresh agent model metadata on session switch

* style(ui): format merged chat controls

* test(ui): avoid shadowed composer geometry names
2026-07-06 16:18:36 -06:00
Peter Steinberger
e9464313b7 feat(ui): polish sidebar rail and hide disabled Workboard nav (#101123) 2026-07-06 20:31:57 +01:00
ZZIPP
979d198fd1 fix(media): recognize m2a as MPEG audio (#92167)
Co-authored-by: Peter Steinberger <steipete@gmail.com>
2026-07-06 17:48:37 +01:00
Dallin Romney
5af7ba92ce refactor: consolidate byte-size formatting (#99768)
* refactor: consolidate byte-size formatting

* fix: stabilize byte formatter import boundary

* fix: keep byte formatter within SDK budget

* fix: emit byte formatter package entry

* refactor: trim byte formatter surface

* fix: use narrow byte formatter import

* refactor: remove byte formatter dependency changes

* fix: refresh rebased byte formatter baseline
2026-07-06 09:26:04 -07:00
Shakker
67ec544884 fix: keep new sidebar sessions visible (#100981) 2026-07-06 16:48:53 +01:00
Peter Steinberger
add5c513ae feat(ui): stable session order, palette-only search, and macOS titlebar brand for the sidebar (#100648)
* feat(ui): declutter the sidebar — pinned/chats groups, stable ordering, palette session search, titlebar brand in macOS app

- Sessions split into Pinned and Chats groups; pins are exempt from the
  nine-row recency cap and the open session highlights in place instead of
  hoisting to the top, so clicking a row no longer reshuffles the list.
- The command palette (Cmd+K) is the single search: it queries sessions
  across agents server-side and lists matching chats next to nav commands;
  the sidebar session-picker popover and its magnifier are removed, and the
  topbar search pill shrinks to an icon button.
- The sidebar brand row is gone: web keeps the breadcrumb wordmark, and the
  macOS app shows a compact brand mark in the native titlebar strip next to
  the traffic lights (CSS-gated on the injected openclaw-native-macos class).
- The agent filter dropdown becomes a compact scope chip in the Chats group
  header; the welcome badge drops its duplicate claw logo.
- Footer collapses to one icon row (status dot, settings, docs, pairing,
  mobile theme switch); default pinned nav routes are now Overview-only and
  the Recent-collapse preference is retired.

* test(ui): keep sidebar hover-reveal proof before the stability click; refresh locale metadata

Clicking the row leaves :focus-within on it, which keeps the management
actions visible; the hidden-actions assertion must run first.

* test(ui): archive an idle session in the sidebar e2e; assert running rows stay archive-disabled

* fix(ui): drop stale and hidden rows from palette session search

Invalidate the in-flight search and clear results on every query change so a
late-resolving previous-query request cannot leave stale rows selectable, and
run results through getVisibleSessionRows so archived/global/unknown/cron/
subagent rows stay hidden like the sidebar list. Codex review findings.

* fix(ui): over-fetch palette session search so hidden rows cannot starve visible matches

Exclude global/unknown rows server-side and fetch a full 50-row page before
applying the sidebar's hidden-row filter, keeping the 10-row display cap.
Codex review finding.

* chore(i18n): refresh sidebar locale metadata after rebase

* fix(ui): bound command palette session search

* docs: defer release notes to release generation
2026-07-06 16:38:26 +01:00
Shakker
2a02379e7d fix: preserve sidebar session position 2026-07-06 16:09:44 +01:00
Vincent Koc
0ecfc522db refactor(ui): trim unused type surface (#100952)
Fixes #100951
2026-07-06 08:04:18 -07:00
Vincent Koc
5733fb0e19 refactor(ui): localize internal-only symbols (#100931) 2026-07-06 07:28:48 -07:00
Peter Steinberger
88f1ec38d4 feat(sessions): grouping, unread state, and full session controls on web, iOS, and Android (#100814)
Gateway (additive, no protocol version bump): SessionEntry gains
lastReadAt/markedUnreadAt/lastActivityAt; session rows expose a derived
unread flag (explicit mark, or last read before latest activity; never-read
sessions stay read so upgrades do not light up). lastActivityAt is stamped
in the canonical post-run store update - user, channel, and cron runs count
as activity; heartbeat, internal-event, and preserved-state runs do not.
sessions.patch gains unread; sessions.create gains fork (transcript fork
from parentSessionKey under the parent lifecycle lock, refusing active,
concurrently-changed, and oversized parents, cross-agent aware).

Web sidebar: Pinned/custom-group/Ungrouped sections, unread dots, kebab and
right-click context menu (pin, mark unread/read, rename, fork, move to group,
archive, delete guarded for agent main sessions and active runs), mark-read
on view with loop-safe re-acknowledgement and failure retry; sessions page
gets unread + fork actions and shared custom-group helpers.

iOS Command Center: grouped sections, unread/pin indicators, Show Archived
gated on per-entry state, full context menu with rename/new-group alerts and
delete confirmation, current-session preview guarantee, read-episode
re-acknowledgement; new patch/delete/fork transport calls; Swift protocol
models regenerated.

Android SessionsScreen: grouped headers, unread/pin indicators, Archived
filter gated on per-entry state, long-press menu with the full control set,
agent-scoped forks, explicit label/category clears from session events,
main-session fallback when archiving/deleting the open chat, read-episode
re-acknowledgement with failure retry.

Closes #100739
2026-07-06 14:30:55 +01:00
Vincent Koc
6418e196b1 refactor: remove unused internal exports (#100882) 2026-07-06 05:59:18 -07:00
Vincent Koc
17777b3a9f refactor: remove proven dead code across runtime surfaces (#100823)
* refactor: remove unused internal helpers

* refactor(ui): remove unused compatibility helpers

* refactor(android): remove unused talk cleanup shim

* refactor(android): remove orphaned legacy UI

* refactor: remove unused private exports

* refactor(docs-i18n): remove dead matcher and satisfy lint
2026-07-06 03:31:19 -07:00
Peter Steinberger
b4b1984fe7 feat(gateway): start a new chat session in a managed worktree (#100788)
Adds an additive worktree flag to sessions.create so any new chat can run in an
isolated managed worktree of the agent's git workspace, with the branch checked
out and .worktreeinclude provisioning applied. The session's spawnedCwd points at
the matching subdirectory inside the worktree so chat runs, CLI, and the file
browser execute there. agents.list gains workspaceGit (workspace or an ancestor
is a git checkout) to gate the affordance; web sidebar, iOS, and Android expose a
New-Chat-in-worktree action. Uses the method's operator.write scope, but the
.openclaw/worktree-setup.sh step runs only for operator.admin callers since it
executes repo code. Deleting the session, or leaving via a plain New Chat, clears
the cwd and lossless-removes the worktree; idle GC treats recent session activity
as worktree activity so an active session's checkout is never swept.

Live-verified end-to-end on a real gateway; follow-up to #100535 (issue #100534).
2026-07-06 10:23:41 +01:00
Peter Steinberger
1b44efec8c feat(ui): redesign session goal into interactive composer pill with elapsed time and /goal edit (#100736)
* feat(ui): redesign session goal into interactive composer pill with elapsed time and /goal edit

* docs: align goal command table cell padding

* docs: regenerate docs map for goal Control UI section
2026-07-06 09:42:49 +01:00
Peter Steinberger
5f3629e944 fix(ui): show selected agent default model (#100719)
Co-authored-by: Harry Xie <harryhsieh963@yahoo.com>
2026-07-06 09:41:38 +01:00
Peter Steinberger
60cf7eaa00 feat(ui): make the sidebar session-first and minimal (#100386)
* feat(ui): bolder sidebar minimalism — pinned/chats session groups, compact icon footer, no brand header

* test(ui): align fixtures with single default pinned route; document pinned-cap invariant

* fix(ui): preserve sidebar session groups

* fix(ui): polish minimal sidebar behavior

* fix(ui): avoid duplicate pinned chat fallback

* docs(changelog): note sidebar layout refresh

* chore(i18n): preserve sidebar locale metadata

* fix(ui): reuse localized sessions label

* test(ui): follow localized sessions label

* chore(ui): trim sidebar landing churn

* docs(ui): update minimal sidebar guidance
2026-07-06 02:08:02 +01:00
Peter Steinberger
89ef6632de feat(ui): scroll truncated sidebar session names on hover (#100276)
* 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
2026-07-05 10:29:46 -07:00
Peter Steinberger
f607ba0691 feat(control-ui): session grouping with drag & drop and channel categorization (#100262)
* 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
2026-07-05 09:13:17 -07:00