Commit Graph
2761 Commits
Author SHA1 Message Date
c_w_xiaohei ceee7f350e fix(ui): preserve upstream sidebar and selection behavior 2026-08-26 02:36:07 +08:00
c_w_xiaohei f329a22cf3 test(ui): align selection with context shell 2026-08-26 02:31:35 +08:00
c_w_xiaohei 1d694932aa fix(ui): complete session rebase integration 2026-08-26 02:31:19 +08:00
c_w_xiaohei 45693e84bd perf(ui): widen markdown session cache
Retain detached Markdown DOM for eight recent sessions so medium-frequency session switching can restore more first-screen content without reparsing it.

Limit each session to four cached parts, reducing the worst-case retained fragment count from 36 to 32 while preventing long sessions from dominating the cache.
2026-08-26 00:44:14 +08:00
c_w_xiaohei fa1503a038 perf(ui): narrow session switch fanout
Keep sidebar rows independent from the active sync directory by moving export history loading behind an explicit-directory command.

Make active-project selection preserve project topology and remove activeProjectId from mounted group render props. Reuse a per-session-array ID index so subscription snapshots do not repeatedly scan session lists.
2026-08-26 00:44:14 +08:00
c_w_xiaohei 701173e399 perf(ui): index and batch session updates
Batch global session, status, ordering, and activity timing mutations at the existing directory event boundary so large subagent bursts publish each owner once.

Maintain active session roots, children, and directory buckets in the global store, reuse them in Sidebar projections, and avoid rebuilding live aggregates and structural data for unrelated renders while preserving authoritative ordering reconciliation.
2026-08-26 00:42:37 +08:00
c_w_xiaohei df924aa532 fix(ui): bound settings mutation history
Skip mutation history when no settings operation is in flight and merge updates that share the same operation visibility window. This keeps stale-response reconciliation unchanged while preventing history from growing with repeated debounced updates.

Add a repeated-update regression covering an older pending load and latest-value reconciliation.

Tests: bun test src/lib/persistence.test.ts
2026-08-26 00:42:37 +08:00
c_w_xiaohei 4454bf7e14 refactor(ui): encapsulate settings mutation tracking
Keep settings mutation revisions and in-flight operations behind a private tracker so stale GET and PUT responses cannot overwrite newer local settings.

Remove redundant runtime identity and numeric operation IDs. Use operation object identity while preserving runtime reset and mutation retention behavior.

Tests: bun test src/lib/persistence.test.ts
2026-08-26 00:42:36 +08:00
c_w_xiaohei 532bdab5e8 fix(ui): preserve upstream behavior after performance rebase 2026-08-26 00:42:36 +08:00
c_w_xiaohei 9b9d7069c7 perf(ui): isolate scroll shadow effects 2026-08-26 00:42:36 +08:00
c_w_xiaohei dd6a632bc5 perf(ui): streamline overlay scrollbar updates 2026-08-26 00:42:36 +08:00
c_w_xiaohei cd179bd118 perf(ui): avoid parsing markdown control icons 2026-08-26 00:42:36 +08:00
c_w_xiaohei ed37d8e249 perf(ui): isolate sidebar session selection 2026-08-26 00:42:36 +08:00
c_w_xiaohei 77da97953f perf(ui): reuse detached markdown DOM 2026-08-26 00:42:36 +08:00
c_w_xiaohei 1dfa3aee2f perf(ui): stage history overscan restoration 2026-08-26 00:42:36 +08:00
c_w_xiaohei 1c3c26f2bf perf(ui): batch Mermaid viewer initialization 2026-08-26 00:42:36 +08:00
c_w_xiaohei 25be29731f perf(ui): reuse warm markdown blocks 2026-08-26 00:42:36 +08:00
c_w_xiaohei 26dbc2f309 perf(ui): streamline session sidebar state 2026-08-26 00:42:36 +08:00
Bohdan Triapitsyn 3b7d5e1c34 refactor(header): drop session tab tooltips
The hover info card (project/branch/PR/time) added noise without pull —
the tab title plus the sidebar already cover it. The tooltip body
component, its per-hover subscriptions, and the native title attribute
are gone; right-click/menu and the status dot are untouched.
2026-08-25 00:52:01 +03:00
Bohdan Triapitsyn 8458d2a446 feat(header): session tabs are opt-in
Default off; the changelog entry points at Settings → General →
Navigation → Session tabs and mentions the Alt+W close shortcut.
2026-08-25 00:50:19 +03:00
Bohdan Triapitsyn b6e14cbf21 refactor(settings): always-docked editor toolbar; reorder Navigation
The 'Always show editor toolbar' preference is gone — the docked
toolbar under the file tabs is now the only mode, and the floating
hover toolbar branch in the files editor (with its open-state and
outside-click machinery) is deleted. The stored preference is dropped
by a store migration and removed from desktop settings persistence,
settings search and every locale.

