Stop treating Provider.env length as credentials, refetch provider
sources after OAuth/API key writes, and respect an explicit auth-panel
Hide so OAuth-only providers do not stick on a stale "Credentials
missing" / empty-models state after a successful login.
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
Branch, project, agent, model, provider, stash, SSH-host, skill-catalog
and archive filters each had their own toLowerCase().includes (or no
ordering at all); the git branch and gitmoji pickers also let cmdk
re-filter and reorder on top of the manual filter, silently dropping
rows. All of them now go through rankByQuery/matchesRankQuery: results
are relevance-ordered, multi-word queries match in any order, matching
ignores punctuation, and cmdk filtering is disabled where the ranked
list is already final. rankBranchesForQuery keeps relevance order
instead of re-sorting matches alphabetically; the model picker now also
matches model ids.
Picking a project in Settings called setActiveProject, which relocates
the chat, the session list, the file tree and the Git surface. Reading
another project's MCP servers or agents moved the user's whole app.
It had to, because the configuration stores resolved the directory
themselves from the active project and held one flat list. Each of them
now takes an explicit directory — omitted still means the active project,
so every caller outside Settings is unchanged — and keys loaded data by
directory next to a flat mirror of the active project. Chat, autocompletes
and pickers keep reading that mirror; a load for another directory writes
only the map. A failed load restores that directory's previous list.
Settings resolves its own directory through useSettingsDirectory, backed
by a session-local settingsProjectPath that follows the active project
until the user picks something else.
Shows the auth panel only when provider credentials are actually required
Keeps custom providers defined in config from being treated as incomplete
Adds coverage for the new provider auth check
* chore: remove verified dead declarations
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
* chore: narrow unused internal exports
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
* chore: remove newly exposed dead helpers
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
* chore: remove unused deep-link serializer
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
* test: drop two tests that assert on copies of the code
mainLayoutMobileSidebarMount read MainLayout.tsx and SessionSidebar.tsx as
strings and asserted on source substrings down to exact indentation, so it
failed on formatting rather than behaviour. useProjectSessionSelection.test
reimplemented the hook's visitNodes logic inside the test file and asserted
against that copy, so it could not observe the hook at all.
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
* test: repair sync suites that had rotted while unrunnable
No runner executed packages/ui, so these drifted from the source unnoticed:
two imported helpers that are no longer exported, one directory-store stub
predated the session field routeMessage reads, and the WebSocket fake missed
the mandatory url-token mint plus the close event the socket wrapper reads.
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
* test: stop the web suite failing on timeouts and a hand-copied mock
The Git suites drive a real git binary, so the 5s default made a valid suite
fail differently per run. The gitApiHttp mock listed ~70 export names by hand
and fell behind the source; it now derives every stub from the real module,
which the added shared-UI aliases make resolvable.
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
* test: run every suite from one command and in CI
packages/ui (232 files) and packages/vscode (22) had no test script at all, CI
ran neither, and 9 vscode files could never run because Node cannot resolve
their extensionless TypeScript imports. Three electron files sat outside every
script list, one of them importing vitest, which that package does not depend
on. A runner gives each file its own process, since these suites keep
module-level singletons and fail by load order when sharing one.
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
* chore: delete a superseded repro harness and a completed plan
The issue-2638 harness needed lsof, overrode process.platform and spawned real
servers, and nothing referenced it; event-stream/rebind.test.js now covers the
same hub-pinned-to-the-old-port behaviour. The pairing v2 plan described relay
and the pairing UI as out of scope, both of which shipped.
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
* docs: point at the theme tools and record the github barrel invariant
convert-vscode-theme and harmonize-theme were referenced nowhere, so the
theme-authoring reference now names them. The github barrel is loaded through
await import('./index.js') and destructured per route, which no static report
can see; documenting that is what stops the next cleanup from deleting it.
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
* test: repair merge drift in bridge and route-registry mocks
upstream/main gained upsertProviderConfig on bridge-system-runtime and a
PATCH scheduled-task route after this branch forked. Their test doubles
were never updated to match:
- bridge-system-runtime.test.js: add upsertProviderConfig to the
opencodeConfig mock so the import resolves.
- sse-routes.test.js: add app.patch to the route registry stub.
---------
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
OpenCode's authorize response reports how the client must finish: `code`
expects a pasted code, while `auto` requires the client to call
oauth/callback immediately and hold it open — upstream blocks in there
polling for the device code or waiting on its loopback redirect, and only
that call persists the credential. Every auth plugin OpenCode ships uses
`auto`; none use `code`.
The page implemented only `code`. It opened the browser, showed a paste
field no provider can fill, and never called back, so a successful sign-in
stored nothing and the app sat unchanged. Authorization now drives the UI:
`auto` chains straight into the callback behind a waiting state with a
cancel, and the paste field appears only when a provider actually asks
for a code.
Two smaller failures shared that surface. Prompts were never collected,
which put GitHub Copilot Enterprise out of reach entirely, so a method
that declares them now asks first and passes the answers to authorize.
Device codes are also recovered from the instructions text, where they
actually live — the old code read fields the API does not return, so the
copy button never appeared.
The callback is exempt from the ordinary proxy deadline and gets a
15-minute budget, bounded by the shortest upstream expiry we know of.
A human sign-in with 2FA does not fit in four minutes, and expiring it
turned a completed login into a 504.
For OAuth-only providers like Cursor, open the auth panel when
credentials are missing and omit the models list until auth/env
credentials are present so placeholder catalog entries are not shown
before login.
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
Only show the API key credential UI when a provider declares API auth
(or auth methods are still unknown). OAuth-only plugin providers such as
Cursor now show Connect/OAuth only, load auth methods on reconnect, and
skip an empty models section until models are discovered.
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
Resolve ProvidersPage and lifecycle conflicts with custom providers and
AppImage ARGV0 stripping. Address review follow-ups: OAuth index helper +
tests, single auth-methods load trigger, shared Google env-alias module with
VS Code parity coverage, and deferred restart for custom provider upsert.
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
Reconnect previously showed only the API key field because
provider.auth() ran solely in add-provider mode. Also keep the
original OpenCode method index when listing OAuth options.
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
Drop phantom pending records when provider disconnect removes nothing
and when Behavior AGENTS.md payloads are not deferred. Clear the Apply
badge after external OpenCode manual-restart guidance. Align skills and
commands save toasts with deferred restart feedback, and fix French
OpenCode elision.
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
Derive the effective OpenCode config layer (custom > project > user) from
provider sources and send it on PUT /api/provider so project/custom edits
update that layer instead of creating a global user override. Resolve
OPENCODE_CONFIG at call time and add UI/web/VS Code coverage for scoped
upserts.
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
Defer OpenCode reloads after settings mutations, track pending changes,
and expose a top-right Apply & Restart OpenCode action with a counter so
sessions stay available until the user explicitly applies.
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
Gate Edit/incomplete-auth on config-layer sources so catalog providers
are not treated as editable custom overrides. Snapshot form initial
values when Edit is clicked and ignore same-id initialValues identity
changes so parent re-renders cannot wipe in-progress edits.
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
Require an API key or {env:VAR} on client and server, add edit/prefill for
existing custom providers, save auth before config, and surface incomplete
auth plus disconnect after partial failures. Add VS Code parity tests and
drop the unused allProvidersConnected locale key.
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
Allow Settings → Providers to define custom providers (id, name, base URL,
API key, models, headers) without code changes. Persist config via OpenCode
layers, store keys through auth.set, and keep web/VS Code parity.
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
* 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>
Fix#1462: handleDisconnectProvider called the SDK auth.remove() which
only clears auth credentials from auth.json. Cloud providers configured
in user/project/custom config files were not removed and reappeared
after reload. Now calls DELETE /api/provider/:id/auth?scope=all which
removes the provider from all config sources.
Co-authored-by: Leonid Skorobogatyy <bash@opencode.itc.local>
* feat: add French locale runtime
Add French to OpenChamber's shared i18n runtime, dictionaries, and parity tests so the existing language picker can load a complete fr locale across shared UI surfaces.
* fix: localize shared UI formatting
Remove remaining shared UI locale hardcodings so dates, numbers, and first-party helper copy follow the active app locale instead of leaking English on French surfaces.
* feat: localize VS Code French surfaces
Localize VS Code bootstrap, native runtime messages, panel titles, and manifest contribution strings so French users get consistent first-party copy across the extension experience.
* fix: TASK-2026-05-30-008 correct French review findings
Fix broken French relative-time and weekday strings reported on PR #1482 and restore proper import order in quota utils without broadening scope.
* fix: TASK-2026-05-30-008 address final PR review comments
Capture the localized More Info label once in the VS Code CLI-missing flow and replace the remaining inline French-only utility strings with dictionary-driven copy plus required locale keys.
* fix: TASK-2026-05-30-008 normalize French glossary
Correct glossary-level French terminology on the live PR branch, keeping canonical technical terms like PR, worktree, stash, HEAD, Mermaid, Markdown, remote, and session while replacing misleading literal translations.
* fix: TASK-2026-05-30-008 refine French terminology pass
Clean up remaining glossary mistakes on the French PR branch, especially around Mermaid, Markdown, PR, worktree, stash, branch, remote, and commit terminology, while keeping behavior unchanged.
* fix: TASK-2026-05-30-008 clean remaining French false friends
Correct the SOCKS5 mistranslation and a final small set of obvious false-friend technical nouns on the French branch without changing behavior.
* fix: TASK-2026-05-30-008 correct French glossary terms
Replace remaining false-friend translations in the French UI dictionaries and normalize technical labels for the French PR branch.
* fix: TASK-2026-05-30-008 remove remaining French Mermaid false friend
Replace the last confirmed Sirène translation with Mermaid and re-run the requested blacklist and build verification on the PR branch.
* fix: TASK-2026-05-30-008 enforce French glossary policy
Keep skill/PR/worktree/remote terminology developer-credible in French and remove remaining machine-translated Git and settings copy.
* fix: TASK-2026-05-30-008 keep prompt terminology in French
Replace remaining technical invite translations with prompt wording across scheduled tasks, multi-run, prompt templates, and Magic Prompts.
* fix: TASK-2026-05-30-008 finalize French terminology cleanup
Polish remaining worktree/remote wording, remove visible metadata leakage, and correct final Git and settings labels on the French PR branch.
* fix: TASK-2026-05-30-008 polish final French strings
Correct the last aria-like artifacts and awkward worktree/remote/GitHub URL phrasing in the French dictionaries.
* fix: TASK-2026-05-30-008 normalize final French glossary framing
Tighten the last worktree/remote/checkout wording and fix remaining French grammar around canonical technical terms.
* fix: TASK-2026-05-30-008 align final developer glossary wording
Normalize the last French framing around canonical developer terms like worktree, remote, prompt, and checkout.
* fix: TASK-2026-05-30-008 harmonize final French sentence framing
Replace the last raw franglais around checkout, remote, worktree, and prompt-facing labels with more natural French framing while keeping the chosen technical terms.
* fix: TASK-2026-05-30-008 add compact relative date keys
Replace French-specific prefix stripping in compact session date labels with dedicated i18n keys across locale dictionaries, preserving existing compact label output while making French wording robust.
* docs: add French documentation
* docs: mention French locale folder
---------
Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
Adds item-level search inside Settings so users can find concrete settings like provider auth, agent mode, terminal font size, tunnel options, notification events, and similar controls instead of only filtering top-level pages.
Groups search results by Settings page and shows localized labels plus optional descriptions where useful.
Supports keyboard navigation with Arrow Up/Down, Enter, and Escape, matching the existing autocomplete interaction style.
Opens the correct Settings page or split-page draft state before scrolling to the matching control.
Highlights the matched setting with a subtle token-based background so users can see where they landed without an aggressive outline.
Adds explicit data-settings-item anchors across Settings pages and a centralized search registry with runtime/mobile availability guards.
Updates Settings UI skill guidance so future Settings changes keep search registry entries, anchors, localization, and availability guards in sync.
Add a packaged-client runtime boundary so the shared UI can talk to local,
desktop, remote, and VS Code runtimes through the right transport instead of
assuming one same-origin web server.
Centralize OpenChamber-owned API access behind RuntimeAPIs, runtimeFetch, and
runtime URL helpers, while keeping official OpenCode traffic on the SDK path.
Support runtime switching, remote host selection, desktop client credentials,
and headless connection links for pairing packaged clients with remote
OpenChamber servers.
Harden the new auth model by moving long-lived client tokens out of browser
URLs, introducing short-lived scoped URL tokens for browser-owned transports,
restricting URL-token access to explicit readable/realtime routes, and making
client-token management session-scoped or self-scoped as appropriate.
Update browser-owned assets and preview proxy flows to work with the split
runtime model, including authenticated project icons, preview token propagation,
CSP-safe preview bridge injection, and preview proxy auth that survives
short-lived URL-token expiry.
Tighten Electron security boundaries for packaged clients by gating privileged
preload state to trusted origins and requiring explicit confirmation before
connect deep-links import or switch remote runtimes.
Also refresh agent guidance and project skills so future runtime/API, auth,
preview, UI, CLI, settings, locale, and drag-to-reorder work follows the new
architecture.
Replace the prompt-template workflow with snippet support that is compatible with opencode snippet conventions. Snippets are now stored and loaded from global and project snippet directories, including legacy pluralized paths, with frontmatter metadata for aliases and descriptions. Snippet expansion supports recursive references plus prepend and append sections, while inject sections are treated as unsupported no-ops so OpenChamber remains compatible without requiring an external plugin.
Add the snippets settings experience and remove the old prompt-template settings surface. The new settings page and sidebar support creating, editing, deleting, selecting, and describing snippets, with localized copy across every supported locale. The settings navigation now exposes Snippets with a dedicated icon and metadata.
Wire snippets into all prompt-entry surfaces that need them. Chat, multi-run groups, and scheduled task prompts now offer hash-trigger snippet autocomplete and expand snippets before sending work to OpenCode. Chat also uses an adaptive compact placeholder on mobile or narrow composer widths so helper trigger guidance stays readable in constrained layouts.
Keep multi-run aligned with grouped prompts. Multi-run sessions now use a shared title builder that handles both legacy titles and the newer g1, g2 prompt-group title format. Fusion parsing now recognizes grouped multi-run titles, scopes fusion sources to the same prompt group, and creates fusion sessions under the matching group so outputs from different prompts are not mixed accidentally.
Harden the icon sprite pipeline. The sprite generator now discovers icon names used through typed icon maps, JSX icon props, IconName returns, and generated-value flows without scanning unrelated string literals or the generated sprite itself. The generated sprite is strictly typed so invalid icon names are caught by type checking, and existing invalid or unsafe icon references were cleaned up across settings, provider, Git identity, scheduled task, voice, header, and sidebar surfaces.
Update backend configuration routes and documentation for snippets. The OpenCode config route layer now exposes snippet CRUD and expansion endpoints, accepts JSON bodies for snippet writes, and removes the old prompt-template provider. Scheduled task runtime expansion now uses snippets before dispatching messages.
Add regression coverage for snippet storage and expansion, config-route JSON handling, and multi-run title parsing. Validated with full type checking, full linting, targeted multi-run title tests, and targeted OpenCode snippet/config route tests.
Replace @remixicon/react with a shared Icon component that renders
via <use href> references to a single hidden SVG sprite. This reduces
DOM node count by replacing inline SVGs with lightweight references.
- Create Icon component with sprite injection (packages/ui/src/components/icon/)
- Migrate all 164 files from @remixicon/react to Icon component
- Auto-generate sprite data from remixicon bundle (scripts/generate-icon-sprite.mjs)
- Add bun run icons:generate to package.json
- Move @remixicon/react to devDependencies
- Add icon usage instructions to theme-system skill
Use base-ui's transition-status pattern (data-starting-style /
data-ending-style) for Dialog, DropdownMenu, Select, Tooltip and Popover
so open/close animate consistently at 150ms ease-out without flicker.
Wrap dialog popups in a centered flex container so the scale animation
no longer fights with translate-based positioning, and switch
PendingChangesBar to a real Popover so it actually animates closed.
Convert ScheduledTaskEditorDialog from raw Radix to the shared Dialog
wrapper, give ScheduledTasksDialog a stable min-height to prevent layout
shift mid-animation, and reset NewWorktreeDialog form state on open
instead of close so fields don't empty during the close transition.
Drop tooltip delay from 700ms to 300ms globally and remove all
per-component overrides except the model/variant/agent selectors in the
chat input (600ms).
Remove body position:fixed lock, visualViewport listener in MainLayout
(keyboard-inset heuristics, scroll-to-zero lock, focusin/focusout RAF),
[data-keyboard-avoid-active] translateY rule, and related CSS vars
(--oc-keyboard-inset, --oc-keyboard-avoid-offset, --oc-keyboard-home-indicator,
--oc-visual-viewport-offset-top). Strip data-keyboard-avoid* attrs and
keyboardAvoid props from Dialog/ScrollableOverlay and consumers. Drop
isKeyboardOpen from useUIStore.
With body unlocked and the layout plain flex-col (h-dvh), the browser
shrinks the viewport on keyboard open naturally — composer sits above
the keyboard, header stops lagging, input no longer jitters.
FilesView.nudgeEditorSelectionAboveKeyboard now derives the occluded
bottom locally from visualViewport + documentElement.clientHeight.
* fix: allow native context menu on links in chat messages
The desktop app was blocking the context menu on all elements except
specific allowlisted ones (terminal, input, textarea, etc.). This
prevented users from right-clicking on HTTP links in chat messages
to access the 'Open Link' option.
Added 'a' (anchor) tag to the allowlist to restore native context
menu functionality for links.
Fixes#708
* fix: use tauri.shell.open for external links in desktop app
- Add global window.open override to init_script that routes HTTP/HTTPS
URLs through tauri.shell.open() instead of window.open()
- Add openExternalUrl utility that prefers tauri.shell.open with window.open fallback
- Add openExternalUrl to MarkdownRenderer for link safety.onLinkCheck
- Replace window.open with openExternalUrl in ProvidersPage for OAuth URLs
Fixes#708
* fix: unify external link opening across desktop and UI
Added a shared URL opener that only allows http/https links.
Replaced duplicated Tauri/window link-open logic in key UI sections.
Removed fragile desktop window.open override and markdown external-link modal behavior.
---------
Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
* refactor(settings): new IA shell + projects section + skills catalog discoverability
* chore(settings): split providers list by scope; show user before project
* fix: navigation flow in mobile Settings
* feat: redesign settings pages to use modern elevated surface patterns
* feat: replace helper text with tooltips in settings
* ui: redesign update dialog and fix external link routing
- Restructures UpdateDialog to focus on changelog readability with a wider max-w-4xl canvas
- Highlights @username contributor mentions with theme primary color
- Strips excessive vertical padding and right-aligns compact action buttons
- Disables streamdown's internal link safety dialog in favor of direct Tauri shell routing
* feat: refactor Git identities into dedicated Git settings page
* feat: unify sidebar background styling across VS Code and web/mobile
* fix: adjust button styling and layout for mobile settings pages
* feat: add MCP settings page and sidebar
* feat: hide models in provider view (thanks to @nguyenngothuong)
* feat: add "Add new provider" option to model selector dropdown
* fix: local evroc logo + provider dropdown icons
* fix: increase width of provider menu
* fix: dark theme background color for better contrast
* feat: update @opencode-ai/sdk dependency to v1.2.10
* fix: restore session sorting to only use updated time
* fix: added settings for sessions deletion dialog
* fix: adjust padding on settings pages for better layout
* fix: standardize select dropdown height across UI
* fix: agent selector UI and notification settings
* fix: remove redundant helper text from settings pages
* fix: update UI layout for description fields
* fix: remove border-none and shadow-none from textarea classes
* fix: enable context menu on sidebar items
* feat: refactor UI controls and layout patterns across settings pages
* fix: use headerless blocks when page title already provides context
* fix: remove subtask option from command settings
* fix: refactor mcp page settings
* fix: reduce spacing in skills configuration pages
* feat: refactor voice settings
* feat: refactor settings sidebar sections
## What / Why
This PR finishes the desktop refactor: the Tauri app is now a thin shell that launches the web server as a sidecar and loads the UI from `http://127.0.0.1:<port>`. All real backend logic lives in `packages/web/server/index.js`; desktop Rust keeps only native integrations (menu/dialog/notifications/updater/deep-link + window chrome).
This unblocks:
- consistent behavior across web/desktop/vscode (single backend)
- simpler desktop maintenance (no duplicated Rust backend)
- host switching between Local + remote instances in desktop
- reliable cold-start behavior on slow machines (VSCode + desktop)
## Key changes
- Desktop sidecar runtime
- build pipeline to bundle web dist + `openchamber-server` sidecar (`packages/desktop/scripts/build-sidecar.mjs`)
- robust local port selection (prefer saved/default, fallback to random; persisted in `~/.config/openchamber/settings.json`)
- improved PATH handling so the sidecar can locate `opencode` CLI (incl `~/.opencode/bin`, overrides, common bins)
- disable native right-click context menu in production builds (dev keeps it)
- Desktop instance switcher (Tauri-only)
- header button + modal to add/edit/delete remote hosts, set default, probe status/ping, switch back to Local escape hatch
- auth gate includes host switcher so you can recover when a remote host is broken/auth-required
- host list stored desktop-locally (not tied to the currently selected remote server)
- Notifications
- decision logic moved server-side; desktop notifications emitted via sidecar stdout and shown natively by Tauri
- prevent double-notifications on desktop Local origin (UI ignores SSE notification when native path is active)
- restore macOS notification sound
- Updates
- Tauri updater used only when viewing Local instance in desktop shell (avoid “remote web update” triggering desktop restart)
- Settings persistence & UX polish
- persist model favorites/recents via `/api/config/settings` (works for web + desktop; not origin-dependent)
- persist per-project sidebar collapse state in `projects[].sidebarCollapsed` via `/api/config/settings` (with debounce on toggles)
- macOS header sizing/traffic-lights offsets fixed (marketing macOS major injected from desktop; MultiRun header aligned)
- VSCode cold-start: keep retrying provider/agent loads after connection to avoid empty UI on slow machines
- misc lint/type fixes + bun.lock sync
- Desktop bootstrap / resiliency
- show onboarding screen when OpenCode CLI is missing (desktop Local origin), with retry hook to restart OpenCode after install
## Testing notes
- Desktop (macOS): switch Local <-> remote, set default host, verify auth gate recovery, native notifications (with sound), updater gated to Local
- Web: favorites/recents + per-project collapsed state persist across reload/restart
- VSCode: slow startup no longer results in missing providers/agents/models
* feat: added themes system
* feat: smart sidebar auto-hide for files/diff tabs + lower files sidebar threshold
* feat: added Checkbox component and update theming
- Add reusable Checkbox component for toggles across UI
- Replace several inputs with Checkbox in settings and commands panels
- Add DiffIcon and apply surface/border theming to key UI areas
* feat: Add convert-vscode-theme.cjs to convert VS Code themes to OpenChamber format
* refactor: remove unused permission logic from ChatInput
- Remove unused permission rules parsing logic from ChatInput
- Memoize renderTheme in DiffWorkerProvider to avoid unnecessary recalculations
- Remove forceOpaque helper in vscode theme adapter
* fix: guard VSCode theme loading in MarkdownRenderer
* feat: add custom user themes loading and reload
- Load user themes from ~/.config/openchamber/themes at runtime
- Expose /api/config/themes to fetch custom themes
- Allow theme reloading from Settings → Theme → Reload themes in the UI
* feat: support scoped removal of provider config (auth, user, project, custom)
* feat: implement UI session token management with cookies for window visibility control
* feat: Implement project management store with project path validation and synchronization
- Added `useProjectsStore` for managing projects, including adding, removing, renaming, and validating project paths.
- Implemented persistence for projects and active project ID using safe storage.
- Introduced synchronization from desktop settings to keep project data consistent.
- Enhanced session store to manage sessions by directory and added new methods for session management.
- Updated todo store to fetch session todos based on the directory context.
- Refactored server code to validate and resolve project directories for various API endpoints.
- Added project entry validation and sanitization to ensure data integrity.
* feat(settings): migrate legacy project settings and update settings loading logic
* feat: enhance project management with directory-aware settings and improved agent/command source handling
* feat: enhance session and project management with directory-aware settings and improved configuration refresh logic
* feat: enhance project management with worktree manager integration and project directory resolution
* feat: enhance agent groups store with project directory resolution and loading logic
* feat: add heartbeat management and global wrapping for SSE blocks in agent and chat providers
* feat: refactor command and project handling in useCommandsStore
- Replaced useDirectoryStore with useProjectsStore to manage project paths.
- Introduced getRequestDirectory function to determine the active project directory.
- Updated command fetching to respect project-level scoping.
- Enhanced error handling and logging for command configuration fetching.
- Improved command configuration saving and updating to utilize project directory context.
feat: enhance project path normalization in useProjectsStore
- Added resolveTildePath function to expand paths starting with ~.
- Updated normalizeProjectPath to utilize home directory for path expansion.
fix: update permission handling in useSessionStore
- Changed Permission type to PermissionRequest for clarity.
- Updated respondToPermission method to use requestId instead of permissionId.
refactor: improve permission utilities
- Introduced types for PermissionAction and PermissionRule.
- Enhanced getAgentDefinition and resolveConfigStore functions for better type safety.
- Added resolvePermissionAction to streamline permission resolution logic.
feat: add agent configuration retrieval endpoint
- Implemented new API endpoint to fetch agent configuration based on project directory.
- Enhanced getAgentPermissionSource to prioritize project-level permissions.
chore: update SDK version in package.json files
- Bumped @opencode-ai/sdk version to ^1.1.1 across all relevant package.json files.
refactor: streamline bridge message handling
- Updated handleBridgeMessage to accept directory parameter for agent and command requests.
- Improved local API request handling to extract directory from query parameters and headers.
feat: enhance project configuration management
- Added functions to retrieve and merge project configuration paths.
- Improved handling of existing project configuration files for agents and commands.
* feat: enhance VSCode integration and session management
- Added support for a sticky sidebar header background in light and dark themes.
- Introduced functions to read VSCode workspace directory and check if running in VSCode.
- Implemented detailed logging for session loading and creation processes.
- Enhanced session filtering based on directory structure and canonical paths.
- Added a new method to reorder projects and prevent modifications in VSCode workspace.
- Improved error handling and logging for app initialization and markdown file parsing.
- Updated API checks and health checks to ensure readiness before proceeding.
- Refactored code for better readability and maintainability across various modules.
* feat: improve agent and branch selection logic, enhance session management, and update multi-run creation response
* feat: add worktree management actions in agent group detail and sidebar, including delete and keep only options
* fix(ui): share IME guard and cover multi-run
* fix(session): reduce maximum visible sessions in group from 7 to 5