From 0c48f0ac3cb7b3715e930848a53bb08fc0305328 Mon Sep 17 00:00:00 2001 From: Jinjing <6427696+AmethystLiang@users.noreply.github.com> Date: Wed, 15 Apr 2026 21:06:37 -0700 Subject: [PATCH] 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. --- .agents/skills/electron/SKILL.md | 35 +++++++++++++++++++++++-- src/renderer/src/store/slices/editor.ts | 24 +++++++++++++++-- 2 files changed, 55 insertions(+), 4 deletions(-) diff --git a/.agents/skills/electron/SKILL.md b/.agents/skills/electron/SKILL.md index 6a8cef37..8e1c8a0c 100644 --- a/.agents/skills/electron/SKILL.md +++ b/.agents/skills/electron/SKILL.md @@ -1,7 +1,7 @@ --- 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. -allowed-tools: Bash(playwright-cli:*), Bash(npx playwright-cli:*), Bash(curl:*), Bash(lsof:*), Bash(open:*), Bash(ps:*), Bash(kill:*) +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:*), Bash(node:*), Bash(pnpm:*), Read, Grep, Monitor --- # Electron App Automation @@ -42,6 +42,37 @@ playwright-cli click e5 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 Every Electron app supports the `--remote-debugging-port` flag since it's built into Chromium. diff --git a/src/renderer/src/store/slices/editor.ts b/src/renderer/src/store/slices/editor.ts index be0f98b4..8a3ffc35 100644 --- a/src/renderer/src/store/slices/editor.ts +++ b/src/renderer/src/store/slices/editor.ts @@ -561,7 +561,7 @@ export const createEditorSlice: StateCreator = (s // remain visible until the file leaves the sidebar, the session resets, or // the file becomes live-unresolved again. trackedConflictPaths is tied to // sidebar presence, not tab lifecycle. - closeFile: (fileId) => + closeFile: (fileId) => { set((s) => { const closedFile = s.openFiles.find((f) => f.id === fileId) const idx = s.openFiles.findIndex((f) => f.id === fileId) @@ -674,7 +674,27 @@ export const createEditorSlice: StateCreator = (s tabBarOrderByWorktree: nextTabBarOrderByWorktree, pendingEditorReveal: null } - }), + }) + + // Why: the unified tab model drives visual tab‐bar 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: () => { const state = get()