Commit Graph
1598 Commits
Author SHA1 Message Date
Bohdan Triapitsyn 08a98ce459 Merge pull request #3171 from pocharlies-org/feat/btw-boundary
feat(btw): make a btw session a side question, not a continuation of the parent
2026-08-28 01:24:03 +03:00
Bohdan Triapitsyn 70b04412de Merge pull request #2488 from pascalandr/fix/856-question-markdown
fix(chat): render question prompts as markdown
2026-08-28 01:23:57 +03:00
Bohdan Triapitsyn f64d8b59c8 Merge pull request #3109 from bashrusakh/fix/2982-mobile-agent-duplicate
fix(agents): open duplicate editor on mobile
2026-08-28 01:23:34 +03:00
Bohdan Triapitsyn 073c55a129 Merge pull request #2858 from TomzxForks/issue-2847
Remove the 5-model limit on multi-run groups
2026-08-28 01:23:28 +03:00
Bohdan Triapitsyn 1d423c32d5 Merge pull request #2314 from floze-the-genius/fix/2312-github-settings-disconnect
fix: keep GitHub settings mounted during refresh
2026-08-28 01:23:10 +03:00
Bohdan Triapitsyn 5c03a2a6a7 Merge pull request #2880 from franzudev/fix/markdown-fence-caret
fix(composer): keep caret inside completed fence
2026-08-28 01:22:45 +03:00
Bohdan Triapitsyn ce61646b27 Merge pull request #2510 from IbrahimKhan12/fix/2504-composer-double-space-period
fix: keep the composer's autocorrect on where the platform provides one
2026-08-28 01:22:16 +03:00
Bohdan Triapitsyn c3f3c5aeb7 Merge pull request #3040 from gaojunran/fix/cjk-markdown-links
fix(markdown): keep CJK/fullwidth punctuation out of bare-URL autolinks
2026-08-28 01:22:11 +03:00
Bohdan Triapitsyn 87eacc4c5e Merge main 2026-08-27 23:17:06 +03:00
Bohdan Triapitsyn 7b0d5b2ce2 Merge pull request #2610 from TTTPOB/fix/composer-empty-caret
fix(ui): keep empty composer caret visible
2026-08-27 23:15:12 +03:00
Bohdan Triapitsyn 5da564df81 Merge pull request #2639 from weixiang1862/fix/add-project-browse-added-directory
fix(ui): allow entering already-added directories in the add-project picker
2026-08-27 23:14:59 +03:00
Bohdan Triapitsyn 2396510a14 Merge pull request #2817 from Dawnfz-Lenfeng/fix/init-command-always-available
fix(ui): always show /init command in autocomplete
2026-08-27 23:14:46 +03:00
Bohdan Triapitsyn 413b7b5e58 Merge pull request #2971 from rvaldemar/fix/chat-input-no-model-toast
fix(chat): show visible error toast when no provider or model is selected
2026-08-27 23:14:33 +03:00
Bohdan Triapitsyn d537d58dd7 Merge pull request #3052 from pascalandr/fix/2788-truncated-diff-crash
fix(chat): handle truncated diff headers
2026-08-27 23:13:57 +03:00
Bohdan Triapitsyn f60d56c423 Merge pull request #3168 from AyoubAchour/fix/cloudflared-download-link
fix(tunnels): update cloudflared download link
2026-08-27 23:13:17 +03:00
Bohdan Triapitsyn 43c4cc625f fix(ui): open saved plans against their owning project
Saved Project knowledge plans opened as an empty editor whenever the
viewer could not resolve the owning project from the current directory:
managed chats (openchamber:chats is not a registered project), worktrees
outside the repo path, and plan tabs restored after a reload. Titles
still rendered because the list reads the manifest through the correct
owner.

- Thread the owner explicitly (savedProjectPlan = { projectRef, planId })
  from the panel, mobile surfaces, and persisted context tabs; PlanView
  no longer guesses the project.
- An unrecognized directory resolves to no owner instead of borrowing
  the active project's knowledge.
- Serialize plan writes per document (planSaveQueue) so close/switch
  within the autosave debounce no longer drops the last edits, saves
  cannot land out of order, and a recovered save clears the error banner.
