💬 Commit message: Update 2026-02-11 04:13:54, 13 files, 595 lines
📁 Files changed: 13 📝 Lines changed: 595 • PLAN.md • TODO.md • browser.d.ts • browser.d.ts.map • browser.js • browser.js.map • mcp.js • mcp.js.map • types.d.ts • types.d.ts.map • browser.ts • mcp.ts • types.ts
This commit is contained in:
@@ -1,238 +1,249 @@
|
|||||||
# Plan: Web Debugging Commands
|
# Plan: Playwright Debugging Features
|
||||||
|
|
||||||
## Phase 1: Storage & Session Commands
|
## Phase 1: Core Debugging (Console & Errors)
|
||||||
|
|
||||||
### Description
|
### Description
|
||||||
Add commands for inspecting and manipulating browser storage and cookies. These are essential for debugging authentication, session state, and client-side data persistence.
|
Implement fundamental debugging capabilities: console message capture and uncaught exception handling. These form the foundation for debugging client-side issues.
|
||||||
|
|
||||||
### Steps
|
### Steps
|
||||||
|
|
||||||
#### Step 1.1: Add Cookies Command
|
#### Step 1.1: Add Console Command
|
||||||
- **Objective**: Implement get/set/clear cookies functionality
|
- **Objective**: Capture and retrieve console messages from browser
|
||||||
- **Files**: `src/types.ts`, `src/browser.ts`, `src/server.ts`, `src/index.ts`
|
- **Files**: `src/types.ts`, `src/browser.ts`, `src/mcp.ts`
|
||||||
- **Dependencies**: None
|
- **Dependencies**: None
|
||||||
|
- **Status**: COMPLETE
|
||||||
- **Implementation**:
|
- **Implementation**:
|
||||||
- Add `CookiesCommand` type with `action: 'get' | 'set' | 'clear'`
|
- Add `ConsoleCommand` type with `level` filter and `clear` option
|
||||||
- Add optional `name`, `value`, `url` fields for set operation
|
- Store messages via `page.on('console')` listener
|
||||||
- Implement `cookies()` method using `context.cookies()` and `context.addCookies()`
|
- Return messages with level, text, timestamp, location
|
||||||
- Add logging with cookie icon
|
|
||||||
|
|
||||||
#### Step 1.2: Add Storage Command
|
#### Step 1.2: Add Page Errors Command
|
||||||
- **Objective**: Implement localStorage and sessionStorage read/write/clear
|
- **Objective**: Capture uncaught exceptions and unhandled promise rejections
|
||||||
- **Files**: `src/types.ts`, `src/browser.ts`, `src/server.ts`, `src/index.ts`
|
- **Files**: `src/types.ts`, `src/browser.ts`, `src/mcp.ts`
|
||||||
- **Dependencies**: Step 1.1
|
- **Dependencies**: Step 1.1
|
||||||
- **Implementation**:
|
- **Implementation**:
|
||||||
- Add `StorageCommand` type with `storage: 'local' | 'session'` and `action: 'get' | 'set' | 'clear'`
|
- Add `ErrorsCommand` type with `clear` option
|
||||||
- Implement via `page.evaluate()` accessing `window.localStorage` / `window.sessionStorage`
|
- Listen to `page.on('pageerror')` for uncaught exceptions
|
||||||
- Return all items on get, or specific key if provided
|
- Store error message, stack trace, timestamp
|
||||||
|
- Add `browser://errors` MCP resource
|
||||||
|
|
||||||
## Phase 2: Console & Debugging Commands
|
## Phase 2: Network Monitoring
|
||||||
|
|
||||||
### Description
|
### Description
|
||||||
Add commands for capturing console output and debugging page state. Critical for understanding client-side errors and application behavior.
|
Implement network request/response capture for debugging API calls, identifying failed requests, and inspecting payloads.
|
||||||
|
|
||||||
### Steps
|
### Steps
|
||||||
|
|
||||||
#### Step 2.1: Add Console Command
|
#### Step 2.1: Add Network Logging
|
||||||
- **Objective**: Capture and return console messages (log, error, warn, info)
|
- **Objective**: Capture all network requests and responses
|
||||||
- **Files**: `src/types.ts`, `src/browser.ts`, `src/server.ts`, `src/index.ts`
|
- **Files**: `src/types.ts`, `src/browser.ts`, `src/mcp.ts`
|
||||||
- **Dependencies**: None
|
- **Dependencies**: None
|
||||||
- **Implementation**:
|
- **Implementation**:
|
||||||
- Add `ConsoleCommand` type with optional `clear: boolean`
|
- Add `NetworkCommand` type with `filter` and `clear` options
|
||||||
- Store console messages in array via `page.on('console')`
|
- Listen to `page.on('request')` and `page.on('response')`
|
||||||
- Initialize listener in `launch()` method
|
- Store: url, method, status, resourceType, timing, headers
|
||||||
- Return accumulated messages with type, text, and timestamp
|
- Add optional body capture for XHR/fetch (with size limit)
|
||||||
|
- Add `browser://network` MCP resource
|
||||||
|
|
||||||
#### Step 2.2: Add Metrics Command
|
#### Step 2.2: Add Failed Requests Filter
|
||||||
- **Objective**: Return performance metrics and DOM statistics
|
- **Objective**: Quick access to failed/error requests
|
||||||
- **Files**: `src/types.ts`, `src/browser.ts`, `src/server.ts`, `src/index.ts`
|
- **Files**: `src/browser.ts`, `src/mcp.ts`
|
||||||
|
- **Dependencies**: Step 2.1
|
||||||
|
- **Implementation**:
|
||||||
|
- Add `failed` filter option to NetworkCommand
|
||||||
|
- Include requests with status >= 400 or network errors
|
||||||
|
- Add `browser://network/failed` MCP resource
|
||||||
|
|
||||||
|
#### Step 2.3: Add Request Interception
|
||||||
|
- **Objective**: Block or mock specific requests
|
||||||
|
- **Files**: `src/types.ts`, `src/browser.ts`, `src/mcp.ts`
|
||||||
|
- **Dependencies**: Step 2.1
|
||||||
|
- **Implementation**:
|
||||||
|
- Add `InterceptCommand` with `action: 'block' | 'mock' | 'clear'`
|
||||||
|
- Support URL patterns (glob or regex)
|
||||||
|
- For mock: allow custom response body/status
|
||||||
|
- Use `page.route()` for interception
|
||||||
|
|
||||||
|
## Phase 3: Performance & Metrics
|
||||||
|
|
||||||
|
### Description
|
||||||
|
Add performance timing and metrics collection for identifying bottlenecks and measuring page load characteristics.
|
||||||
|
|
||||||
|
### Steps
|
||||||
|
|
||||||
|
#### Step 3.1: Add Performance Metrics
|
||||||
|
- **Objective**: Return page performance timing data
|
||||||
|
- **Files**: `src/types.ts`, `src/browser.ts`, `src/mcp.ts`
|
||||||
- **Dependencies**: None
|
- **Dependencies**: None
|
||||||
- **Implementation**:
|
- **Implementation**:
|
||||||
- Add `MetricsCommand` type
|
- Add `MetricsCommand` type
|
||||||
- Use `page.evaluate()` to gather `performance.timing`, DOM node counts
|
- Collect via `performance.timing` and `performance.getEntriesByType()`
|
||||||
- Return structured metrics object
|
- Return: domContentLoaded, load, firstPaint, firstContentfulPaint
|
||||||
|
- Include DOM stats: nodeCount, scriptCount, styleCount
|
||||||
|
|
||||||
## Phase 3: Interaction Commands
|
#### Step 3.2: Add Resource Timing
|
||||||
|
- **Objective**: Get timing breakdown for individual resources
|
||||||
|
- **Files**: `src/browser.ts`, `src/mcp.ts`
|
||||||
|
- **Dependencies**: Step 3.1
|
||||||
|
- **Implementation**:
|
||||||
|
- Add `resources` option to MetricsCommand
|
||||||
|
- Use `performance.getEntriesByType('resource')`
|
||||||
|
- Return: name, duration, transferSize, initiatorType
|
||||||
|
|
||||||
|
## Phase 4: Accessibility
|
||||||
|
|
||||||
### Description
|
### Description
|
||||||
Add commands for advanced page interactions beyond click and type. Enables testing hover states, keyboard shortcuts, and form controls.
|
Implement accessibility tree inspection for debugging screen reader and a11y issues.
|
||||||
|
|
||||||
### Steps
|
### Steps
|
||||||
|
|
||||||
#### Step 3.1: Add Scroll Command
|
#### Step 4.1: Add Accessibility Snapshot
|
||||||
- **Objective**: Scroll to position, element, or by delta
|
- **Objective**: Dump accessibility tree for page or element
|
||||||
- **Files**: `src/types.ts`, `src/browser.ts`, `src/server.ts`, `src/index.ts`
|
- **Files**: `src/types.ts`, `src/browser.ts`, `src/mcp.ts`
|
||||||
- **Dependencies**: None
|
- **Dependencies**: None
|
||||||
- **Implementation**:
|
- **Implementation**:
|
||||||
- Add `ScrollCommand` with `selector?: string`, `x?: number`, `y?: number`, `behavior?: 'smooth' | 'instant'`
|
- Add `A11yCommand` with optional `selector` for subtree
|
||||||
- If selector provided, use `element.scrollIntoView()`
|
|
||||||
- Otherwise use `window.scrollTo()`
|
|
||||||
|
|
||||||
#### Step 3.2: Add Hover Command
|
|
||||||
- **Objective**: Trigger hover state on element
|
|
||||||
- **Files**: `src/types.ts`, `src/browser.ts`, `src/server.ts`, `src/index.ts`
|
|
||||||
- **Dependencies**: None
|
|
||||||
- **Implementation**:
|
|
||||||
- Add `HoverCommand` with `selector: string`
|
|
||||||
- Use `page.hover(selector)`
|
|
||||||
- Return success with element info
|
|
||||||
|
|
||||||
#### Step 3.3: Add Select Command
|
|
||||||
- **Objective**: Select option(s) in dropdown/select elements
|
|
||||||
- **Files**: `src/types.ts`, `src/browser.ts`, `src/server.ts`, `src/index.ts`
|
|
||||||
- **Dependencies**: None
|
|
||||||
- **Implementation**:
|
|
||||||
- Add `SelectCommand` with `selector: string`, `value: string | string[]`
|
|
||||||
- Use `page.selectOption(selector, value)`
|
|
||||||
- Return selected values
|
|
||||||
|
|
||||||
#### Step 3.4: Add Keys Command
|
|
||||||
- **Objective**: Send keyboard shortcuts and special keys
|
|
||||||
- **Files**: `src/types.ts`, `src/browser.ts`, `src/server.ts`, `src/index.ts`
|
|
||||||
- **Dependencies**: None
|
|
||||||
- **Implementation**:
|
|
||||||
- Add `KeysCommand` with `keys: string` (e.g., "Control+a", "Escape", "Enter")
|
|
||||||
- Use `page.keyboard.press()` for single keys
|
|
||||||
- Support key combinations
|
|
||||||
|
|
||||||
## Phase 4: Network Commands
|
|
||||||
|
|
||||||
### Description
|
|
||||||
Add commands for network inspection and manipulation. Enables debugging API calls, blocking resources, and simulating network conditions.
|
|
||||||
|
|
||||||
### Steps
|
|
||||||
|
|
||||||
#### Step 4.1: Add Network Logging
|
|
||||||
- **Objective**: Capture and return network requests/responses
|
|
||||||
- **Files**: `src/types.ts`, `src/browser.ts`, `src/server.ts`, `src/index.ts`
|
|
||||||
- **Dependencies**: None
|
|
||||||
- **Implementation**:
|
|
||||||
- Add `NetworkCommand` with `action: 'log' | 'clear'`, optional `filter: string`
|
|
||||||
- Store requests via `page.on('request')` and `page.on('response')`
|
|
||||||
- Return array of {url, method, status, type, timing}
|
|
||||||
|
|
||||||
#### Step 4.2: Add Block Command
|
|
||||||
- **Objective**: Block URLs or patterns (ads, analytics, etc.)
|
|
||||||
- **Files**: `src/types.ts`, `src/browser.ts`, `src/server.ts`, `src/index.ts`
|
|
||||||
- **Dependencies**: Step 4.1
|
|
||||||
- **Implementation**:
|
|
||||||
- Add `BlockCommand` with `patterns: string[]` and `action: 'add' | 'remove' | 'clear'`
|
|
||||||
- Use `page.route()` to abort matching requests
|
|
||||||
- Maintain list of blocked patterns
|
|
||||||
|
|
||||||
#### Step 4.3: Add Throttle Command
|
|
||||||
- **Objective**: Simulate slow network conditions
|
|
||||||
- **Files**: `src/types.ts`, `src/browser.ts`, `src/server.ts`, `src/index.ts`
|
|
||||||
- **Dependencies**: None
|
|
||||||
- **Implementation**:
|
|
||||||
- Add `ThrottleCommand` with `preset: 'slow3g' | 'fast3g' | 'offline' | 'none'`
|
|
||||||
- Use CDP session to set network conditions via `Network.emulateNetworkConditions`
|
|
||||||
|
|
||||||
## Phase 5: Output Commands
|
|
||||||
|
|
||||||
### Description
|
|
||||||
Add commands for exporting page content in different formats.
|
|
||||||
|
|
||||||
### Steps
|
|
||||||
|
|
||||||
#### Step 5.1: Add PDF Command
|
|
||||||
- **Objective**: Save page as PDF
|
|
||||||
- **Files**: `src/types.ts`, `src/browser.ts`, `src/server.ts`, `src/index.ts`
|
|
||||||
- **Dependencies**: None
|
|
||||||
- **Implementation**:
|
|
||||||
- Add `PdfCommand` with `path: string`, optional `format`, `landscape`, `margin`
|
|
||||||
- Use `page.pdf()` (WebKit supports this)
|
|
||||||
- Return path to saved file
|
|
||||||
|
|
||||||
#### Step 5.2: Add Accessibility Command
|
|
||||||
- **Objective**: Dump accessibility tree snapshot
|
|
||||||
- **Files**: `src/types.ts`, `src/browser.ts`, `src/server.ts`, `src/index.ts`
|
|
||||||
- **Dependencies**: None
|
|
||||||
- **Implementation**:
|
|
||||||
- Add `AccessibilityCommand` with optional `selector` for subtree
|
|
||||||
- Use `page.accessibility.snapshot()`
|
- Use `page.accessibility.snapshot()`
|
||||||
- Return tree structure
|
- Return tree with role, name, value, description
|
||||||
|
- Add `browser://a11y` MCP resource
|
||||||
|
|
||||||
## Phase 6: Advanced Commands
|
## Phase 5: Dialog Handling
|
||||||
|
|
||||||
### Description
|
### Description
|
||||||
Add commands for viewport manipulation, device emulation, and frame handling.
|
Implement automatic handling of browser dialogs (alert, confirm, prompt) to prevent blocking during automation.
|
||||||
|
|
||||||
### Steps
|
### Steps
|
||||||
|
|
||||||
#### Step 6.1: Add Viewport Command
|
#### Step 5.1: Add Dialog Command
|
||||||
- **Objective**: Resize viewport dynamically
|
- **Objective**: Configure how dialogs are handled
|
||||||
- **Files**: `src/types.ts`, `src/browser.ts`, `src/server.ts`, `src/index.ts`
|
- **Files**: `src/types.ts`, `src/browser.ts`, `src/mcp.ts`
|
||||||
- **Dependencies**: None
|
- **Dependencies**: None
|
||||||
- **Implementation**:
|
- **Implementation**:
|
||||||
- Add `ViewportCommand` with `width: number`, `height: number`
|
- Add `DialogCommand` with `action: 'accept' | 'dismiss' | 'status'`
|
||||||
|
- Option to set default behavior for future dialogs
|
||||||
|
- Option to provide text response for prompts
|
||||||
|
- Store dialog history (type, message, response)
|
||||||
|
- Listen to `page.on('dialog')`
|
||||||
|
|
||||||
|
## Phase 6: Storage & Cookies
|
||||||
|
|
||||||
|
### Description
|
||||||
|
Add commands for inspecting and manipulating browser storage, complementing the existing session save/restore.
|
||||||
|
|
||||||
|
### Steps
|
||||||
|
|
||||||
|
#### Step 6.1: Add Cookies Command
|
||||||
|
- **Objective**: Get, set, and clear cookies
|
||||||
|
- **Files**: `src/types.ts`, `src/browser.ts`, `src/mcp.ts`
|
||||||
|
- **Dependencies**: None
|
||||||
|
- **Implementation**:
|
||||||
|
- Add `CookiesCommand` with `action: 'get' | 'set' | 'delete' | 'clear'`
|
||||||
|
- Use `context.cookies()` and `context.addCookies()`
|
||||||
|
- Support filtering by name/domain
|
||||||
|
- Add `browser://cookies` MCP resource
|
||||||
|
|
||||||
|
#### Step 6.2: Add Storage Command
|
||||||
|
- **Objective**: Inspect/modify localStorage and sessionStorage
|
||||||
|
- **Files**: `src/types.ts`, `src/browser.ts`, `src/mcp.ts`
|
||||||
|
- **Dependencies**: None
|
||||||
|
- **Implementation**:
|
||||||
|
- Add `StorageCommand` with `type: 'local' | 'session'`
|
||||||
|
- Actions: get, set, delete, clear
|
||||||
|
- Implement via `page.evaluate()`
|
||||||
|
- Add `browser://storage/local` and `browser://storage/session` resources
|
||||||
|
|
||||||
|
## Phase 7: Advanced Interactions
|
||||||
|
|
||||||
|
### Description
|
||||||
|
Add additional interaction commands for comprehensive testing scenarios.
|
||||||
|
|
||||||
|
### Steps
|
||||||
|
|
||||||
|
#### Step 7.1: Add Hover Command
|
||||||
|
- **Objective**: Trigger hover state on elements
|
||||||
|
- **Files**: `src/types.ts`, `src/browser.ts`, `src/mcp.ts`
|
||||||
|
- **Dependencies**: None
|
||||||
|
- **Implementation**:
|
||||||
|
- Add `HoverCommand` with `selector`
|
||||||
|
- Use `page.hover(selector)`
|
||||||
|
|
||||||
|
#### Step 7.2: Add Select Command
|
||||||
|
- **Objective**: Select options in dropdown elements
|
||||||
|
- **Files**: `src/types.ts`, `src/browser.ts`, `src/mcp.ts`
|
||||||
|
- **Dependencies**: None
|
||||||
|
- **Implementation**:
|
||||||
|
- Add `SelectCommand` with `selector` and `value` (or values array)
|
||||||
|
- Use `page.selectOption()`
|
||||||
|
|
||||||
|
#### Step 7.3: Add Keys Command
|
||||||
|
- **Objective**: Send keyboard shortcuts and special keys
|
||||||
|
- **Files**: `src/types.ts`, `src/browser.ts`, `src/mcp.ts`
|
||||||
|
- **Dependencies**: None
|
||||||
|
- **Implementation**:
|
||||||
|
- Add `KeysCommand` with `keys` string (e.g., "Control+a", "Escape")
|
||||||
|
- Use `page.keyboard.press()`
|
||||||
|
|
||||||
|
#### Step 7.4: Add Upload Command
|
||||||
|
- **Objective**: Set files on file input elements
|
||||||
|
- **Files**: `src/types.ts`, `src/browser.ts`, `src/mcp.ts`
|
||||||
|
- **Dependencies**: None
|
||||||
|
- **Implementation**:
|
||||||
|
- Add `UploadCommand` with `selector` and `files` array
|
||||||
|
- Use `page.setInputFiles()`
|
||||||
|
|
||||||
|
#### Step 7.5: Add Scroll Command
|
||||||
|
- **Objective**: Scroll page or element into view
|
||||||
|
- **Files**: `src/types.ts`, `src/browser.ts`, `src/mcp.ts`
|
||||||
|
- **Dependencies**: None
|
||||||
|
- **Implementation**:
|
||||||
|
- Add `ScrollCommand` with optional `selector`, `x`, `y`
|
||||||
|
- If selector: use `element.scrollIntoView()`
|
||||||
|
- Otherwise: use `window.scrollTo()`
|
||||||
|
|
||||||
|
## Phase 8: Viewport & Emulation
|
||||||
|
|
||||||
|
### Description
|
||||||
|
Add device emulation and viewport manipulation for responsive testing.
|
||||||
|
|
||||||
|
### Steps
|
||||||
|
|
||||||
|
#### Step 8.1: Add Viewport Command
|
||||||
|
- **Objective**: Resize browser viewport dynamically
|
||||||
|
- **Files**: `src/types.ts`, `src/browser.ts`, `src/mcp.ts`
|
||||||
|
- **Dependencies**: None
|
||||||
|
- **Implementation**:
|
||||||
|
- Add `ViewportCommand` with `width` and `height`
|
||||||
- Use `page.setViewportSize()`
|
- Use `page.setViewportSize()`
|
||||||
- Return new dimensions
|
|
||||||
|
|
||||||
#### Step 6.2: Add Emulate Command
|
#### Step 8.2: Add Emulate Command
|
||||||
- **Objective**: Emulate mobile devices
|
- **Objective**: Emulate specific devices
|
||||||
- **Files**: `src/types.ts`, `src/browser.ts`, `src/server.ts`, `src/index.ts`
|
- **Files**: `src/types.ts`, `src/browser.ts`, `src/mcp.ts`
|
||||||
- **Dependencies**: Step 6.1
|
- **Dependencies**: Step 8.1
|
||||||
- **Implementation**:
|
- **Implementation**:
|
||||||
- Add `EmulateCommand` with `device: string` (e.g., 'iPhone 12', 'Pixel 5')
|
- Add `EmulateCommand` with `device` name
|
||||||
- Use Playwright's device descriptors
|
- Use Playwright's device descriptors
|
||||||
- Apply viewport, userAgent, deviceScaleFactor
|
- Apply viewport, userAgent, deviceScaleFactor, touch support
|
||||||
|
|
||||||
#### Step 6.3: Add Frames Command
|
## Phase 9: Documentation
|
||||||
- **Objective**: List and switch to iframe contexts
|
|
||||||
- **Files**: `src/types.ts`, `src/browser.ts`, `src/server.ts`, `src/index.ts`
|
|
||||||
- **Dependencies**: None
|
|
||||||
- **Implementation**:
|
|
||||||
- Add `FramesCommand` with `action: 'list' | 'switch'`, optional `selector` or `index`
|
|
||||||
- Use `page.frames()` to list, `frame.locator()` to switch context
|
|
||||||
- Track current frame for subsequent commands
|
|
||||||
|
|
||||||
#### Step 6.4: Add Dialog Command
|
|
||||||
- **Objective**: Handle alert/confirm/prompt dialogs
|
|
||||||
- **Files**: `src/types.ts`, `src/browser.ts`, `src/server.ts`, `src/index.ts`
|
|
||||||
- **Dependencies**: None
|
|
||||||
- **Implementation**:
|
|
||||||
- Add `DialogCommand` with `action: 'accept' | 'dismiss'`, optional `text` for prompt
|
|
||||||
- Set up `page.on('dialog')` handler
|
|
||||||
- Queue dialogs and respond based on command
|
|
||||||
|
|
||||||
#### Step 6.5: Add Upload Command
|
|
||||||
- **Objective**: Fill file input elements
|
|
||||||
- **Files**: `src/types.ts`, `src/browser.ts`, `src/server.ts`, `src/index.ts`
|
|
||||||
- **Dependencies**: None
|
|
||||||
- **Implementation**:
|
|
||||||
- Add `UploadCommand` with `selector: string`, `files: string[]`
|
|
||||||
- Use `page.setInputFiles(selector, files)`
|
|
||||||
- Return success with file count
|
|
||||||
|
|
||||||
## Phase 7: Documentation & Polish
|
|
||||||
|
|
||||||
### Description
|
### Description
|
||||||
Update documentation and CLI help text with all new commands.
|
Update all documentation with new commands and examples.
|
||||||
|
|
||||||
### Steps
|
### Steps
|
||||||
|
|
||||||
#### Step 7.1: Update README
|
#### Step 9.1: Update README
|
||||||
- **Objective**: Document all new commands with examples
|
- **Objective**: Document all commands with examples
|
||||||
- **Files**: `README.md`
|
- **Files**: `README.md`
|
||||||
- **Dependencies**: Phases 1-6
|
- **Dependencies**: Phases 1-8
|
||||||
- **Implementation**:
|
- **Implementation**:
|
||||||
- Add command reference section
|
- Add command reference grouped by category
|
||||||
- Include curl examples for each command
|
- Include curl/MCP examples
|
||||||
- Document response formats
|
- Document response formats
|
||||||
|
|
||||||
#### Step 7.2: Update CLAUDE.md
|
#### Step 9.2: Update CLAUDE.md
|
||||||
- **Objective**: Update developer documentation
|
- **Objective**: Update developer documentation
|
||||||
- **Files**: `CLAUDE.md`
|
- **Files**: `CLAUDE.md`
|
||||||
- **Dependencies**: Step 7.1
|
- **Dependencies**: Step 9.1
|
||||||
- **Implementation**:
|
- **Implementation**:
|
||||||
- Update architecture section with new command flow
|
- Update architecture notes
|
||||||
- Document internal logging format
|
- Document new command types
|
||||||
|
|
||||||
#### Step 7.3: Update CLI Help
|
|
||||||
- **Objective**: Update --help output with command list
|
|
||||||
- **Files**: `src/cli.ts`
|
|
||||||
- **Dependencies**: Phases 1-6
|
|
||||||
- **Implementation**:
|
|
||||||
- Expand server mode help section
|
|
||||||
- Group commands by category
|
|
||||||
|
|||||||
@@ -1,36 +1,39 @@
|
|||||||
# TODO: Web Debugging Commands
|
# TODO: Playwright Debugging Features
|
||||||
|
|
||||||
## Phase 1: Storage & Session Commands
|
## Phase 1: Core Debugging (Console & Errors)
|
||||||
- [ ] Step 1.1: Add Cookies Command
|
- [x] Step 1.1: Add Console Command
|
||||||
- [ ] Step 1.2: Add Storage Command
|
- [ ] Step 1.2: Add Page Errors Command
|
||||||
|
|
||||||
## Phase 2: Console & Debugging Commands
|
## Phase 2: Network Monitoring
|
||||||
- [ ] Step 2.1: Add Console Command
|
- [ ] Step 2.1: Add Network Logging
|
||||||
- [ ] Step 2.2: Add Metrics Command
|
- [ ] Step 2.2: Add Failed Requests Filter
|
||||||
|
- [ ] Step 2.3: Add Request Interception
|
||||||
|
|
||||||
## Phase 3: Interaction Commands
|
## Phase 3: Performance & Metrics
|
||||||
- [ ] Step 3.1: Add Scroll Command
|
- [ ] Step 3.1: Add Performance Metrics
|
||||||
- [ ] Step 3.2: Add Hover Command
|
- [ ] Step 3.2: Add Resource Timing
|
||||||
- [ ] Step 3.3: Add Select Command
|
|
||||||
- [ ] Step 3.4: Add Keys Command
|
|
||||||
|
|
||||||
## Phase 4: Network Commands
|
## Phase 4: Accessibility
|
||||||
- [ ] Step 4.1: Add Network Logging
|
- [ ] Step 4.1: Add Accessibility Snapshot
|
||||||
- [ ] Step 4.2: Add Block Command
|
|
||||||
- [ ] Step 4.3: Add Throttle Command
|
|
||||||
|
|
||||||
## Phase 5: Output Commands
|
## Phase 5: Dialog Handling
|
||||||
- [ ] Step 5.1: Add PDF Command
|
- [ ] Step 5.1: Add Dialog Command
|
||||||
- [ ] Step 5.2: Add Accessibility Command
|
|
||||||
|
|
||||||
## Phase 6: Advanced Commands
|
## Phase 6: Storage & Cookies
|
||||||
- [ ] Step 6.1: Add Viewport Command
|
- [ ] Step 6.1: Add Cookies Command
|
||||||
- [ ] Step 6.2: Add Emulate Command
|
- [ ] Step 6.2: Add Storage Command
|
||||||
- [ ] Step 6.3: Add Frames Command
|
|
||||||
- [ ] Step 6.4: Add Dialog Command
|
|
||||||
- [ ] Step 6.5: Add Upload Command
|
|
||||||
|
|
||||||
## Phase 7: Documentation & Polish
|
## Phase 7: Advanced Interactions
|
||||||
- [ ] Step 7.1: Update README
|
- [ ] Step 7.1: Add Hover Command
|
||||||
- [ ] Step 7.2: Update CLAUDE.md
|
- [ ] Step 7.2: Add Select Command
|
||||||
- [ ] Step 7.3: Update CLI Help
|
- [ ] Step 7.3: Add Keys Command
|
||||||
|
- [ ] Step 7.4: Add Upload Command
|
||||||
|
- [ ] Step 7.5: Add Scroll Command
|
||||||
|
|
||||||
|
## Phase 8: Viewport & Emulation
|
||||||
|
- [ ] Step 8.1: Add Viewport Command
|
||||||
|
- [ ] Step 8.2: Add Emulate Command
|
||||||
|
|
||||||
|
## Phase 9: Documentation
|
||||||
|
- [ ] Step 9.1: Update README
|
||||||
|
- [ ] Step 9.2: Update CLAUDE.md
|
||||||
|
|||||||
Vendored
+5
-1
@@ -1,12 +1,14 @@
|
|||||||
import { type BrowserContext, type Page } from 'playwright';
|
import { type BrowserContext, type Page } from 'playwright';
|
||||||
import type { BrowserCommand, BrowserOptions, CommandResponse, ElementInfo } from './types.js';
|
import type { BrowserCommand, BrowserOptions, CommandResponse, ConsoleMessage, ElementInfo } from './types.js';
|
||||||
export declare class ClaudeBrowser {
|
export declare class ClaudeBrowser {
|
||||||
private browser;
|
private browser;
|
||||||
private context;
|
private context;
|
||||||
private page;
|
private page;
|
||||||
private options;
|
private options;
|
||||||
|
private consoleMessages;
|
||||||
constructor(options?: BrowserOptions);
|
constructor(options?: BrowserOptions);
|
||||||
launch(): Promise<void>;
|
launch(): Promise<void>;
|
||||||
|
private setupConsoleListener;
|
||||||
close(): Promise<void>;
|
close(): Promise<void>;
|
||||||
private ensurePage;
|
private ensurePage;
|
||||||
/** Get the current page instance (for advanced usage) */
|
/** Get the current page instance (for advanced usage) */
|
||||||
@@ -43,6 +45,8 @@ export declare class ClaudeBrowser {
|
|||||||
wait(ms?: number): Promise<void>;
|
wait(ms?: number): Promise<void>;
|
||||||
newPage(): Promise<void>;
|
newPage(): Promise<void>;
|
||||||
eval(script: string): Promise<unknown>;
|
eval(script: string): Promise<unknown>;
|
||||||
|
getConsole(level?: string, clear?: boolean): ConsoleMessage[];
|
||||||
|
clearConsole(): void;
|
||||||
executeCommand(cmd: BrowserCommand): Promise<CommandResponse>;
|
executeCommand(cmd: BrowserCommand): Promise<CommandResponse>;
|
||||||
}
|
}
|
||||||
//# sourceMappingURL=browser.d.ts.map
|
//# sourceMappingURL=browser.d.ts.map
|
||||||
Vendored
+1
-1
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AACA,OAAO,EAAgB,KAAK,cAAc,EAAE,KAAK,IAAI,EAAU,MAAM,YAAY,CAAC;AAElF,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE/F,qBAAa,aAAa;IACxB,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,OAAO,CAA+B;IAC9C,OAAO,CAAC,IAAI,CAAqB;IACjC,OAAO,CAAC,OAAO,CAA2B;gBAE9B,OAAO,GAAE,cAAmB;IAQlC,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAWvB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAS5B,OAAO,CAAC,UAAU;IAOlB,yDAAyD;IACzD,OAAO,IAAI,IAAI,GAAG,IAAI;IAItB,gEAAgE;IAChE,UAAU,IAAI,cAAc,GAAG,IAAI;IAI7B,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAM1D,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAOjD,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKnD,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAiB/C,UAAU,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,UAAQ,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAOvF,MAAM,IAAI,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAKjD,OAAO,CAAC,IAAI,UAAQ,GAAG,OAAO,CAAC,MAAM,CAAC;IAMtC,IAAI,IAAI,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAMhC,OAAO,IAAI,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAMnC,MAAM,IAAI,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAMlC,IAAI,CAAC,EAAE,SAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAK9B,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAOxB,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAKtC,cAAc,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC;CAsIpE"}
|
{"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AACA,OAAO,EAAgB,KAAK,cAAc,EAAE,KAAK,IAAI,EAAU,MAAM,YAAY,CAAC;AAElF,OAAO,KAAK,EACV,cAAc,EACd,cAAc,EACd,eAAe,EACf,cAAc,EACd,WAAW,EACZ,MAAM,YAAY,CAAC;AAEpB,qBAAa,aAAa;IACxB,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,OAAO,CAA+B;IAC9C,OAAO,CAAC,IAAI,CAAqB;IACjC,OAAO,CAAC,OAAO,CAA2B;IAC1C,OAAO,CAAC,eAAe,CAAwB;gBAEnC,OAAO,GAAE,cAAmB;IAQlC,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAY7B,OAAO,CAAC,oBAAoB;IAYtB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAS5B,OAAO,CAAC,UAAU;IAOlB,yDAAyD;IACzD,OAAO,IAAI,IAAI,GAAG,IAAI;IAItB,gEAAgE;IAChE,UAAU,IAAI,cAAc,GAAG,IAAI;IAI7B,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAM1D,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAOjD,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKnD,KAAK,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAiB/C,UAAU,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,UAAQ,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAOvF,MAAM,IAAI,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAKjD,OAAO,CAAC,IAAI,UAAQ,GAAG,OAAO,CAAC,MAAM,CAAC;IAMtC,IAAI,IAAI,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAMhC,OAAO,IAAI,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAMnC,MAAM,IAAI,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAMlC,IAAI,CAAC,EAAE,SAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAK9B,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAQxB,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAK5C,UAAU,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,KAAK,UAAQ,GAAG,cAAc,EAAE;IAW3D,YAAY,IAAI,IAAI;IAId,cAAc,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC;CA0IpE"}
|
||||||
Vendored
+31
@@ -6,6 +6,7 @@ export class ClaudeBrowser {
|
|||||||
context = null;
|
context = null;
|
||||||
page = null;
|
page = null;
|
||||||
options;
|
options;
|
||||||
|
consoleMessages = [];
|
||||||
constructor(options = {}) {
|
constructor(options = {}) {
|
||||||
this.options = {
|
this.options = {
|
||||||
headless: options.headless ?? true,
|
headless: options.headless ?? true,
|
||||||
@@ -22,6 +23,18 @@ export class ClaudeBrowser {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
this.page = await this.context.newPage();
|
this.page = await this.context.newPage();
|
||||||
|
this.setupConsoleListener(this.page);
|
||||||
|
}
|
||||||
|
setupConsoleListener(page) {
|
||||||
|
page.on('console', (msg) => {
|
||||||
|
const location = msg.location();
|
||||||
|
this.consoleMessages.push({
|
||||||
|
level: msg.type(),
|
||||||
|
text: msg.text(),
|
||||||
|
timestamp: Date.now(),
|
||||||
|
location: location.url ? `${location.url}:${location.lineNumber}` : undefined,
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
async close() {
|
async close() {
|
||||||
if (this.browser) {
|
if (this.browser) {
|
||||||
@@ -113,11 +126,25 @@ export class ClaudeBrowser {
|
|||||||
throw new Error('Browser not launched. Call launch() first.');
|
throw new Error('Browser not launched. Call launch() first.');
|
||||||
}
|
}
|
||||||
this.page = await this.context.newPage();
|
this.page = await this.context.newPage();
|
||||||
|
this.setupConsoleListener(this.page);
|
||||||
}
|
}
|
||||||
async eval(script) {
|
async eval(script) {
|
||||||
const page = this.ensurePage();
|
const page = this.ensurePage();
|
||||||
return page.evaluate(script);
|
return page.evaluate(script);
|
||||||
}
|
}
|
||||||
|
getConsole(level, clear = false) {
|
||||||
|
let messages = this.consoleMessages;
|
||||||
|
if (level && level !== 'all') {
|
||||||
|
messages = messages.filter((m) => m.level === level);
|
||||||
|
}
|
||||||
|
if (clear) {
|
||||||
|
this.consoleMessages = [];
|
||||||
|
}
|
||||||
|
return messages;
|
||||||
|
}
|
||||||
|
clearConsole() {
|
||||||
|
this.consoleMessages = [];
|
||||||
|
}
|
||||||
async executeCommand(cmd) {
|
async executeCommand(cmd) {
|
||||||
try {
|
try {
|
||||||
switch (cmd.cmd) {
|
switch (cmd.cmd) {
|
||||||
@@ -177,6 +204,10 @@ export class ClaudeBrowser {
|
|||||||
const result = await this.eval(cmd.script);
|
const result = await this.eval(cmd.script);
|
||||||
return { ok: true, result };
|
return { ok: true, result };
|
||||||
}
|
}
|
||||||
|
case 'console': {
|
||||||
|
const messages = this.getConsole(cmd.level, cmd.clear);
|
||||||
|
return { ok: true, count: messages.length, messages };
|
||||||
|
}
|
||||||
case 'favicon': {
|
case 'favicon': {
|
||||||
const result = await image.createFavicon(cmd.input, cmd.outputDir);
|
const result = await image.createFavicon(cmd.input, cmd.outputDir);
|
||||||
return { ok: true, files: result.files, outputDir: result.outputDir };
|
return { ok: true, files: result.files, outputDir: result.outputDir };
|
||||||
|
|||||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+37
@@ -106,6 +106,19 @@ server.tool('eval', 'Execute JavaScript in the browser context', { script: z.str
|
|||||||
const result = await browser.eval(script);
|
const result = await browser.eval(script);
|
||||||
return textResult(JSON.stringify({ ok: true, result }));
|
return textResult(JSON.stringify({ ok: true, result }));
|
||||||
}));
|
}));
|
||||||
|
// Console
|
||||||
|
server.tool('console', 'Get captured console messages (log, warn, error, etc.) from the browser', {
|
||||||
|
level: z
|
||||||
|
.enum(['log', 'info', 'warn', 'error', 'debug', 'all'])
|
||||||
|
.optional()
|
||||||
|
.default('all')
|
||||||
|
.describe('Filter by log level'),
|
||||||
|
clear: z.boolean().optional().default(false).describe('Clear messages after retrieving'),
|
||||||
|
}, withLogging('console', async ({ level, clear }) => {
|
||||||
|
await ensureLaunched();
|
||||||
|
const messages = browser.getConsole(level, clear);
|
||||||
|
return textResult(JSON.stringify({ ok: true, count: messages.length, messages }));
|
||||||
|
}));
|
||||||
// Utility
|
// Utility
|
||||||
server.tool('wait', 'Wait for a specified time in milliseconds', { ms: z.number().optional().default(1000) }, withLogging('wait', async ({ ms }) => {
|
server.tool('wait', 'Wait for a specified time in milliseconds', { ms: z.number().optional().default(1000) }, withLogging('wait', async ({ ms }) => {
|
||||||
await ensureLaunched();
|
await ensureLaunched();
|
||||||
@@ -337,6 +350,30 @@ server.resource('Full Page HTML', 'browser://html/full', { description: 'Complet
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
// Resource: browser://console - Captured console messages
|
||||||
|
server.resource('Console Messages', 'browser://console', { description: 'Console messages captured from the browser', mimeType: 'application/json' }, async () => {
|
||||||
|
if (!launched) {
|
||||||
|
return {
|
||||||
|
contents: [
|
||||||
|
{
|
||||||
|
uri: 'browser://console',
|
||||||
|
mimeType: 'application/json',
|
||||||
|
text: JSON.stringify({ launched: false, messages: [] }),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const messages = browser.getConsole('all', false);
|
||||||
|
return {
|
||||||
|
contents: [
|
||||||
|
{
|
||||||
|
uri: 'browser://console',
|
||||||
|
mimeType: 'application/json',
|
||||||
|
text: JSON.stringify({ launched: true, count: messages.length, messages }),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
});
|
||||||
// Resource: browser://screenshot - Current page screenshot (base64)
|
// Resource: browser://screenshot - Current page screenshot (base64)
|
||||||
server.resource('Page Screenshot', 'browser://screenshot', { description: 'Screenshot of the current page as base64 PNG', mimeType: 'image/png' }, async () => {
|
server.resource('Page Screenshot', 'browser://screenshot', { description: 'Screenshot of the current page as base64 PNG', mimeType: 'image/png' }, async () => {
|
||||||
if (!launched) {
|
if (!launched) {
|
||||||
|
|||||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+13
-1
@@ -100,7 +100,18 @@ export interface ThumbnailCommand {
|
|||||||
output: string;
|
output: string;
|
||||||
size?: 'small' | 'medium' | 'large';
|
size?: 'small' | 'medium' | 'large';
|
||||||
}
|
}
|
||||||
export type BrowserCommand = GotoCommand | ClickCommand | TypeCommand | QueryCommand | ScreenshotCommand | UrlCommand | HtmlCommand | BackCommand | ForwardCommand | ReloadCommand | WaitCommand | NewPageCommand | CloseCommand | EvalCommand | FaviconCommand | ConvertCommand | ResizeCommand | CropCommand | CompressCommand | ThumbnailCommand;
|
export interface ConsoleCommand {
|
||||||
|
cmd: 'console';
|
||||||
|
clear?: boolean;
|
||||||
|
level?: 'log' | 'info' | 'warn' | 'error' | 'debug' | 'all';
|
||||||
|
}
|
||||||
|
export interface ConsoleMessage {
|
||||||
|
level: string;
|
||||||
|
text: string;
|
||||||
|
timestamp: number;
|
||||||
|
location?: string;
|
||||||
|
}
|
||||||
|
export type BrowserCommand = GotoCommand | ClickCommand | TypeCommand | QueryCommand | ScreenshotCommand | UrlCommand | HtmlCommand | BackCommand | ForwardCommand | ReloadCommand | WaitCommand | NewPageCommand | CloseCommand | EvalCommand | FaviconCommand | ConvertCommand | ResizeCommand | CropCommand | CompressCommand | ThumbnailCommand | ConsoleCommand;
|
||||||
export interface SuccessResponse {
|
export interface SuccessResponse {
|
||||||
ok: true;
|
ok: true;
|
||||||
url?: string;
|
url?: string;
|
||||||
@@ -116,6 +127,7 @@ export interface SuccessResponse {
|
|||||||
height?: number;
|
height?: number;
|
||||||
format?: string;
|
format?: string;
|
||||||
size?: number;
|
size?: number;
|
||||||
|
messages?: ConsoleMessage[];
|
||||||
}
|
}
|
||||||
export interface ErrorResponse {
|
export interface ErrorResponse {
|
||||||
ok: false;
|
ok: false;
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1 +1 @@
|
|||||||
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACpC;AAGD,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,OAAO,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,OAAO,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,YAAY,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,KAAK,CAAC;CACZ;AAED,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,SAAS,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,QAAQ,CAAC;CACf;AAED,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,SAAS,CAAC;CAChB;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,OAAO,CAAC;CACd;AAED,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;CAChB;AAGD,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,SAAS,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,SAAS,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;CAC1C;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,QAAQ,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAC;CAC3D;AAED,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,UAAU,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC/B,GAAG,EAAE,WAAW,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;CACrC;AAED,MAAM,MAAM,cAAc,GACtB,WAAW,GACX,YAAY,GACZ,WAAW,GACX,YAAY,GACZ,iBAAiB,GACjB,UAAU,GACV,WAAW,GACX,WAAW,GACX,cAAc,GACd,aAAa,GACb,WAAW,GACX,cAAc,GACd,YAAY,GACZ,WAAW,GACX,cAAc,GACd,cAAc,GACd,aAAa,GACb,WAAW,GACX,eAAe,GACf,gBAAgB,CAAC;AAGrB,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,IAAI,CAAC;IACT,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,WAAW,EAAE,CAAC;IACzB,MAAM,CAAC,EAAE,OAAO,CAAC;IAEjB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,KAAK,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,eAAe,GAAG,eAAe,GAAG,aAAa,CAAC"}
|
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
||||||
+41
-1
@@ -1,13 +1,20 @@
|
|||||||
import { resolve } from 'node:path';
|
import { resolve } from 'node:path';
|
||||||
import { type Browser, type BrowserContext, type Page, webkit } from 'playwright';
|
import { type Browser, type BrowserContext, type Page, webkit } from 'playwright';
|
||||||
import * as image from './image.js';
|
import * as image from './image.js';
|
||||||
import type { BrowserCommand, BrowserOptions, CommandResponse, ElementInfo } from './types.js';
|
import type {
|
||||||
|
BrowserCommand,
|
||||||
|
BrowserOptions,
|
||||||
|
CommandResponse,
|
||||||
|
ConsoleMessage,
|
||||||
|
ElementInfo,
|
||||||
|
} from './types.js';
|
||||||
|
|
||||||
export class ClaudeBrowser {
|
export class ClaudeBrowser {
|
||||||
private browser: Browser | null = null;
|
private browser: Browser | null = null;
|
||||||
private context: BrowserContext | null = null;
|
private context: BrowserContext | null = null;
|
||||||
private page: Page | null = null;
|
private page: Page | null = null;
|
||||||
private options: Required<BrowserOptions>;
|
private options: Required<BrowserOptions>;
|
||||||
|
private consoleMessages: ConsoleMessage[] = [];
|
||||||
|
|
||||||
constructor(options: BrowserOptions = {}) {
|
constructor(options: BrowserOptions = {}) {
|
||||||
this.options = {
|
this.options = {
|
||||||
@@ -26,6 +33,19 @@ export class ClaudeBrowser {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
this.page = await this.context.newPage();
|
this.page = await this.context.newPage();
|
||||||
|
this.setupConsoleListener(this.page);
|
||||||
|
}
|
||||||
|
|
||||||
|
private setupConsoleListener(page: Page): void {
|
||||||
|
page.on('console', (msg) => {
|
||||||
|
const location = msg.location();
|
||||||
|
this.consoleMessages.push({
|
||||||
|
level: msg.type(),
|
||||||
|
text: msg.text(),
|
||||||
|
timestamp: Date.now(),
|
||||||
|
location: location.url ? `${location.url}:${location.lineNumber}` : undefined,
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async close(): Promise<void> {
|
async close(): Promise<void> {
|
||||||
@@ -135,6 +155,7 @@ export class ClaudeBrowser {
|
|||||||
throw new Error('Browser not launched. Call launch() first.');
|
throw new Error('Browser not launched. Call launch() first.');
|
||||||
}
|
}
|
||||||
this.page = await this.context.newPage();
|
this.page = await this.context.newPage();
|
||||||
|
this.setupConsoleListener(this.page);
|
||||||
}
|
}
|
||||||
|
|
||||||
async eval(script: string): Promise<unknown> {
|
async eval(script: string): Promise<unknown> {
|
||||||
@@ -142,6 +163,21 @@ export class ClaudeBrowser {
|
|||||||
return page.evaluate(script);
|
return page.evaluate(script);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getConsole(level?: string, clear = false): ConsoleMessage[] {
|
||||||
|
let messages = this.consoleMessages;
|
||||||
|
if (level && level !== 'all') {
|
||||||
|
messages = messages.filter((m) => m.level === level);
|
||||||
|
}
|
||||||
|
if (clear) {
|
||||||
|
this.consoleMessages = [];
|
||||||
|
}
|
||||||
|
return messages;
|
||||||
|
}
|
||||||
|
|
||||||
|
clearConsole(): void {
|
||||||
|
this.consoleMessages = [];
|
||||||
|
}
|
||||||
|
|
||||||
async executeCommand(cmd: BrowserCommand): Promise<CommandResponse> {
|
async executeCommand(cmd: BrowserCommand): Promise<CommandResponse> {
|
||||||
try {
|
try {
|
||||||
switch (cmd.cmd) {
|
switch (cmd.cmd) {
|
||||||
@@ -201,6 +237,10 @@ export class ClaudeBrowser {
|
|||||||
const result = await this.eval(cmd.script);
|
const result = await this.eval(cmd.script);
|
||||||
return { ok: true, result };
|
return { ok: true, result };
|
||||||
}
|
}
|
||||||
|
case 'console': {
|
||||||
|
const messages = this.getConsole(cmd.level, cmd.clear);
|
||||||
|
return { ok: true, count: messages.length, messages };
|
||||||
|
}
|
||||||
case 'favicon': {
|
case 'favicon': {
|
||||||
const result = await image.createFavicon(cmd.input, cmd.outputDir);
|
const result = await image.createFavicon(cmd.input, cmd.outputDir);
|
||||||
return { ok: true, files: result.files, outputDir: result.outputDir };
|
return { ok: true, files: result.files, outputDir: result.outputDir };
|
||||||
|
|||||||
+49
@@ -183,6 +183,25 @@ server.tool(
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Console
|
||||||
|
server.tool(
|
||||||
|
'console',
|
||||||
|
'Get captured console messages (log, warn, error, etc.) from the browser',
|
||||||
|
{
|
||||||
|
level: z
|
||||||
|
.enum(['log', 'info', 'warn', 'error', 'debug', 'all'])
|
||||||
|
.optional()
|
||||||
|
.default('all')
|
||||||
|
.describe('Filter by log level'),
|
||||||
|
clear: z.boolean().optional().default(false).describe('Clear messages after retrieving'),
|
||||||
|
},
|
||||||
|
withLogging('console', async ({ level, clear }) => {
|
||||||
|
await ensureLaunched();
|
||||||
|
const messages = browser.getConsole(level, clear);
|
||||||
|
return textResult(JSON.stringify({ ok: true, count: messages.length, messages }));
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
// Utility
|
// Utility
|
||||||
server.tool(
|
server.tool(
|
||||||
'wait',
|
'wait',
|
||||||
@@ -512,6 +531,36 @@ server.resource(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Resource: browser://console - Captured console messages
|
||||||
|
server.resource(
|
||||||
|
'Console Messages',
|
||||||
|
'browser://console',
|
||||||
|
{ description: 'Console messages captured from the browser', mimeType: 'application/json' },
|
||||||
|
async () => {
|
||||||
|
if (!launched) {
|
||||||
|
return {
|
||||||
|
contents: [
|
||||||
|
{
|
||||||
|
uri: 'browser://console',
|
||||||
|
mimeType: 'application/json',
|
||||||
|
text: JSON.stringify({ launched: false, messages: [] }),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const messages = browser.getConsole('all', false);
|
||||||
|
return {
|
||||||
|
contents: [
|
||||||
|
{
|
||||||
|
uri: 'browser://console',
|
||||||
|
mimeType: 'application/json',
|
||||||
|
text: JSON.stringify({ launched: true, count: messages.length, messages }),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
// Resource: browser://screenshot - Current page screenshot (base64)
|
// Resource: browser://screenshot - Current page screenshot (base64)
|
||||||
server.resource(
|
server.resource(
|
||||||
'Page Screenshot',
|
'Page Screenshot',
|
||||||
|
|||||||
+17
-1
@@ -124,6 +124,19 @@ export interface ThumbnailCommand {
|
|||||||
size?: 'small' | 'medium' | 'large';
|
size?: 'small' | 'medium' | 'large';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ConsoleCommand {
|
||||||
|
cmd: 'console';
|
||||||
|
clear?: boolean;
|
||||||
|
level?: 'log' | 'info' | 'warn' | 'error' | 'debug' | 'all';
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ConsoleMessage {
|
||||||
|
level: string;
|
||||||
|
text: string;
|
||||||
|
timestamp: number;
|
||||||
|
location?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export type BrowserCommand =
|
export type BrowserCommand =
|
||||||
| GotoCommand
|
| GotoCommand
|
||||||
| ClickCommand
|
| ClickCommand
|
||||||
@@ -144,7 +157,8 @@ export type BrowserCommand =
|
|||||||
| ResizeCommand
|
| ResizeCommand
|
||||||
| CropCommand
|
| CropCommand
|
||||||
| CompressCommand
|
| CompressCommand
|
||||||
| ThumbnailCommand;
|
| ThumbnailCommand
|
||||||
|
| ConsoleCommand;
|
||||||
|
|
||||||
// Response types
|
// Response types
|
||||||
export interface SuccessResponse {
|
export interface SuccessResponse {
|
||||||
@@ -163,6 +177,8 @@ export interface SuccessResponse {
|
|||||||
height?: number;
|
height?: number;
|
||||||
format?: string;
|
format?: string;
|
||||||
size?: number;
|
size?: number;
|
||||||
|
// Console fields
|
||||||
|
messages?: ConsoleMessage[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ErrorResponse {
|
export interface ErrorResponse {
|
||||||
|
|||||||
Reference in New Issue
Block a user