Loads sessions from the active workspace directory
Fetches session messages using both session ID and directory
Resets expanded raw messages when the directory changes
Add a root-session action that creates a generated worktree from the session directory's current branch, transfers uncommitted changes, and moves the parent session plus its descendants through OpenCode's control-plane API.
Reuse existing project/worktree topology and quick-create behavior, keep the UI non-blocking, reconcile live and global session state across directories, and roll back partial moves and failed worktree creation safely.
Split worktree bootstrap readiness into directory-created, git-ready, and setup-ready phases across web and VS Code. Session moves wait for Git readiness while existing setup-aware flows continue waiting for full setup completion, and worktree removal is serialized with active bootstrap tasks.
Expose the move only for idle root sessions, show localized progress and explanatory tooltips in the sidebar, and keep pending/ready worktree metadata synchronized with authoritative session attachments to avoid stale setup indicators.
Add coverage for control-plane payloads, session-state migration, bootstrap phase ordering and compatibility, removal races, progress metadata, and fast-ready attachment races.
Retries transient index.lock conflicts during worktree population
Removes unchanged stale locks automatically and continues bootstrap
Adds coverage for stale lock recovery
Updates the SDK dependency across web, UI, and VS Code packages.
Refreshes the lockfile and package versions to match the release.
Adds unreleased changelog notes for the current set of user-facing changes.
* Group settings navigation menu
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
* Revert "Group settings navigation menu"
This reverts commit 5983a4e82074b8dab1084af1cadd803ba28ea65d.
* Standardize settings layout feedback
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
* Fix settings save status timer typing
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
* Retain settings save status
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
* Report color mode save state
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
* Match Appearance settings to two-column layout
Rebuild Appearance into Color mode & Theme, Localization, and Density & type sections with responsive two-column grids, consistent section headers, page description, and green save status.
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
* Migrate settings pages to SettingsPageLayout and SettingsSection
Replace ScrollableOverlay/max-w-3xl shells with the shared settings
layout primitives across entity and static settings pages, normalize
section headers, and add settings.page.behavior.description locales.
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
* Unify remaining settings pages on shared section chrome
Wire Appearance, Projects, and Remote Instances through SettingsSection/SettingsPageLayout so every settings surface shares the same header, divider, and page shell treatment.
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
* Align settings UI with OpenChamber design system kit
Apply kit geometry and control specs: 840px content width, 32/48 padding, fixed 260/280 sidebars, radius/spacing tokens, settings select height, stepper dimensions, and shared field/link typography.
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
* Migrate OpenChamberVisualSettings to shared settings primitives
Replace ad-hoc radio/checkbox/chip/field layouts with SettingsSection
shared chrome for Appearance, Density, Navigation, Chat/behavior, and
Privacy while preserving handlers and data-settings-item anchors.
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
* Migrate settings pages to shared field/checkbox/radio primitives
Unify Defaults, Notifications, Behavior, Git, Session Retention, Passkeys,
OpenCode CLI, Commands, About, Keyboard Shortcuts, and Desktop Network on
SettingsFieldRow / SettingsCheckboxRow / SettingsRadioGroup / SettingsChipGroup
for consistent grid, spacing, and DRY layout. Also remove the GitPage double
SettingsSection wrap around GitHubSettings.
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
* Unify remaining settings pages onto shared field primitives
Migrate Agents, Snippets, Skills, Usage, MCP identity rows and selects to
SettingsFieldRow/CheckboxRow/ChipGroup and SETTINGS_SELECT_*; align page
titles; light-touch Voice/Tunnel/Providers/Plugins without rewriting
complex OAuth, permissions, or tunnel flows.
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
* Polish settings section dividers and transport helper text
Slightly stronger section borders for clearer group separation, and keep
message-stream transport description under the chip control.
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
* Fix settings grid alignment, control heights, and Chat section titles
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
* Tighten settings grid: flat Chat 2x2 and full-width stacked selects
Message options use a flat two-column grid so row headers share a baseline.
Stacked selects fill their column; field-row selects keep a fixed sm:w-56 width.
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
* Align mixed settings controls to shared FieldRow/CheckboxRow grid
Separate FieldRows from CheckboxRows with SettingsInset, move enum
radios into ControlGroups, and convert misplaced StackedFields to
full-width FieldRows so left edges no longer clash.
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
* Translate Behavior response-style preset labels for es and pl
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
* Group settings nav into categories and improve icons/order
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
* Fix settings layout: fewer hrs, shared control widths, chat transport section
Remove SettingsInset top borders, align App install/Density controls to full cluster width, give Message Stream Transport its own Chat section, and fold Sessions Small Model into the first section to cut extra dividers.
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
* Align Voice and MCP settings labels with shared heading classes
Swap form field labels to SETTINGS_FIELD_LABEL_CLASS and use
SettingsGroupTitle for MCP control-group headings (manual auth fallback,
request headers).
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
* Differentiate settings heading levels by context
Page titles are larger and quieter than section titles; group and field
labels use dedicated shared classes so hierarchy is consistent across
settings surfaces without ad-hoc typography mixes.
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
* Use shared settings title classes in SettingsView home
Wire home and unavailable headings through the shared L1/L2 class
constants so they stay aligned with SettingsPageLayout.
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
* Keep settings number steppers from stretching +/- buttons
Density & type NumberInputs no longer flex-grow across the row, and
NumberInput locks minus/plus to fixed width so the plus side cannot
inflate when the control is placed in a full-width cluster.
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
* Place spacing and input-bar offset on their own row
Density & type now lays out as font families, then font sizes, then
Spacing Density / Input Bar Offset on the row below.
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
* Regroup settings nav and improve Voice layout
Drop Advanced/Usage/Git nav categories: Voice and About under
Interface, Usage under OpenCode, Git under Workspace. Voice provider
chips and STT model cards use shared settings primitives with roomier
spacing and a two-column model grid.
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
* Space out chat feature groups in visual settings
* Polish settings: save-state wiring, container-query layouts, unified dropdown triggers
- Wire shared save indicator into Behavior page saves and git identity CRUD
- Convert settings layout primitives and page rows from viewport to container
queries so narrow panes stack instead of clipping
- Unify custom dropdown triggers (model/agent/provider pickers) and remaining
page selects on the settings control size
- Bump global radius scale by 1px; align variant input with select size
- Migrate stray raw controls (MCP OAuth checkbox, worktree remove button,
git identity dialog rows, skills dialog labels) onto shared primitives
- Make settings nav items span full sidebar width; trim nav to 240px
* Add General settings page, regroup nav, cap control widths, promote chat feature headers
* Mobile settings nav: plain background and touch-sized rows
* Hide secondary settings descriptions behind clickable info hints
* Move quota credentials to Usage, navigation settings to General, rename External Tunnel
* Quiet settings save indicator: silent success, delayed spinner, visible errors
* Rewrite settings-ui-patterns skill around shared primitives and refactored conventions
* Remove settings starter page; open last visited page, defaulting to General
* Settings polish: spacing, control sizes, trigger widths, readable model names, device dates
* Centralize dropdown trigger chrome, settings nav polish, mobile-only input bar offset
* Fix global line-height regression, auto-hide first-section divider, shortcut row spacing
* Global line-height 1.45, align scheduled tasks header button with select
* Hide editor toolbar and About in VS Code, animate chat render preview outside desktop dialog
* Rebuild agent tool permissions on source-of-truth model
Edit the agent's own permission map verbatim (inherit vs explicit actions, pattern rules only for pattern-capable keys), save permission-only, drop the server-side non-wildcard re-merge that resurrected deleted rules, and surface session-granted rules as read-only.
* Agents model parameters polish: row spacing, variant dropdown, unified widths, dash for unset numbers
---------
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
Replace the legacy terminal flow with a shared authenticated WebSocket
runtime used across web, desktop, relay, and mobile surfaces.
- introduce the v3 terminal protocol with scoped attachments, snapshots,
ordered output, bounded replay history, reconnects, and explicit lifecycle
- harden PTY creation, restart, resize, close, force-kill, idle cleanup,
shell selection, login mode, environment sanitization, and appearance sync
- add runtime-aware terminal APIs with relay authentication and Electron parity
- add a fullscreen mobile terminal workspace with touch scrolling,
long-press selection, safe-area controls, quick keys, and Ctrl/Alt input
- add terminal selection attachments, preview detection, project actions,
shell settings, and localized UI
- harden Ghostty rendering, resize recovery, Unicode handling, block
characters, line height, and stale-row behavior
- remove the obsolete terminal SSE path and update reverse-proxy guidance
- expand terminal runtime, transport, input, selection, and store coverage
- avoid duplicate web builds when preparing mobile assets in root CI builds
* fix(sessions): route new sessions to the correct project when server omits directory
createSession() passed the server response's `directory` field to
setCurrentSession as `directoryHint`. When the server response omitted
the field (a common path), `directoryHint` was `null` and
setCurrentSession fell back to `opencodeClient.getDirectory()`, which
could still hold a stale directory from a different project.
That fallback caused:
- #1637: clicking `+` on one project while browsing another created
a session grouped under the wrong project.
- #2270: in a parent Git repo with multiple child projects (some
without their own Git), sessions from a child with its own Git were
grouped under a sibling child without Git.
Capture the effective directory passed to the SDK and reuse it as the
fallback for the server response. This guarantees `setCurrentSession`
and `registerSessionDirectory` always see the directory the user
explicitly selected for the new session.
Add regression tests covering both reported topologies and the
no-override / no-server-directory preservation path.
* fix(sessions): prefer registered project paths
---------
Co-authored-by: bashrusakh <bashrusakh@users.noreply.github.com>
Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
Add a VS Code-specific foreground permission responder while preserving the server-owned implementation for web, desktop, and mobile runtimes.
Persist the authoritative VS Code policy in extension global state and expose matching GET/PUT bridge routes. Broadcast policy updates to the sidebar, session editor panels, and agent manager so every active webview observes the same explicit per-session policy.
Resolve missing child-session lineage through OpenCode, honor nearest explicit ancestor overrides, deduplicate concurrent requests, retry transient replies, and reconcile pending permissions after enablement, bootstrap, and reconnect. Treat resolved requests as handled and route notification suppression through the same responder outcome.
Keep post-toggle reconciliation failures non-fatal after policy persistence and fail closed when lineage or replies cannot be confirmed. Document that auto-accept intentionally cannot run while every OpenChamber webview is closed or suspended.
Regenerate the shared UI icon sprite from current source usages. The video-chat icon is no longer referenced anywhere under packages/ui/src, so the generator removes its stale SVG path from the generated asset.
Keep the new-session draft open until the backend confirms that the session was created successfully. This prevents a failed request from closing the draft and discarding the user's creation context.
Restore the exact submitted composer text after a new-session send failure and persist it as the draft. Only restore when the composer is still empty or unchanged, so text entered while the request is pending is not overwritten.
Add regression coverage that simulates an offline session creation request and verifies that the draft remains open with its title intact.
Add pin and unpin actions for user and assistant text messages, with clear compaction-survival labels, localized tooltips, status-info active styling, and VS Code gating where the server runtime is unavailable.
Persist pinned message IDs, creation timestamps, and roles under the OpenChamber session metadata namespace using fresh-read merge updates so goal, review, and other metadata remain intact.
Introduce a server runtime that reacts to OpenCode's dedicated session.compacted event, fetches pinned messages by ID, extracts and chronologically orders their text parts, and injects them as hidden synthetic context through prompt_async. The restoration prompt tells the agent to use the context silently while work remains and limits idle summaries to one short paragraph.
Track the last handled compaction summary to avoid replay duplication, tolerate individually missing pinned messages, integrate runtime shutdown, document ownership and limitations, and cover metadata round trips plus compaction injection behavior with focused tests.
Supports {env:NAME} and {file:path} apiKey substitutions in provider config.
Keeps resolved credentials and file contents server-side.
Adds coverage for env and file-based credential resolution.
Uses thinkingLevel for Gemini 3 Flash models
Keeps older Gemini Flash models on thinkingBudget: 0
Updates docs and tests for the new Google request payload
New drafts now receive the active project ID from sidebar project actions.
Project-group draft creation also forwards the selected project.
Aligns draft opening behavior across project and session selection flows.
Shows the evaluation provider/model used for the latest successful goal audit in the UI.
Persists evaluation model metadata on session goals and covers it in tests.
Adds diagnostic logging for small-model calls and session-goal audit parsing.
The editor font size setting controls code editors and should not also resize the chat composer. Code and conversational input have different readability and layout requirements, so forcing them to share one size is not appropriate.
Delete the share opinion dialog and its sidebar trigger.
Remove the related toast and footer action wiring.
Clean up unused i18n entries in all supported languages.
Commit 5c6546245 removed the editorFontSize reading and inline font-size
styling from ChatInput, calling it 'unused'. However this code was the
core of the editor font size feature (feat/e0229917f) — it applies the
user's chosen font size to the chat input textarea.
Without it, changing Settings > Appearance > Editor font size has no
effect on the chat input textarea. The CodeMirror editor (FilesView,
PlanView) was unaffected because its font size path was not touched.
This reverts the ChatInput portion of 5c6546245, restoring:
- useUIStore selector for editorFontSize
- inline fontSize style on the textarea element
Co-authored-by: bashrusakh <bashrusakh@users.noreply.github.com>
Re-checks authoritative session status after the quiet window
Skips auditing while a direct child session is still busy or retrying
Retries the quiet window when live status data is unavailable
* fix(chat): anchor prompt navigator to last turn at chat bottom
The scroll spy activates the last turn whose top edge crossed the reading
line (100px below the container top). A final turn short enough to fit
below that line could never become active — sitting at the very bottom of
the chat kept the previous prompt highlighted on the navigator rail.
When the container is scrolled to the bottom (within 8px), force the last
turn active.
* feat(chat): enable prompt navigator by default
Users who already persisted an explicit preference keep their choice.
Prefers a real APK asset when the update API points to an AAB
Keeps direct APK links from the API unchanged
Uses the GitHub releases API as a fallback for Android mobile downloads
Use the Task part's state.metadata.sessionId as the only live identity contract for child sessions. Remove timestamp, status, and ordering heuristics that could misassociate concurrent subagents or repeatedly scan directory sessions while parts stream.
Extract Task metadata parsing and child-summary projection into a focused model with cached projections for unchanged message records. Preserve output and part-level metadata parsing only for legacy persisted records, and keep standalone Task rows visible when sorted activity groups are rendered.
Validated with focused Task and turn projection tests, UI type-check, lint, and dead-code analysis.
* feat(chat): prompt navigator list preview with prompt filtering
The hover preview is now an interactive scrolling mini-list of prompts:
rows render as bordered two-line cards, the highlighted row stays inside
a center dead zone and the list glides only near the window edges, wheel
steps the highlight, and the panel stays open when the pointer moves into
it so a click can be corrected inside the list.
Rail entries are filtered to real prompts: previews are built from
normalized user display parts (synthetic context stripped), fully
synthetic user messages are excluded, and shell-mode messages show their
extracted command via the shared shell bridge helpers.
* fix(chat): render shell command status transitions
The injected /shell text part carries live state in shellAction, which
the render-relevant part comparator ignored — a running→completed update
reached the store but never re-rendered the message row until the next
send. Compare shellAction command/output/status for text parts.
* fix(sync): stream shell bridge part updates while running
Streaming suspension keeps part updates out of the static message records
while an assistant message streams, relying on the live streaming-tail
path to render it. Shell-mode bridge messages are hidden from the
timeline and rendered inside the user row, so they have no live path —
suspension froze their output chunks and left the card without a Show
output action until the run finished. Exempt shell bridges (single bash
tool part parented to a synthetic shell-marker user message) from
suspension; their updates arrive at command-output pace, not delta pace.
* feat(chat): syntax-highlight shell command card
Render the shell-mode command and its output through the shared
WorkerHighlightedCode (Shiki) with bash grammar, matching the bash tool
part presentation, instead of plain pre blocks.
Keep always-on instructions concise and route specialized work through focused skills. Split large skills into progressive references and add dedicated change, desktop, sync, and performance guidance.
Replace repeated project-by-session directory matching across sidebar hooks with a shared ownership index that resolves each unique directory once and exposes direct project and folder-scope buckets.
Gate destructive folder reconciliation on authoritative session data and topology readiness, preserve last-known worktrees after discovery failures, and retain nested-project, VS Code, active/archive dedupe, and Windows drive-root semantics.
Narrow cross-directory subscriptions to session and status slices so streaming deltas no longer trigger global aggregation. Reuse a cached session ID index for permission lineage checks instead of rebuilding it on every session switch.
On the reported 15-project, 67-worktree, 14,561-session shape, ownership indexing averages 3.81 ms versus roughly 450 ms for the cache-only hotfix.
Validation: 28 targeted tests, UI type-check, UI lint, and dead-code analysis.
* fix(chat): rework prompt navigator rail into sliding tape with hover preview
- Pin the active indicator to the target during programmatic scrolls so the
scroll spy's intermediate reports don't drag it backwards mid-animation
- Replace the visibility-ratio active-turn picker with a stable reading-line
rule (last turn whose top is above the line), dropping IntersectionObserver
- Replace the list panel with a Codex-style gutter: the whole strip is one
hover/click target mapped to the nearest tick, with a per-prompt preview
card that follows the cursor
- Cap the rail at a fixed window of ticks; hovering the edges carousels
through the rest, with gradient masks hinting at more content
- Render ticks as a tape that glides to keep the active prompt centered,
remounting on history prepend to avoid spurious slide animations
- Keep load-earlier as a compact button aligned over the tick column
* fix(chat): shrink navigator gutter when message column sits under it
On narrow windows the centered message column extends under the rail's
full-width invisible hover zone, which swallowed clicks on the right edge
of user bubbles — including the expand/collapse control. Measure the
column against the gutter and switch to a narrow hit zone when they
overlap.
* fix(sync): stop runaway history auto-load on sessions with empty assistant messages
An assistant message fetched with zero parts (e.g. a run aborted before any
output) was stored as absence — indistinguishable from parts that were never
fetched. getSessionMaterializationStatus therefore reported the session as
never renderable, so the ensure-renderable effects (ChatContainer,
ModelControls) retried syncSession forever; each retry refetched the whole
grown window and fired another background prepend, progressively loading the
entire history of large sessions on open.
Commit an explicit empty [] snapshot for assistant messages so fetched-empty
counts as renderable, while non-assistant messages keep the absent
representation and its no-op commit behavior.
Reproduced and verified headless against a real 857-message session: before,
20 message fetches escalating to limit=857; after, one initial page and a
single progressive-mount prepend.
* feat(chat): add desktop prompt navigator rail
Add a ChatGPT-style right-center prompt marker rail for web/desktop chat
with hover/keyboard preview panel, load-more for partial history (panel only),
Chat setting, and mod+alt+p shortcut. Disabled in VS Code across rail,
shortcut, settings, help, and search surfaces.
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
* fix(ui): read promptNavigatorEnabled from getState in shortcut handler
Match the file convention used by other shortcut handlers so the toggle
does not rely on a hook-level selector closure.
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
* fix(ui): drop use-no-memo and default prompt navigator off
Remove the project-unprecedented React Compiler opt-out, and ship the
prompt navigator as opt-in to match other recent chat UI toggles.
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
* feat(electron): add Linux AppImage releases
* ci: cache Linux OpenCode CLI artifacts
* fix(ci): await Linux release inventory check
* fix(electron): add frameless window controls on Linux desktop
Linux AppImages were created without native WM decorations and without
in-app controls, leaving users unable to close the window with a mouse.
Treat Linux like Windows: frameless BrowserWindow plus the existing
WindowsWindowControls header buttons and app-menu entry. macOS keeps
hidden title bar with traffic lights unchanged.
Shared usesFramelessElectronChrome() helper drives main window, mini
chat, header insets, and titlebar controls.
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
* feat(desktop): add configurable window controls position by OS
Add desktopWindowControlsPosition setting (auto/left/right) with OS-aware
defaults: Linux left, Windows right. Wire frameless chrome controls in
Header, TitlebarLeftControls, and MiniChatLayout, plus a Sessions settings
control for Windows and Linux desktop shells.
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
* fix(desktop): address Linux AppImage release review findings
Propagate updater capability errors to the UI, treat missing
latest-linux.yml feeds as no-update, stop installed-apps IPC spam on
Linux, document FUSE/AppImage limits, add CHANGELOG entry, migrate
remaining btriapitsyn URLs, and run Electron Linux unit tests on PRs.
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
---------
Co-authored-by: jibanez-staticduo <staticduo@gmail.com>
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
* fix: add support for custom provider base URLs from config
* feat: read custom provider apiKey from config and use it as primary credential when it exists
* doc: update small-model documentation
Omits the craft-goal command from draft starters in VS Code
Prevents the starter from being resolved or pinnable in that runtime
Keeps non-VS Code behavior unchanged
* fix(ui,server): normalize Windows drive letter casing for consistent path resolution
Provider settings were failing to persist for specific projects on Windows
because path normalization was inconsistent across the codebase. Some
normalizePath functions uppercased the Windows drive letter (c:\ -> C:\)
and others did not, causing:
- directoryScoped cache misses (different keys for the same directory)
- broken model selection in the affected project
- lost conversation history (sessions could not match their project)
- false cache hits in resolveConfigDirectory on undefined inputs
This change extracts a single shared normalizePath utility and uses it
from the 5 client sites that were missing the drive letter normalization.
The server-side normalizePathForPersistence is updated to uppercase the
drive letter both before and after safeRealpathSync, so the persisted
path is consistent even when realpath returns a symlink/junction with
a lowercase drive letter on some Windows environments.
Fixes#2109
* test(ui,server): add coverage for Windows path normalization
Address review feedback on #2154:
- Add Windows-platform test for normalizePathForPersistence covering
drive letter uppercase on input and after realpath resolution
- Add dedicated test suite for the shared normalizePath utility
- Defensive fix: normalizePath now returns null for paths that consist
only of slashes (\\, ///), matching the documented contract
Refs #2154
* fix(server): scope drive casing normalization to Windows
---------
Co-authored-by: bashrusakh <bashrusakh@users.noreply.github.com>
Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
Adds section headers and tooltip help for the goal settings area
Reorganizes chat settings into Session Assistance, Reasoning, Message Appearance, Tools & Files, and Composer groups
Adds localized labels and search entries for the new section headings
Relay connect used to serialize a dead LAN probe (up to 8s per stale address
on mobile, 2-4s on desktop) in front of the relay attempt, then paid a second
WebSocket connect + E2EE handshake because the probe tunnel was thrown away.
- mobile probeConnectionCandidates: race the relay probe against the direct
chain with a 1.5s direct headstart; a live LAN still wins, a dead one no
longer delays startup
- relay probes adopt their tunnel as the runtime tunnel (adoptRelayTunnel)
instead of dialing a fresh one — applies to auto-connect, pairing redeem,
password login, and the desktop host switcher's relay fallback
- relay probe drops the /health round-trip: the E2EE handshake already proves
the server identity, /auth/session alone proves liveness and auth
- desktop restoreDesktopRelayRuntime: same headstart race; a late direct
success hot-switches back (stable runtimeKey); startup probe now passes
expectedServerId so a re-leased LAN address never sees the token
- launch splash shows 'Connecting to device: <label>' with animated dots
under the (still centered) logo, translated in all locales
- editing a saved instance no longer rebuilds it from the URL field alone:
the id is passed through, relay/https candidates are preserved, and a
token-key change migrates the Keychain token instead of orphaning it