- Install dependencies:
bun install - Run development server:
bun dev - Run project:
bun start - Run tests:
bun testorbunx playwright test - Run single test:
bun test path/to/test.js - Run Stagehand test:
bun run test:stagehand - Debug tests:
bunx playwright test --debug - Visual test UI:
bunx playwright test --ui - Install Playwright browsers:
bunx playwright install - Inspect Chrome:
bun run inspect-chrome - Inspect IWA frames:
bun run inspect-iwa - Control frames:
bun run control-frames
- TypeScript: Use strict typing with Zod for validation
- Naming: camelCase for variables/functions, PascalCase for types/classes
- Imports: Group by: 1) Node built-ins, 2) External packages, 3) Internal modules
- Error Handling: Use try/catch blocks with specific error types
- Async/Await: Prefer over promise chains
- Documentation: JSDoc for public interfaces and complex functions
This project is an experiment for automating controlled frames in Chrome using:
- Chrome Debug Protocol
- Playwright for browser automation
- Stagehand for AI-powered browser interactions
- Zod for type validation and schema definition
-
Configure API keys in .env file:
# Anthropic API key (for Claude 3.7) ANTHROPIC_API_KEY=sk-ant-xxx... # Model configuration STAGEHAND_MODEL=claude-3-7-sonnet-20250219 STAGEHAND_MODEL_PROVIDER=anthropic # Debug mode STAGEHAND_DEBUG=true -
Initialize Stagehand with Claude model:
const stagehand = new Stagehand({ modelName: process.env.STAGEHAND_MODEL || 'claude-3-7-sonnet-20250219', modelClientOptions: { apiKey: process.env.ANTHROPIC_API_KEY }, headless: false }); await stagehand.init(); const page = stagehand.page;
-
Always close Stagehand when finished:
try { // Use Stagehand... } finally { await stagehand.close(); }
For inspecting and controlling IWA frames:
-
Start Chrome with remote debugging:
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=9222
-
Connect to Chrome DevTools Protocol:
const CDP = require('chrome-remote-interface'); const client = await CDP({ port: 9222 });
-
Find frames:
const { frameTree } = await client.Page.getFrameTree();
-
Execute in specific frame:
const frameContext = contexts.find(context => context.auxData && context.auxData.frameId === frameId ); await client.Runtime.evaluate({ expression: "document.title", contextId: frameContext.id, returnByValue: true });
-
Always close the connection:
await client.close();
- ANTHROPIC_API_KEY: API key for Claude 3.7
- STAGEHAND_MODEL: Claude model to use (default: claude-3-7-sonnet-20250219)
- STAGEHAND_DEBUG: Set to 'true' to enable debug logging
- Create feature branches from main
- Commit messages: Use descriptive prefixes (feat:, fix:, etc.)
- PRs should include test plan and clear description of changes