Adds `gh` CLI as a GitHub credential fallback for users who already have
`gh auth login` configured locally. OpenChamber-owned OAuth credentials
remain the primary source of truth; the `gh` token is only used when no
stored OpenChamber GitHub access token exists and the fallback is not
disabled.
The fallback is implemented as a credential provider only: GitHub features
continue to use the existing Octokit/GitHub API paths for issues, pull
requests, checks, merges, and related operations. The PR does not replace
those endpoints with `gh issue` or `gh pr` CLI commands.
Server changes:
- Add `gh-cli-credential.js` to read `gh auth token` with a bounded timeout.
- Cache the `gh` token lookup for 30 seconds, including negative results,
to avoid repeated subprocess spawning on status/polling paths.
- Hide the subprocess window on Windows via `windowsHide: true`.
- Clear the gh CLI token cache when the fallback setting changes.
- Update `getOctokitOrNull()` to prefer stored OpenChamber OAuth tokens and
fall back to the `gh` token only when enabled.
- Add `ghCliDisabled` persistence in the existing settings file with atomic
writes and `0o600` file permissions.
- Add `POST /api/github/auth/gh-cli` to enable or disable the fallback.
- Extend `/api/github/auth/status` with `ghCli` metadata: availability,
disabled state, active state, and active user when applicable.
UI/runtime changes:
- Extend `GitHubAuthStatus` and `GitHubAPI` with gh CLI fallback metadata
and toggle support.
- Add web RuntimeAPI support for toggling the gh CLI fallback through
`runtimeFetch`, preserving active runtime/remote target behavior.
- Add deterministic VS Code unsupported handling for the gh CLI toggle.
- Update GitHub Settings to show gh CLI availability and active status.
- When gh CLI is the active auth source, show it in the connected account
card and offer Disable instead of Disconnect.
- Keep Add Account available so users can still connect an OpenChamber OAuth
account, which then takes priority over gh CLI.
- Add localized gh CLI settings strings across supported settings locales.
Fixes addressed during review:
- Removed unreachable UI branches in the inactive gh CLI card.
- Avoided duplicate and repeated `gh auth token` subprocess calls.
- Hardened settings file permissions for the new persisted flag.
- Routed the gh CLI toggle through the RuntimeAPI/runtimeFetch path instead
of direct browser `fetch`.
- Added targeted tests for hidden subprocess options and negative-result
cache behavior.
- Fixed a VS Code webview Response body typing issue that blocked type-check.
Start managed OpenCode from the app data directory instead of the home folder
Prevent unnecessary Desktop, Documents, Downloads, and Music access prompts
Add coverage for configured OpenCode working directory
Agent @mentions in markdown use the primary accent instead of generic link color
Mentions render without external URL favicons
Markdown mode now matches plain text mention styling
Add proper VS Code multi-root workspace support. New sessions now start in the workspace folder the user chooses instead of always using the first folder.
The VS Code sidebar now shows one shared flat session list for the currently opened workspace folders, keeps that list synced when folders are added or removed, and excludes sessions from worktrees unless that worktree is opened as a workspace folder.
Also keep the OpenCode server process independent from a specific workspace folder so changing the selected folder does not restart or interrupt existing sessions.
* 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>
Four sync tests had been failing for a while (CI doesn't run them, so
nobody noticed). All four asserted behavior that was deliberately
changed by earlier refactors — the production code is correct:
- Three event-pipeline tests still expected message.part.updated events
to coalesce in the queue. That coalescing was removed in #1167 to
preserve part update ordering (the new contract is covered by
event-pipeline.test.ts). Updated the delta-ordering and no-coalescing
expectations, and switched the routes-before-queueing test to
session.status, which is still a coalescible type, so it keeps
proving that coalescing happens on the resolved directory.
- One session-ui-store test expected shell sends to run inside an
opencodeClient.withDirectory scope. Since #1228 the session directory
travels as an explicit request param on shellSession; the test now
asserts that contract directly.
All 165 sync tests pass.
The tray showed the busy indicator for at most one session at a time.
Several gaps in how per-session status was sourced stacked up to that:
- Status was derived by iterating each sync child store's session list,
so a busy session missing from the list (created moments earlier from
another window, the tray, or the API while session.created raced or
the list got trimmed) was invisible even though the store's
session_status map already held its busy entry.
- The upstream /session/status endpoint is directory-scoped — querying
it without a directory only covers the server's own cwd, so there was
no authoritative cross-project snapshot to fall back on.
- Status events for directories without a child store were dropped by
the sync dispatcher, so sessions in unopened projects always rendered
idle.
Fix, layer by layer:
- Add a cross-project session-status store (sync/global-session-status)
fed two ways: the sync dispatcher now records status-bearing events
(session.status / session.idle / session.error) for ALL directories,
and the tray polls /session/status per visible-session directory to
seed initial state and reconcile missed events. Snapshots clear stale
entries both by directory key and by session id, so canonicalized
(realpath) directory mismatches can't strand a busy entry.
- Read live status straight from each child store's session_status map
instead of via its session list, and never let one store's idle entry
clobber another store's busy/retry for the same session.
- Resolve a session as active when either source (child stores or the
cross-project map) reports busy/retry, instead of letting the synced
store's idle shadow the fallback.
Verified end-to-end in the dev shell: two sessions running concurrently
in different projects — including a brand-new session in the open
project root, the exact case that failed — now both show busy in the
tray, and both return to idle when they finish.
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.
Added a mobile MCP overlay so MCP tools can be opened and managed from the mobile UI without relying on desktop-only dropdown behavior.
Improved mobile session panel touch handling so tapping the status/session area opens the right panel reliably on phones and tablets.
Cleaned up mobile usage provider metadata by removing duplicate rows, hiding unset providers, and showing provider logos consistently.
Added eager loading for provider logos used in mobile usage views to avoid delayed or missing icons when the panel opens.
Refined the mobile update and about flows in OpenChamber settings so release/update information is easier to read on small screens.
Adjusted related layout, header, VS Code layout, command palette, and settings text/localization details needed for the mobile polish.
Desktop app windows should follow native conventions where clickable controls
use the arrow cursor, not the web's pointer/hand. Under the desktop runtime
only (web in a browser is unchanged), neutralize pointer cursors on buttons,
role=button, links, summary/label, the cursor-pointer utility (and its
hover/group-hover variants), and markdown file links. Resize, grab, text and
not-allowed cursors are left intact.
Enrich each session row in the macOS tray menu and refine its layout.
- Add a "project · branch" sublabel to every session row, resolved from the
session directory: project-root sessions map to their project + live/cached
git branch; worktree sessions map back to their parent project and use the
worktree's branch. Branch resolution falls back live VCS → git store → worktree
metadata, with normalized directory keys.
- Replace the inline text status glyph with a native left-aligned status icon
(vertically centred across the title + sublabel). Idle rows use a transparent
placeholder so every row shares the same gutter and both text lines align.
- Status icons use the app icon set: pulse (busy), check (unread), error-warning
(error), loop-right (retry); all rendered as tinted template images.
- Drop the unread count "(n)" from the row label — the check icon already
signals it and the number wasn't self-explanatory.
- Show the first 8 sessions inline; the rest stay in the overflow submenu.
- Subscribe the tray to the projects, worktree and git stores so subtitles stay
current.
Surface rate-limit usage in the tray, mirroring the header/mobile usage view.
- New "Usage (Used/Remaining)" submenu groups enabled providers with their
window limits (e.g. 5-Hour, Weekly Limit, Credits) and per-window values,
reusing the quota store and the same formatting helpers as the rest of the UI.
- Honors the "configured to show" rule: only providers the user enabled for the
dropdown and that report as configured are shown; when none qualify the submenu
is omitted entirely.
- Tray-side data: build usage groups in useTraySync, push on quota-store changes,
do one initial fetch for enabled providers on launch, and refresh on a
desktop-only interval that respects the user's auto-refresh setting (no change
to web behavior).
- Rows are read-only (greyed) info items; provider flush, windows indented.
- Show the first 8 sessions inline and move the rest into the overflow submenu.
Add an always-visible macOS status bar (tray) item that surfaces OpenChamber's
live state and acts as a quick launcher, plus a series of related desktop UX
fixes around mini-chat, window routing, notifications and shortcuts.
Tray (new):
- Monochrome template cube glyph that adapts to the menu bar light/dark.
- Icon-driven activity indicator: a smooth, eased, infinite "breathing" fill
while sessions are busy; a static filled cube when finished sessions are left
unread; a plain outline when idle. Text counters next to the icon only for
actionable states (pending approvals, errors).
- Menu lists active sessions (status glyph, branch, unread count) with overflow
rolled into a submenu; pending permission/question approvals with inline
Allow once / Allow always / Deny; quick actions (New Session, New Mini Chat,
Show OpenChamber, Quit). Header shows the active instance name
("Local OpenChamber" or the remote host label) for multi-window clarity.
- Session list sourced from the global (cross-project) sessions store, sorted by
last-updated, independent of which directories are currently open; live
status/unread/branch merged in from directory sync stores where available.
Sub-session (multi-run) activity rolls up to the parent row.
- Event-driven updates (global store + directory stores + notifications +
registry) with a short debounce; polling kept only as a slow safety net.
Tray/window routing:
- Opening a session from the tray targets the surface the user was last on: if a
mini-chat is active it switches that existing window to the session in place
(no new window); otherwise the main window (revealed without a reload).
- app.activate (dock click) restores the last-focused/minimized window instead
of spawning a new main window; only creates one when nothing is left.
- "Open in main window" and tray session-open now create the main window when
none exists, queuing the session as a pending deep-link so it opens once the
fresh renderer is ready.
Mini chat:
- New Mini Chat is now a customizable shortcut, exposed in Settings > Shortcuts,
in the File menu (hint only, renderer owns the binding), and in the tray.
- Themed splash backdrop on window open to remove the white flash / flicker;
dismissed once content is ready, leaving the content's single cube logo.
- Mini-chat can switch sessions in place via openchamber:open-session.
Notifications:
- The active/selected session only counts as "seen" when the window is focused,
so turns completing while the app is backgrounded raise an unread marker;
refocusing the window clears it.
Add native macOS vibrancy behind the left sidebar (the only translucent
surface; header/chat/right sidebar stay opaque), plus a setting to turn it off.
- Window created with vibrancy applied after first show (avoids the cold-launch
no-composite quirk); minimize/restore suppress the frost during the genie
animation. Renderer frosts the sidebar via --sidebar-vibrancy-overlay once
data-oc-vibrancy[-ready] are set; project-actions pill matches when open.
- data-oc-vibrancy-ready defaults are set in cssGenerator (DOM guaranteed),
not the preload (document-start race left the sidebar un-frosted on launch).
- prefers-reduced-transparency falls back to solid surfaces.
- Appearance settings (macOS desktop only): a checkbox to enable/disable
vibrancy, persisted to settings.json and applied via a Save & restart button
(vibrancy is a window-creation option, so it needs a relaunch).
Rework the desktop layout so the left sidebar spans the full window
height and reads as a distinct column, separate from the header.
- Persistent top-left controls (sidebar toggle + project actions) as a
single overlay that no longer migrates between header and sidebar, so
it stays put while panels animate. Drag regions carve out only under
the buttons so the strip stays draggable and the buttons clickable.
- Header sits in the content column (bg-background); the divider lives
on the chat content (border-t) so it doesn't run between header and
right sidebar. Right sidebar gets a top border + small content padding.
- Drop the rounded chat card and corner masks for flat 1px borders.
- Right sidebar, context panel and git/files views inherit the
background color instead of bg-sidebar.
- Remove hover background from Changes/Staged rows.
- Mini-chat header: borderless, bg-background.