* fix(control-ui): keep the dashboard mounted with a reconnect banner on gateway drops
Once a session is established, a dropped gateway WebSocket no longer
unmounts the dashboard into the login gate. The client's close handler
now reports willRetry (the same fact that drives its reconnect
scheduling), the gateway store derives a `reconnecting` snapshot state
from it (everConnected && willRetry), and the app shell stays mounted
with an amber "Gateway connection lost - reconnecting" banner plus a
Retry now action while the client retries with backoff. The login gate
is reserved for first connects, credential rejections, and manual gate
submissions; event-gap recovery also no longer flashes the gate.
createApplicationGateway moved from bootstrap.ts to gateway-store.ts
with an injectable client factory for direct behavior tests. Adds the
previously unstyled `.callout.warn` variant and a "Connection loss and
reconnect" docs section.
Fixes#100475
* chore(i18n): regenerate control-ui locale bundles for connection banner strings
* chore(control-ui): unbreak CI - add reconnecting to overlays snapshot fixture, regenerate docs map
* chore(i18n): re-sync locale metadata after rebase onto refreshed main locales
* chore(i18n): refresh raw-copy baseline after rebase
* fix(macos): reap orphaned SSH tunnels that survive app crashes and squat the preferred local port
* chore(i18n): sync native app string inventory for PortGuardian changes
MacNodeRuntime's browser proxy gate read OPENCLAW_CONFIG_PATH-resolved config
at invoke time, so parallel tests mutating process env (raw setenv outside
TestIsolationLock in LogLocatorTests/WideAreaGatewayDiscoveryTests) could make
the gate read the real host config. Inject the gate state in tests, cover the
config flag parsing in OpenClawConfigFileTests, and route remaining raw setenv
test users through TestIsolation.withEnvValues.
* fix(skills): keep command spec descriptions UTF-16 safe at the truncation cut
* chore: fix oxlint no-unnecessary-type-assertion in test
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* chore: fix Skill type completeness in test fixture
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix(skills): prove UTF-16-safe command truncation
* fix(skills): apply description limits per channel
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* fix(browser): preserve managed Chrome cookies
* fix(browser): guard graceful close process ownership
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* 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
* fix(diffs): share SSR preloads and repair language-pack hydration
Render viewer and file documents from a single @pierre/diffs SSR preload
per file (mode=both previously ran the full diff+highlight pipeline
twice; 651ms -> 303ms on an 8-file patch), apply the file-mode font bump
as a document-level override, and keep hydration payloads
variant-faithful.
Fix the language-pack runtime downgrading pack-only languages to plain
text at hydration by defining a per-target build flag and forwarding it
to payload normalization.
Also: case-insensitive language hints, identical before/after
short-circuit with details.changed, patch input failures classified as
tool input errors, canonical config values now win over deprecated
aliases, hash-pinned viewer runtime served immutable, truthful
browser-vs-render errors, timing-safe artifact token compare, unref
idle browser timer.
* docs(changelog): link diffs rendering entry to PR
* test(diffs): narrow manifest validation results before value access
* test(tooling): allowlist diffs viewer-client define suppression
* fix(slack): normalize react emoji glyphs and clarify member-info userId param
Slack's reactions.add/remove only accept shortcode names, never a raw
Unicode glyph, but the react action's emoji param had no description
steering models away from passing one, so calls like
emoji="✅" failed with invalid_name. Consolidates the glyph-to-shortcode
map that already existed privately in the ack-reaction dispatch path into
the shared normalizeSlackEmojiName export in actions.ts, the layer that
owns the actual Slack API calls, so the message-tool react action gets the
same normalization.
Also tightens the generic userId param description so models stop trying
target on member-info, which has no target mode and requires userId
directly.
* fix(slack): preserve emoji reaction semantics
* fix(slack): default reactions to inbound message
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>