- Send saved-plan contents inline in Improve/Implement prompts (they
  have no file path); disable those actions for managed-chat plans,
  which have no project directory to create a session in.
- Drop persisted plan tabs that carry an id without an owner rather than
  reopening them against a guessed project.
2026-08-27 20:18:12 +03:00
Bohdan Triapitsyn 03f4b5e3e0 fix(ui): scope agent memory to project context owner 2026-08-27 20:18:12 +03:00
ChangeHowandIuliia Ivashko 7aae5a6634 fix: preserve Markdown blocks when copying messages (#2944)
* fix: preserve Markdown blocks when copying messages

* fix: preserve blank lines when copying code

---------

Co-authored-by: Iuliia Ivashko <yulia.ivashko@gmail.com>
2026-08-27 19:37:49 +03:00
dibanez 0389af6cb3 refactor(btw): read the promoted flag from the panel state, not a second subscription
`useBtwPanelState` already subscribes to the composer's own session — it is
what the fork link is derived from — so asking `useSession` for the same
session and directory a second time in `ChatInput` was a duplicate
subscription for a value already in hand. Expose it as `parentSession` and
read the promoted flag from there.

No behavior change.
2026-08-27 14:04:12 +02:00
dibanez 7a95efc4ac fix(btw): stop the boundary from outliving the session it applies to
Review catch: `promoteBtwSession` removes the btw metadata, but the
boundary instruction is persisted on every message the session sent while
it was a side conversation, and there is no API to delete a message part
after the fact. A promoted session therefore keeps reading "no sub-agents,
do not touch the workspace" out of its own history, in a session that is
no longer a side conversation.

Promotion cannot delete those lines, so it answers them instead:
`withoutBtwSessionMarker` now leaves `openchamber.btwPromoted`, and the
composer sends `BTW_PROMOTION_NOTICE` with every message in a session
carrying it — stating that the session is now the main thread and the
usual tool, sub-agent and workspace permissions are in force.

It rides with every send for the same reason the boundary does: the
instructions it revokes are re-read on every turn, so a one-shot notice
would lose its position relative to them as the conversation grows.

`btwPromoted` is additive and optional. A session that never went through
`/btw` never has it, and one promoted before this change simply keeps the
old behavior.
2026-08-27 13:54:29 +02:00
dibanez 92c3e0d5e5 feat(btw): keep the inherited thread as reference, not an active plan
`/btw` forks the session, so the model receives the parent's whole
conversation — including whatever plan was in flight when the user typed
the command. Nothing tells it that this history is context rather than
its own task, so the fork frequently carries on with the parent's work
instead of answering the side question, which is the opposite of what
`/btw` is for.

Send a boundary instruction as a synthetic part with every message in a
btw session: with the first question in `startBtwSession`, and with each
later send while the panel is expanded and the composer is talking to the
fork.

The wording is deliberately position-independent — it names the history
inherited from the parent thread rather than "everything before this
boundary". The instruction rides along with each send instead of being
pinned once at fork time, so a positional phrasing would be re-anchored
every turn and would end up telling the model to disregard the btw
session's own earlier turns.

The part is synthetic, so it is filtered out of the rendered transcript
whenever the message also carries user text — which is always the case
here. No visual change.
2026-08-27 09:21:42 +02:00
Ayoub Achour 61741e58c4 fix(tunnels): update cloudflared download link 2026-08-27 04:10:09 +01:00
Bohdan Triapitsyn 11dd8c4eb0 fix(mobile): pin the chat composer above the keyboard on Android browsers
The chat screen relied on the browser's focused-field reveal, which holds
on iOS Safari but not on Android, where interactive-widget is also widely
ignored — the composer just stayed behind the keyboard. The draft screen's
visual-viewport pin now covers the chat screen on Android; iOS chat keeps
the native reveal.
2026-08-26 23:10:37 +03:00
Bohdan Triapitsyn 25be1985ef chore(ui): remove code orphaned by the shortcut and plan-action cleanups
The eslint pass in release:prepare caught what the package-scoped checks
did not: Header's handleOpenContextPlan and servicesTabs lost their last
callers with the removed shortcuts, the settings-synced listeners no
longer need the DesktopSettings import, and the store's openContextPlan
action itself went unused once the plan surface was reachable only through
the digit switcher and the rail.
2026-08-26 20:40:18 +03:00
Bohdan Triapitsyn 6770bc3717 fix(browser): keep the panel closed when an agent opens a page
The agent's browser.open used to force the context panel open and steal
the active surface, which read as panels opening by themselves. Tab
upserts now take a reveal option: the agent's opener passes reveal: false,
so the tab mounts invisibly (panes are kept alive regardless of
visibility, so agent control still works) while the panel and the active
tab stay exactly as the user left them. Manual opens are unchanged.
2026-08-26 20:32:12 +03:00
𝖎𝖚𝖑𝖎𝖎𝖆 057a4447a3 fix(ui): preserve default in thinking cycle (#3153) 2026-08-26 20:12:01 +03:00
Bohdan Triapitsyn 717854d06b refactor: remove aborted status banner from chat UI
Removes the transient aborted banner from the composer status area
Simplifies status row rendering to focus on working state and pending changes
Cleans up unused abort-status localization strings
2026-08-26 19:50:07 +03:00
Bohdan Triapitsyn 067c6caf0c refactor(chat): slim the selection menu down to comment and notes
Add to input leaves the desktop menu (mod+L owns it; mobile keeps the
button) and the New session action is gone from both variants along with
its handler and dead locale keys.
2026-08-26 19:17:55 +03:00
Bohdan Triapitsyn 098034dc33 fix(desktop): stop windows from adopting each other's active project
Every window shares one server settings document, and every PUT returns the
merged whole, so one window's activeProjectId write was adopted by the
other on its next unrelated settings save — its sidebar then auto-selected
a session in that project and wrote the pointer back, converging both
windows onto one session. settings-synced now carries an adoptWorkspace
flag: only bootstrap-grade syncs (startup, runtime switch) may adopt the
shared workspace pointers; reconcile responses keep the window's own active
project while it exists. Notification clicks and session deep links also
stopped broadcasting the session switch to every window.
2026-08-26 18:36:50 +03:00
Bohdan Triapitsyn f7a006dc6a feat(auth): detect session expiry live and offer re-login in place
Every response already funnels through runtimeFetch, so a classifier there
spots 401s, confirms them against /auth/session (a proxied provider 401
must not read as a logout), and flips a small auth-session store. The web
and hosted surfaces show a frosted banner under the header whose Log in
button hands off to the session gate's existing unlock flow; sends are
paused while expired, the session-load error screen explains the auth case
and retries itself after login, and returning to a long-idle window
revalidates once via visibility/focus. Native mobile feeds the same signal
into its connection re-probe instead of showing the banner; VS Code is
exempt.
2026-08-26 18:22:04 +03:00
Alexandre Reyes Martins 8ea94a119f fix: restore baseline validation (#3142) 2026-08-26 17:15:49 +03:00
Bohdan Triapitsyn 27377efaf3 fix(chat): return the typed prompt to the input on any send failure
The failure handler restored the text only for a new-session draft; a
regular session kept its attachments but lost the prompt to a toast. The
restore now runs before any cause-specific branching: an unchanged composer
gets the text (and the session draft) back, new typing gets the failed
prompt appended instead of clobbered, and a mid-send session switch writes
it into the originating session's persisted draft.
2026-08-26 17:10:05 +03:00
Bohdan Triapitsyn 087c148b2e fix(chat): rescue stranded viewports and settle navigation jumps
Opening a session (or any relayout that shrinks off-screen size estimates)
could leave the viewport in a phantom tail below the measured content, with
every row out of reach above; a totalSize-change check now detects the
fully blank viewport and returns to the real end, and settling a width
resize re-asserts the end for a reader who was on it. Prompt-rail and
message jumps land on estimated offsets that shift as the target mounts and
measures; a short settle loop now re-aligns the target until layout rests,
backing off on the first user gesture.
2026-08-26 16:42:42 +03:00
Bohdan Triapitsyn 2e49e44205 feat(ui): let users hide context rail surfaces
A trailing configure button on the rail — outside the sortable list and the
digit shortcuts — opens a dialog that toggles each surface. The choice is
stored as the hidden set so newly added surfaces appear for everyone, and
the rail and the mod+alt+digit switcher share the same visibility filter, so
badges and shortcuts always agree. Hidden surfaces keep their data and stay
reachable from the command palette.
2026-08-26 16:18:15 +03:00
Bohdan Triapitsyn f2ec9b1003 feat(ui): add session history navigation, permission keys, and review shortcuts
mod+alt+arrows step through this window's session-open history (or between
neighbouring tabs when session tabs are on), mod+k r renames the current
session inline, and mod+k a toggles permission auto-accept. Pending
permission cards respond to alt+enter / alt+shift+enter / alt+backspace with
the keys printed on the buttons. The commit message box commits on
mod+enter, alt+arrows step the diff review between changed files, and the
command palette gains search-only commands for rare actions so the initial
list stays short.
2026-08-26 15:46:44 +03:00
Bohdan Triapitsyn 7977842e1e feat(ui): redesign the default shortcut layout around a mod+k leader
Single chords stay for everyday actions; open/go actions move to two-step
mod+k sequences; held mod+digit switches header session tabs and held
mod+alt+digit switches context panel surfaces. Rare actions leave the
shortcut schema for the command palette, every remaining action ships with
a default binding, and stored overrides from the old layout reset once.
Key matching now follows the physical key on non-Latin layouts and for
Option-modified digits on macOS, including in the recording dialog.
2026-08-26 14:52:31 +03:00
Bohdan Triapitsyn 94f6b5fd38 feat(ui): migrate all shortcut surfaces to the centralized registry 2026-08-26 10:59:04 +03:00
Bohdan Triapitsyn f1c3870909 feat(ui): land the centralized shortcuts core from #2532 with review fixes
The schema/config/bindings/registry/dispatcher module, useKeybind hooks,
recording dialog, reworked shortcuts settings page, help dialog, and the
localized action labels — re-based onto current main rather than merged
(the branch predates 440+ commits including the session-tabs shortcuts).

Review fixes applied on top of the original:
- close_session_tab (alt+w) joins the schema with labels in every locale;
  it shipped on main after the PR's base and would otherwise silently die.
- switch_context_surface's special-case in conflict resolution is now a
  declared prefixStyle config property instead of a magic id string.
- Duplicate handler registration warns in dev builds.
- The risky-browser-shortcut warning inspects every chord and covers
  mod+q/d/h/j/o/u plus mod+shift+w/q.
- The dispatcher remembers which target armed a two-chord prefix so the
  window-level completion handler can distinguish a deliberate sequence
  from typing in an editable field (guard lands with the dispatch hook).
- Schema tests: unique normalized default bindings enforced, and the
  flat-file-era override format proven to keep resolving.
2026-08-26 10:47:44 +03:00
Bohdan Triapitsyn 428854fd78 refactor(sync): replace the session-status setState monkeypatch with an owned API
The global session-status store patched its own setState to derive
active membership for callers replacing statusById — a boundary that
silently trusted any caller passing both fields to keep them consistent.
replaceGlobalSessionStatusById is now the one sanctioned way to swap the
map from outside the event reducers; the runtime-switch reset and the
tests that replaced the map directly go through it, and the patch is
gone. Follow-up to #3126 review.
2026-08-26 03:13:21 +03:00
Bohdan Triapitsyn f0b1c889f0 Merge main into pr1-large-file-preview
The floating editor toolbar this branch was based on was removed on main
(the toolbar is always docked now); the file-view region resolves to
main's structure with this branch's virtualizer-bound ScrollableOverlay.
2026-08-26 02:26:20 +03:00
Bohdan Triapitsyn 448ecc12b8 fix(ui): close review findings from the switch-and-scroll integration
- Markdown DOM cache: key includes a content-length fingerprint so an
  edited or reverted part re-materializing under the same id cannot
  restore stale DOM, memoization uses scalar identities instead of the
  part object (store reducers recreate part objects on unrelated updates,
  which re-ran the async render pipeline for identical content), and a
  probe with a mismatched locale/directory no longer destroys the entry
  it failed to claim.
- Sidebar bootstrap: the layout-level sync owner only knows known
  directories, so expanded projects bootstrapped serialized at background
  priority. The visible collection now publishes a second, expansion-
  aware demand owner, restoring concurrent hydration for expanded
  projects and worktree groups.
- Settings: local changes still sitting in the debounce buffer are not
  yet tracked as mutations, so a settings GET racing the debounce window
  briefly reverted them; reconciled results now reapply the pending
  buffer.
2026-08-26 01:03:47 +03:00
Bohdan Triapitsyn ac880e8e62 Merge main (anchored-turn chat scrolling) into perf/switch-and-scroll
Main replaced the chat timeline scroll engine while this branch was in
flight, which obsoletes two of its subareas and reshapes a third:

- Chat timeline: main's LegendList-based MessageList/ChatContainer win;
  the activation-overscan staircase targeted the removed tanstack path
  (LegendList provides adaptive rendering natively) and is dropped along
  with its test.
- Scroll shadows: main's hook-based masks stay (the virtualized list owns
  its scroll element — there is no wrapper to hand the styling to); the
  viewport-wrapper ScrollShadow rewrite, its index.css replacement, its
  test, and the call-site viewportClassName adaptations are reverted to
  main. The chat OverlayScrollbar keeps this branch's disableHorizontal.
- OverlayScrollbar: the direct-DOM rewrite lands, but binding now follows
  the live container node instead of binding once per ref object — the
  chat scroller remounts on every session switch, and a bind-once
  contract left the scrollbar attached to a dead element.
- Markdown renderer: the detached-DOM cache and warm-block fast path
  merge with main's block-commit reveal (enter cascade), streaming code
  highlighting, and gutter reservation; the per-block reconcile keeps
  both the decoration-refresh path and the reveal cascade.
2026-08-26 00:59:45 +03:00
Bohdan Triapitsyn 5f0f8e64ed refactor(chat): split the composer status bar from the assistant status chip
The composer rendered a second StatusRow instance carrying the
pending-changes bar and the todos dropdown, so every restyle of the
floating assistant-status chip (glass, placement, sizing) silently
restyled the composer bar and its dropdown too — for the fourth time.

StatusRow is now only the floating chip above the composer; the
composer's own bar is a new ComposerStatusBar with the pre-glass layout,
its own container name, and its own container-query classes (the
anti-overlap rules that hide the long active todo under 38rem and the
changed-files label under 30rem moved with it — losing them during the
split let the two dropdown triggers overlap on mobile). The two
components share no markup and no CSS hooks anymore.
2026-08-26 00:35:25 +03:00
Bohdan Triapitsyn 2d8571c6f2 fix(chat): animate end following only during a live stream
The animated maintainScrollAtEnd also ran outside streaming, so opening
a historical session glided visibly through the whole conversation as
late row measurements corrected the end position, and an in-flight glide
could supersede explicit navigation. Corrections are instant unless the
session is actively working.

Returning to the bottom during a stream also lands on the end as of that
moment, and the list's own follow may not have re-armed after the user's
earlier gestures — the queued-send jump then fell behind the growing
reply. goToBottom now re-asserts the edge a few times (150/400/800ms)
until it holds; a new user gesture cancels the window.
2026-08-25 23:54:00 +03:00
Bohdan Triapitsyn 5e37a436c1 feat(chat): soften the committed-block reveal into a materialize cascade
The 140ms fade read as a pop next to the scroll glide. The reveal now
runs 320ms on an ease-out-quint curve with a 10px rise and a touch of
blur resolving — paint-only properties throughout, so row measurement is
untouched — and blocks committed in the same tick cascade with a 55ms
stagger instead of appearing together. Reduced motion still disables the
whole thing.
2026-08-25 23:08:36 +03:00
c_w_xiaohei ceee7f350e fix(ui): preserve upstream sidebar and selection behavior 2026-08-26 02:36:07 +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