ea0a01a0466ef545cceb4a2e7f08a53b0163f470
34
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
69b39db427 |
fix(sidebar): make file tree rows reliably clickable
On macOS trackpads, a light touch on a file/folder row can start a native HTML5 drag after ~4px of movement, and Chromium then swallows the resulting click. Track the drag start position and, on dragend, treat a micro-drag (dropEffect 'none' and under 8px of travel) as the click the gesture was meant to be. Reconciled with main's OS file drag-drop upload handlers on the same rows: kept onDrop/onDragOver/hasExternalFiles for external file uploads, and wired the new click-recovery logic alongside it on both the file tree row and the search-results row. Dropped the row's cursor-grab/active:cursor-grabbing classes, since these rows are not meant to read as draggable to the user. Closes #2368 |
||
|
|
99873a7b12 |
fix(files): harden drag-and-drop uploads
Co-authored-by: Serhii Dziupin <serkraser@gmail.com> Co-authored-by: Alan Chen <2144783+alanzchen@users.noreply.github.com> |
||
|
|
423f5b9652 | feat(files): upload files with drag and drop | ||
|
|
652e9c0124 |
fix(sidebar): make file tree rows reliably clickable (#2368)
Native HTML5 drag starts after ~4px of pointer travel and suppresses the click event for the gesture, so the draggable sidebar file tree rows randomly ignored clicks on macOS trackpads/Magic Mouse: folders neither expanded nor collapsed and files did not open. Keep the rows draggable (dragging a file into the chat input inserts an @mention) and recover the suppressed click on dragend: a drag that ended within a small slop radius of its origin without dropping anywhere runs the row's primary action. Also drop the misleading grab cursor so rows read as clickable, matching FilesView. Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com> |
||
|
|
f02969548a |
fix(files): hide desktop-only reveal action and label download in browser clients
Reveal-in-file-manager was always offered whenever the server exposed revealPath, including in a plain browser tab where there is no local file manager to reveal into. Gate it behind a new isBrowserClientRuntime check (web platform, no Electron shell) and relabel the save action to "Download" for that case, since it triggers a browser-style file download rather than an in-place save. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|
|
d35cf957ac |
fix(files): pass directory into context panel binary open guard
Scope context-file open validation to the active project directory so binary opens resolve against the correct workspace root. Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com> |
||
|
|
e2fa7dbad2 |
feat(ui): context panel 2.0 - surface rail, changes-first git view, live PR surface (#2418)
* feat(ui): add context surface registry and rail switcher * feat(ui): move git and project notes into context surfaces, embed editor file tree * feat(ui): replace right sidebar with context surfaces, per-surface panel widths * refactor(ui): retire legacy main-tab overlays and right-sidebar state * feat(ui): rail polish, right-docked file tree, terminal surface * feat(ui): move terminal into context surface, per-surface tab closing, editor empty state * feat(ui): tune default rail order and activity dot * fix(ui): keep context panel controls anchored during width animations * feat(ui): lazy-follow context panel resize with window-level drag tracking * feat(ui): panel dividers, right-dock tree icon, muted outline folder icons * feat(ui): restructure git view into changes-first surface with standalone PR surface - Remove commit/update/pr tabs; git view is always changes + commit - Promote pull request to its own rail surface with shared repo context - Move update-branch and re-integrate flows into separate dialogs - Add PR status chip and repo actions menu to the git header row - Seed new PR-status entries from resolved sibling remotes to avoid a false "checking status" state when the PR is already known - History/graph dialog refresh button, fingerprint global identity icon, muted outline folder icons follow-ups * feat(ui): progressive-disclosure PR surface with live checks and pinned chat context - Segment the PR surface into Overview / Checks / Comments pill tabs with live badges; merge controls move to the status row - Live checks segment: progress bar, per-run rows with workflow names, elapsed timers, expandable failures, auto-refresh while pending - PR comments and failed checks pin as chat-context drafts (like terminal selections) instead of sending an immediate message; works on new-session drafts too - Shared prContext cache client+server, ETag conditional requests in the octokit wrapper (304s bypass rate limits), extended checks aggregate (inProgress/queued/startedAt) - Resolve gh-CLI auth login for merge-permission checks - Full-width description editor with matched control heights * fix(ui): single source of truth for PR checks and status readers - Derive the checks aggregate from the visible run list and sync it into the PR-status store so bar, badges, header, and git-view chip agree - Route PR body hydration through the shared context cache - Git-view PR chip reads the freshest entry across remote keys * fix(github): freshness stamps prevent stale cache responses from regressing PR state - pr/status and pulls/context responses carry a server-side fetchedAt that survives cache serves - The status store rejects responses older than the held snapshot (only clearing the loading flag), and the checks sync adopts the context's stamp so stale status polls cannot flip fresher derived checks - Regression test for the stale-response guard * perf(github): repo-level pull-list cache collapses per-branch PR resolution - One pulls.list per repo per state per 45s answers every branch (10 worktrees = 1 call, not 10 query fans); in-flight fetches coalesce - A complete repo list makes a no-PR miss authoritative, skipping the per-owner head queries AND the Search API fallback (the 30/min killer) - force refresh bypasses the repo list cache; PR create/merge/ready invalidate it * perf(github): back off Search API misses per repo+branch A branch without a PR re-searched on every poll; with >100 closed PRs the list miss is never authoritative, so the search fallback still ran and burned the 30/min search quota. Remember misses for 10 minutes; PR creation clears remembered misses for the repo. * fix(github): dedupe re-run check runs to the latest per (app, name) listForRef returns the superseded completed run alongside its re-run; GitHub's UI shows only the latest per name. Mirror that in both pr/status and pulls/context so counts and run lists match github.com. * fix(ui): address review findings on registry test, surface docs, and PR-context keys - Rail-order test asserts against the registry itself (was stale after the 'pr' surface landed and failed) - surfaces DOCUMENTATION.md describes actual behavior: has-content surfaces hide until content exists; only multi-instance/terminal panes are keep-alive, singleton surfaces remount and restore from stores - PR-context cache keys are runtime-scoped JSON tuples; invalidation compares the directory exactly instead of by string prefix (+ test) * fix(ui): wrap long unbreakable tokens in check-run details Annotation messages with long SHAs/URLs overflowed the panel; break-words on annotation title/message/rawDetails and output summary/text, and the expanded run body clips instead of widening the panel. * fix(ui): busy state for context-attach buttons and honest attach labels - 'Attach failed checks' / 'Attach all to chat' show a spinner and disable while the context request runs (previously nothing happened for seconds) - Action labels/tooltips reworded from send-to-agent to attach-to-chat semantics across all locales * fix(i18n): Ukrainian attach wording uses 'прикріпити' with proper cases * fix(ui): runtime-scope PR-view remote caches, correct surfaces doc on preview - Remote/remote-url caches in PullRequestView are keyed by runtime + directory so a backend switch never serves another runtime's remotes - surfaces DOCUMENTATION.md: preview is not keep-alive; preview tabs remount on switch like singleton surfaces * fix(ui): rail active color, clearer collapse icon, remove dead bottom-terminal dock Design-review feedback on the context panel: - Context rail: icons enlarged 16px -> 18px; the active surface is now highlighted with the primary color only (no background, no scale animation), replacing the previous scale-up effect that read as a resize rather than a selected state. - Files tree: the icon-only 'collapse all folders' toolbar button now uses collapse-vertical instead of contract-up-down, which was easily mistaken for a close button. The labelled 'Collapse all' dropdown item in the session sidebar keeps its icon since text removes the ambiguity. - Terminal: removed the leftover bottom-dock expand/close buttons that rendered in the context-panel terminal but controlled a dock that no longer exists (nothing toggles it anymore), so the expand button appeared to do nothing and duplicated the panel-header fullscreen control. Cleaned up the entire inert layer with it: four useUIStore fields (isBottomTerminalOpen/Expanded, bottomTerminalHeight, hasManuallyResizedBottomTerminal), five actions, their persistence, the MainLayout resize listener that only served the dock height, the dock-driven refit effect in TerminalView, and the terminalView.bottomDock.* keys across all 10 locale dictionaries. Validated: ui type-check and lint clean; messages parity test (2 pass) and useUIStore contextPanel test (13 pass) green; icon sprite regenerated via icons:generate. * refactor: use PR visual state for git header icon Derives the pull request icon color from a single visual state Covers merged, closed, draft, blocked, and open PR states Removes conditional class handling from the git header icon |
||
|
|
85400459e9 |
perf: overhaul session loading, caching, and runtime isolation (#2360)
Improve OpenChamber responsiveness under large session workloads while fixing cache, synchronization, and persistence correctness across runtimes, projects, directories, and worktrees. - prioritize selected and visible sessions during bootstrap and defer non-critical enrichment work - reduce redundant message loading, event processing, store publication, and hidden sidebar work - prevent stale session and message requests from overwriting newer authoritative state - preserve existing data when authoritative fetches fail instead of treating failures as successful empty responses - scope session materialization, messages, drafts, queues, todos, pins, permissions, folders, tabs, Git state, and pull request data by runtime and directory identity - harden runtime switching, reconnect, cleanup, mutation reconciliation, and persisted-state ordering - preserve live subagent Task linkage when metadata arrives after an older message request or while streaming parts are suspended - coalesce overlapping tail refreshes without losing newer refresh demand - improve cold-session loading by moving deferrable work out of the critical bootstrap path - isolate URL authentication, mobile credentials, native secrets, and other runtime-owned state across endpoint changes - bound long-lived caches and remove avoidable allocations from event and rendering hot paths - limit virtualization to archive collections where it improves rendering without disrupting active sidebar layout - stabilize session folders, pin ordering, expanded state, and persisted sidebar behavior - open skill files through the same secure editor and outside-workspace grant flow used by file navigation, including worktree sessions - expand regression coverage for stale completions, runtime collisions, reconnect behavior, persistence races, authoritative empty results, and subagent refresh ordering - document the updated synchronization, cache ownership, performance, and runtime-isolation invariants |
||
|
|
f214af15fc | fix(sidebar): avoid duplicate refresh loads | ||
|
|
cd1ffa8b66 |
fix(sidebar): keep file tree expanded while refreshing root (#2092)
Replace the destructive refreshRoot() with an incremental refresh that re-fetches the root and every expanded directory while preserving childrenByDir. This keeps the file tree expanded instead of collapsing it to the root on every manual refresh. Closes #2036 Co-authored-by: bashrusakh <bashrusakh@users.noreply.github.com> |
||
|
|
9199798a14 |
perf(right-sidebar): gate live effects, memoize lookups, always-mount tabs (#1674)
* perf(right-sidebar): gate live effects, memoize lookups, always-mount tabs
Performance fixes for the right sidebar (git/files/context tabs).
== Correctness / leak fixes (P0)
* RightSidebar: drop dead useEffect that re-nulled refs the resize
handler already nulled; collapse the redundant width/minWidth/maxWidth
triple into width + the existing --oc-right-sidebar-width variable.
* useUIStore: clamp setRightSidebarWidth to [MIN, MAX]; simplify
setRightSidebarOpen (22 lines -> 12).
* RightSidebarTabs: useRightSidebarGitSync now takes the right tab and
main tab and only polls when the right git tab is the visible consumer
and the browser is online + visible. Replaces a global poll that
fired for the lifetime of the open sidebar.
* GitView: commit-files fetch refactored to cancelled + Promise.all
(was a per-hash loop that could setState after unmount); getRemoteUrl
and refreshRemotes gated on cancelled/mountedRef; new module-scoped
mountedRef guards setIsSettingIdentity from firing after unmount.
* GitView + useGitmojiList: extract gitmoji fetch/cache into a hook
with module-level inflight promise + subscribers Set; stale-while-
revalidate from localStorage; ensureLoaded() for call-site-initiated
hydration; cancelled flag on setIsLoading to avoid the React
setState-after-unmount race.
* ProjectNotesTodoPanel: 400 ms notes debounce now cancels on blur
(was double-saving); persistProjectData chained per project through
a module-level Map<projectId, Promise> so a fast todo toggle racing
the debounced save no longer hits the server in parallel; resize
auto-adjust guards against same-value pings.
== Render fanout (P1)
* RightSidebarTabs: all three tab content components are now always
mounted with the hidden attribute. State and cache survive tab
switches. When activeMainTab === 'git' (or 'context') the matching
right tab is filtered out of the tab strip and a redirect effect
snaps any persisted-but-now-hidden right tab to 'files'. onSelect is
now a type-guarded handler instead of `as RightTab`.
* GitView: 13 separate useGitStore action selectors collapsed into one
useShallow block (one re-evaluation per store change instead of 13).
* GitView: new isGitViewActive flag (true when this instance is the
visible consumer) gates the 7 live effects — load identities, fetch
remote URL, refresh remotes, ensureAll, sessionEvents.onGitRefreshHint,
worktree bootstrap poll, default-identity auto-apply. Hidden
GitView instances no longer run these.
* GitView: gitViewSnapshots module-level Map is now backed by an
LRU wrapper (cap 20) so per-directory draft snapshots cannot leak
across hundreds of project switches. Removed the dead `unique.set`
dedup in changeEntries — GitStatus.files is already unique by path.
* SidebarFilesTree: statusByPath Map<path, FileStatus> and
badgeByDir Map<dirPath, { modified, added }> are precomputed once
per gitStatus change. Tree render is O(1) per node instead of O(N)
per node via the previous per-row find/scan. badgeByDir walks each
file's path segments and increments counters for every ancestor
dir, so total cost is O(N + total_dirs_in_files) per gitStatus
change.
* SidebarFilesTree: FileRow wrapped in React.memo with a custom
comparator. Context-menu open state moved INTO FileRow as local
state — opening a menu in one row no longer re-renders siblings.
* SidebarFilesTree: loadDirectory accepts an isCancelled predicate;
the batch-load effect for expandedPaths passes a stable predicate
so per-dir fetches stop touching state once the effect tears down.
* SidebarFilesTree: module-level fileTreeCacheByRoot Map (LRU,
cap 8 roots) hydrates childrenByDir / loadErrorsByDir /
loadedDirsRef on mount or root change. Mirror effects write state
back to the cache. Survives close-and-reopen of the right sidebar;
populated entries are dropped on unmount only when they had no
data.
== Result
Net diff: 6 files modified, 1 new (useGitmojiList.ts), 682 insertions,
283 deletions. Existing test suite baseline preserved (537 pass / 58
fail / 1 error) — no new regressions. The 58 pre-existing failures are
in unrelated chat/streaming tests and were verified via git stash on
the same branch.
Architecture assumptions, verified by manual review:
- P1.1's redirect effect snaps rightSidebarTab to 'files' whenever
activeMainTab === 'git', so the right and main GitView instances
are mutually exclusive — isGitViewActive cannot be true for both.
- The 7 gated effects plus the useRightSidebar GitSync poll cover all
cases where git state should advance: visible consumer fetches; the
poll keeps the store warm when only the right git tab is visible.
- The aborted loadDirectory predicate is sufficient because
inFlightDirsRef and loadedDirsRef dedup at the call site before
any network IO is initiated.
* fix(sidebar): always clean up inFlightDirsRef regardless of cancellation
* refactor(sidebar): deduplicate RIGHT_SIDEBAR_MIN/MAX_WIDTH constants, export from useUIStore
* docs: split right sidebar perf plan into standalone file, clean up merged master status from chat plan
* fix(git): gate GitView effects by instance visibility
---------
Co-authored-by: Leonid Skorobogatyy <bash@opencode.itc.local>
Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
|
||
|
|
ca87428216 | fix: harden file previews and downloads | ||
|
|
12c8cbf544 |
feat: add right-click menus across sidebar rows
Open row actions at the pointer position Keep three-dot menus working separately Reuse shared menu styling for consistent visuals |
||
|
|
f9acf68c8f |
feat(ui): full-height left sidebar with decoupled header layout
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. |
||
|
|
de0ebbac8b |
fix: make file tree loading more reliable
Avoid gitignore filtering during folder browsing Show folder load errors instead of empty folders Add timeout fallback for gitignore checks |
||
|
|
becd240168 |
Add Windows Electron desktop support (#1093)
* fix: make upstream sync actions target the selected remote Ensure fetch and pull actually honor upstream selection so fork maintenance works from the Git sidebar, and surface upstream branch status alongside the primary origin-tracking indicators. * feat: add Windows Electron desktop foundation * fix(electron): stabilize Windows desktop packaging * fix(electron): stabilize Windows desktop chrome Use native Windows titlebar behavior with an Alt-accessible hidden menu, and harden Windows dev command launching so the desktop app follows platform conventions. * fix(electron): stabilize Windows dev startup * fix(electron): clarify desktop artifact names * fix(electron): harden Windows desktop release and launch * fix(electron): address Windows release review * fix(electron): point updater and release links to org repo * Fix Windows settings persistence fallback * Fix Windows Electron dev startup * Add Windows Electron window controls * Fix Windows Electron install and opencode launch * fix: resolve git status for repositories without upstream Fixes repository detection stuck on Checking repository Handles git status when no upstream is configured Adds regression coverage for git status loading * Add Windows app menu button * fix: preserve file editor line endings * ci: add desktop release smoke workflow --------- Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com> |
||
|
|
b7440bef39 |
Fix (mobile) add long-press support to shared tooltips (#1386)
* Add long-press support to shared tooltips * fix bot comments * Fix controlled tooltip long-press suppression --------- Co-authored-by: Konstantin Zolin <zolin_ka@vk.com> Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com> |
||
|
|
0f015a495b |
fix: constrain oversized loading spinners (#1326)
Prevents loading icons from rendering too large Adds explicit sizing to file and diff loading states |
||
|
|
14357257ae |
perf(ui): migrate icons to SVG sprite system
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 |
||
|
|
4523e9c486 |
perf: reduce re-renders, fix mobile keyboard handling, add chunk load recovery, and improve PATH management (#1028)
* fix: exclude file content from reverted prompt text Revert and fork now restore only the user's original prompt, not server-injected file content Uses existing isSyntheticPart helper for type-safe filtering * fix: keep scrollbar visible when hovering over thumb * fix: prevent ESC abort from triggering when terminal is focused * fix: pass directory to permission/question reply calls so approvals actually resolve * fix: default model selection not responding after Base UI migration * fix: prevent modal content from shifting and clipping footer buttons * fix: improve session switching performance and add sub-agent export with prompt collapse Defer viewport anchor saving to eliminate ~800ms UI freeze when switching sessions Add export dialog to include sub-agent tasks recursively in markdown export Add collapse chevron button for expanded user prompts in sticky header * fix: resolve sidebar scroll and TDZ crash in session sidebar * perf: reduce CPU overhead and re-renders across chat, layout, and settings * fix: position collapse button at top of message and prevent ESC abort in terminal * fix: position collapse button at top and add padding only when expanded * refactor: extract shared PATH utilities and mobile keyboard hook * refactor: import shared path-utils in electron, use module-level style constants - Electron now imports pathLooksUserConfigured/mergePathValues from shared path-utils.js instead of inline duplication - ToolPart collapsedCustomStyle moved from useMemo([]) to module const * fix: resolve remaining merge conflicts and type errors - Remove duplicate variable declarations in SessionNodeItem - Remove orphaned export callback body from conflict resolution - Fix HelpDialog description -> descriptionKey (i18n rename) * fix: resolve type-check and lint errors in session-actions.test.ts - Added missing bun:test type declarations (beforeEach, mock, mock.module) - Removed unused State import - Replaced 'as any' casts with proper OpencodeClient and ChildStoreManager types - Added eslint-disable for unused _ parameter in mock function * fix PR 1028 export and PATH edge cases * fix startup retry exhaustion state * remove opencode package lock change * fix sub-session rename cancellation --------- Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com> |
||
|
|
7d7285655d |
Add i18n foundation and translations (#1027)
* feat: add i18n foundation * feat: localize sessions sidebar * Localize multirun/scheduled tasks and fix dialog dropdown interactions * localize git sidebar surface and add zh-CN keys * feat(ui): localize context panel, diff/plan views, and context sidebar content * fix(config): resolve user config home via fs/home before embedded home * localize header/chat UI and complete model/worktree panel strings * localize worktree + github issue/pr dialog flows * localize settings sections and split settings i18n dictionaries * localize additional settings sections and sidebars * localize more settings pages and dialogs * fix settings select trigger localization * localize tunnel settings ui surface * localize additional settings sections * localize keyboard shortcuts labels in settings * localize terminal and utility dialogs surfaces * feat(i18n): localize remaining UI strings * Add Ukrainian locale * Add Spanish locale * Add Brazilian Portuguese locale * Polish locale translations |
||
|
|
bc6cb91954 |
Chat input: drag-drop files and folders from file tree with @folder autocomplete (#963)
* feat(chat): drag-drop files/folders from file tree into chat input Features: - Support drag-and-drop files and folders from file tree into chat input - Support @folder autocomplete for file/folder mentions in chat input - Add drag support to file tree nodes for dropping into chat input - Persist confirmed mentions to localStorage across sessions Fixes: - Fix drag state getting stuck with drag enter counter and onDragEnd cleanup - Fix pendingSearchRef counter leak on query cancellation - Fix confirmed mentions highlight/delete for folder paths - Fix clear confirmed mentions on send and autocomplete loading state - Guard drag-start against empty and root-relative paths - Reset loading state when pendingSearchRef reaches zero * fix(chat): address Greptile PR review findings - P1: move confirmedMentionsRef.clear() out of handleQueueMessage to prevent bare-name mentions from being lost when queued messages are sent via handleSubmit - P2: distinguish internal file-tree drag from external file drag in overlay text (Drop to insert as mention vs Drop files here to attach) - P2: add directories to marquee overflow effect dependency array * fix(chat): prune stale confirmed mentions --------- Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com> |
||
|
|
fd8972a7d9 |
Add save actions and cross-platform file manager support (#848)
* files-download-feature * feat: add save option to file directory context menus and viewer * fix: open files in the system file manager |
||
|
|
952132a08d | fix: remove desktop translucency to reduce macOS compositing cost | ||
|
|
c9e31a0e6c |
perf: harden sync architecture and modularize runtimes (#803)
* fix: added desktop app background throttling
* perf: add streaming debug metrics panel
- Show streaming performance metrics in the debug panel
- Auto-enable stream profiling while the panel is open
- Add JSON export for sharing UI and VS Code metrics
* perf: batch streaming updates more aggressively
- Buffer message deltas and metadata updates to cut render churn
- Skip no-op part updates before they touch the message store
- Fix the desktop debug panel shortcut binding
* perf: split streaming event handling and coalesce deltas
- Move streaming content events onto a dedicated fast path
- Defer non-critical stream side effects off the hot path
- Merge repeated message delta events before they reach the UI
* perf: isolate streaming rows from chat rerenders
- Memoize chat rows against render-relevant message changes only
- Read live assistant text directly from store to narrow streaming updates
- Split the active streaming entry from the stable message list path
* perf: streamline chat streaming and SSE proxying
- Reduce chat rerenders around the active streaming path
- Simplify server SSE forwarding to avoid duplicate proxy work
* fix: preserve the first streaming text chunk
- Show the initial text chunk immediately before batched deltas arrive
- Bypass batching for the first text or reasoning part update
- Keep later streaming updates buffered for performance
* perf: align streaming/render hot paths with opencode parity
* perf: harden turn/cache stability and stale delta suppression
* fix: stabilize chat rendering and disable timeline interactions
- Disabled timeline dialog access from shortcuts, commands, and chat input
- Reduced chat render churn by simplifying message list and turn staging behavior
- Improved session-switch stability to prevent update-depth crashes
* perf: track static message rerenders during streaming
* perf: reduce sorted-mode activity rerender fanout
* perf: reduce chat rerender fanout and add active-turn metrics
- Reduced sorted-mode rerender coupling by tightening turn context propagation
- Added a metric for static rerenders outside the active turn during streaming
- Exposed new chat render counters in the debug panel for parity tracking
* fix: keep sorted activity mounted while stream grows
* fix: stabilize session and history scroll rendering
* refactor: decouple server routes from index
* refactor: extract fs module from server index
* refactor: move opencode route ownership into module
* refactor: extract notification route registration
* refactor: extract opencode and notification runtimes from index
* refactor: extract settings runtime and complete server modularization pass
* refactor: modularize server config, skills, icons, and tunnel routes
* refactor: extract server modules from monolithic index.js
Split proxy, routes, runtime helpers, and notification emitter
into dedicated modules under packages/web/server/lib/.
* refactor: replace session/message stores with SSE-driven sync layer
Delete ~9200 lines of old architecture (useEventStream, messageStore,
sessionStore, useSessionStore, questionStore, useTodoStore, client SSE).
New sync layer: event pipeline with coalescing + 16ms flush, pure event
reducer, per-directory child stores with LRU eviction, cursor pagination,
optimistic updates, deferred timeline staging, text throttle.
Migrate all UI consumers to sync hooks (useSessionMessages,
useSessionMessageRecords, useSessionStatus, useSessionPermissions, etc).
Strip session-ui-store to UI-only state, delegate SDK ops to
session-actions with abort-if-busy, optimistic store updates, and
response merging for revert/fork/archive/delete.
Add notification-store for SSE-driven session attention tracking,
cross-directory GlobalSessionStatusStore for sidebar indicators,
client-side diff snapshot sanitization to prevent memory bloat,
and revert message filtering via useVisibleSessionMessages.
* feat: notification store, session actions, activity detection
Add notification-store.ts for SSE-driven attention tracking.
Add sanitize.ts to strip diff snapshot memory bloat.
Add session-actions.ts with optimistic revert/fork/archive/delete.
Improve useSessionActivity with incomplete-message fallback.
Delete useServerSessionStatus polling hook.
* fix: add directory param to all SDK calls, fix command/shell/abort routing
All SDK calls in session-actions.ts now pass directory parameter —
required by OpenCode server to scope session operations. Without it,
abort, commands, revert, fork, and other operations returned 500.
Add routeMessage() in session-ui-store for shell mode (session.shell),
slash commands (session.command), and normal prompts. Command lookup
checks both sync child store and useCommandsStore. Handle /compact
locally via session.summarize().
Implement getContextUsage() to restore header context usage display —
reads token counts from last assistant message in sync store.
* refactor: replace custom API proxy with http-proxy-middleware
Remove ~280 lines of custom proxy code: forwardSseRequest,
forwardGenericApiRequest, collectRequestBodyBuffer, header
manipulation, hop-by-hop filtering, SSE block buffering.
Replace with single createProxyMiddleware() call that handles
SSE streaming, large bodies, and timeouts out of the box.
Dynamic router for OpenCode port changes after restarts.
Auth headers injected via proxyReq hook.
Keep: readiness gate, Windows session merge, API prefix detection.
* perf: targeted event draft cloning to fix streaming render cascade
Event handler was eagerly cloning all state slices on every event,
breaking Zustand selector referential equality. During streaming
(~60 events/sec), this caused every subscriber to re-render regardless
of which slice actually changed.
Now only clones fields the specific event type mutates. Also extracts
StatusRowContainer to isolate high-frequency useAssistantStatus
subscription, removes dead messageStreamStatesMap subscription from
ChatContainer, and narrows useAssistantStatus to only track last
assistant message parts.
MessageList renders: 1972 → 296 per streaming session (-85%).
* fix: null safety for sync state slices
Add defensive ?? {} guards on permission, question, session_status,
and message record access. Prevents crashes when child store state
is partially initialized during bootstrap.
* perf: dedup inflight SDK calls, extract concurrency util, delay PR tracking
Extract mapWithConcurrency to shared lib/concurrency.ts. Add in-flight
dedup for loadProviders/loadAgents to prevent concurrent duplicate SDK
calls. Delay initial PR background tracking by 5s to reduce startup
CPU burst.
* fix: header session lookup across all child stores
Session title and context panel click failed when session belonged to
a different directory than the current child store. Fall back to
getAllSyncSessions() to search all initialized stores.
* chore: bump @opencode-ai/sdk to 1.3.5
* docs: add sync event handling guide
* Optimize session prefetch and improve delete/archive UX
- Add settlement delay to session prefetch to avoid race conditions on
rapid session switches
- Reduce git diff prefetch and session cache limits for better performance
- Implement optimistic UI updates for session delete/archive operations
with proper rollback on failure
- Wire session prefetch hook into SessionSidebar with sync integration
* Add file content cache and sync optimizations
- Wrap FilesAPI with in-memory LRU cache for file content with dual
constraints (entry count and byte size)
- Optimize chat timeline scroll restoration using useLayoutEffect
- Preserve React references in message and part arrays to prevent
unnecessary re-renders when prepending history
- Add session prefetch TTL cache to prevent redundant fetches
- Integrate session prefetch cache clearing with eviction flow
* Improve session sidebar error handling and add diff prefetch filtering
Load active and archived sessions independently using Promise.allSettled
to prevent one failure from blocking the other. Add retry logic to session
API calls and skip large files during diff prefetch to improve performance.
* Replace sendMessage with optimisticSend wrapper
Introduces optimistic UI updates for normal chat messages to provide
instant feedback. Messages appear immediately in the UI while the API
call executes in the background, with automatic rollback on errors.
* perf: split stores, proper optimistic send, fix revert/directory bugs
- split session-ui-store into voice/input/selection/viewport stores
to reduce subscriber re-evaluation during streaming
- wire optimisticSend through useSync shadow Map infrastructure
matching OpenCode's pattern (no heuristic part detection)
- port OpenCode Identifier.ascending ID format for correct sorting
- pass messageID to promptAsync to prevent duplicate messages
- fix worktree directory not propagating to session actions
(dynamic dir() via opencodeClient.getDirectory)
- fix setCurrentSession accepting directoryHint for new sessions
- fix revert not hiding messages (session limit was 5, bumped to match loaded count)
- fix revert optimistic message removal from store
- fix load-more flicker (useLayoutEffect scroll compensation)
- add prefetch TTL cache, file content LRU cache
- add session prefetch for adjacent sessions
- add instant archive/delete (optimistic before SDK call)
- migrate legacy window.__zustand_session_store__ to session-ui-store
- add retry + independent error handling for archived sessions
- add AGENTS.md performance rules
* perf: startup optimization — dedup, caching, light git status, diff rendering gates
- defer diff prefetch to git tab open, reduce concurrency 4→2, skip >500 changed lines
- cap project git checks concurrency (2), directory status probe (3)
- dedup provider/agent loading, github auth, worktree list (in-flight + TTL caches)
- delay PR tracking 5s, cache 403 search failures per-repo
- coalesce settings PUT (200ms debounce), cache settings GET (2s TTL)
- cache canonical directory resolution (60s TTL)
- persist missing directory status to localStorage (10min TTL)
- light/heavy git status: polling skips numstat+line counting+rev-list
- large diff rendering gate (>500 lines → "render anyway" button)
- tokenization degradation for >500KB files in Pierre
- parallelize main.tsx pre-render awaits
- batch sidebar file tree expanded paths restoration (3 at a time)
- remove bare useConfigStore() subscription in AgentsPage
- sync worktree sandboxes to OpenCode SQLite DB
- fix RightSidebarTabs ternary → explicit tab matching
- defensive guards on sync state (session_status, permission, question, message)
* fix: add defensive guards on remaining sync state field accesses
guard session_status, permission, message, todo, part, config with ?? {}
in useDirectorySync selectors, session-cache, and bootstrap
* fix: add missing directory dep to useCallback in use-sync.ts
* fix: preserve diffStats when light-mode polling overwrites status
* perf: optimize startup git status polling and diff rendering
Preserves diff stats when lightweight polling updates repository status
Reduces startup overhead with smarter git polling and store updates
Adds detailed optimization and migration docs for next performance steps
* fix: keep chat diff stats stable during git status updates
Prevents lightweight git polling from dropping diff statistics
Keeps MessageList diff indicators consistent while status refreshes
Improves reliability of git-aware chat rendering
* fix: user animation replay, queued message variant, startup provider loading
- consume animation ID after first play to prevent re-animation
on neighbor assistant message completion
- capture send config (model/agent/variant) at queue time matching
OpenCode's FollowupDraft pattern instead of re-resolving at send time
- replace one-shot startup recovery effect with polling interval
that retries every 2s until providers and agents load
- fix optimistic bridge to avoid re-render loop (stable ref wrappers)
* chore: update tauri to 2.10.3 and all plugins to latest
- tauri 2.9.4 → 2.10.3
- tauri-build 2.5.3 → 2.5.6
- tauri-plugin-dialog 2.4.2 → 2.6.0
- tauri-plugin-log 2.7.1 → 2.8.0
- tauri-plugin-shell 2.3.3 → 2.3.5
- tauri-plugin-updater 2 (floating) → 2.10.0 (pinned)
- @tauri-apps/api ^2.9.0 → ^2.10.1
- wry 0.53.5 → 0.54.4 (transitive)
* refactor: decouple web server index orchestration runtimes
* fix: align VS Code runtime behavior with web and reduce draft view CPU load
- Queue VS Code bridge and SSE startup requests until API readiness to avoid false bootstrap failures
- Make agent manager actions directory-aware and remove real worktrees with safer partial-failure handling
- Replace heavy logo animation path with a lightweight pulse to cut draft-session CPU usage
* fix: restore auto-selected file sending in chat input
- Send server-selected files as proper file URLs in the message payload
- Include server-backed attachments in submit flow instead of dropping them
- Restore queued-message attachments through the refactored input store
* fix: restore session model selection consistently on session switch
- Restore agent, model, and variant from the latest loaded user message for each session
- Wait for session messages before applying restored selections to avoid stale or missing state
- Remove legacy session-choice inference paths that caused overlap and instability
* fix: restore permission replies and auto-accept across sessions
- Scope permission and question replies to the target session directory so answers take effect reliably
- Make permission auto-accept immediately handle pending requests and react to new permission prompts
- Keep parent-session handling working for child-session requests through the shared response path
* feat: add reusable fuzzy branch fuzzy-search helper and dialog integration (#798)
* feat: add reusable fuzzy branch search for worktrees
* chore: drop planning docs from feature branch
* feat: make worktree branch refresh manual
* feat: add configurable session retention action
* refactor: centralize global session state in ui store
* fix: cancel debounced permission push after reply
* docs: clarify global and directory session store architecture
* docs: refine agent development rules and session activity guidance
- Clarify agent code of conduct and durable development patterns
- Add explicit shared-store rerender and live-state guidance
- Narrow session activity fallback to avoid stale working state
* chore: updated .gitignore
---------
Co-authored-by: Iuliia Ivashko <yulia.ivashko@gmail.com>
|
||
|
|
b4949c6e33 |
fix(files): incremental directory refresh on create/rename/delete (#721)
Replace the full-tree nuke-and-reload in refreshRoot() with a targeted refreshDirectory(parentPath) that only evicts and reloads the single parent directory whose contents changed. Before: every create/rename/delete call cleared the entire childrenByDir cache and reloaded only the root, causing all expanded subdirectories to flash empty and visually reset. After: only the parent directory of the affected entry is reloaded in-place; every other expanded directory keeps its cached children, so the tree state is preserved and there is no visible flash or scroll-position reset. Applies to both FilesView and SidebarFilesTree. |
||
|
|
79143bff4c |
feat: massive chat reliability + UX pass (web/desktop/mobile/vscode) (#593)
## Added Features - Add VS Code save-as-image flow for assistant messages via webview bridge + native save dialog. - Add hourly desktop update checks after startup. - Add new tool output display mode: `Changes` (auto-expand edit/write/patch only; keep activity expanded; mode guidance text). - Add GitHub PR attachment flow in chat input with PR picker + attached PR chip/details. - Add mobile overlay presentation for GitHub Issue and PR pickers (shared with desktop picker content). ## Fixes - Save-gate project icon updates until explicit Save; allow icon removal with same save-gated behavior. - Restore clickable chat action buttons in sticky header mode (desktop + Firefox hit-target issue). - Clamp sticky user messages to bounded chat height and allow internal scrolling. - Prevent drawer context crash during iPad/tablet orientation switching. - Improve text-selection action menu placement on narrow screens. - Move assistant message time into clock tooltip; keep duration display clean. - Hide `Link GitHub Issue` row in VS Code chat input area (GitHub flow is not yet ready there). - Remove laggy close animation in text-selection popover; keep open motion/positioning behavior. - Fetch branches when picker opens and cache empty; show loading state instead of false “No branches found”. - Fix share-image export metadata rendering (theme background resolution, timestamp rendering, footer alignment). - Scope MCP services status/toggles to active directory to avoid cross-project leakage. - Improve long user-message clamp behavior (40% cap variant, hidden scrollbar, scroll shadows, expansion detection). - Fix desktop `Check for Updates` menu handler; prevent duplicate checks; show clear success/error toasts. - Stabilize long user-message scrolling behavior (follow-up hardening). - Avoid premature web update failure on slower servers. - Restore user message image previews + fullscreen gallery navigation payload. - Repair desktop chat drag-and-drop image attachments when native drop coords are missing. - Move GitHub issue linking entry into Add attachment menu. - Align header context usage percentage visuals with context panel. - Align `@` file search with active project in all runtimes. - Route `@` file discovery through OpenCode SDK `find.files`; remove legacy `/api/fs/search` reliance. - Make chat `@` mention behavior consistent with files-style behavior. - Keep status-row todos in stable order after status changes; add compact status icons; replace noisy priority labels. ## Refactors / UX Consistency - Simplify chat attachment model and remove project file picker path. - Keep composer focused on `@` mention file flow. - Use direct `Attach files` action in VS Code instead of attachment dropdown path. - Unify issue/PR picker behavior between desktop and mobile overlays. |
||
|
|
ca754d6589 |
feat: make chat file references clickable and responsive (#587)
* docs: clarify named and quick Cloudflare tunnel usage * feat: make chat file paths openable from rendered responses * perf: speed up chat file-path links and open behavior * fix: open chat file references at mentioned lines * fix: prevent context panel flicker on blocked file opens |
||
|
|
bcbc2646fd |
Improve files view behavior and Open In integration (#579)
* feat: open focused file in selected desktop app * fix: make file tree indicators match active open tabs * fix: limit preview functionality to markdown files only * feat: add Open In action to file editor toolbar. add antigravity to openin app list |
||
|
|
1d8ff97c95 |
feat(ui): add dynamic window title and sprite-based project/file icons (#529)
* feat(ui): add dynamic titles and sprite-based project/file icons * feat(files): add viewer syntax fallback and tab file icons * fix(files): restore file viewer highlighting and add diff file icons * feat(git): add file icons and async file-viewer syntax fallback * fix(files): force codemirror token colors in file viewer * feat(files): add shiki view mode for file viewer * fix(files): force codemirror parse after programmatic content updates * feat(files): support markdown frontmatter preview * feat(chat): use pierre diffs for tool previews * feat(chat): add configurable beautiful-mermaid rendering * feat(perf): virtualize chat rendering and add react-scan toggle * feat(build): enable React Compiler in Vite React apps * fix(chat): reduce rerenders from tooltips and streamed activity * fix(ui): make MessageList React Compiler safe * chore(ui): batch commit remaining pending ui updates * fix: polish chat and diff preview rendering - Keep Mermaid action buttons fixed while diagram content scrolls - Align Diff All Files headers and match Git-style path truncation - Default chat tool diffs to unified view with lightweight indicators disabled * fix: preserve file tree expansion and delay git action label collapse * fix: refine project icon controls in settings --------- Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com> |
||
|
|
10851bd7ac |
feat: move projects to sidebar rail and speed up session switching (#506)
* feat: move projects from header tabs to left sidebar rail * refactor: remove variant from git generation session context * feat: implemented drandrop action for navrails * refactor: improve sidebar drag-and-drop smoothness and remove floating overlay * fix: prevent mobile nav rail touch from closing drawer and opening menu * fix: hide header tabs on desktop * fix: prevent session flicker when switching projects * style: soften chat panel divider borders * style: improve icon contrast across core navigation * fix: stabilize session selection during project switching * style: unify sidebar surfaces and transparent section layers * style: remove UI shadows and keep only scroll shadow * perf: speed up project switching with cached session loading * perf: speed up Git changes view and background refresh * perf: make session switching lighter and less aggressive * perf: optimized sessions list loading while project switching * perf: smooth chat rendering and reduce interaction spikes * fix: restore reliable load older messages visibility |
||
|
|
989593ed72 |
feat(files): add 'Reveal in Finder' to file tree context menus (#482)
* feat(session-folders): drag-to-folder DnD, sort by activity, and UX improvements - Add DraggableSessionRow wrapping each session row so the whole row is draggable; stopPropagation prevents outer group-reorder DnD from firing - Add DroppableFolderWrapper + SessionFolderDndScope (inner DndContext scoped per group) with closestCenter collision detection - DragOverlay matches exact width/height of dragged row so cursor stays aligned - Folder header highlights (ring + primary colour) when a session hovers over it during drag - + button on folder header opens a dropdown: 'New session' / 'New folder' - + button on each folder row creates a session scoped to that folder - Empty folders are no longer auto-deleted (removed .filter(sessionIds.length>0) from addSessionToFolder / removeSessionFromFolder / cleanupSessions) - Sessions inside a folder are sorted by most-recent activity (same compareSessionsByPinnedAndTime logic used everywhere else) - Sort comparator now takes sessionAttentionStates so lastUserMessageAt / lastStatusChangeAt is used when newer than session.time.updated; all sort call-sites and their useMemo/useCallback deps updated accordingly - Remove foldersMap from cleanup effect deps to prevent cascade re-renders when folders change; read current value via getState() instead * fix(session-folders): new session is placed into the correct folder sendMessage() was calling useSessionManagementStore.createSession() directly, bypassing the targetFolderId logic in useSessionStore.createSession. Fix: read targetFolderId from draft at the top of the draft branch in sendMessage, then call addSessionToFolder immediately after the session is created and before the draft is closed. Also propagate targetFolderId through openNewSessionDraft options and NewSessionDraftState type. * feat(session-folders): add sub-folder support (one level deep) - SessionFolder gains optional parentId field for hierarchy - createFolder accepts parentId to create sub-folders - deleteFolder cascades to remove all child sub-folders - SessionFolderItem renders sub-folders before sessions in body; new sub-folder button (RiFolderAddLine) visible at depth 0 only - renderOneFolderItem in SessionSidebar builds the tree recursively; sub-folders are indented via depth prop (ml-3 on root's children) - Persist/hydrate parentId correctly from localStorage * feat(session): add delete confirm dialogs and improve subtitle UX - Add confirmation dialogs before deleting sessions or folders - Show relative time (e.g., '2h ago', '35min ago') for recent sessions - Replace +/- diff numbers with file change count (e.g., '3 files changed') - New folders use default name without forcing rename - Cleaner, less cluttered session list UI * fix(session-folders): skip folder cleanup while sessions are loading Prevents race condition on reload where cleanupSessions() runs before the server returns the full session list, causing folder-session assignments to be incorrectly wiped from localStorage. * feat(files): add 'Reveal in Finder' to file tree context menus Add a new context menu action to reveal files and folders in the system file manager (Finder on macOS, Explorer on Windows, xdg-open on Linux). - Add POST /api/fs/reveal server endpoint with cross-platform support - Add revealPath() to FilesAPI interface and web implementation - Add 'Reveal in Finder' menu item to SidebarFilesTree and FilesView - Files are highlighted in Finder (open -R), folders are opened directly |
||
|
|
47cecfc356 |
refactor: unify clipboard copy flow across desktop/web/vscode runtimes (#458)
* fix: prevent copying incomplete diagnostics report * refactoring: clipboard writes to unified cross-runtime fallback helper |
||
|
|
47c943b487 |
feat(ui): redesign workspace shell with context panel, tabbed sidebars, and faster diff UX (#433)
* feat: tabbed right sidebar, context panel, floating diff comments * fix: auto-close left sidebar when context panel opens - Increase default context panel width from 520 to 600 pixels - Increase sidebar minimum width from 200 to 300 pixels - Replace collapsible component with custom button in diff view * refactoring: rework sidebars, tabs, and file tree layout - Rewrite AnimatedTabs as segment-style with sliding indicator - Upgrade SidebarFilesTree to match FilesView features (context menus, git status, file icons, CRUD dialogs, fuzzy search ranking) - Restructure FilesView header: tabs row + actions row, remove breadcrumbs - Show relative path in context panel header, track active tab - Allow left sidebar to stay open alongside context panel - Hide diff/files tabs from header on desktop (mobile-only) - Move chevron after group name in session sidebar - Compact tab heights in right sidebar and git view - Size PreviewToggleButton to match other action buttons - Remove directory loading spinner from folder icons * feat: add project icon and color customization - Enable users to assign custom icons to projects - Allow users to choose accent colors for projects - Stabilize repo status UI during project switching * feat: add scroll fade indicators to editor tabs * style: reduce spacing and icon sizes in header * style: adjust tab component padding from uniform to vertical-horizontal * feat: Add session state indicators to project tabs * feat: Enhance session status handling and improve UI responsiveness * fix: preserve upstream tracking on branch rename * fix: improve initial remote selection for pull requests - Uses saved remote name from previous session when available - Selects remote based on tracking branch when possible - Falls back to origin or first available remote * perf(diff): faster highlight, stable stacked scroll - split/unified Pierre worker pools; prefer shiki-wasm - align diff CSS line-height; disable scroll anchoring; drop WebKit compositing hacks - harden stacked pin/align (cancel on user scroll/input); prevent overscroll - make overlay scrollbar MutationObserver optional; disable for diff container * feat: handle binary files in diff view * fix: adjust project tabs layout and drag regions * style: update drag overlay visual styling * feat: enable number keys to switch projects in the sidebar * fix: recognize octet-stream as text-based MIME type * feat: add keyboard navigation to context panel * feat: add session pinning to sidebar - Pin important sessions to keep them at the top - Pinned sessions persist across browser sessions * refactor: move context usage display from chat input to header |