Add agent name input with confirmation pattern to enable a "Quit & Delete
Working Dirs" button. Widen modal, reduce button size/font, prevent wrapping.
Guard against window.maestro timing issues in production.
- Add customModel field to ModeratorConfig type for storing selected model
- Update NewGroupChatModal to pass agentConfig.model through moderatorConfig
- Update App.tsx handleCreateGroupChat to accept customModel parameter
- Update spawnModeratorSynthesis to pass sessionCustomModel from moderatorConfig
- Update initial moderator spawn to pass sessionCustomModel for both spawns
- Verify modelArgs config produces correct --model flag in arguments
This enables users to select a custom model when creating a group chat,
and ensures the selected model is applied when spawning the OpenCode moderator.
Introduces an "About Me" field in Settings → General that allows users
to describe their background, preferences, and communication style.
This profile is exposed as {{CONDUCTOR_PROFILE}} template variable and
included in AI chat, group chat, and wizard prompts so agents can
tailor their responses to the user.
Shows a modal on first launch for Windows users explaining that Windows
support is actively being improved. Features:
- Inline toggle to enable beta updates for latest bug fixes
- Link to report issues on GitHub (with note that vetted PRs welcome)
- Link to join Discord Windows-specific channel for community support
- Create Debug Package button for easy bug reporting
- Checkbox to suppress the modal for future sessions
- Console debug function: window.__showWindowsWarningModal()
When pasting content, automatically trim leading and trailing whitespace
to reduce manual cleanup. The trimming only intercepts paste when there
is actual whitespace to remove, otherwise native paste behavior is used.
Input areas updated:
- Main AI/terminal input (App.tsx)
- Group chat input (GroupChatInput.tsx)
- Prompt composer modal (PromptComposerModal.tsx)
- Auto Run document editor (useAutoRunImageHandling.ts)
- Wizard document editor (DocumentEditor.tsx)
- Inline wizard document generation (DocumentGenerationView.tsx)
- Symphony modal now receives sessions list for richer contribution context 🧩
- Active contributions show clickable session name with new Terminal icon 🖥️
- Added “navigate to session” flow directly from contribution cards 🧭
- Selecting a session updates active session and auto-closes modal ⚡
- Session lookup wires contributions to matching session IDs seamlessly 🔗
When Claude Code performs multi-tool turns (many internal API calls),
accumulated token values cause estimateContextUsage to return null,
freezing the context gauge. This adds estimateAccumulatedGrowth which
provides conservative 1-3% per-turn growth estimates so the gauge
keeps moving during tool-heavy sessions.
Safety: App.tsx caps all estimates at yellowThreshold - 5, guaranteeing
that estimates can never trigger compact warnings — only real
measurements from non-accumulated turns can.
The fileTree prop was passed as `activeSession?.fileTree || []` which
creates a new array reference on every render, defeating React.memo()
on FilePreview during agent activity. Memoize it with useMemo so the
reference only changes when the actual fileTree changes.
Moved tab naming logic from onSessionId callback to useInputProcessing
hook. Tab naming now starts immediately when the user sends their first
message, running in parallel with the actual agent request instead of
waiting for the agent to respond with a session ID.
Changes:
- Added automaticTabNamingEnabled prop to UseInputProcessingDeps
- Tab naming triggered in processInput for new AI sessions with text
- Removed ~140 lines of tab naming code from onSessionId handler
- Removed unused automaticTabNamingEnabledRef
The tabNaming:generateTabName IPC handler was defined in registerAllHandlers()
but that function was never called. Instead, handlers are registered individually
in main/index.ts. Added registerTabNamingHandlers import and call with required
dependencies (processManager, agentDetector, agentConfigsStore, settingsStore).
Also removed debug console.log statements that were added during investigation.
- Added detailed console logs to debug automatic tab naming conditions 🧭
- Logged user message discovery and first message preview for naming 📝
- Emitted telemetry for prepared tab-naming payload before AI processing 🔍
- Logged tab-naming trigger state, including feature-flag enablement 🚦
When user opens the rename modal, clear isGeneratingName flag to stop
showing the spinner. Also clear the flag when the rename is confirmed
to prevent any race conditions with the automatic naming completing.
When users save AI chat response content to a markdown file, the file
list in the right panel was not updating to show the new file. This
made it difficult to reference or open the saved file immediately.
Added onFileSaved callback prop to SaveMarkdownModal that triggers the
file tree refresh after a successful save. The callback is passed
through TerminalOutput from MainPanel, which calls refreshFileTree
with the active session ID.
- Toast clicks now always reveal the AI terminal, not file previews 🧠
- Session switching clears active file preview to prevent confusing UI state 🧹
- Toast-driven navigation can target a specific AI tab when available 🎯
- Missing tab IDs fall back gracefully while still entering AI input mode 🛟
- Context usage warnings are less noisy with higher yellow threshold (75%) 🟡
- Red context warnings now trigger later at 90% for calmer workflows 🔴
Add "Command Palette" menu item with CMD+K shortcut below "Introductory Tour"
in the main hamburger menu. This provides quick access to the quick actions
modal from the menu for discoverability.
- Add Command icon import from lucide-react
- Add setQuickActionOpen prop through the component chain
- Display keyboard shortcut (Cmd+K) with proper formatting
- Update tests with Command icon mock
- File preview tab scroll now syncs into navigation history for restores 🧭
- Breadcrumb close/restore keeps the exact scroll position per history entry 📌
- Session UUID pill hides when a file preview tab is focused 🪪
- Cost tracking pill hides during file preview to reduce UI noise 💸
- Context window usage widget hides in file preview for cleaner focus 🧹
Tier 1 performance optimizations for snappier app experience:
1. Lazy-load SettingsModal in App.tsx
- SettingsModal is ~2.6K lines, now only loaded when settings opened
- Wrapped in Suspense with conditional rendering
2. Add manual chunk splitting to vite.config.mts
- Split vendor chunks: react, xterm, markdown, syntax, mermaid, charts, flow, diff
- Enables better browser caching and smaller initial bundle
- Heavy visualization libs (mermaid ~500KB, recharts ~400KB, etc.) now in separate chunks
3. Cache static files in web server (staticRoutes.ts)
- index.html, manifest.json, sw.js now read once and cached
- Eliminates blocking sync file reads on every web request
- Improves web/mobile interface responsiveness
When pressing cmd+j to switch between AI/terminal mode, the previously
active file preview tab is now saved and restored. This allows users
to view a file, switch to terminal, run commands, then switch back and
have the same file preview re-opened automatically.
Added preTerminalFileTabIdRef to UILayoutContext to track the active
file tab before switching to terminal mode. Updated toggleInputMode
to save/restore this state.
- Switching to Terminal now clears file preview, avoiding confusing leftovers 🧹
- Cmd+J toggle works from file preview straight into Terminal view ⌨️
- Keyboard handler now whitelists toggleMode even with modals open, improving flow 🔓
handleCloseCurrentTab was duplicating file tab close logic inline
but not adding closed tabs to unifiedClosedTabHistory, causing
Cmd+Shift+T to restore a different tab instead of the most recently
closed one. Now uses closeFileTabHelper which properly tracks history.
- App.tsx: Remove unused import (reopenClosedTab), legacy navigation
variables (backHistory, forwardHistory, filePreviewHistory,
filePreviewHistoryIndex), legacy callbacks (setFilePreviewHistory,
setFilePreviewHistoryIndex), unused async handler (handleOpenFileTabAsync),
and legacy navigation handlers (handleNavigateBack, handleNavigateForward,
handleNavigateToIndex) - all superseded by per-tab navigation system
- MainPanel.tsx: Prefix unused destructured props with underscore
- contextUsage.ts: Remove unused UsageStats import
This removes ~250 lines of dead code from the legacy session-level
file preview navigation system, which has been replaced by the per-tab
breadcrumb navigation in the unified tab system.
Key changes:
- Accept main's fix for context usage calculation (returns null for
accumulated multi-tool turn values instead of capping at 100%)
- Adopt main's refactored structure:
- agent-detector.ts → agents/detector.ts + definitions.ts + capabilities.ts
- stats-db.ts → stats/*.ts modules
- agent-session-storage types → agents/index.ts
- Port factory-droid agent to new agents/definitions.ts structure
- Remove obsolete shared/contextUsage.ts (logic now in renderer/utils)
- Update all import paths to reference new module locations
- Preserve all RC features: Symphony, File Preview Tabs, TabNaming, etc.
The context window fix is critical: main's approach correctly handles
when Claude Code reports accumulated token values from multi-tool turns
by returning null, causing the UI to preserve the last valid percentage.
RC's approach masked this by capping at 100%, hiding the issue.
After saving a file in the file preview tab, the UI was reverting to the
original content despite showing "Saved". This occurred because:
- editContent was cleared to undefined after save
- The base content field was never updated to the saved value
- UI fell back to stale original content
Added savedContent parameter to handleFileTabEditContentChange to update
the tab's base content alongside clearing editContent after save.
- Added FilePreviewHistoryEntry type to track navigation history per tab
- Extended FilePreviewTab with navigationHistory and navigationIndex fields
- Updated handleOpenFileTab to build navigation history when replacing content
- Added handleFileTabNavigateBack/Forward/ToIndex handlers for per-tab nav
- Wired navigation props through MainPanel to FilePreview component
- Each file tab maintains its own independent navigation history
The context formula was excluding cacheReadInputTokens, causing the gauge to
drastically underestimate usage (e.g., 3% when reality was 23%). During
multi-tool turns, accumulated token totals could exceed the context window,
producing false 100% readings and premature compact warnings.
- Include cacheReadInputTokens in the formula (input + cacheRead + cacheCreation)
- Detect accumulated values (total > window) and return null to preserve last valid %
- Skip context updates during accumulated turns instead of displaying inflated values
- Fix MainPanel tooltip deriving from raw tab stats instead of preserved session percentage
- Handle group chat participant/moderator accumulated values with -1 sentinel
Use Wong's colorblind-safe palette for file extension badges when
colorBlindMode is enabled. Colors are distinguishable across
protanopia, deuteranopia, and tritanopia color vision deficiencies.
- Add COLORBLIND_EXTENSION_PALETTE to colorblindPalettes.ts
- Update getExtensionColor() in TabBar and TabSwitcherModal
- Pass colorBlindMode through App → MainPanel → TabBar
- Add 11 unit tests for colorblind extension badge colors
The previewFile state was a legacy mechanism for the file preview overlay.
Now that files open in tabs (session.filePreviewTabs), this state is dead
code. This commit removes it and all its references:
- Removed previewFile/setPreviewFile from UILayoutContext
- Updated App.tsx to use activeSession.activeFileTabId/activeFileTab
- Removed legacy file preview rendering block from MainPanel.tsx
- Updated useAppHandlers.ts to remove legacy overlay code path
- Updated props hooks (useMainPanelProps, useRightPanelProps)
- Updated FileExplorerPanel to use activeFileTabId for selection
- Updated keyboard handler to check activeFileTabId instead
- Updated/removed tests for legacy previewFile behavior
Migrated the onDocumentOpen callback in DocumentGraphView from the
legacy setPreviewFile overlay system to use handleOpenFileTab for
tab-based file preview. The implementation now:
1. Fetches content and stat in parallel for efficiency
2. Opens file in a tab (or selects existing tab if already open)
3. Provides lastModified timestamp for file info display
4. Properly handles SSH remote execution
All 615 DocumentGraph tests and 370 tab-related tests pass.
Update handleNavigateBack, handleNavigateForward, and handleNavigateToIndex
handlers to use handleOpenFileTab instead of the legacy setPreviewFile overlay.
Each handler now:
- Updates the filePreviewHistoryIndex for state tracking
- Calls handleOpenFileTab which selects an existing tab or creates a new one
- Has proper dependency array including handleOpenFileTab
Modified handleMainPanelFileClick to use the new file tab system
instead of the legacy preview overlay:
- Now calls handleOpenFileTab instead of setPreviewFile
- Fetches file content and stat in parallel for efficiency
- Provides lastModified timestamp for file tabs
- Removes legacy filePreviewHistory updates (tabs handle navigation)
Flow: TerminalOutput → MarkdownRenderer → MainPanel → handleOpenFileTab
Updated handleFileClick in useAppHandlers.ts to use the new tab-based
file preview system. When onOpenFileTab callback is provided, file clicks
now open tabs instead of using the legacy setPreviewFile overlay.
Changes:
- Added FileTabInfo interface and onOpenFileTab optional callback to
UseAppHandlersDeps
- Modified handleFileClick to fetch file stat for lastModified timestamp
- handleFileClick now calls onOpenFileTab when provided, falling back to
legacy setPreviewFile behavior otherwise
- Moved handleOpenFileTab definition in App.tsx to before useAppHandlers
call and wired it as the onOpenFileTab callback
Updated TabSwitcherModal to display both AI and file preview tabs:
- Added fileTabs, activeFileTabId, and onFileTabSelect props
- File tabs show in "Open Tabs" mode with AI tabs, sorted alphabetically
- Each file tab displays: filename, extension badge with type-specific
coloring, file path, "File" indicator, active/unsaved indicators
- Search works across file names, extensions, and paths
- Updated AppModals and App.tsx to pass file tabs and handlers
- Added 9 new tests (total 85 tests pass)
- Create navigateToNextUnifiedTab() and navigateToPrevUnifiedTab() functions
that cycle through unifiedTabOrder (both AI and file tabs)
- Update keyboard handler to use new unified navigation functions
- Support showUnreadOnly filter (AI tabs filtered, file tabs always navigable)
- Add comprehensive test coverage (20 new tests)
Add unified closed tab history system that tracks both AI and file
preview tabs, enabling Cmd+Shift+T to restore any recently closed tab:
- Add ClosedTabEntry discriminated union type for AI/file tabs
- Add unifiedClosedTabHistory to Session (runtime-only, not persisted)
- Add closeFileTab() function with unified history support
- Add addAiTabToUnifiedHistory() for AI tab close tracking
- Add reopenUnifiedClosedTab() with duplicate detection for both types
- Update closeTab() to also update unifiedTabOrder
- Update forceCloseFileTab() to use helper and add to history
- Update performTabClose() to track AI tabs in unified history
- Add comprehensive test coverage (12 new tests)
Update keyboard shortcuts to navigate through unified tab order
(both AI and file tabs) instead of just AI tabs:
- Add navigateToUnifiedTabByIndex() for Cmd+1-9 tab jumping
- Add navigateToLastUnifiedTab() for Cmd+0 (last tab)
- Functions handle AI tabs (clear activeFileTabId) and file tabs
(preserve activeTabId for easy switching back)
- Update useMainKeyboardHandler to use new unified functions
- Add comprehensive test coverage (18 new tests)
- Add initialSearchQuery and onSearchQueryChange props to FilePreview
- Auto-open search panel when initialSearchQuery is provided and non-empty
- Add handleFileTabSearchQueryChange handler in App.tsx
- Wire search state through useMainPanelProps and MainPanel
- Add 4 tests for search state persistence in FilePreview.test.tsx
- Added initialScrollTop and onScrollPositionChange props to FilePreview
- Implemented throttled scroll position reporting (200ms) in content scroll handler
- Added scroll position restoration with requestAnimationFrame for DOM readiness
- Created handleFileTabScrollPositionChange handler in App.tsx
- Wired handler through useMainPanelProps to MainPanel
- Added 4 tests for scroll position persistence behavior
- Renamed handleCloseFileTab to forceCloseFileTab (performs unconditional close)
- Added new handleCloseFileTab wrapper that checks for unsaved changes
- When tab.editContent !== undefined, shows confirmation modal before closing
- Uses existing showConfirmation pattern with setConfirmModal* state
- Modal displays: "<filename>" has unsaved changes. Are you sure you want to close it?
- On confirm, calls forceCloseFileTab to perform actual close
- Add `lastModified: number` field to FilePreviewTab interface to track
when content was loaded from disk
- Add `fileTabAutoRefreshEnabled` setting (default: disabled) to control
whether file tabs auto-refresh when switched to
- Update handleOpenFileTab to accept and store lastModified
- Update handleOpenFileTabAsync to fetch file stat and set lastModified
from the file's actual modification time
- Modify handleSelectFileTab to check if file changed on disk when
auto-refresh is enabled:
- Compares current file mtime with stored lastModified
- Refreshes content if file was modified since last load
- Skips refresh if tab has unsaved edits to prevent data loss
- Update all FilePreviewTab test fixtures with lastModified field
- Fix MainPanel to use activeFileTab.content as source (was using empty editContent)
- Add sshRemoteId and isLoading fields to FilePreviewTab interface
- Update handleOpenFileTab to accept optional sshRemoteId parameter
- Add handleOpenFileTabAsync for SSH files with async loading:
- Creates tab immediately with loading state
- Fetches content asynchronously
- Updates tab when content loaded (or removes on error)
- Add loading state UI in MainPanel for file tabs
- Add tests for file tab content storage and SSH loading support
This enables proper file content management for the unified tab system,
with support for SSH remote files that need async loading.
Store file content directly on FilePreviewTab (Option A) for simplicity.
File previews are typically small, and we already store larger AI logs.
Updated handleOpenFileTab to populate content when opening file tabs.
Connect FilePreviewTab rendering to the unified tab system:
- Add unified tab props to MainPanel (unifiedTabs, activeFileTabId, etc.)
- Remove !previewFile condition so TabBar always renders in AI mode
- Update content area to prioritize activeFileTabId over legacy previewFile
- Add showCloseButton prop to FilePreview (false when rendered as tab)
- Add activeFileTab computation in App.tsx
- Connect handlers through useMainPanelProps hook
Implements handleCloseCurrentTab that:
- Determines which tab is active (file tab via activeFileTabId first, then AI tab via activeTabId)
- Closes file tabs immediately without wizard confirmation
- For AI tabs, returns info to allow keyboard handler to show wizard confirmation
- Prevents closing the last AI tab (keeps at least one AI tab)
Updated keyboard handler (Cmd+W) to use handleCloseCurrentTab for unified tab support.
Updated handleCloseOtherTabs, handleCloseTabsLeft, and handleCloseTabsRight
to support both AI and file preview tabs based on unifiedTabOrder position:
- Determine active tab from activeFileTabId or activeTabId
- Use unifiedTabOrder to determine which tabs are left/right/other
- Close AI tabs using closeTab helper (with wizard history handling)
- Close file tabs by removing from filePreviewTabs and unifiedTabOrder
Implements unified tab reorder functionality that operates on the
unifiedTabOrder array, allowing both AI and file preview tabs to be
reordered relative to each other. This supplements the existing
handleTabReorder (AI-only) for the unified tab system.
Changes:
- Added handleUnifiedTabReorder in App.tsx with index validation
- Propagated through useMainPanelProps.ts, MainPanel.tsx, TabBar.tsx
Adds handleSelectFileTab handler that sets the activeFileTabId to select a file preview tab. The activeTabId is preserved (not nullified) following the established pattern from handleOpenFileTab, which tracks the last active AI tab for when the user switches back.
Implements the handler to open file preview tabs in the unified tab system:
- Checks if a tab with the same file path already exists and selects it
- Creates new FilePreviewTab with proper extension parsing
- Adds tab to both filePreviewTabs and unifiedTabOrder arrays
- Sets activeFileTabId to activate the new file tab