* feat(ui): worktrees page owners and creation, structured snapshot failures, preserved-checkout cleanup
- Worktrees settings page gains an Owner column (manual/Workboard/session
with a link into the owning chat) and a New worktree form with repo
default, optional name, and a worktrees.branches-backed base picker
- non-forced worktrees.remove snapshot failures are a structured
{ removed: false, snapshotError } result (typed WorktreeSnapshotError in
the service) instead of error-string sniffing in the UI
- deleting a session whose dirty/unpushed checkout was preserved now
reports worktreePreserved through the session capability and offers an
explicit force removal instead of silently orphaning the checkout
Part of #103431
* fix(ui): report preserved checkouts from batch session deletes
deleteMany now aggregates worktreePreserved results, and the Sessions
page surfaces one notice pointing at Settings -> Worktrees instead of
silently orphaning dirty checkouts during bulk deletion.
Part of #103431
* fix(ui): reconcile generated locale artifacts after rebase
* 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
* feat(gateway): session worktree targeting, branch listing, and group catalog
- sessions.create accepts worktreeBaseRef/worktreeName (write scope) and
execNode (admin); worktree binding persists on the session entry as
worktree { id, branch, repoRoot } and projects onto session rows with
execNode so UIs can show checkout/branch/node state
- new worktrees.branches RPC lists local/remote branches (no fetch) for
base-ref pickers; worktrees.remove now reports snapshotError
- sessions.delete reports preserved dirty checkouts as worktreePreserved
- gateway-owned session group catalog in the shared state DB with
sessions.groups.list/put/rename/delete; rename/delete update member
categories server-side without bumping recency; sessions.patch absorbs
ad-hoc categories into the catalog
- group session display names prefer the human chat title (subject or
space #channel) over stored compact tokens
Part of #103431
* fix(gateway): route group category updates through the session accessor and regen protocol models
- bulk member-category rename/clear uses applySessionEntryReplacements
instead of legacy updateSessionStore call sites (session accessor
boundary guard)
- regenerate Swift GatewayModels for the worktrees.branches schemas,
snapshotError, and new sessions.create params
Part of #103431
* fix(gateway): resolvable remote branch refs and workspace-scoped branch listing
- worktrees.branches returns remote-only branches remote-qualified
(origin/feature-a) so every advertised name works as a worktree base ref
- write-scoped worktrees.branches callers are limited to configured agent
workspaces; other host paths require operator.admin, matching the
sessions.create cwd bar
Part of #103431
* fix(gateway): guard worktree name reuse by owner and env-scope group transactions
- managedWorktrees.create rejects a caller-chosen name whose live or
restorable record belongs to a different owner, so write-scoped
sessions.create cannot bind a session into another session's or a
manual checkout
- session group catalog writes run their SQLite transaction on the same
env-scoped handle as their statements, keeping OPENCLAW_STATE_DIR
overrides atomic and away from the default state DB
Part of #103431
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).
Centralized managed worktrees under <state-dir>/worktrees/<repo-fingerprint>/<name>
with branch-per-task (openclaw/<name>), .worktreeinclude provisioning, an optional
.openclaw/worktree-setup.sh repo hook, and a SQLite registry in the shared state DB.
Removal always snapshots the tree (untracked included, gitignored excluded) to
refs/openclaw/snapshots/<id>; restore rebuilds the branch at the original commit with
the snapshot content as uncommitted state. Lossless run-end cleanup, 7-day idle GC for
run-owned worktrees (manual exempt), orphan reconciliation, 30-day snapshot retention.
Surfaces: worktrees.* gateway RPC (operator.admin mutations), openclaw worktrees CLI,
Control UI page, plugin-SDK facade + Workboard kind:"worktree" materialization.
E2E-verified on Testbox: full create->work->remove->restore->gc lifecycle.