* feat(ui): finish the chat session → thread rename across the Control UI
Completes the #110933 creation-surface rename mechanically: Threads page
(title, filters, archive/delete/rename/pin menus, transcript search),
sidebar labels and menus, welcome suggestion, palette category, tools
availability copy, workboard lifecycle/card strings, dreaming history,
board/diff/workspace-rail chrome, and the untitled main/channel fallback
names. Technical identifiers stay: Session ID, session keys, terminal
sessions, protocol wording. Living docs updated (control-ui.md);
historical release notes left as shipped.
* style(ui): format session-management e2e
* fix(ui): finish thread rename in navigation labels and stale test literals
Codex review caught the palette Threads entry and the Worktrees owner
column still saying Session; CI caught test literals asserting the old
copy (Threads page overview tile, filter tooltips, group counts, catalog
terminal notice, create-rejection error, workboard lifecycle hint). Also
completes the usage-stat cluster (Threads + hints) and the tool-catalog
group label. Native app strings (iOS/Android/macOS) keep session wording
and reconcile through their own i18n pipelines as a follow-up.
* docs: add The main session concept page and cross-links
* docs: precise memory-priming wording on the main-session page
* docs: update Control UI sidebar description to the Home and zones model
* feat(chat): rewind and fork a session from a message bubble
* docs(web): document chat rewind and fork bubble actions
* fix(chat): lint cleanups, protocol regen, and test splits for rewind/fork CI
* fix(ui): fit chat rewind disabled styles inside the startup CSS budget
* feat(mac): show native notification permission in dashboard Notifications settings
The Mac app's embedded Control UI showed the web-push section as
Unsupported/Not subscribed even though the app delivers notifications
natively. The dashboard now installs an openclawNotifications WebKit
bridge (status / request-permission / send-test) and the Notifications
settings page renders native permission state with Enable, Open System
Settings, and Send test actions when hosted in the Mac app. Browsers
keep the existing web-push UI. The notifications section renderer moved
out of the oversized config view module.
* fix(ui): break config view import cycle and satisfy lint/deadcode/i18n gates
Move the notifications section props to a leaf contract (no view.ts
type import), unexport the status-event constant, use bracket access
for the injected dunder global, default-case the status switch, and
refresh the native i18n inventory line offset.
* feat(ui): manage MCP servers directly on the Settings MCP page
* refactor(ui): mcp config section owned by the MCP settings page only
* chore(ui): drop test-only McpServersCard export for knip
* fix(gateway): emit config.changed from the reload committer for every accepted write
Agent config_set, CLI, and doctor writes reach the gateway through the file
watcher's reload path, which never broadcast config.changed - only direct RPC
writes did. Move the broadcast to a single onConfigCandidateCommitted hook in
the reload committer so all writers notify connected UIs, including
runtime-skipped commits (writer-intent echo suppression, reload mode off),
and delete the duplicate RPC-side broadcasts.
* feat(ui): sync chat follow-up and commentary prefs across devices
Add chatPersistCommentary and chatFollowUpMode to the ui.prefs sync surface
(schema, types, docs) with clearable null removal for the follow-up override.
Rewrite server-prefs around a descriptor table so a synced pref is one entry
instead of five hand-written code sites. Caption synced rows/sections
(chat prefs, theme, language) and refresh the stale Settings subtitle.
* refactor(ui): dedupe settings constants, drop dead composer branch, refresh copy and docs
Derive the Security tool-profile options from PROFILE_OPTIONS and General's
thinking levels from BASE_THINKING_LEVELS instead of parallel literals.
Remove the unused composer mode:"model" branch, the orphaned
.config-view-toggle CSS family, and stale quick-settings wording. Add static
settings-search entries for the Sessions and Managed Worktrees pages plus a
provenance-row test, and update docs/cli/openclaw.md to describe the current
system-agent config-write policy (denylist roots, route-backing plugin guard,
per-agent routing escalations).
* chore: refresh plugin SDK API baseline after rebase onto current main
- gateway broadcasts a hash-only config.changed event after every
persisted config write (operator.read scoped); the Control UI refreshes
its snapshot on the event so agent-approved ui.prefs changes apply live
on every connected client (skipped while a local draft is dirty)
- the chat composer's model picker shows provenance — 'Using default
from Settings' vs 'Session override' with an icon reset back to the
default — mirroring the existing reasoning-row anatomy
- the AI & Agents settings page is renamed Agent Defaults to separate it
from the per-agent Agents manager
- Memory Import renders through the settings design language (sections,
rows, toggle, status badges); only the collection review list, apply
report, skeleton, and confirm dialog keep custom markup, and the dead
bespoke CSS is pruned
* refactor(ui): restructure Settings IA around user-facing pages
Settings sidebar shrinks to settings-only destinations grouped by attention:
General/Appearance/Notifications up top, Connections, Agents & Tools,
Privacy & Security, System. Sessions, Worktrees, Activity, and Memory
Import leave the takeover: Sessions/Activity return to the workspace
sidebar, Worktrees becomes a Sessions hub tab, Memory Import is reached
from the Agents memory panel. Model Setup becomes a Models subpage.
New config pages: Notifications (web push), Privacy & Security (curated
policy rows + security/approvals schema sections), Advanced (uncurated
schema sections + raw editor, replacing the General quick/advanced
toggle). General slims to model defaults, language, and gateway host;
identity moves to Profile, lobster appearance rows to Appearance.
* feat(agents): widen system-agent config writes to operator parity
Every config surface the Control UI can edit is now agent-writable behind
the exact-operation human approval gate, except a small documented
denylist ($include, auth, env, models, secrets). tools.* and
plugins.entries.* writes are allowed; plugin_uninstall works for plugins
that provably do not back the active default inference route (fail closed
otherwise); set_default_model takes an optional agentId and live-tests a
per-agent model with the same rigor as the default route. Per-agent
routing fields on non-default agents are direct-writable; the default
agent's route keeps the verified set_default_model/onboard paths. A new
config-write-parity contract test forces explicit classification of every
top-level config key.
* feat(ui): sync operator display prefs through config ui.prefs
Theme, theme mode, text scale, locale, and chat display prefs get a
canonical server-side home in config ui.prefs. The Control UI mirrors
them into localStorage for instant boot, writes local changes through to
the gateway (best-effort; viewer-scope or offline clients stay
device-local), and applies server-side deltas on connect and on every
config snapshot reload — so an agent changing the theme through the
approval gate takes effect in the UI, and prefs follow the operator
across devices.
* chore: prune quick.ts from max-lines baseline after slim-down
* style: oxfmt changed files
* chore: regenerate plugin-sdk api baseline for ui.prefs config surface
* fix: dedupe runPluginUninstall dep type and narrow locale extraction
* docs: update Control UI settings structure and ui.prefs sync
* fix: address autoreview findings on parity guards and prefs sync
- plugins.entries.* config writes get the same active-route ownership
check as plugin_uninstall (fail closed when unprovable)
- system-agent prompt now describes the guarded write policy instead of
the old blanket refusals
- per-agent set_default_model logs the agent-scoped label
- legacy /config?section=... deep links redirect to the Advanced page
- prefs sync: pushes coalesce and drain serially (no CAS races dropping
updates), replaced config hashes mark pre-patch snapshots as stale, and
the last-seen server value persists per gateway scope so reloads cannot
revert unpushable viewer-scope edits
- lint: theme membership checks use Sets
* fix: harden uninstall route guard and scope prefs queue per gateway
- plugin uninstall ownership now covers execution owners (runtime policy,
embedded harness override) in addition to the provider, and re-verifies
inside the commit boundary so a concurrent route switch cannot slip a
destructive uninstall past the pre-approval check
- prefs push queue binds to one gateway client; switching gateways drops
the old queue (device-local fallback) instead of cross-writing prefs
* style: top-level type import in config-page test
* fix: close review races in config-write guards and prefs reconciliation
- config_set/config_set_ref re-verify the inference-route guard inside
the commit boundary so conditional verdicts (per-agent routing, plugin
entries) cannot be flipped by a concurrent edit after approval
- server prefs apply per changed field, so a server change to one pref
no longer reverts unpushable local edits of the others
- replaced-hash staleness retires once post-patch state is observed, so
a genuine restore of the pre-patch config becomes authoritative again
- moved-section deep links (communications notifications, automation
approvals) redirect to their new pages
* style: satisfy no-useless-assignment and loop-condition lints in prefs sync
* fix(ci): resolve unhandled profile-test rejections and knip unused exports
The profile page's new identity section reads context.config; the test
context mock now provides it, eliminating the unhandled rejections that
failed checks-ui and the compact-large shard. Exports flagged by the
dependency gate (extract/patch helpers, section-key and prop types) go
module-private; extraction coverage moves behind applyServerUiPrefs.
* refactor(agents): move config-write policy to its own module
The static path classifier and documented denylist move to
config-write-policy.ts, shared by the execution guard and the parity
contract test — no test-only exports left for the dependency gate to
flag. Blocked-root refusals now cite the denylist's documented
escalation for that root.
Stream bounded browser camera frames directly to Gemini Live and keep camera media off the Gateway. Add lifecycle, function-calling, fake-camera E2E, and live-smoke coverage.
Co-authored-by: shushushu <1064076525@qq.com>
* feat(ui): fold the mobile navigation row into the chat title bar
On plain-browser mobile layouts the chat route drops the 58px shell topbar;
the pane title bar gains a leading nav-drawer toggle and a trailing
command-palette search button (~50px more chat). The shared mobile-nav
breakpoint moves into one module used by shell and chat; native shells and
non-chat routes keep today's chrome.
* improve(ui): anchor the workspace chip right after the session title
The chip now hugs the title text with the header's standard gap instead of
sitting at the far right; the action cluster claims the leftover width and
stays right-pinned. Where field-sizing is supported the rename input hugs
its text too, so the chip tracks the title while typing.
* chore(ui): keep hasNativeShellClass module-local
* feat(gateway): add sessions.files.reveal to open a session workspace on the gateway host
Resolves the session's workspace root server-side (same resolution as
sessions.files.list), refuses exec-node and cloud-worker placements, and
opens the directory with the platform opener. The opener helpers move out
of config.ts into a shared open-path module that config.openFile now uses.
* feat(ui): always-on chat title bar with inline rename and workspace menu
Every chat pane now renders its header: click the session title to rename
it inline (Enter commits via sessions.patch, Escape cancels), a workspace
chip names the session's checkout with reveal/copy-path/copy-branch
actions, and cloud-worker sessions show a globe. The single-pane floating
toggle cluster and the transcript's reserved titlebar drag band fold into
the header, which keeps native macOS window dragging.
* fix(ui): resolve title-bar session aliases and clear the collapsed-nav overlay
Live verification found two gaps: route aliases like ?session=main showed
the generic key-derived title instead of the session's label (resolve via
hello defaults + key equivalence, matching the pane), and the floating
sidebar-expand pill overlapped the header title on plain web while the nav
was collapsed (52px inset, mirroring the native-shell clearances).
* fix(ui): keep the protocol schema layer out of the Control UI startup bundle
The title-bar change made session-row-badges runtime-import the
gateway-protocol barrel for one classifier, dragging typebox and every
schema into startup JS (395 KiB gzip vs the 370 KiB budget). The placement
vocabulary now lives in a dependency-free session-placement-state module:
the schema union derives from it, the barrel re-exports it, and the UI
deep-imports it (startup back to 361.8 KiB).
* fix(gateway-protocol): keep SessionPlacementStateSchema statically typed
Type.Union over a mapped array loses tuple inference and collapses Static
to never; the literal list stays explicit with a compile-time guard tying
it to the shared SESSION_PLACEMENT_STATES vocabulary.
* chore(protocol): regenerate Swift/Kotlin bindings for sessions.files.reveal
* chore: narrow new exports flagged by the deadcode gate
* chore(i18n): leave generated locale artifacts to the locale-refresh workflow
The generated-artifact isolation gate (067635cb51) landed mid-flight;
source PRs now carry en.ts only.
* feat(migrate): add Hermes memory-only import and a shared memory-import core
* feat(onboarding): offer detected memory imports during CLI setup and guided onboarding
* feat(ui): show a first-run memory-import offer in Control UI onboarding mode
* feat(linux-app): open the first-run dashboard in onboarding mode
* feat(macos): add the onboarding memory-import page
* docs: document the onboarding memory-import page across surfaces
* chore(i18n): translate onboarding memory-import strings for control-ui and native locales
* refactor: keep memory-import internals unexported for deadcode gates
* fix(ci): resolve lint findings in onboarding memory import
* chore(i18n): refresh native inventory after lint refactor
* fix(ci): skip updater artifacts in the unsigned Linux companion PR lane
* chore(i18n): reconcile locale artifacts after rebase
* feat(ui): add follow-up behavior setting (queue vs steer) for active runs
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* default follow-up behavior to steer
Follow-ups sent while a run is active now steer into the running turn by
default; queue mode becomes the persisted opt-out. Offline/disconnected
sends still always queue.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(ui): steer active follow-ups by default
---------
Co-authored-by: openclaw-clawsweeper[bot] <openclaw-clawsweeper[bot]@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Catalog session rows (sidebar context menu + click), the built-in viewer
header, and a new "Open Codex/Claude sessions in" preference can launch the
native CLI (codex resume / claude --resume) in the operator terminal on the
machine that owns the session.
- Gateway-local sessions spawn through the existing terminal launch policy
(sandbox/enabled gates preserved) with the resume command in the session cwd.
- Paired-node sessions run through a new seq-ordered node PTY relay: a
duplex node-host command streams PTY output via node.invoke.progress and
receives keystrokes/resize via a new node.invoke.input event, behind the
unchanged terminal.* client protocol (TerminalSessionManager gains a backend
abstraction; node relay reuses the streaming-invoke controller).
- Owner boundary: each plugin owns its resume command and builds argv from a
validated thread id; the gateway routes node opens through the node command
allowlist and plugin invoke policy (no advertisement-only trust), and nodes
re-verify session eligibility before spawning.
- UI setting catalogOpenTarget + canOpenTerminal capability gate every entry
point; capability requires the owning host to actually have the CLI.
Node PATH is normalized before command-availability probes, Windows .cmd/.bat
shims spawn via ComSpec, and catalog terminal opens reattach persisted tabs
before opening the new tab.
* feat(web): show session branch row for local changed files
The pre-PR branch row above the composer only appeared once the branch
was pushed and ahead of the default branch. Sessions with local work
(committed, uncommitted, or untracked changes) showed nothing.
The gateway now emits the branch payload whenever the working tree has
changed files vs the default-branch merge base; createUrl is withheld
until GitHub's pull/new page has something to compare, and the UI only
renders the Create PR link when it is present.
* refactor(gateway): keep control-ui-session-prs under LOC ratchet
* docs(gateway): note explicit-base diff counts conflict paths
Sessions is session management, not a day-to-day workspace destination.
It now lives in Settings under Agents & Tools at /settings/sessions,
with the old /sessions path kept as a route alias; stale pinned-route
prefs drop automatically via normalizeSidebarPinnedRoutes. Also repairs
the sidebar-customization e2e that #105777 broke on main by opening
Settings through the agent-chip menu.
The sidebar's expandable "MORE" section (uppercase header, chevron, persisted
sidebarMoreExpanded pref, dedicated "Edit pinned items" row) collapses into a
single More nav row that opens a transient popup menu with the unpinned
routes, dynamic plugin tabs, and the pin editor entry. Menu rows are real
anchors, so Cmd/middle-click keeps native link behavior; the More row carries
the active highlight when the current route lives inside the menu. The
sessions list gets the reclaimed vertical space, and one persisted setting is
gone (stale keys are ignored on load). The nav rows and menus move to
app-sidebar-nav-menus.ts to keep app-sidebar.ts under the TS LOC ratchet.
Docs: docs/web/control-ui.md sidebar-navigation section updated.
Fixes#105905
* feat(ui): add a Create PR branch row with rate-limit staleness to session PR chips
* fix(ui): gate the Create PR row on a pushed branch
* improve(ui): gate the Create PR row on comparable pushed commits and count untracked work
* fix(ui): satisfy spread lint and align branch-row test fixtures
* chore(ui): translate Create PR branch row copy
* chore(ui): drop zh-CN retranslation churn from the aborted backfill
* fix(ui): guard branch diff stats against checkout diff drivers and fail closed without a default branch
* feat(mac): swap dashboard titlebar buttons with sidebar state
The Control UI reports sidebar collapsed/width over a new openclawNav
WKScriptMessage; the titlebar accessory shows toggle+back/forward
right-aligned to the sidebar edge while expanded, and
toggle+search+new-session while collapsed. Search opens the command
palette and + opens the new-session surface via openclaw:native-*
events. Older gateway bundles that never report keep the shipped
toggle/back/forward layout.
Refs #105129
* docs: describe state-dependent mac titlebar buttons
Rebuilds the Control UI cron page as a sidebar-first Automations master-detail workspace: a task list pane (All/Active/Paused tabs, search, filter popover, curated emoji suggestion cards, scheduler footer) beside a detail pane that edits the selected task inline (prompt, row-style Details/Frequency groups, collapsible Advanced, per-task run history) and shows all-task recent activity when nothing is selected. Create & run now kicks a new task immediately after creation. The modal editor and quick-create wizard are retired; the automation-ideas catalog from #104761 is ported into the new suggestions list. Nav item renamed to Automations and pinned by default; route (/cron) and cron.* RPC contracts unchanged.
Closes#104217
Co-authored-by: Claude <noreply@anthropic.com>