Navigation section order now reads: file editor keymap, auto-save,
terminal shell + login shell, Terminal Quick Keys, and the Session
tabs group last.
2026-08-25 00:32:09 +03:00
Bohdan Triapitsyn f40a247be9 fix(settings): include the Session tabs toggle in the General page's visible list
The General section renders OpenChamberVisualSettings with an explicit
visibleSettings allowlist, so the new control was searchable but never
rendered.
2026-08-25 00:20:37 +03:00
Bohdan Triapitsyn ce90e7e24f feat(settings): Session tabs toggle in General → Navigation
A new Session tabs group (web/desktop only) turns the header session
tabs off; disabled, the header renders the exact pre-tabs view — plain
session title with meta row and the always-visible session menu (the
same block VS Code uses). The Alt+W close-tab shortcut no-ops while
tabs are off. Registered in settings search with a matching anchor;
labels translated in all locales.
2026-08-25 00:05:45 +03:00
Bohdan Triapitsyn 2c1d8d592e feat(header): Alt+W closes the active session tab, customizable in Settings
The close-with-neighbour-activation logic moved into a shared helper
(the strip and the shortcut use the same path). Alt+W is the default
because the browser owns Cmd/Ctrl+W on web; desktop users can rebind it
— the action is registered as customizable, so it appears in the
Settings shortcuts section and the shortcuts help automatically. VS
Code is excluded (it has no session tabs).
2026-08-24 20:57:01 +03:00
Bohdan Triapitsyn 71bfb3c8e0 fix(header): cap session tabs at 10 2026-08-24 20:50:22 +03:00
Bohdan Triapitsyn dcacf4b3fc perf(header): cap session tabs at 20; tooltip data loads on hover only
Auto-add means the strip only grows, so past 20 tabs the oldest one
leaves the working set (the newly opened tab is always the survivor).
The branch/worktree/PR/project subscriptions that feed the hover
tooltip moved into the tooltip body component, which mounts only while
the tooltip is open — a resting tab now subscribes only to its status
dot's session status and unread count.
2026-08-24 20:47:51 +03:00
Bohdan Triapitsyn 275d381bd0 docs: changelog entry for header session tabs 2026-08-24 20:41:42 +03:00
Bohdan Triapitsyn a53c78b54a fix: adjust light theme selection color 2026-08-24 20:37:25 +03:00
Bohdan Triapitsyn 4b2ad01b4a fix(header): inactive-tab rename actually starts; snappier tab state change
Rename from another tab's menu stored only a boolean that the
session-switch reset effect wiped before the menu finished closing, so
the tab activated but rename never began. The pending rename now
carries the target session id and begins exactly when that session
becomes active (whether the menu closes before or after the switch),
without the reset effect cancelling it — and without an in-flight
rename being cancelled by unrelated re-renders. Tab background/text
state changes animate at 75ms so activation reads immediate.
2026-08-24 20:18:45 +03:00
Bohdan Triapitsyn b1023b87e7 fix(header): tab title fade is resting-state only; clearer separators
The title fade no longer sits on controls: it lifts while the tab is
hovered or its controls/menu are open (hard clip instead) and is not
applied at all while the active tab renames. The active tab clips its
title instead of showing an ellipsis, matching inactive tabs. Tab
separators drop the extra transparency that made them nearly
invisible.
2026-08-24 20:16:06 +03:00
Bohdan Triapitsyn aad9c25164 fix(vscode): adjust expanded layout threshold for showing sessions sidebar
Keeps enough space for the chat panel when the sessions sidebar stays visible
Bases the expanded layout breakpoint on the sidebar width instead of a fixed value
2026-08-24 20:11:18 +03:00
Bohdan Triapitsyn c47c7190f4 feat(header): session tab tooltips, status dots, cursor context menu
Right-click now opens the session menu under the cursor (the sidebar's
context-menu pattern; the same header-supplied items back both the
"..." dropdown and the context menu via injected menu primitives) and
still never changes the active tab. Hovering a tab shows the sidebar's
session tooltip — title, last-activity time, project, branch and PR
status — after a delay, suppressed while a menu is open or a drag is in
flight. Each tab carries the sidebar's status dot at its end (accent
while the session runs, info-blue for unread), hidden while the hover
controls overlay it. Tab titles fade out instead of ending in "...",
and while the active tab is renaming its hover controls stay hidden so
only the rename controls show.
2026-08-24 20:02:59 +03:00
Bohdan Triapitsyn 338dc73e96 fix(header): one session-tab menu, hidden scrollbar, right-click, control order
The strip now owns a single dropdown per tab, fed by the header with
items bound to that tab's session — rename (activates the tab first),
copy id, share/copy link/unshare, export and move-to-worktree (active
tab only, they need the loaded directory), close other tabs, archive
and delete with the confirm dialog targeting the right session. The
separate inactive-tab menu is gone, and there is no Close item — the
tab's close button covers it, now placed after the menu button.

