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()