Merge pull request #1819 from jonasherr/feat/add-playwright-cli-provider

feat(browser-automation): add playwright-cli as browser automation provider
This commit is contained in:
YeonGyu-Kim
2026-02-17 01:34:34 +09:00
committed by GitHub
6 changed files with 346 additions and 1 deletions

View File

@@ -553,6 +553,18 @@ describe("BrowserAutomationProviderSchema", () => {
// then // then
expect(result.success).toBe(false) expect(result.success).toBe(false)
}) })
test("accepts 'playwright-cli' as valid provider", () => {
// given
const input = "playwright-cli"
// when
const result = BrowserAutomationProviderSchema.safeParse(input)
// then
expect(result.success).toBe(true)
expect(result.data).toBe("playwright-cli")
})
}) })
describe("BrowserAutomationConfigSchema", () => { describe("BrowserAutomationConfigSchema", () => {
@@ -577,6 +589,17 @@ describe("BrowserAutomationConfigSchema", () => {
// then // then
expect(result.provider).toBe("agent-browser") expect(result.provider).toBe("agent-browser")
}) })
test("accepts playwright-cli provider in config", () => {
// given
const input = { provider: "playwright-cli" }
// when
const result = BrowserAutomationConfigSchema.parse(input)
// then
expect(result.provider).toBe("playwright-cli")
})
}) })
describe("OhMyOpenCodeConfigSchema - browser_automation_engine", () => { describe("OhMyOpenCodeConfigSchema - browser_automation_engine", () => {
@@ -607,6 +630,18 @@ describe("OhMyOpenCodeConfigSchema - browser_automation_engine", () => {
expect(result.success).toBe(true) expect(result.success).toBe(true)
expect(result.data?.browser_automation_engine).toBeUndefined() expect(result.data?.browser_automation_engine).toBeUndefined()
}) })
test("accepts browser_automation_engine with playwright-cli", () => {
// given
const input = { browser_automation_engine: { provider: "playwright-cli" } }
// when
const result = OhMyOpenCodeConfigSchema.safeParse(input)
// then
expect(result.success).toBe(true)
expect(result.data?.browser_automation_engine?.provider).toBe("playwright-cli")
})
}) })
describe("ExperimentalConfigSchema feature flags", () => { describe("ExperimentalConfigSchema feature flags", () => {

View File

@@ -4,6 +4,7 @@ export const BrowserAutomationProviderSchema = z.enum([
"playwright", "playwright",
"agent-browser", "agent-browser",
"dev-browser", "dev-browser",
"playwright-cli",
]) ])
export const BrowserAutomationConfigSchema = z.object({ export const BrowserAutomationConfigSchema = z.object({
@@ -12,6 +13,7 @@ export const BrowserAutomationConfigSchema = z.object({
* - "playwright": Uses Playwright MCP server (@playwright/mcp) - default * - "playwright": Uses Playwright MCP server (@playwright/mcp) - default
* - "agent-browser": Uses Vercel's agent-browser CLI (requires: bun add -g agent-browser) * - "agent-browser": Uses Vercel's agent-browser CLI (requires: bun add -g agent-browser)
* - "dev-browser": Uses dev-browser skill with persistent browser state * - "dev-browser": Uses dev-browser skill with persistent browser state
* - "playwright-cli": Uses Playwright CLI (@playwright/cli) - token-efficient CLI alternative
*/ */
provider: BrowserAutomationProviderSchema.default("playwright"), provider: BrowserAutomationProviderSchema.default("playwright"),
}) })

View File

@@ -140,4 +140,35 @@ describe("createBuiltinSkills", () => {
// #then // #then
expect(skills.length).toBe(4) expect(skills.length).toBe(4)
}) })
test("returns playwright-cli skill when browserProvider is 'playwright-cli'", () => {
// given
const options = { browserProvider: "playwright-cli" as const }
// when
const skills = createBuiltinSkills(options)
// then
const playwrightSkill = skills.find((s) => s.name === "playwright")
const agentBrowserSkill = skills.find((s) => s.name === "agent-browser")
expect(playwrightSkill).toBeDefined()
expect(playwrightSkill!.description).toContain("browser")
expect(playwrightSkill!.allowedTools).toContain("Bash(playwright-cli:*)")
expect(playwrightSkill!.mcpConfig).toBeUndefined()
expect(agentBrowserSkill).toBeUndefined()
})
test("playwright-cli skill template contains CLI commands", () => {
// given
const options = { browserProvider: "playwright-cli" as const }
// when
const skills = createBuiltinSkills(options)
const skill = skills.find((s) => s.name === "playwright")
// then
expect(skill!.template).toContain("playwright-cli open")
expect(skill!.template).toContain("playwright-cli snapshot")
expect(skill!.template).toContain("playwright-cli click")
})
}) })

