When removing an orphaned worktree, `git worktree remove` fails but the
directory is cleaned up via `rm`. Without a subsequent `git worktree prune`,
git's internal tracking remains stale — `git worktree list` continues to
show the entry and the branch stays locked. Add `git worktree prune` after
the rm in both the IPC handler and OrcaRuntimeService to fix this.
Move dirty-dot indicator and close button into a shared fixed-width
container so toggling between dirty/clean states during auto-save
does not cause the tab to resize.
* fix: address review findings
* fix: improve error handling in terminal e2e helper JSON parsing
* fix: remove unused catch parameter in terminal e2e helper
* fix: use nullish coalescing assignment for LANG default in PTY spawn
The object spread approach ({LANG: default, ...process.env}) produced
undefined on CI (Ubuntu/Node 22) despite working locally. Switch to
explicit ??= assignment after the spread for reliable cross-platform
behavior.
Move build resources to resources/build/, icon source files to
resources/icon-source/, scripts to config/scripts/, and patches
to config/patches/ for a cleaner top-level directory layout.
- Make the "+" new tab button a compact rounded icon button instead of
a full-height rectangle
- Increase titlebar height from 38px to 42px for better proportions
- Remove font-medium from active tabs to prevent layout shift when
switching between tabs
* chore: clean up repo root for faster README visibility
- Delete unused images (debug_orca.png, orca_3d.jpg, screenshot.png)
- Delete stale design docs from docs/
- Move tsconfig sub-configs, electron-builder config, and vitest config to config/
- Move file-drag.gif to docs/assets/ and design doc to docs/
- Update all path references in package.json, tsconfig.json, and moved configs
* fix: remove stale worktree dialog callback dependency
Adds a platform-aware context menu option to reveal files/folders in the
system file manager (Finder on macOS, File Explorer on Windows, Files on Linux).
- Move xterm FitAddon refresh() outside the resize conditional so
sub-cell-width container shrinks don't leave blank content
- Defer startup notification to window 'show' event so the macOS
permission dialog appears after the window is visible
- Add click handler on startup notification to open System Preferences
- Prevent GC of startup notification via activeNotifications set
- Fix lint-staged config: remove yaml/html/md from oxfmt pattern
since oxfmt only supports json and css beyond JS/TS
* feat: run setup script in split pane so main terminal stays interactive (#381)
Instead of running the worktree setup script in the main terminal pane
(blocking user interaction), queue a setup-split signal that TerminalPane
consumes on mount — creating the initial pane clean, then splitting right
and injecting the command into the new pane's PTY.
* fix: address review findings
* fix(terminal): run context menu Close Pane through request-close lifecycle
* feat: run setup script in split pane so main terminal stays interactive (#381)
Instead of running the worktree setup script in the main terminal pane
(blocking user interaction), queue a setup-split signal that TerminalPane
consumes on mount — creating the initial pane clean, then splitting right
and injecting the command into the new pane's PTY.
* fix: address review findings
* fix: address review findings
* fix: mock process.platform as darwin in system-denied test
The test exercises the macOS notification permission gate, which only
checks systemPreferences.getNotificationSettings on darwin. Without
mocking the platform, Linux CI takes the non-darwin path and the
assertion fails.
* chore: remove stale test files
* refactor: remove macOS notification permission checking
The systemPreferences.getNotificationSettings() check added friction
without meaningful benefit — macOS handles permission prompting natively
when a notification is posted, making the manual check redundant.
Removes getPermissionStatus(), the system-denied dispatch reason,
the IPC handler, the renderer permission-blocked banner, and all
related tests.
- Fix ZoomOverlay to fully unmount after fade-out so the fixed overlay
doesn't linger and interfere with Radix portal layering, click-outside
detection, or focus management (fixes broken file switching)
- Lower z-index from 9999 to z-50 to match app conventions
- Fix editor zoom percent to use actual base font size from settings
and computeEditorFontSize for clamping instead of hardcoded 14
- Extract useTerminalFontZoom to own file to keep keyboard-handlers
under the 300-line lint limit
* fix: address review findings
* fix: mock process.platform as darwin in system-denied test
The test exercises the macOS notification permission gate, which only
checks systemPreferences.getNotificationSettings on darwin. Without
mocking the platform, Linux CI takes the non-darwin path and the
assertion fails.
* chore: remove stale test files
Patch @xterm/addon-fit to refresh the full viewport and restore scroll
position after reflow, batch ResizeObserver through requestAnimationFrame
to coalesce rapid-fire reflows, and recover terminal rendering after
WebGL context loss.
* fix: address review findings
- Add try/catch to debounced serialization timer callback for consistency
with flushPendingSerialization (prevents crash if editor is destroyed
during the 300ms debounce window)
- Use TextEncoder.encodeInto() with pre-allocated buffer instead of
encode() to avoid allocating a new Uint8Array on every render
- Extract keyboard handler to rich-markdown-key-handler.ts to stay under
the 400-line file limit
* feat: improve markdown file typing speed
- Debounce ProseMirror getMarkdown() serialization (300ms) to eliminate
the dominant typing-speed bottleneck on large markdown files
- Add 300KB size limit that falls back to Monaco source mode for files
too large for ProseMirror's in-memory document tree
- Expose flushPendingEditorChange() bridge so autosave, quiesce, and
restart flows capture debounced edits without data loss
- Signal dirty state immediately via onDirtyStateHint so close prompts
and beforeunload guards don't miss edits during the debounce window
- Always render through TabGroupSplitLayout (even single groups) to prevent TerminalPane unmounts that kill PTY processes
- CSS Grid flat rendering keeps TabGroupPanels as stable keyed siblings across layout changes
- Use effectiveVisibleRef in pty-connection so split-but-visible terminals receive PTY output
- Eagerly initialize layout in createUnifiedTab before first split
- Keep layout leaf when collapsing to single group (prevent unmount)
- Prevent Monaco model disposal with keepCurrentModel so split editors share models safely
- Keep titlebar spacer visible in split mode for right sidebar toggle positioning
When switching between worktrees, the active terminal tab was reset to
the first tab because activeTabId was global. This adds a per-worktree
map (activeTabIdByWorktree) mirroring the existing pattern used for
editor files, so users return to the same terminal tab they left.
* WIP: Changes before auto-review fixes
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add custom title support for terminal panes
Users can set a custom title on individual terminal panes via the
right-click context menu ("Set Title...") or by clicking an existing
title. Titles display as a minimal floating label at the top of each
pane with inline editing (Enter to save, Escape to cancel). An X
button on hover removes the title.
Titles persist across restarts via titlesByLeafId in
TerminalLayoutSnapshot, piggybacking on the existing session:set flow.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: address review findings for pane title feature
- Guard rename input against double-submit on Enter/Escape + blur race
- Memoize persistLayoutSnapshot with useCallback to prevent keyboard
listener re-registration on every render
- Eagerly update paneTitlesRef in onPaneClosed so persistLayoutSnapshot
sees correct data before React flushes state
- Document portal rendering's implicit dependency on paneTitles state
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: write pane titles in shutdown snapshot even when buffers are empty
captureBuffers had an early return when no terminal scrollback content
existed, which skipped writing titlesByLeafId to the layout snapshot.
This caused titles to be lost on restart for fresh or cleared panes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* chore: remove design doc from PR
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add consistent gaps between worktree cards
Use TanStack Virtual's built-in `gap` option (8px) instead of padding
on the wrapper div. The virtualizer accounts for the gap directly in
its position calculations, guaranteeing consistent spacing between
cards regardless of estimation/measurement mismatches.
* test: update estimate tests for virtualizer gap change
* feat: auto-reveal active file in explorer on tab switch
Adds useFileExplorerAutoReveal hook that scrolls the file explorer to
show the active editor file when switching tabs, mirroring VS Code's
explorer.autoReveal behavior. Files already visible in the tree get
scrolled to directly; files with collapsed ancestors trigger the reveal
machinery with flash disabled to avoid visual noise.
* refactor: extract file explorer handlers to fix max-lines lint rule
Move handleClick, handleDoubleClick, and handleWheelCapture into a
dedicated useFileExplorerHandlers hook to bring FileExplorer.tsx under
the 400-line limit.