Match the new-session composer geometry with chat, keep the model picker at the bottom right, and anchor its menu so it expands left. Add browser coverage for composer alignment and model-menu placement.
* fix(tui): keep the newer session when a stale switch history resolves last
setSession set state.currentSessionKey synchronously and then awaited
loadHistory, but nothing serialized overlapping switches. When a user
switched to session A then quickly to B, if A's loadHistory RPC resolved
after B's, A's completion saw sessionInfo.key !== the now-current key and
unconditionally reverted currentSessionKey, currentSessionId, and the
chat log back to A, and adopted A's in-flight run onto activeChatRunId.
The next typed message was then routed to A while the user believed they
were on B.
Give setSession and loadHistory a monotonic generation token, mirroring
the existing refreshSessionInfo overlap guard. setSession bumps the
generation and loadHistory captures it before the RPC, so a completion
whose generation is stale no-ops instead of clobbering the newer session.
* fix(tui): ignore rejected history from a superseded session switch
Guard the loadHistory catch path with the session-switch generation so a
stale switch whose history RPC rejects no longer writes a history-failed
notice into the session the user has since moved to.
Add a fake-backend PTY rapid-switch e2e test that drives the real runTui
loop and a reject-path regression test for the superseded-switch case.
* fix(tui): guard stale session refreshes
* test(tui): cover session alias canonicalization
* fix(tui): reject stale session refresh generations
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* feat(linux): canvas via CLI-node + Tauri app IPC bridge
* refactor: extract gateway helper modules
* build(linux-canvas): register plugin package in lockfile
* fix(linux-canvas): move canvas advertise test out of core, regen docs/protocol/deadcode
* fix(gateway): break node-catalog/registry import cycle via leaf normalize module; add canvas glossary term
* style: oxfmt invoke.ts and runtime.ts after buildNodeEventParams extraction
* fix(linux): load Canvas WebView via dedicated data_directory context
Wry's Linux/WebKitGTK incognito mode discards Tauri's registered
WebContext (wry webkitgtk/mod.rs), so the Canvas window got a fresh
ephemeral context without the openclaw-canvas:// scheme handler — the
bundled A2UI page never committed (stayed about:blank) and every A2UI
command timed out. Use an isolated cache-backed data_directory instead,
which keeps the protocol handler while still isolating Canvas storage
from the dashboard window.
* fix(linux): keep Canvas WebView ephemeral via incognito + data_directory
Autoreview flagged that a dedicated data_directory alone persists Canvas
browser state (cookies, localStorage, IndexedDB, service workers) across
restarts, so an agent that navigates Canvas to a site could leak an
authenticated session into a later session. iOS uses a non-persistent
store; Linux should match.
Add .incognito(true) alongside .data_directory(): the distinct directory
gives Tauri a fresh WebContext key so it still attaches the
openclaw-canvas:// protocol closure, and incognito makes Wry swap in a
fresh *ephemeral* context carrying those protocols. Live-verified on a
Wayland/WebKitGTK box: the bundled page still loads
(location.href=openclaw-canvas://localhost/index.html, openclawA2UI
present, A2UI renders) and the canvas-webview dir holds no persistent
cookie/storage files.
Successful Codex dynamic-tool results now use the shared failure classifier, preventing Skill Workshop and plugin lifecycle metadata from being persisted as failed calls.
Refs #107684.
Prepared head SHA: e5bfcdb085
Co-authored-by: Shakker <165377636+shakkernerd@users.noreply.github.com>
Reviewed-by: @shakkernerd
The Crestodian->OpenClaw reconciliation restored a pre-#102197 `if (opts.approved)`
wrapper around the execute-time plugin-install trust check, so an unapproved
plugin-install op produced a formatted plan for an arbitrary npm/url/file
source instead of rejecting it. Validate unconditionally, matching #102197,
and restore its dropped regression test. Also fix a stale
crestodian-ring-zero-setup id in the CI compat list and a doubled
openclaw-openclaw-planner tmpdir prefix from the mechanical rename.
* fix(sessions): wire SQLite transcript byte size into preflight compaction guard
readSessionLogSnapshot returned {} for SQLite-backed transcripts, so
maxActiveTranscriptBytes never saw a byte count and silently degraded to
token-only compaction triggering for every migrated session. Read the
size via readTranscriptStatsSync using the identity already encoded in
the SQLite sessionFile marker.
Fixes#104762
* test(memory): cover SQLite byte-triggered flush
---------
Co-authored-by: Peter Steinberger <peter@steipete.me>
Co-authored-by: Peter Steinberger <steipete@gmail.com>