Right-click opens that menu without activating the tab. The menu's
anchor overlay stays mounted until the close animation finishes, which
removes the popup flashing in the top-left corner on close. The
scroller hides its scrollbar via a dedicated CSS class (the bar was
shifting the header content vertically).
2026-08-24 19:24:17 +03:00
Bohdan Triapitsyn 97ddab73a1 fix(header): session tabs span to the right controls, close buttons, even padding
The old flex spacer split the header in half, boxing the strip into the
middle while tabs shrank to slivers; the spacer now renders only for
the VS Code and surface-title layouts, tabs keep a fixed width (w-44)
and the strip scrolls behind the right-side buttons. Every tab gains a
hover-revealed close button next to the menu; the active tab's menu is
hover-revealed too (it was always visible) — the header passes it into
the strip so both overlays behave identically. The active tab's inner
padding matches inactive tabs.
2026-08-24 19:08:33 +03:00
Bohdan Triapitsyn 447e43eac5 style(header): session tabs follow the titlebar tab design language
Uniform compact tabs (h-7, 6px radius, 13px medium) that share the strip
width and shrink before scrolling, thin separators between inactive
neighbours that disappear around the active or hovered tab, a
hover-revealed menu button anchored to the tab's end, a soft selection
pill for the active tab, and hidden scrollbars with fade edges. The
active tab is single-line: the project/branch meta row stays only in the
VS Code header, which keeps the plain title.
2026-08-24 17:41:34 +03:00
Bohdan Triapitsyn a3813f57e9 feat(header): session tabs — a horizontal working set of open sessions
Web/desktop header replaces the single session title with a strip of
soft pill tabs, one per session the user has opened (sidebar, palette
or deep link — opening anywhere adds a tab once). The active tab is the
familiar title block — rename, meta row and the full session menu —
inside a gently selected pill; a brand-new draft shows as a transient
pill until its session exists. Inactive tabs show the title with a
hover-revealed "..." menu (close tab, close other tabs, copy id) that
nudges the text like sidebar rows, and close by middle-click too.

Tabs drag to reorder, scroll behind the right-side header buttons with
soft fade edges, respect the reserved window-controls inset, and
persist across reloads. Closing the active tab activates its neighbour
(or opens a new draft when it was the last). Tab ids whose session is
not in the loaded list stay stored but hidden, so a partial session
list never destroys the working set. VS Code keeps the plain title;
mobile is untouched.
2026-08-24 17:07:09 +03:00
Bohdan Triapitsyn 7bd27d44d6 fix(vscode): bundle syntax worker imports 2026-08-24 16:58:45 +03:00
Bohdan Triapitsyn c82f188fc8 refactor(surface): remove the main-area surface concept entirely
activeSurface was permanently 'chat' after the legacy mobile layout
removal, so the whole concept is gone: the store field, surfaceGuard,
setActiveSurface/setSurfaceGuard, the per-runtime surface memory in
prepare/restoreForRuntimeSwitch, and WorkspaceSurface itself. All ~30
setActiveSurface('chat') call sites were no-ops and are deleted;
always-true 'is the chat active' checks in keyboard shortcuts, Header
and ChatContainer are unconditional now. FilesView's dirty-file guard
kept its file-switch and close protection but drops the surface-switch
branch nothing could trigger. TerminalView visibility comes only from
its callers. The router keeps parsing legacy ?tab= links (they open the
matching context-panel surface) via its own RouteTab type and no longer
serializes a tab or diff file into URLs — desktop URLs never carried
them anyway.
2026-08-24 16:36:41 +03:00
Bohdan Triapitsyn c6e39f15fe docs: changelog entry for the app-shell viewport switch 2026-08-24 16:21:13 +03:00
Bohdan Triapitsyn 4da7604d7d refactor(surface): drop the deprecated main-tab aliases and dead diagram surface
MainTab/activeMainTab/setActiveMainTab/setMainTabGuard were deprecated
mirrors of the surface names — every call site now uses
activeSurface/setActiveSurface/setSurfaceGuard directly and the aliases
are gone, including the persisted mirror field.

