* feat(ios): read-only offline cache for chat sessions and transcripts
Cache-first cold open for the iOS chat tab: the last known transcript and
session list render immediately from a local SQLite cache, then live gateway
history replaces them wholesale through the existing reconciliation path.
When the gateway is unreachable, recent sessions and transcripts stay
browsable read-only; sending remains gated by the existing connection state.
- New OpenClawChatTranscriptCache protocol seam plus SQLite-backed store in
OpenClawChatUI (raw SQLite3, no new dependencies), scoped per gateway
stableID so transcripts never leak across paired gateways.
- Bounds: 50 sessions, 50 transcripts, 200 messages per session; text rows
only (attachment/binary payloads and tool arguments are stripped).
- Disposable cache: schema versioned via user_version; any open/schema/decode
mismatch drops and rebuilds silently. File protection
completeUntilFirstUserAuthentication on iOS.
- View model pre-paints from cache only until a live response applies
(hasAppliedLiveHistory/hasAppliedLiveSessions guards); write-through is
chained and off the render path.
- iOS wiring keys the chat view model identity on transport mode plus cache
gateway ID so switching paired gateways rebuilds the view model.
Part of #100194
* fix(ios): harden offline transcript cache
* fix(ios): expose offline cached sessions
* fix(ios): isolate transcript caches by gateway
* chore(i18n): sync native inventory
* fix(ios): allow cache extension to replace messages
* feat(logbook): automatic work journal plugin with a plugin-contributed Control UI tab
Squash of PR #99930 work for rebase onto the Control UI route refactor:
- extensions/logbook: Dayflow-style capture -> observations -> timeline cards
pipeline with SQLite store, node capture commands, standup/ask, retention
- plugin SDK/gateway seam: surface "tab" Control UI descriptors projected
into hello-ok controlUiTabs (scope-filtered, deterministic order)
- Control UI: dynamic plugin tabs with bundled Logbook view
- docs, tests, labeler wiring
* feat(ui): port plugin tabs and Logbook to the route-owned Control UI architecture
- shared /plugin route carries the tab id in the query (?id=<tab>), matching
the router's exact-path contract
- openclaw-plugin-page renders bundled views (Logbook), sandboxed plugin
frames (descriptor path), or the unavailable card
- sidebar renders hello controlUiTabs after each group's static routes
- Logbook view/controller live under ui/src/pages/plugin/
* fix(ui): namespace plugin tabs by pluginId to prevent cross-plugin tab id collisions
* fix(logbook): prefer app capture nodes and rotate off failing nodes
* fix(plugins): reject protocol-relative Control UI tab paths
* fix(logbook): harden automatic journal
* docs(changelog): remove maintainer self-credit
* chore(ui): refresh locale metadata after rebase
* fix(logbook): preserve analysis window boundaries
* fix(logbook): align status privacy and timezone
* fix(ui): stop hidden plugin tab polling
* 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
* fix(tui): show last tool-error summary on aborted runs
When a run ends while looping on tool-call validation errors the TUI showed
only "run aborted". Carry the last tool failure on the terminal lifecycle
metadata and render a sanitized one-line summary on the abort line, e.g.
"run aborted: edit tool validation failed: edits: must have required properties edits".
Argument dumps are stripped; with no summary it stays "run aborted".
Refs #90982
* fix(tui): secure abort validation diagnostics
* docs(changelog): move TUI fix to unreleased
* docs(changelog): aggregate TUI fixes
* fix(tui): scope abort validation diagnostics
* docs(changelog): restore unreleased spacing
* fix(tui): scope abort validation diagnostics
* fix(tui): scope abort validation diagnostics
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
The plugin-approvals schema gained approvalReviewerDeviceIds (#100251)
without refreshing the generated Swift model, so the bundled-protocol
drift gate fails on every PR. Mechanical pnpm protocol:gen:swift output.
Aligns the shared OpenClawMascotView with the website hero styling:
per-part bounding-box gradients (SVG objectBoundingBox semantics; the
claws were nearly flat-colored before), antenna stroke width 2, eye
glow r=2, float depth -8% of size, and a light-scheme palette from the
site theme variables. The float now offsets the whole canvas like the
site floats the hero container, so the antennae no longer clip at the
float peak.
macOS adopts the hero glow treatment: the About pane mascot gets the
coral silhouette drop-shadow with the teal hover glow and 1.1 hover
scale, and the onboarding hero replaces its hand-rolled breathing glow
circle with the same silhouette glow.
* feat(crestodian): AI-first conversational onboarding with typed-op guardrails
Interactive `openclaw onboard` (and bare `openclaw` on a fresh install) now
opens the Crestodian conversation: detection-backed first-run proposal
(Claude Code/Codex logins, API keys), persona AI turns for every free-form
message (configless local-runtime fallback, 60s deadline, deterministic
degradation), approval-gated typed operations, chat-hosted channel setup
(`connect <channel>`), config get/schema read ops with secret redaction, and
a post-write validation hook that feeds schema errors back for a self-fix
turn. Adds the additive gateway `crestodian.chat` method so app clients run
the same conversation. Classic wizard stays behind --classic/explicit flags;
non-interactive automation unchanged; `--modern` becomes a deprecated alias
for `openclaw crestodian`.
* feat(macos): Crestodian chat onboarding and importance-ordered permissions
Replace the gateway step-wizard page with a Crestodian chat over the new
crestodian.chat method (works before any model auth exists), sort the
permissions page by importance with no scrolling, drop the redundant manual
refresh, and bump the onboarding version.
* feat(crestodian): run the custodian on the real agent loop with a ring-zero tool
Crestodian conversations now execute through the same embedded agent runner
as regular agents: a persistent agent session with a single construction-gated
`crestodian` tool wrapping the typed operations (read actions free; mutations
require approved=true asserted from explicit user consent, audited, with
post-write config validation fed back into the loop). The engine prefers the
loop (configured models or the Codex app-server fallback) and degrades to the
single-turn planner, then to deterministic commands. Setup approval seeds the
crestodian exec approval so local model harnesses can run; the configless
Codex backend config now enables exec and direct tool loading (it was
dead-on-arrival behind tools.exec.mode=deny and the tool-search index).
* test(crestodian): type the engine mock signatures for the core test lane
* fix(crestodian): map the advertised create_agent tool action
* fix(crestodian): host-verified approval arming and a macOS setup completion gate
Review findings: the model-supplied approved flag alone could authorize
ring-zero mutations (prompt injection / model error), and removing the macOS
wizard gate let users Next past the Crestodian page with nothing configured.
Mutating tool actions now also require host-verified consent (the engine arms
approval only when the user's actual message is an explicit yes), and local
macOS onboarding blocks advancing until setup authored the config, using the
same signal the old step wizard checked.
* fix(crestodian): bind approval to the exact proposed operation and gate dot navigation
A generic yes no longer authorizes arbitrary mutations: denied mutating tool
calls register a canonical operation fingerprint (host-owned, per session),
and an armed turn executes only the identical call, once. The denial message
is arming-aware so the approved turn self-heals in one roundtrip, and the
agent protocol pre-registers proposals. macOS onboarding page dots now honor
the same setup-completion gate as the Next button.
* fix(crestodian): redact sensitive wizard answers, skip logged-out CLIs, gate programmatic advance
Sensitive channel-wizard answers (tokens, passwords) are redacted from the
AI-visible conversation history; setup and the onboarding welcome never pick
or advertise a definitively logged-out CLI as the model; and macOS
handleNext() honors the page gates for programmatic callers (chat handoff)
just like the Next button.
* fix(crestodian): align the onboarding welcome's configured predicate with the app gate
A valid config carrying only a default model (partial/hand-written) now still
gets the first-run proposal instead of the ready guide, so the macOS setup
gate can always be satisfied from the conversation.
* fix(crestodian): armed turns can never mint their own executable proposal
An approval-mismatched call inside an armed turn no longer re-registers and
invites a retry (which let the model swap the approved operation for another
in the same turn); it voids the approval entirely and requires a fresh yes.
Proposals register only in unarmed turns, which the agent protocol already
does when proposing.
* fix(onboard): route any explicit setup flag to the classic wizard
* fix(ci): satisfy new lint rules, tool-display guard, and generated artifacts for crestodian
* chore(i18n): refresh native inventory after permissions copy wrap
* fix(crestodian): harden conversational onboarding
* docs(crestodian): document conversational onboarding
* test(crestodian): type embedded runner mock
* fix(crestodian): close onboarding security gaps
* chore: retrigger ci
Ports the animated OpenClawMascotView to the macOS app: the About pane
icon and the onboarding hero now render the Canvas+TimelineView mascot
(float/blink/antenna-wiggle/claw-snap, still under Reduce Motion)
instead of the static app icon.
The view moves from apps/ios into the shared OpenClawChatUI target of
OpenClawKit so iOS and macOS consume one copy; the iOS lint filelist
tracks the moved file.
Allow busy TUI sessions to forward prompts into the configured queue while
keeping queued-turn admission, cancellation, restart, and transcript ownership
consistent across the TUI, Gateway, and followup queue.
Co-authored-by: Sebastien Tardif <sebtardif@ncf.ca>
* feat: add session thread management
Squash of codex/thread-management (025aefc3ad1) onto origin/main:
pin/archive/rename sessions via sessions.patch, archived-aware
sessions.list, lifecycle fencing, read-only archived chat, SDK +
Swift protocol support, Control UI session management.
* refactor(ui): minimal session rows with hover-revealed management
Chat picker and sidebar recents share session-row primitives: single-line
rows, relative timestamps, rename/archive/pin revealed on hover or focus,
accent pin badge for pinned rows, and an active-run spinner in the trail
slot. Sidebar floats pinned sessions above recency via the shared
comparator and gains archive/pin actions through the unified sessions-view
patch fallback. Archive eligibility is one shared policy
(canArchiveSessionRow); the sidebar/picker active-run tooltip now uses the
real sessionsView.activeRun locale key.
* fix: align session admission with mailbox-era main
Integration fixes after rebasing onto current main: sessions_list mailbox
test expectations learn the archived/pinned row fields and archived:false
list param; gateway agent admission treats a session as deleted only when
both the requested and canonical alias sets miss it (legacy bare-main
stores and exec-approval followups read under different spellings); cron
persist tests keep a consistent store across claim-guarded persist calls;
the ACP abort hook test asserts abort propagation instead of signal
identity; drop dead lifecycle writes flagged by no-useless-assignment and
fix the promise-executor return in the codex compact test.
* fix(qa): align UI e2e and shard fixtures with redesigned session rows
Sidebar session rows are wrapper divs with an inner link now: update the
navigation browser tests and chat-flow Playwright selectors. Seed a real
per-test session store for the auto-fallback admission guard instead of
depending on leftover host files at /tmp/sessions.json. Teach the
test-projects routing fixture about the suites that newly import the
shared temp-dir helper. Document the Codex thread-format contract for
archivedAt/pinnedAt (flag derived from server-stamped timestamp, epoch ms
here vs Codex epoch seconds) at the type and in the session docs.
* test: route auto-fallback suite through temp-dir helper plans
The auto-fallback suite now imports the shared temp-dir helper for its
seeded session store, so the top-level helper routing fixture must list
it in the auto-reply plan.
* feat(gateway): add device.pair.setupCode RPC for connect QR
The OpenClaw mobile/companion app scans a pairing setup code to connect to the gateway, but that code + QR could only be produced by the openclaw qr CLI (ASCII to stdout). Non-terminal clients driving onboarding had no way to display the connect QR.
Add a device.pair.setupCode gateway method that reuses resolvePairingSetupFromConfig + encodePairingSetupCode + renderQrPngDataUrl to return { setupCode, qrDataUrl?, gatewayUrl, auth, urlSource }. The embedded setup code mints a short-lived bootstrap token that hands off broad operator scopes (read/write/approvals/talk.secrets), so the method requires operator.admin (matching the wizard methods a companion already uses) and is not advertised. auth is a label only; the gateway credential is never returned, and an oversized QR is omitted so the response always satisfies the result schema.
Refs #94661.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat(ui): pair mobile devices from Control UI
* docs: refresh generated docs map
* docs: clarify mobile QR auto-connect
* docs: clarify mobile QR auto-connect
* docs: clarify mobile QR auto-connect
---------
Co-authored-by: Barbara Kudiess <76582160+bkudiess@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Move iOS accent and status colors through design tokens so raw SwiftUI color literals are blocked outside token definitions.
Set the app-wide tint in SwiftUI and UIKit from code, without relying on Assets.xcassets AccentColor.
Render Telegram progress draft rows with clean plain previews while preserving Telegram HTML formatting through parse_mode.
The progress HTML path now stays transport-owned, including richMessages=false progress messages, while debug/plain/sanitized text remains readable without raw markup.
Thanks @snowzlmbot!