Commit Graph
1349 Commits
Author SHA1 Message Date
ChangeHow 61626db245 feat: improve mobile markdown image previews 2026-08-13 16:19:06 +08:00
ChangeHow f790b58d83 feat: add markdown image gallery previews 2026-08-13 16:19:06 +08:00
Serhii Dziupin 8a6eca5597 fix(sessions): select the active project using session ownership (#2865)
* fix(sessions): select the active project using session ownership

Keep a same-project worktree session while its rendered map is stale, but switch to the remembered or fallback session when the current session is known to belong to another project.

Fixes #2317

* test(sessions): pin project-switch ownership recovery in the selection hook
2026-08-13 10:51:40 +03:00
Bohdan Triapitsyn 069d9ad5c9 feat: cap subagent list height in work status panel
Limits the expanded subagents list to eight rows
Adds independent scrolling so other sections stay visible
Documents the new subagents panel behavior
2026-08-12 02:10:27 +03:00
Bohdan Triapitsyn 5917325d49 feat: switch OpenCode Go usage to API
OpenCode Go now reads quota usage with a bearer API key from OpenCode auth.json
Removes the old workspace ID and browser cookie credential flow
Deletes legacy OpenCode Go credential files during upgrade
2026-08-12 01:49:22 +03:00
Bohdan Triapitsyn 22b3665077 feat: show work status on draft sessions and resolve project worktrees
Keeps the work status panel aligned to the draft's target directory
Resolves project labels for sibling worktrees using shared session-directory logic
Adds coverage for resolving a worktree back to its registered project
2026-08-11 17:00:23 +03:00
Bohdan Triapitsyn a20b87e984 fix(work-status): label project details clearly 2026-08-11 17:00:23 +03:00
Andrea VandChangeHow 454119ac25 fix(ui): mount only the active session chat iframe (#2816)
* fix(ui): mount only the active session chat iframe

* repro(ui): mount-all-persisted session-chat iframes (#2815)

Adds a regression-style reproduction for issue #2815: ContextPanel
renders one full-application iframe for every chat tab (inactive tabs
are only hidden via the Tailwind 'hidden' class, never unmounted), so a
reload restores all persisted session-chat tabs from the ui-store and
mounts N embedded OpenChamber apps in one browser tab.

The test reads the real ContextPanel.tsx render block, drives the real
useUIStore with the issue's persisted scenario (11 tabs, 8 read-only
session-chat tabs), and models the render block with the real
buildEmbeddedSessionChatURL helper, showing 8 live src iframes (7
hidden but loaded).

* test(ui): adapt issue 2815 reproduction for active chat

* fix(ui): unmount session chat when panel closes

---------

Co-authored-by: ChangeHow <23733347+ChangeHow@users.noreply.github.com>
2026-08-11 16:11:25 +03:00
Bohdan Triapitsyn b55152db6f fix(usage): refresh work status quotas automatically 2026-08-11 12:58:36 +03:00
Bohdan Triapitsyn a0207e3857 test: cover work-status empty panel recovery 2026-08-10 23:31:58 +03:00
Aaron Hogue 02872ff9d3 fix: keep work-status panel reachable when all sections are hidden (#2805)
* fix: keep work-status panel reachable when all sections are hidden

When every section was unchecked in the Panel Sections dialog, the panel
went transparent and inert, making the settings gear icon unreachable.
The only recovery was knowing to toggle the panel off and on from the
header, which still rendered the same empty/inert state.

Changes:
- Panel stays interactive (not inert) when visible, even with zero
  rendered sections. This matches how other panels in the app use inert
  only for visually-collapsed (width/height = 0) states.
- Empty state shows 'No sections selected' with a link to reopen the
  sections dialog, matching the centered text-muted-foreground pattern
  used by the file tree, review panel, and home page empty states.
- Sections dialog gains a 'Show all' link (visible whenever any section
  is hidden) and a warning when all sections are unchecked, matching the
  keybinds settings 'Reset to defaults' pattern.
- Added i18n keys to all 10 locale files (English fallback).

Fixes #2804

* Round 1: fix interactive guard for fresh-mount; translate i18n keys

Address openchamber-bot review findings:

1. (blocker) Replace English fallback strings in all 10 non-English
   locale files with real translations per locale-ui-patterns guidance.

2. (non-blocker) Restore the renderedSections > 0 guard for the
   transient no-data-on-mount state so the panel doesn't flash a bare
   bordered card. The interactive condition is now:
     visible && (renderedSections > 0 || allSectionsHidden)
   Empty-state rendering is gated on allSectionsHidden alone (not
   renderedSections === 0) so it works correctly on fresh mount when
   all sections were already hidden in persisted settings.

Validation:
  tsc --noEmit: 0 errors
  bun test work-status: 34 pass, 0 fail

* Round 2: use .every() guard, dedup chooseLabel key, add tests

1. Replace >= length check with areAllWorkStatusSectionsHidden() helper
   that uses .every() — stale section ids left in persisted settings
   from a future removal can no longer inflate the count.

2. Remove duplicate chooseLabel i18n key from all 11 locales — the
   empty-state link now reuses the existing sections.open key.

3. Add 6 focused tests for areAllWorkStatusSectionsHidden covering
   empty, null/undefined, partial, full, stale-id, and stale+full.

Validation:
  tsc --noEmit: 0 errors
  bun test work-status: 40 pass (6 new), 0 fail
2026-08-10 23:28:50 +03:00
Bohdan Triapitsyn fb286653f1 fix: adjust model picker scroll shadows 2026-08-10 20:55:39 +03:00
Bohdan Triapitsyn 75978cf188 fix(mcp): reliable OAuth across runtimes and honest pre-restart UI
MCP authorization was broken in several stacked ways. The browser return
leg landed on the SPA behind the auth gate, so the system browser saw a
login page instead of finishing; the pending-context store silently
saved nothing because its route had no JSON body parser; and the
callback-URL config write started deferring behind Apply & Restart, so
authorization ran against a runtime without the URL and dead-ended on
OpenCode's loopback listener.

The return leg is now completed entirely server-side by an
unauthenticated GET /mcp/oauth/callback that only forwards a code whose
state matches a parked context. Desktop with the local server and VS
Code switch to OpenCode's native flow over its fixed loopback port —
no config writes or restarts at all, with a one-time cleanup of the
previously written callback URL — and its completion signal drives the
page instead of blind status polling. Remote, hosted-web, and mobile
keep the server-callback flow, applying a queued callback-URL write
immediately since authorization cannot wait for a manual restart.

Also: a server queued behind Apply & Restart now shows an Awaiting
restart badge and explanation instead of connect/reauthorize buttons
that can only fail, and Reauthorize is offered only while the server is
actually connected.
2026-08-10 20:23:45 +03:00
Bohdan Triapitsyn 3feee346da fix: replace glass dialog styling with solid background
Dialogs and settings window now use the standard background color
Removed dialog from the glass utility styles
Preserves existing glass effects for other surfaces
2026-08-10 18:49:45 +03:00
Bohdan Triapitsyn f9595cb80b fix(projects): open draft after adding project 2026-08-10 16:10:03 +03:00
Bohdan Triapitsyn e5eab8c8be style: soften diff action container shadow 2026-08-10 15:10:37 +03:00
Bohdan Triapitsyn 5e26390ad2 fix: make the composer caret more visible
Thickens the CodeMirror cursor to 2px
Adds a slight vertical scale so the caret stands out above glyphs
Covers the new cursor styling with a test
2026-08-10 15:10:37 +03:00
Bohdan Triapitsyn 2c30af5807 refactor: remove macOS vibrancy support and unify glass surfaces
Drops the macOS vibrancy toggle, IPC, and related settings copy
Updates dialogs, popovers, tooltips, and dropdowns to use shared glass styles
Adds sticky header fade behavior to model picker and sidebar lists
2026-08-10 15:10:37 +03:00
Bohdan Triapitsyn 90a16d1d44 fix(chat): refresh work status from git hints 2026-08-10 15:10:36 +03:00
Bohdan Triapitsyn dfa7b45dd0 fix(mobile): recover pending questions after cold start 2026-08-10 15:10:36 +03:00
Bohdan Triapitsyn e13b4526c6 feat(tasks): manage markdown loops from scheduled tasks 2026-08-09 21:43:16 +03:00
Bohdan Triapitsyn 121685e564 revert: restore auto-hiding overlay scrollbars 2026-08-09 19:53:49 +03:00
Bohdan Triapitsyn f4743ea060 feat(chat): work-status panel, and MCP auth and settings fixes (#2776)
Adds a work-status panel beside the transcript. Context fill, model and
cost, todos, running subagents and the permission requests blocking
them, branch and working-tree state, MCP servers, pinned messages and
context sources were scattered across the header, the composer and the
context panel — a blocked subagent was reported nowhere at all. The
panel reads them from live channels rather than persisted history, and
becomes an overlay where the chat is too narrow to seat a column.

It is on by default, including for existing installs. Because it now
carries these readouts, the desktop header and composer drop the ones it
duplicates: todo and changed-files chips, usage and MCP tabs. VS Code
and mobile keep theirs — neither hosts the panel.

Fixes MCP authorization, which was broken from the panel, invalidated by
a directory switch through a redirect URI that encoded the working
directory, and left the desktop app in the background because browsers
will not follow a custom-protocol link without a user gesture. The
settings page no longer asks the user to understand the MCP spec before
adding a server: one field takes the command or the link, with the kind
inferred and a visible override, and client-registration fields appear
only when a server actually asks for its own credentials.

Also: skills load from the panel instead of only when the composer's
slash autocomplete opens; the header button names the current instance
rather than falling through to the word "Instance" for relay hosts.

Three new optional UI settings keys, all migrated. No change to stored
MCP server configuration.
2026-08-09 19:30:25 +03:00
Bohdan Triapitsyn 4faf660a38 feat(usage): add xAI quota reporting #2628
feat(usage): add xAI quota reporting
2026-08-07 11:48:56 +03:00
Bohdan Triapitsyn c19418cba0 Merge origin/main into deferred OpenCode restart branch 2026-08-07 10:08:50 +03:00
Serhii DziupinandSerhii Dziupin bc380e6e1b perf: cut cold-start download 58% and startup heap 22% via measured chunk-graph fixes (#2742)
* fix(ui): update session-switch-resync test to current handleEvent/setSessionTodos signatures

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>

* perf(build): split Shiki grammars/themes, CodeMirror legacy modes, and @pierre/diffs into on-demand chunks

Merging @shikijs/langs into one manual vendor chunk made the first language
request download every grammar (7.4 MB raw / 1 MB gzip). Letting Rollup split
these packages per dynamically imported module downloads only the languages,
themes, and modes actually used — matching how the worker build already
behaves. @pierre/diffs is split the same way so its pure patch parser (used by
the eager tool renderer) no longer drags the Shiki-importing render stack into
the startup graph.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>

* perf(ui): restore lazy heavy views and stop eager settings-graph loading

- MainLayout: DiffView/FilesView/GitView/PlanView return to lazyWithChunkRecovery
  (they were silently made static in 2031e3b4 while their Suspense wrappers
  remained), keeping the CodeMirror and @pierre/diffs stacks out of startup.
- ContextPanel: same lazy treatment for its Diff/Files/Git/Plan/Walkthrough
  tabs, with null Suspense fallbacks.
- CommandPalette imported getSettingsNavIcon from SettingsView, statically
  pulling the entire settings surface (SkillsPage -> CodeMirrorEditor -> vim
  mode, theme registry -> @pierre/diffs) into the eager graph; the helper now
  lives in lib/settings/metadata.
- The windowed SettingsWindow mounts only after its first open: rendering the
  lazy component closed made React fetch the SettingsView chunk graph at
  startup.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>

* perf(ui): keep @pierre/diffs + Shiki out of the eager chat graph and defer diff worker warmup

- DiffWorkerProvider no longer statically imports @pierre/diffs/worker or the
  theme registry, and no longer spawns 3 workers plus a main-thread shared
  highlighter during mount. Pools are created on demand through a dynamic
  module load, warmed via requestIdleCallback after startup settles, and
  useWorkerPool notifies consumers when a pool becomes available.
- ToolPart's rich diff preview moves to lazily loaded ToolPartDiffPreview;
  the plain-text patch (PlainDiffFallback) renders while the chunk loads,
  mirroring the existing error fallback. Theme registration happens during
  render inside the lazy module so PatchDiff never renders unregistered ids.
- ChatInput mounts its lazy ToolOutputDialog only after the first attachment
  preview opens instead of fetching the dialog chunk on the draft screen.
- getMarkdownSyntaxVars moves to a pierre-free markdownSyntaxVars module so
  eager code-rendering consumers stop importing the registration module.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>

* perf(web): load ghostty-web and Nerd Fonts on first terminal use

- ghostty-web (638 KB raw JS + WASM VT) is dynamically imported when a
  terminal actually mounts; TerminalView stays eagerly importable for the
  bottom dock.
- The ~2 MB of CDN Nerd Fonts are no longer preloaded and force-loaded on
  every cold start. index.html exposes an idempotent
  __openchamberEnsureNerdFonts hook; TerminalViewport requests it on mount
  and waits up to 2s so a cached font is in place before the glyph atlas is
  built, while a cold CDN fetch never blocks the terminal. Runtimes without
  the hook (VS Code, mobile) resolve immediately, matching their existing
  fallback-font behavior.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>

---------

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
2026-08-07 09:01:31 +03:00
Bohdan Triapitsyn da3d467f82 fix(desktop): recover from macOS directory permission failures #2744 2026-08-07 08:52:36 +03:00
deatheros f5603153df fix(ui): use readable permission error color 2026-08-07 02:29:27 +03:00
deatheros d8518bf053 fix(desktop): recover from macOS directory permission failures 2026-08-07 01:49:44 +03:00
Wsyjq 70226149ce fix(chat): pin existing-session sends to captured target (#2424)
* fix(chat): pin sends to captured session

* fix(chat): handle runtime cancellation consistently
2026-08-07 00:46:21 +03:00
Serhii Dziupin 834d2edb87 feat(ui,server): surface active instance service URLs in About settings (#2669)
Show the running instance's local server URL and tunnel URL (when a
tunnel is active) as labeled, click-to-open buttons on the About page.
/api/system/info now reports the instance port and tunnel URL, resolved
lazily from the tunnel runtime so each Git-worktree instance identifies
itself in the UI without parsing terminal output.

Refs OPE-194
2026-08-07 00:25:57 +03:00
Aman Tahiliani bcc64f7586 fix(settings): preserve notification template edits (#2300) 2026-08-06 21:17:16 +03:00
Sérgio Pedro fa63866cbb fix(ui): make overlay scrollbar persistent on desktop shells (#2581)
PR #2520 fixed #2475 in the wrong layer (overflow classes on
SettingsView.tsx wrapper divs that aren't the actual scroll containers),
so the "no scrollbar in Settings" bug shipped in v1.17.2 unchanged, and
the sessions feed has the same underlying issue (#2402).

The actual scroll containers render through ScrollableOverlay ->
OverlayScrollbar, which hides the native scrollbar and draws its own
JS thumb that auto-hides ~1s after scroll activity stops, with a
second CSS rule fully hiding that thumb inside Settings specifically.

Fix both at the shared component/CSS layer so every consumer (Settings,
sessions feed, git panels, chat, etc.) gets a persistent scrollbar on
desktop shells (Electron + VS Code webview) in one change:

- OverlayScrollbar.tsx: skip the auto-hide timer and show the thumb
  immediately on mount when content overflows, on desktop runtimes.
  userIntentOnly consumers (chat auto-follow scroll, reasoning blocks)
  keep today's intent-gated behavior unchanged.
- index.css: scope the Settings-specific hide rule to non-desktop, so
  mobile/web keep existing behavior and desktop gets the thumb back.
2026-08-06 21:10:22 +03:00
Pascal André 7d9af7aa3a fix(chat): expand shell output by default (#2492) 2026-08-06 20:58:49 +03:00
Serhii Dziupin 9368d44b99 Merge pull request #2685 from makeittech/fix/gh-2558-ios-shift-enter
fix(composer): restore Shift+Enter newline on iOS
2026-08-06 18:13:29 +03:00
Serhii Dziupin 99a6dcd052 Merge branch 'main' into feat/gh-2634-pending-question 2026-08-06 13:04:16 +03:00
Serhii Dziupin 5964a7d8ba Merge pull request #2698 from makeittech/feat/gh-2583-markdown-loops
feat(tasks): support markdown scheduled-task loops in .agents/loops
2026-08-06 09:57:49 +03:00
makeittech 59a6c1b70d fix(tasks): guard loop name length and surface loop ownership in the UI
Review follow-up:

- Reject loop files whose frontmatter name exceeds MAX_TASK_NAME_LENGTH
  (80): task names are clamped at storage time, so a raw name longer than
  the limit could never match the stored task identity. The file is treated
  as malformed (definition: null) instead of creating an unreachable
  definition; MAX_TASK_NAME_LENGTH is now exported from project-config.js
  and shared with loops.js.
- Surface loop-sourced tasks in the scheduled-tasks dialog: tasks carrying
  loopFile show a 'Managed by loop file <path>' note, and the enable
  toggle / edit / delete actions are disabled with an explanatory tooltip,
  since the file remains authoritative and would revert any such change.
  run-now stays available. New locale keys added to all 11 message files
  (i18n parity test enforces exact key sets).
- ScheduledTask type gains an optional loopFile field (additive, unknown
  to older clients).
2026-08-06 09:38:18 +03:00
Cursor AgentandSerhii Dziupin 938e58868f fix(ui): let Escape reach the terminal PTY from the context panel
The desktop ContextPanel captured Escape on the panel aside and closed
the whole pane before ghostty-web's bubble-phase listener could forward
the key. Skip closing when the event target is inside the terminal so
apps like Vim can leave insert mode.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
2026-08-05 17:11:41 +00:00
Serhii Dziupin 23a677b45e Merge pull request #2679 from makeittech/feat/gh-2364-git-changes-count
feat(ui): show the changed-files count badge on the Git rail surface
2026-08-05 17:06:24 +03:00
Serhii DziupinandSerhii Dziupin 341b4b45c8 fix(ui): stop painting git activity dots on non-git rail surfaces
The badge PR inverted showActivityDot to !== 'git', so editor/terminal/diff
picked up the blue activity dot whenever git had changes. Git already shows
a numeric badge; other surfaces should stay quiet. Also split the count
aria/tooltip strings into singular/plural keys.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
2026-08-05 13:26:46 +00:00
Serhii Dziupin 7ff86a3bc7 fix(composer): restore Shift+Enter newline on iOS
CodeMirror defers Enter on iOS (and Chrome Android): the real keydown is
captured without running the keymaps and the keymaps then run against a
synthetic keydown that dispatchKey builds from the key name alone, with
no modifier keys. The composer's Shift+Enter thus arrived as a plain
Enter, and on devices where Enter sends (iPad Safari/PWA, where the
desktop layout applies) it submitted the message instead of inserting a
newline.

Record the real Enter keydown's shift state on the view's contentDOM and
restore it onto the deferred synthetic event before the caller's
onKeyDown policy runs, so Shift+Enter means newline again on every
runtime. Plain Enter behavior is untouched: on iOS it still follows the
same deferred path it used before this change.

Fixes #2558
2026-08-05 13:44:36 +03:00
Serhii Dziupin c1ba631964 feat(sessions): show a pending-question indicator on session rows
Adds a per-session pending-question badge to sidebar rows, driven by the
live directory-store question state through a dedicated per-session
subscription channel so unrelated streaming never re-renders rows.

Collapsed parent rows roll up pending questions of hidden descendants
from their owning directory stores without bootstrapping them. Question
state is cloned on session delete/archive so badges clear when sessions
disappear. Adds the questionChangeCallbacks sync performance counter,
i18n keys for all locales, and unit tests for the subscription channel
and scope selection.

Fixes #2634
2026-08-05 13:41:48 +03:00
Serhii Dziupin 9b7c032524 feat(ui): show the changed-files count badge on the Git rail surface
Replaces the plain activity dot on the context panel rail's Git button with
a numeric badge of the changed-files count from the git store status, so the
count is visible at a glance without opening the Git surface. Large counts
cap at 99+ to keep the pill within the 36px button. The badge is reflected
in the button's accessible label and the hover tooltip.

Fixes #2364
2026-08-05 13:37:46 +03:00
Serhii Dziupin 654e9cdb64 feat(chat): refocus composer after adding message to context
After the add-to-context (context pin) action completes successfully, move
focus back to the chat input so the user can keep typing immediately. Uses
the existing focusChatInput helper and the requestAnimationFrame refocus
pattern already used by the model/agent selectors.

Fixes #2447
2026-08-05 13:37:20 +03:00
Bohdan Triapitsyn 094f728777 perf(ui): swap the session activity spinner for a dot and a turn timer
The spinner ran a CSS animation on every active row for the whole turn,
repainting a composited layer at frame rate. Rows now carry a static dot —
primary while running, info while unread — and the metadata slot on the right
shows how long the turn has been going, updating once per second in the dot's
colour. The counter is the motion the spinner used to provide, at 1 fps.
Collapsed groups, folders and projects take the dot only, since one counter
cannot speak for several running turns.

Elapsed time is measured client-side because SessionStatus carries no
timestamps, and starts are persisted so a reload resumes the same count. Two
rules keep that honest. Only a liveness stamp — refreshed while a session is
observed active, stamped as the page hides, and compared against the page's
navigation start so a slow bootstrap is not charged to the absence — and a 90s
adoption window may expire a record; a snapshot that cannot yet see a session
is not evidence its turn ended. And a busy event is never read as a turn
boundary, because OpenCode republishes busy at every step of the agent loop, so
after a reload one of those repeats normally beats the first status snapshot.
Idle and error events do end a turn, and retire the record with it.

Snapshot reconciliation walks the running turns and asks whether the snapshot
covers each one, rather than being handed everything it covers: only a live
start can settle, so the pass scales with timing work instead of with the
directory's session list, and allocates nothing per poll.

Also applied to the mobile sessions sheet and session switcher. The shared
duration ticker moves to hooks/ now that it has a second consumer.
2026-08-05 03:06:35 +03:00
Henry Moran 543b2a2dd1 feat(usage): add xAI quota reporting
packages/ui/src/components/sections/usage/UsagePage.tsx\n  - What: Show selected configured-provider errors in Usage settings.\n  - Why: Preserve provider-specific failures when another provider succeeds.\n\npackages/ui/src/lib/quota/providers/index.ts\n  - What: Register xAI in shared quota metadata.\n  - Why: Expose xAI across shared usage surfaces.\n\npackages/ui/src/types/quota.ts\n  - What: Add xAI to the quota provider contract.\n  - Why: Allow typed xAI results across runtimes.\n\npackages/vscode/src/opencodeAuth.ts\n  - What: Preserve secure auth-file persistence for refreshed xAI credentials.\n  - Why: Reuse the VS Code auth boundary safely.\n\npackages/vscode/src/quotaProviders.ts\n  - What: Add xAI SuperGrok quota fetching, refresh, parsing, and failure isolation.\n  - Why: Provide VS Code usage parity.\n\npackages/web/server/lib/opencode/auth.js\n  - What: Enforce secure auth directory, auth file, and backup permissions.\n  - Why: Protect refreshed OAuth credentials.\n\npackages/web/server/lib/quota/DOCUMENTATION.md\n  - What: Document the xAI quota provider.\n  - Why: Keep provider ownership documentation current.\n\npackages/web/server/lib/quota/providers/index.js\n  - What: Register the xAI web quota adapter.\n  - Why: Expose xAI through the existing quota route.\n\npackages/web/server/lib/quota/providers/xai.js\n  - What: Add SuperGrok usage fetching, inherited OAuth refresh, strict parsing, and zero/error semantics.\n  - Why: Report xAI billing-period usage without new auth architecture or credentials.
2026-08-04 14:40:44 -07:00
Bohdan Triapitsyn ce0e1cea27 fix(git): resolve the base branch from the repository instead of its name
Follow-up to #2629, which stopped the walkthrough from comparing against a
branch that does not exist. The same guessing, and the same near-misses in how
the answer was applied, were left elsewhere:

- The default branch travelled as `rootBranchHint`, whose documented meaning is
  "the branch the project root worktree is on". It gets its own option, because
  a parameter that means two things is one the next caller gets wrong.
- A candidate equal to the branch being compared is skipped. In a plain checkout
  the root hint *is* the current branch, so it won every time and produced a
  comparison with itself; the repository default now wins there.
- The Changes and pull-request surfaces read the default branch too. A pull
  request opened against a branch that does not exist is a worse failure than a
  walkthrough that will not generate.
- `hasResolvableBaseBranch` matched `origin/feature/main` for a base of `main`,
  passing the check and then failing the comparison it exists to prevent.
- `getRangeDiff` promoted only `origin/<base>`. A base carried by any other
  remote stayed a bare name, which git resolves against refs/heads and nowhere
  else, so it failed exactly as before.
- `getBranches` dropped every branch of a remote that did not answer, turning
  "we could not ask" into "these branches are gone" — offline, that silently
  removed comparisons that work fine against local remote-tracking refs.
- A remote with no `remote/HEAD` is asked once with `ls-remote --symref` rather
  than falling back to the guess this data exists to replace.

The `defaultBranches` contract was documented under the status response; it
belongs to the branches response, which now has a section of its own.
2026-08-04 22:41:09 +03:00
Bohdan Triapitsyn 9aa8a3e375 Merge pull request #2629 from RyderAsKing/fix/walkthrough-remote-default-branch
fix(walkthrough): use remote default branch
2026-08-04 22:32:55 +03:00
Bohdan Triapitsyn f3dd894209 feat(ui): numbered context-panel surface switching with configurable prefix
- Add switch_context_surface shortcut (default Cmd/Ctrl + 1..9, 0 for the 10th
  surface) that opens/closes/switches context panel rail surfaces by their
  visible order, configurable and persisted in Settings -> Shortcuts.
- Show order-number badges on rail icons while the modifier is held >500ms;
  dismiss on release, blur, or a number press until the next press-and-hold.
- Remove the legacy mod+2/3/4 (diff/terminal/git) and switch_tab_1..9 bindings
  so numbered surface switching goes only through the new mechanism.
- Replace the help-dialog 'Switch Project' row with the surface-switch row and
  update the shortcuts footer/header icons to the command icon.
2026-08-04 20:39:45 +03:00