The 'diagram' surface had no way to open it (navigateToDiagram had no
callers except a .drawio attachment click that navigated to a surface
nothing rendered); the surface, DiagramView, and its store plumbing are
removed, and a .drawio attachment now opens in the file panel.

?tab= deep links map to the matching context-panel surface instead of
setting a main-area surface nothing renders, and a persisted non-chat
surface can no longer rehydrate into a blank main area.
2026-08-24 16:21:05 +03:00
Bohdan Triapitsyn 8b7d7803de refactor(layout): remove the legacy mobile layout from MainLayout and Header
Phone viewports run the separate MobileApp shell (and a viewport crossing
now reloads into it), so the desktop layout's mobile branch was
unreachable: the drawer machinery, the full-screen secondaryView surface
switch (including the terminal/diagram desktop carve-out nothing could
trigger), the mobile header with its tab bar, the Cmd+number tab
shortcuts, the mobile quota panel, and the surface guard that reset
non-chat tabs. DrawerContext had no consumers left and is deleted.
Header drops from 2630 to 1853 lines; the desktop render is unchanged.
2026-08-24 16:15:16 +03:00
Bohdan Triapitsyn 841eca5720 feat(surface): switch app shells when the viewport crosses the phone threshold
The mobile-vs-desktop surface is stamped once at boot, so a browser
window narrowed past the phone threshold kept the desktop shell (and
its legacy squeezed layout) until a manual reload. A viewport watcher
now reloads into the other shell once the resize settles — the same
mechanism the old Settings toggle used. Fixed shells (Capacitor,
desktop, VS Code) and ?surface= overrides never switch.

With the new mobile app reachable this way, the old/new mobile layout
preference is gone: phones always get the mobile app.
2026-08-24 16:08:04 +03:00
Bohdan Triapitsyn 98c2a616c3 docs: extend dropdown search changelog bullet with sidebar filters 2026-08-24 15:04:23 +03:00
Bohdan Triapitsyn da309a2a8d refactor(search): session sidebar and project-context filters use the shared matcher
Sidebar session/folder/group search and the Todos, Memory, Plans and
Notes filters required the whole query as one literal substring; they
now match tokens in any order and ignore punctuation via
matchesRankQuery, keeping their own list order and tree structure.
2026-08-24 15:04:14 +03:00
Bohdan Triapitsyn c02d7ff399 docs: changelog entry for unified dropdown search 2026-08-24 15:01:11 +03:00
Bohdan Triapitsyn b8716fe808 refactor(search): unify dropdown filtering on the shared ranked matcher
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.
2026-08-24 15:00:52 +03:00
Bohdan Triapitsyn 081056e6e5 feat(search): canonical rankByQuery matcher for searchable dropdowns
One matcher for every dropdown filter: multi-token queries match in any
order, matching is punctuation-insensitive, single-token queries
tolerate typos, and results come back relevance-ordered (prefix, then
word-boundary, then substring, original order on ties). matchesRankQuery
is the boolean companion for lists that keep their own grouping.
2026-08-24 14:54:14 +03:00
Bohdan Triapitsyn 2eefd46b70 docs: changelog entries for search, terminal, and mobile keyboard fixes 2026-08-24 14:50:03 +03:00
Bohdan Triapitsyn d9f4b4b6cc fix(terminal): stop mobile keyboards auto-capitalizing terminal input
ghostty-web marks the terminal container contenteditable but only its
hidden textarea opts out of IME text mangling, so iOS and Android
keyboards uppercased the first letter of every command. Set
autocapitalize/autocorrect/spellcheck off on the container after open.
2026-08-24 14:30:00 +03:00
Bohdan Triapitsyn 2f27f0ec4b fix(terminal): reconcile tabs with server sessions and keep shown terminals alive
The tab list lived only in per-tab sessionStorage, so a new browser
tab, another device, or cleared storage showed an empty terminal
sidebar while PTYs kept running server-side, and orphans leaked until
the idle sweep. Add GET /api/terminal/sessions and adopt unknown
server sessions into the local tab projection (additive only; a failed
listing changes nothing).

The idle sweep also reaped terminals in background tabs because only
the active tab holds a WebSocket attachment. Add POST
/api/terminal/touch and have open clients periodically refresh
activity for every session their tabs reference.
2026-08-24 14:30:00 +03:00