fix: close editor/diff tabs should navigate to visual neighbor tab (#693)

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.
This commit is contained in:
Jinjing 2026-04-15 21:06:37 -07:00 committed by GitHub
parent 8c3501f8c5
commit 0c48f0ac3c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 55 additions and 4 deletions

View file

@ -1,7 +1,7 @@
--- ---
name: electron name: electron
description: Automate Electron desktop apps (VS Code, Slack, Discord, Figma, Notion, Spotify, etc.) using playwright-cli via Chrome DevTools Protocol. Use when the user needs to interact with an Electron app, automate a desktop app, connect to a running app, control a native app, or test an Electron application. Triggers include "automate Slack app", "control VS Code", "interact with Discord app", "test this Electron app", "connect to desktop app", or any task requiring automation of a native Electron application. description: Launch, automate, and validate Electron desktop apps using playwright-cli via Chrome DevTools Protocol. Use this skill to validate UI changes in Orca, test features in the running Electron app, verify code fixes work end-to-end, or automate any Electron app (VS Code, Slack, Discord, etc.). Triggers include "validate in Electron", "test in the app", "verify the fix", "check the UI", "/electron", "automate Slack app", "control VS Code", or any task requiring interaction with a running Electron application.
allowed-tools: Bash(playwright-cli:*), Bash(npx playwright-cli:*), Bash(curl:*), Bash(lsof:*), Bash(open:*), Bash(ps:*), Bash(kill:*) allowed-tools: Bash(playwright-cli:*), Bash(npx playwright-cli:*), Bash(curl:*), Bash(lsof:*), Bash(open:*), Bash(ps:*), Bash(kill:*), Bash(node:*), Bash(pnpm:*), Read, Grep, Monitor
--- ---
# Electron App Automation # Electron App Automation
@ -42,6 +42,37 @@ playwright-cli click e5
playwright-cli screenshot playwright-cli screenshot
``` ```
## Launching Orca Dev Build with CDP
Orca uses electron-vite for dev builds. The correct way to launch with CDP:
```bash
# Launch Orca dev with remote debugging (run in background)
node config/scripts/run-electron-vite-dev.mjs --remote-debugging-port=9333 2>&1 &
# Wait for "DevTools listening on ws://..." in the output, then attach
playwright-cli attach --cdp="http://localhost:9333"
```
**Key details:**
- Pass `--remote-debugging-port=NNNN` directly to the script — do NOT use `pnpm run dev -- --` (the double `--` breaks Chromium flag parsing)
- electron-vite also supports `REMOTE_DEBUGGING_PORT` env var: `REMOTE_DEBUGGING_PORT=9333 pnpm run dev`
- The Zustand store is exposed at `window.__store` — use `window.__store.getState()` and `window.__store.getState().someAction()` to read/mutate state
- Use port 9333 (not 9222) to avoid conflicts with other Electron apps
### Accessing Orca State via eval
```bash
# Read store state
playwright-cli eval "(() => { const s = window.__store?.getState(); return JSON.stringify({ activeWorktreeId: s.activeWorktreeId, activeTabId: s.activeTabId, activeFileId: s.activeFileId, activeTabType: s.activeTabType }); })()"
# Open an editor file
playwright-cli eval "(() => { const s = window.__store?.getState(); const wtId = s.activeWorktreeId; s.openFile({ worktreeId: wtId, filePath: '/path/to/file', relativePath: 'file.ts', mode: 'edit', language: 'typescript' }); return 'done'; })()"
# Close a file
playwright-cli eval "(() => { window.__store.getState().closeFile('/path/to/file'); return 'closed'; })()"
```
## Launching Electron Apps with CDP ## Launching Electron Apps with CDP
Every Electron app supports the `--remote-debugging-port` flag since it's built into Chromium. Every Electron app supports the `--remote-debugging-port` flag since it's built into Chromium.

View file

@ -561,7 +561,7 @@ export const createEditorSlice: StateCreator<AppState, [], [], EditorSlice> = (s
// remain visible until the file leaves the sidebar, the session resets, or // remain visible until the file leaves the sidebar, the session resets, or
// the file becomes live-unresolved again. trackedConflictPaths is tied to // the file becomes live-unresolved again. trackedConflictPaths is tied to
// sidebar presence, not tab lifecycle. // sidebar presence, not tab lifecycle.
closeFile: (fileId) => closeFile: (fileId) => {
set((s) => { set((s) => {
const closedFile = s.openFiles.find((f) => f.id === fileId) const closedFile = s.openFiles.find((f) => f.id === fileId)
const idx = s.openFiles.findIndex((f) => f.id === fileId) const idx = s.openFiles.findIndex((f) => f.id === fileId)
@ -674,7 +674,27 @@ export const createEditorSlice: StateCreator<AppState, [], [], EditorSlice> = (s
tabBarOrderByWorktree: nextTabBarOrderByWorktree, tabBarOrderByWorktree: nextTabBarOrderByWorktree,
pendingEditorReveal: null pendingEditorReveal: null
} }
}), })
// Why: the unified tab model drives visual tabbar order and neighbor
// selection via pickNeighbor(group.tabOrder). Without this, closing an
// editor/diff tab picks the next active file from the openFiles array
// instead of the visual tab order, producing inconsistent behavior vs
// terminal/browser tab closes which already go through closeUnifiedTab.
for (const tabs of Object.values(get().unifiedTabsByWorktree ?? {})) {
const unifiedTab = tabs.find(
(entry) =>
entry.entityId === fileId &&
(entry.contentType === 'editor' ||
entry.contentType === 'diff' ||
entry.contentType === 'conflict-review')
)
if (unifiedTab) {
get().closeUnifiedTab(unifiedTab.id)
break
}
}
},
closeAllFiles: () => { closeAllFiles: () => {
const state = get() const state = get()