View File

@@ -4,6 +4,7 @@ import type { BrowserAutomationProvider } from "../../config/schema"
import { import {
playwrightSkill, playwrightSkill,
agentBrowserSkill, agentBrowserSkill,
playwrightCliSkill,
frontendUiUxSkill, frontendUiUxSkill,
gitMasterSkill, gitMasterSkill,
devBrowserSkill, devBrowserSkill,
@@ -17,7 +18,14 @@ export interface CreateBuiltinSkillsOptions {
export function createBuiltinSkills(options: CreateBuiltinSkillsOptions = {}): BuiltinSkill[] { export function createBuiltinSkills(options: CreateBuiltinSkillsOptions = {}): BuiltinSkill[] {
const { browserProvider = "playwright", disabledSkills } = options const { browserProvider = "playwright", disabledSkills } = options
const browserSkill = browserProvider === "agent-browser" ? agentBrowserSkill : playwrightSkill let browserSkill: BuiltinSkill
if (browserProvider === "agent-browser") {
browserSkill = agentBrowserSkill
} else if (browserProvider === "playwright-cli") {
browserSkill = playwrightCliSkill
} else {
browserSkill = playwrightSkill
}
const skills = [browserSkill, frontendUiUxSkill, gitMasterSkill, devBrowserSkill] const skills = [browserSkill, frontendUiUxSkill, gitMasterSkill, devBrowserSkill]

View File

@@ -1,4 +1,5 @@
export { playwrightSkill, agentBrowserSkill } from "./playwright" export { playwrightSkill, agentBrowserSkill } from "./playwright"
export { playwrightCliSkill } from "./playwright-cli"
export { frontendUiUxSkill } from "./frontend-ui-ux" export { frontendUiUxSkill } from "./frontend-ui-ux"
export { gitMasterSkill } from "./git-master" export { gitMasterSkill } from "./git-master"
export { devBrowserSkill } from "./dev-browser" export { devBrowserSkill } from "./dev-browser"

View File

@@ -0,0 +1,268 @@
import type { BuiltinSkill } from "../types"
/**
* Playwright CLI skill — token-efficient CLI alternative to the MCP-based playwright skill.
*
* Uses name "playwright" (not "playwright-cli") because agents hardcode "playwright" as the
* canonical browser skill name. The browserProvider config swaps the implementation behind
* the same name: "playwright" gives MCP, "playwright-cli" gives this CLI variant.
* The binary is still called `playwright-cli` (see allowedTools).
*/
export const playwrightCliSkill: BuiltinSkill = {
name: "playwright",
description: "MUST USE for any browser-related tasks. Browser automation via playwright-cli - verification, browsing, information gathering, web scraping, testing, screenshots, and all browser interactions.",
template: `# Browser Automation with playwright-cli
## Quick start
\`\`\`bash
# open new browser
playwright-cli open
# navigate to a page
playwright-cli goto https://playwright.dev
# interact with the page using refs from the snapshot
playwright-cli click e15
playwright-cli type "page.click"
playwright-cli press Enter
# take a screenshot
playwright-cli screenshot
# close the browser
playwright-cli close
\`\`\`
## Commands
### Core
\`\`\`bash
playwright-cli open
# open and navigate right away
playwright-cli open https://example.com/
playwright-cli goto https://playwright.dev
playwright-cli type "search query"
playwright-cli click e3
playwright-cli dblclick e7
playwright-cli fill e5 "user@example.com"
playwright-cli drag e2 e8
playwright-cli hover e4
playwright-cli select e9 "option-value"
playwright-cli upload ./document.pdf
playwright-cli check e12
playwright-cli uncheck e12
playwright-cli snapshot
playwright-cli snapshot --filename=after-click.yaml
playwright-cli eval "document.title"
playwright-cli eval "el => el.textContent" e5
playwright-cli dialog-accept
playwright-cli dialog-accept "confirmation text"
playwright-cli dialog-dismiss
playwright-cli resize 1920 1080
playwright-cli close
\`\`\`
### Navigation
\`\`\`bash
playwright-cli go-back
playwright-cli go-forward
playwright-cli reload
\`\`\`
### Keyboard
\`\`\`bash
playwright-cli press Enter
playwright-cli press ArrowDown
playwright-cli keydown Shift
playwright-cli keyup Shift
\`\`\`
### Mouse
\`\`\`bash
playwright-cli mousemove 150 300
playwright-cli mousedown
playwright-cli mousedown right
playwright-cli mouseup
playwright-cli mouseup right
playwright-cli mousewheel 0 100
\`\`\`
### Save as
\`\`\`bash
playwright-cli screenshot
playwright-cli screenshot e5
playwright-cli screenshot --filename=page.png
playwright-cli pdf --filename=page.pdf
\`\`\`
### Tabs
\`\`\`bash
playwright-cli tab-list
playwright-cli tab-new
playwright-cli tab-new https://example.com/page
playwright-cli tab-close
playwright-cli tab-close 2
playwright-cli tab-select 0
\`\`\`
### Storage
\`\`\`bash
playwright-cli state-save
playwright-cli state-save auth.json
playwright-cli state-load auth.json
# Cookies
playwright-cli cookie-list
playwright-cli cookie-list --domain=example.com
playwright-cli cookie-get session_id
playwright-cli cookie-set session_id abc123
playwright-cli cookie-set session_id abc123 --domain=example.com --httpOnly --secure
playwright-cli cookie-delete session_id
playwright-cli cookie-clear
# LocalStorage
playwright-cli localstorage-list
playwright-cli localstorage-get theme
playwright-cli localstorage-set theme dark
playwright-cli localstorage-delete theme
playwright-cli localstorage-clear
# SessionStorage
playwright-cli sessionstorage-list
playwright-cli sessionstorage-get step
playwright-cli sessionstorage-set step 3
playwright-cli sessionstorage-delete step
playwright-cli sessionstorage-clear
\`\`\`
### Network
\`\`\`bash
playwright-cli route "**/*.jpg" --status=404
playwright-cli route "https://api.example.com/**" --body='{"mock": true}'
playwright-cli route-list
playwright-cli unroute "**/*.jpg"
playwright-cli unroute
\`\`\`
### DevTools
\`\`\`bash
playwright-cli console
playwright-cli console warning
playwright-cli network
playwright-cli run-code "async page => await page.context().grantPermissions(['geolocation'])"
playwright-cli tracing-start
playwright-cli tracing-stop
playwright-cli video-start
playwright-cli video-stop video.webm
\`\`\`
### Install
\`\`\`bash
playwright-cli install --skills
playwright-cli install-browser
\`\`\`
### Configuration
\`\`\`bash
# Use specific browser when creating session
playwright-cli open --browser=chrome
playwright-cli open --browser=firefox
playwright-cli open --browser=webkit
playwright-cli open --browser=msedge
# Connect to browser via extension
playwright-cli open --extension
# Use persistent profile (by default profile is in-memory)
playwright-cli open --persistent
# Use persistent profile with custom directory
playwright-cli open --profile=/path/to/profile
# Start with config file
playwright-cli open --config=my-config.json
# Close the browser
playwright-cli close
# Delete user data for the default session
playwright-cli delete-data
\`\`\`
### Browser Sessions
\`\`\`bash
# create new browser session named "mysession" with persistent profile
playwright-cli -s=mysession open example.com --persistent
# same with manually specified profile directory (use when requested explicitly)
playwright-cli -s=mysession open example.com --profile=/path/to/profile
playwright-cli -s=mysession click e6
playwright-cli -s=mysession close # stop a named browser
playwright-cli -s=mysession delete-data # delete user data for persistent session
playwright-cli list
# Close all browsers
playwright-cli close-all
# Forcefully kill all browser processes
playwright-cli kill-all
\`\`\`
## Example: Form submission
\`\`\`bash
playwright-cli open https://example.com/form
playwright-cli snapshot
playwright-cli fill e1 "user@example.com"
playwright-cli fill e2 "password123"
playwright-cli click e3
playwright-cli snapshot
playwright-cli close
\`\`\`
## Example: Multi-tab workflow
\`\`\`bash
playwright-cli open https://example.com
playwright-cli tab-new https://example.com/other
playwright-cli tab-list
playwright-cli tab-select 0
playwright-cli snapshot
playwright-cli close
\`\`\`
## Example: Debugging with DevTools
\`\`\`bash
playwright-cli open https://example.com
playwright-cli click e4
playwright-cli fill e7 "test"
playwright-cli console
playwright-cli network
playwright-cli close
\`\`\`
\`\`\`bash
playwright-cli open https://example.com
playwright-cli tracing-start
playwright-cli click e4
playwright-cli fill e7 "test"
playwright-cli tracing-stop
playwright-cli close
\`\`\`
## Specific tasks
* **Request mocking** [references/request-mocking.md](references/request-mocking.md)
* **Running Playwright code** [references/running-code.md](references/running-code.md)
* **Browser session management** [references/session-management.md](references/session-management.md)
* **Storage state (cookies, localStorage)** [references/storage-state.md](references/storage-state.md)
* **Test generation** [references/test-generation.md](references/test-generation.md)
* **Tracing** [references/tracing.md](references/tracing.md)
* **Video recording** [references/video-recording.md](references/video-recording.md)`,
allowedTools: ["Bash(playwright-cli:*)"],
}