Split view, chat organization, chat folders, UI overhaul & refactor#41
Conversation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…rm polish Merge model/config/effort dropdowns into a single engine picker dropdown alongside agent switching. Extract toChatSession() and buildPersistedSession() helpers to eliminate inline duplication. Fix empty folders missing in branch-grouped sidebar, sync Electron nativeTheme with app theme for Windows Mica, and add light-mode glass sidebar text overrides for macOS. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ol drawers Add multi-pane split view system allowing up to 4 concurrent chat sessions side by side. Sessions can be opened in split view via sidebar context menu or by dragging from sidebar onto the chat area. Each pane hosts its own engine triple (Claude/ACP/Codex) via the new useSessionPane hook, with independent tool drawers, scroll state, and permission handling. Background event routing is updated to skip sessions that are actively rendered in split panes. Also adds release skill for automated version bumping and GitHub release creation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… polish Add tool glyph system with per-tool icons and colored/monochrome modes, ANSI SGR color rendering for bash output, switchable mac background effects (liquid glass / vibrancy / off), assistant turn duration dividers, diff stats on edit/write tool cards, browser per-tab color scheme, TodoPanel redesign with progress bar, Git panel streamlining, and extracted shared chat layout constants. Expand appearance settings with tool icon, background effect, and edit expansion options. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Important Review skippedToo many files! This PR contains 299 files, which is 149 over the limit of 150. ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (299)
You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
… controls Add a WorktreeBar above the composer that shows branch chips for switching between worktrees, with inline create/remove and .harnss/worktree.json setup automation. Replace the modal SpaceCreator dialog with an inline sidebar draft flow and a SpaceCustomizer popover for editing existing spaces. Split view panes now send, stop, and control engine settings independently — each pane resolves its own project path, git panel, and permission/plan-mode state. Also: simplified macOS background effect handling (transparency toggle is now independent of native material), fixed chat scroll bottom padding via ResizeObserver on the composer, stopped fabricating a 200k context window when the real value is unknown, added softer flat-layout dividers, and extracted welcome-screen logic into testable modules. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…endent split pane controls Implement the ACP auth protocol (initialize → authenticate → newSession) with an auth dialog UI, auth-required error detection, and Cursor-specific guidance. Per-session effort, permissionMode, and model are now persisted and restored on session switch. Split panes get their own independent controls for model, effort, permissions, plan mode, and agent switching instead of being read-only mirrors. Also improves model resolution with family-based fallback, adds platform-aware agent store download links, and wraps ACP protocol calls with timeouts. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…gement Replace per-pane tool drawers with a full island-based docking system. Tool panels can now be docked as independent islands in the top row (stacked vertically in resizable columns) or bottom row, dragged between positions, and remembered across open/close cycles. Narrow ToolPicker strip (48/44px) with visual side/bottom separation. Add PanelDockControls, PanelDockPreview, and SplitPaneToolStrip components. BrowserPanel gains per-persistKey session persistence across instances. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extract ~2,350 lines from AppLayout into 5 new components (SplitChatPane, MainTopToolArea, MainBottomToolDock, RightPanel, ToolIslandContent) and 10 new hooks (useGlassTheme, usePaneController, useToolIslandContext, useMainToolWorkspace, useMainToolPaneResize, useBottomHeightResize, useToolColumnResize, useSpaceSwitchCooldown, useJiraBoard, useToolDragDrop). Add shared types (pane-controller, tool-islands) and utility modules (tool-island-utils, workspace-drag). Main workspace now uses the same tool island system as split view, replacing the old side-column/bottom-row tool placement. Add clean-code-refactor and refactor-analyst agent definitions. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…reorganize lib into domains, add Zustand settings store
Complete refactoring pass that decomposes god components and hooks into
focused sub-modules, reorganizes the flat src/lib/ directory into domain
subdirectories, introduces a Zustand settings store, extracts shared
types to canonical locations, and rewires all imports across the codebase.
128 new files added, 64 old files deleted, ~150 existing files modified.
Net result: -16,233 lines from monolithic files, code redistributed into
focused, independently testable modules.
== Component decompositions ==
InputBar (1,900 → 10-line re-export shim):
→ src/components/input-bar/ (11 files): InputBar orchestrator,
AttachmentPreview, CommandPicker + useCommandAutocomplete hook,
ContextGauge (SVG ring + tooltip), EngineControls (per-engine
plan/permission UI), EnginePickerDropdown (model/effort/agent/ACP
config), MentionPicker + useMentionAutocomplete hook, constants,
input-bar-utils with in-source vitest tests, barrel index
BrowserPanel (1,010 → ~350 lines):
→ src/components/browser/ (6 files): BrowserNavBar, BrowserStartPage,
BrowserUrlBar (shared between start page and nav bar — eliminates
duplicated URL input), WebviewInstance, browser-types (typed
ElectronWebviewElement interface replacing inline casts),
browser-utils (URL resolution, history persistence, tab reordering)
JiraBoardPanel (1,098 → ~300 lines):
→ src/components/jira/ (3 files): JiraBoardSetup wizard,
JiraIssueCard with React.memo, KanbanBoard with column
sub-component and drag-and-drop
→ src/hooks/useJiraBoardData (530 lines): all data fetching,
column building from board config or inference, sort, drag-drop
transition execution
McpPanel (612 → ~200 lines):
→ src/components/mcp/ (4 files): AddServerDialog, McpAuthStatus
(4-state auth with shared AuthenticateButton/ReconnectButton),
McpServerRow, mcp-utils (transport/status display config,
parseKeyValuePairs)
AppLayout (2,316 → ~1,000 lines):
renderSplitTopRowItem (352-line useCallback) → SplitTopRowItem
component with module-level helpers for island rendering, stack
entry building, and column wrapper layout
renderSplitBottomToolIsland (113-line useCallback) →
SplitBottomToolIsland component
Inline tool drag state → useToolDragDrop hook
Layout computation → useMainToolAreaLayout hook
Resize handlers → useMainToolAreaResize hook
Agent props → AgentContext (React context)
Theme props → ThemeProvider (React context)
Sidebar props restructured into grouped sub-objects
AppSidebar:
Session callbacks → SidebarActionsContext (eliminates prop drilling)
Sessions pre-grouped by projectId in a Map (O(n) vs O(n*m))
Settings polling (5s setInterval) → event-driven settings.onChanged
ChatView:
6 display prefs + 2 grouping props → Zustand store selectors
Agent props → useAgentContext()
Manual ref-based structural caching → primitive structKey string
SettingsView: ~30 individual setting props → Zustand store direct reads
WelcomeWizard: ~15 props removed → Zustand store + AgentContext
CodexAuthDialog: rewritten with AuthDialogShell, proper event-driven
auth (waitForLoginCompletion) replacing setTimeout(500)
ACPAuthDialog: now uses AuthDialogShell shared component
== Hook decompositions ==
useAppOrchestrator (1,130 → ~400 lines):
→ src/hooks/app-layout/ (6 files):
useAppContextualPanels — todo/agent panel auto-show
useAppEnvironmentState — glass, notifications, dev settings
useAppLayoutUIState — window focus, welcome, grabbed elements
useAppSessionActions — send, model change, agent change, new chat
useAppSpaceWorkflow — space CRUD, switching with session restore
session-utils — buildSessionOptions, getSyncedPlanMode
useSessionLifecycle (1,586 → ~400 lines):
→ src/hooks/session/ (4 new files):
useSessionCache — LRU payload cache with idle-time prefetch
useSessionCrud — create/switch/delete/rename/deselect/import
useSessionRestart — ACP restart with session/load fallback,
worktree restart across all 3 engines, full revert with SDK fork
useSessionSettings — all setActive*/setSession* mutations
New standalone hooks:
useBrowserWebviewEvents, useClickOutside, useContextMenuPosition,
useFolderManager, useGlassOrchestrator, useInlineRename,
useKeyboardShortcuts, useSettingsCompat (compat bridge for
Zustand ↔ legacy useSettings API)
== Library reorganization (src/lib/ flat → domain subdirectories) ==
src/lib/background/ (8 files): BackgroundSessionStore, per-engine
handlers (claude, acp, codex), BackgroundAgentStore, agent-store-utils
src/lib/chat/ (7 files): annotation-types, assistant-turn-divider,
scroll, thinking-animation, todo-utils, turn-changes, virtualization
src/lib/diff/ (3 files): diff-stats, patch-utils, unified-diff
src/lib/engine/ (10 files): acp-adapter, acp-agent-registry,
acp-agent-updates, acp-task-adapter, acp-utils, codex-adapter,
permission-queue, protocol, streaming-buffer
src/lib/layout/ (3 files): constants, split-layout, split-view-state
src/lib/session/ (3 files): derived-data, records, space-projects
src/lib/sidebar/ (2 files): dnd, grouping
src/lib/workspace/ (6 files): drag, main-tool-widths, tool-docking,
tool-groups, tool-island-utils
src/lib/analytics/ (2 files): analytics, posthog
src/lib/git/ (1 file): discover-repos-cache
All 44 old flat src/lib/ files deleted; all imports across ~150 files
rewired to new paths.
== Zustand settings store ==
src/stores/settings-store.ts (667 lines): replaces 777-line useSettings
hook. Per-project settings keyed by projectId with stable frozen
DEFAULT_PROJECT_SETTINGS reference (prevents infinite re-render from
Zustand selector reference changes). Legacy localStorage migration runs
once on first boot. Components subscribe to individual slices — changing
theme only re-renders theme consumers, not the entire app.
useSettingsCompat bridge preserves the old useSettings() API shape for
files not yet migrated to direct Zustand selectors.
== Shared types extraction ==
shared/types/git.ts — GitFileStatus, GitFileChange, GitBranch,
GitRepoInfo, GitStatus, GitLogEntry
shared/types/settings.ts — AppSettings, NotificationSettings,
ThemeOption, MacBackgroundEffect, PreferredEditor, VoiceDictationMode,
CodexBinarySource, ClaudeBinarySource (eliminates 4x MacBackgroundEffect
and 3x ThemeOption duplications across electron/renderer)
shared/types/registry.ts — InstalledAgent, BinaryCheckResult (moved
from electron/src/lib/agent-registry.ts)
src/types/ domain split (9 new files): agents, attachments,
engine-hook (React-dependent, moved from shared/), mcp, permissions
(added codexRpcId field), search, session (ClaudeEffort as union
type), spaces, tools (ToolId, PanelToolId)
src/types/ui.ts gutted to pure re-exports
src/types/index.ts reorganized into categorized re-export blocks
src/types/window.d.ts — IpcResult type alias replacing ~40 inline
signatures; Jira IPC returns now use | { error: string } unions
== Electron changes ==
jira.ts: ~400 lines of fetch handlers → 1-line delegates to new
jira-client.ts; returns { error } unions instead of throwing
json-file-store.ts: generic JsonFileStore<T> with optional safeStorage
encryption; jira-oauth-store, jira-store, mcp-oauth-store, mcp-store
all rewritten to use it (each ~70 lines → ~30 lines)
settings.ts: pushes settings:changed events to renderer (replaces
5-second polling in AppSidebar)
claude-sessions.ts / acp-sessions.ts: McpServerInput and
buildSdkMcpConfig imported from shared instead of duplicated;
added stopAll() exports for graceful shutdown
main.ts: cleanup in window-all-closed uses stopAll() instead of
inline session iteration
app-settings.ts: types moved to @shared/types/settings, re-exports kept
== Build/config changes ==
package.json: added zustand@^5.0.12, dompurify@^3.3.3, @types/dompurify
vite.config.ts: added @shared path alias
shared/lib/mcp-config.ts: added onWarn callback for diagnostic logging
== Dead code removed ==
src/components/GitPanel.tsx (2-line shim, 0 consumers)
src/components/split/PaneToolDrawer.tsx + PaneToolTabBar.tsx
src/hooks/useResolvedThemeClass.ts (replaced by useTheme.tsx)
src/hooks/useTheme.ts (deleted and rewritten with ThemeProvider)
src/lib/events.ts (constant moved to layout/constants.ts)
Deprecated type aliases in tool-islands.ts (MainToolIsland, etc.)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…zing Add workspace-constraints module that enforces minimum widths for chat panes and tool panels during resize operations. Refactor split-layout, tool-island, and main-tool-area hooks to use centralized constraint logic instead of ad-hoc per-site clamping. Expand main-tool-widths with full test coverage for edge cases. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… IPC Add scheduleTerminalResize helper that deduplicates and debounces resize calls to the PTY backend, preventing resize storms during panel drags. Skip no-op resizes in the main process, return cols/rows from snapshot so xterm initializes at the correct dimensions, and subscribe to PTY events before awaiting snapshot to avoid missed data. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…kflow refinements Add GitHub Releases API-based pre-release detection in the main process with a sidebar banner prompting users to switch to stable via settings. Migrate organize-by-branch setting to the Zustand settings store and add test coverage for the settings store and space-project resolution logic. Refine space switching and remembered session handling across the orchestrator hooks. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c7781764cb
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Summary
Massive feature + refactoring branch spanning 13 commits, 352 changed files, +31,515 / −12,655 lines. Introduces a split view system, chat organization, tool docking islands, worktree management, ACP authentication, and a full codebase restructuring pass.
Split View System
useSessionPanewith independent tool drawers, scroll state, and permission handlingChat Organization
Tool Docking Islands
PanelDockControls,PanelDockPreview,SplitPaneToolStripWorktree Bar & Inline Space Creation
WorktreeBarabove the composer with branch chips for switching between worktrees, inline create/remove, and.harnss/worktree.jsonsetup automationSpaceCreatordialog with an inline sidebar draft flow andSpaceCustomizerpopover for editing existing spacesACP Authentication & Per-Session Settings
Tool Icons & ANSI Rendering
ToolGlyphcomponent with per-tool colored icons and colored/monochrome appearance settingMac Background Effects & Cross-Platform Polish
nativeThemewith app theme for Windows MicaChat UI Polish
TodoPanelredesign with progress barInlineSelectorreplacing ShadCN SelectUnified Engine Picker
toChatSession()andbuildPersistedSession()session record helpers to eliminate inline duplicationPre-Release Version Banner
Terminal Resize Fix
scheduleTerminalResizehelper that deduplicates and debounces resize calls to the PTY backend, preventing resize storms during panel dragsCodebase Restructuring
AppLayout Decomposition
Extracted ~2,350 lines from
AppLayoutinto 5 new components (SplitChatPane,MainTopToolArea,MainBottomToolDock,RightPanel,ToolIslandContent) and 10 new hooks (useGlassTheme,usePaneController,useToolIslandContext,useMainToolWorkspace,useMainToolPaneResize,useBottomHeightResize,useToolColumnResize,useSpaceSwitchCooldown,useJiraBoard,useToolDragDrop). Added shared types (pane-controller,tool-islands) and utility modules (tool-island-utils,workspace-drag).Massive Component & Hook Decomposition
128 new files added, 64 deleted, ~150 modified. Net: −16,233 lines from monolithic files, redistributed into focused modules.
Components decomposed:
InputBar(1,900 → 10-line re-export shim) →src/components/input-bar/(11 files): orchestrator,AttachmentPreview,CommandPicker,ContextGauge,EngineControls,EnginePickerDropdown,MentionPicker, constants, utils with in-source testsBrowserPanel(1,010 → ~350 lines) →src/components/browser/(6 files):BrowserNavBar,BrowserStartPage,BrowserUrlBar(shared, eliminates duplicated URL input),WebviewInstance, typedElectronWebviewElementinterface, utilsJiraBoardPanel(1,098 → ~300 lines) →src/components/jira/(3 files) +useJiraBoardDatahook (530 lines)McpPanel(612 → ~200 lines) →src/components/mcp/(4 files):AddServerDialog,McpAuthStatus,McpServerRow, utilsAppLayoutfurther:SplitTopRowItem,SplitBottomToolIsland,AgentContext,ThemeProvider, grouped sidebar propsAppSidebar:SidebarActionsContext(eliminates prop drilling), pre-grouped sessions by projectId (O(n)vsO(n*m)), event-drivensettings.onChangedreplacing 5s pollingChatView: 6 display prefs + 2 grouping props → Zustand store selectors, agent props →useAgentContext()SettingsView/WelcomeWizard: ~45 individual props removed → Zustand store direct readsCodexAuthDialog: rewritten withAuthDialogShell, proper event-driven auth replacingsetTimeout(500)Hooks decomposed:
useAppOrchestrator(1,130 → ~400 lines) →src/hooks/app-layout/(6 files):useAppContextualPanels,useAppEnvironmentState,useAppLayoutUIState,useAppSessionActions,useAppSpaceWorkflow,session-utilsuseSessionLifecycle(1,586 → ~400 lines) →src/hooks/session/(4 new files):useSessionCache(LRU payload cache with idle-time prefetch),useSessionCrud,useSessionRestart,useSessionSettingsuseBrowserWebviewEvents,useClickOutside,useContextMenuPosition,useFolderManager,useGlassOrchestrator,useInlineRename,useKeyboardShortcuts,useSettingsCompatLibrary Reorganization
Flat
src/lib/→ 10 domain subdirectories. All 44 old flat files deleted; all imports across ~150 files rewired.background/chat/diff/engine/layout/session/sidebar/workspace/analytics/git/Zustand Settings Store
New
src/stores/settings-store.ts(667 lines) replaces 777-lineuseSettingshook. Per-project settings keyed by projectId with stable frozenDEFAULT_PROJECT_SETTINGS. Legacy localStorage migration on first boot. Components subscribe to individual slices — changing theme only re-renders theme consumers.useSettingsCompatbridge preserves the old API for gradual migration.Shared Types Extraction
shared/types/git.ts—GitFileStatus,GitFileChange,GitBranch,GitRepoInfo,GitStatus,GitLogEntryshared/types/settings.ts—AppSettings,NotificationSettings,ThemeOption,MacBackgroundEffect,PreferredEditor,VoiceDictationMode,CodexBinarySource,ClaudeBinarySource(eliminates 4×MacBackgroundEffectand 3×ThemeOptionduplications)shared/types/registry.ts—InstalledAgent,BinaryCheckResult(moved from electron)src/types/split into 9 domain files: agents, attachments, engine-hook, mcp, permissions, search, session, spaces, toolssrc/types/window.d.ts—IpcResulttype alias replacing ~40 inline signatures; Jira IPC returns use| { error: string }unionsElectron Changes
jira.ts: ~400 lines of fetch handlers → 1-line delegates to newjira-client.ts; returns{ error }unions instead of throwingjson-file-store.ts: genericJsonFileStore<T>with optionalsafeStorageencryption; jira/mcp OAuth and data stores rewritten to use it (~70 → ~30 lines each)settings.ts: pushessettings:changedevents to renderer (replaces 5s polling)claude-sessions.ts/acp-sessions.ts:McpServerInputandbuildSdkMcpConfigimported from shared; addedstopAll()for graceful shutdownmain.ts: window-all-closed cleanup usesstopAll()Dead Code Removed
GitPanel.tsx(2-line shim, 0 consumers),PaneToolDrawer.tsx,PaneToolTabBar.tsx,useResolvedThemeClass.ts,useTheme.ts(rewritten asThemeProvider),events.ts, deprecated tool-island type aliasesNew Dependencies
zustand@^5.0.12— settings storedompurify@^3.3.3+@types/dompurify— HTML sanitizationTests Added
New:
acp-auth,codex-plan-mode-sync,agent-store-utils,assistant-turn-divider,split-layout,split-view-state,workspace-constraints, settings store, space-project resolution. Existing tests updated for new import paths.Test plan