⌘⇧N conflicts with the well-known "New Window" convention in VS Code
and Chrome. ⌘⇧M is a clear mnemonic for Markdown and doesn't clash
with any existing shortcut. Also adds New Browser Tab and New Markdown
entries to the Settings keyboard shortcuts pane.
tabsByWorktree can retain entries for worktrees deleted outside Orca or
whose cleanup didn't complete. This caused phantom agents to appear in
the titlebar count. Now both countWorkingAgents and
getWorkingAgentsPerWorktree filter against worktreesByRepo as the source
of truth.
Increase gap between last tab and the "+" button (ml-0.5 → ml-2),
add more vertical padding to dropdown menu items (py-0.5 → py-1.5),
and align dropdown to open rightward (align end → start).
Add two workarounds for Chrome/ProseMirror drag-selection breakage:
1. DragSelectionGuard extension — suppresses selectionchange → selectionToDOM
during active drags, blocks CellSelection transactions from prosemirror-tables,
and restores native selection post-mouseup to preserve table-cell highlighting.
2. safeReactNodeViewRenderer — patches handleSelectionUpdate so selectNode/
deselectNode only fire for actual NodeSelections, preventing React re-renders
mid-drag that disrupt native selection tracking (Tiptap #7647).
Unregister PTY data handlers before killing PTYs during worktree
shutdown so the final data flush cannot trigger bell/agent-status
notifications. Also cancels accumulated closure state (staleTitleTimer,
agent tracker) via teardown callbacks, and adds a hasLivePtys guard
at notification dispatch time as a belt-and-suspenders check.
closeFile() only removed the file from openFiles and picked the next
active file by array position. Terminal and browser closes already went
through closeUnifiedTab() which uses pickNeighbor(group.tabOrder) for
visual neighbor selection. Add the same closeUnifiedTab() call to
closeFile() so editor, diff, and conflict-review tab closes behave
consistently.
Also update the /electron skill with Orca-specific CDP launch recipe
and broader trigger keywords for more reliable invocation.
* fix: return error objects from IPC repo handlers instead of throwing
Electron IPC does not preserve Error objects across the process boundary,
so throwing from main-process handlers can result in opaque failures on
the renderer side. Switch repos:add and repos:addRemote to return
{ repo: Repo } | { error: string } discriminated unions, and update all
call sites to check for the error variant.
* fix: address review findings
- Add explicit return type to repos:add handler for type safety
- Log errors in NonGitFolderDialog catch block (direct IPC call
bypasses store toast handling)
* fix: show toast on remote folder add failure
The NonGitFolderDialog calls addRemote directly (bypassing the store),
so errors were silently swallowed. Show a toast so the user sees feedback.
Reset defaultBaseRef to null on repo change so effectiveBaseRef becomes
falsy until the IPC resolves, preventing branch compare from firing with
a stale cross-repo value. Also fix loading→error→loading flicker by only
resetting to loading state on first request or when base ref changes.
* refactor: enable split groups
* Fix split groups terminal host rollout
* refactor: remove split groups from add-tab menu
* refactor: dark-launch split groups with correctness fixes
* refactor: eliminate useEffect anti-patterns across 5 components
- MonacoEditor, RichMarkdownEditor: assign callback/prop refs directly
during render instead of via useEffect, so ProseMirror and Monaco
handlers always read the current closure rather than a one-render-
stale copy.
- SettingsFormControls (FontAutocomplete): replace useEffect that reset
highlightedIndex on filteredSuggestions/open changes with the
"adjusting state during render" pattern (track prevOpen /
prevFilteredSuggestions), so the correct item is highlighted on the
same paint as the dropdown opens or the filter updates.
- ChecksPanel: replace useEffect that reset 5 local state fields on
activeWorktreeId change with the "adjusting during render" pattern
(track prevActiveWorktreeId), so stale title/loading UI from the
previous worktree is cleared before the first paint of the new one.
- SshPassphraseDialog: split one useEffect that both reset form state
and focused the input into (a) during-render state reset and (b) a
focused DOM-only useEffect, so the cleared input is visible
immediately rather than after a post-paint effect flush.
* fix: resync font autocomplete highlight on value change
The debounced onUpdate serialization feeds back through the content prop,
and if the user types between the debounce firing and the useEffect
running, the stale prop triggers setContent — resetting the cursor.
Skip the destructive setContent when the content prop matches our own
last serialization (lastCommittedMarkdownRef).