| name | dev-command |
| description | Interact with the running VSCode extension via Playwright. Use when automating, testing, or debugging the OpenCode webview UI. |
Dev Command
Launch and interact with the VSCode extension using pnpm dev.
Commands
pnpm dev
pnpm dev exec "<code>"
pnpm dev snapshot
pnpm dev stop
Exec environment
The exec command provides three objects:
frame — the webview active-frame (SolidJS UI). Use this for most interactions.
page — the top-level VSCode Electron page. Use for screenshots or VSCode-level actions.
browser — the Playwright Browser instance.
Common selectors
All selectors below target elements inside frame.
Input
pnpm dev exec "await frame.locator('[contenteditable]').pressSequentially('hello world')"
pnpm dev exec "await frame.locator('[contenteditable]').press('Meta+Enter')"
pnpm dev exec "await frame.locator('[contenteditable]').fill(''); await frame.locator('[contenteditable]').pressSequentially('new text')"
Buttons
pnpm dev exec "await frame.locator('.shortcut-button--stop').click()"
pnpm dev exec "await frame.locator('.shortcut-button--secondary').click()"
pnpm dev exec "await frame.locator('.new-session-button').click()"
pnpm dev exec "await frame.locator('.session-switcher-button').click()"
Permissions
pnpm dev exec "await frame.locator('.permission-button--primary').click()"
pnpm dev exec "await frame.locator('button[aria-label=\"Allow always\"]').click()"
pnpm dev exec "await frame.locator('button[aria-label=\"Reject\"]').click()"
pnpm dev exec "const btns = await frame.locator('.permission-button--primary').all(); for (const b of btns) await b.click()"
Messages
pnpm dev exec "const msgs = await frame.locator('.message-text').allTextContents(); return msgs"
pnpm dev exec "const msgs = await frame.locator('.message--assistant .message-text').allTextContents(); return msgs[msgs.length - 1]"
pnpm dev exec "await frame.locator('.message--assistant').last().waitFor()"
pnpm dev exec "return await frame.locator('.loading-indicator').isVisible()"
Reading state
pnpm dev exec "return await frame.locator('[contenteditable]').textContent()"
pnpm dev exec "return await frame.locator('.message').count()"
pnpm dev exec "return await frame.locator('.session-error').textContent()"
Important notes
- Do NOT pass
undefined as a second argument to frame.evaluate(() => ...) — it causes "Too many arguments" errors. Just call with one arg.
- Screenshots must be taken from
page, not frame — CDP screenshot only works on top-level targets.
- The webview frame takes ~10-15s to appear after VSCode starts. The
exec command handles this automatically.
- The input uses Tiptap (ProseMirror), so use
pressSequentially instead of fill for realistic typing. fill works for clearing.