@korvol/fixwright
v0.1.3
Published
AI-powered Playwright code fixer that automatically analyzes failures and creates pull requests
Readme
@korvol/fixwright
AI-powered Playwright code fixer that automatically analyzes failures and generates fixes using Claude.
Features
- AI-powered Analysis - Uses Claude to understand failures and generate fixes
- AgentFixer - Autonomous agent that reads code, analyzes failures, and applies fixes
- Failure Sources - Read failure cases from files or databases
- Git Integration - Create branches and commits for fixes
- PR Creation - Automatically create pull requests with fixes
Installation
npm install @korvol/fixwright
# or
pnpm add @korvol/fixwrightQuick Start
Using AgentFixer
The AgentFixer is an autonomous agent that analyzes failure cases and applies fixes:
import { AgentFixer } from '@korvol/fixwright';
import { generateFailureCase } from '@korvol/stepwright';
// Create fixer with configuration
const fixer = new AgentFixer({
model: 'claude-sonnet-4-20250514',
maxTurns: 20,
timeout: 300000, // 5 minutes
verbosity: 'normal',
});
// Subscribe to events for progress feedback
fixer.on('agent:text', (text) => {
console.log(`Agent: ${text.slice(0, 100)}...`);
});
fixer.on('agent:tool_use', (toolName, input) => {
console.log(`Using tool: ${toolName}`);
});
// Fix a failure case
const result = await fixer.fix(failureCase, process.cwd());
if (result.success) {
console.log('Fix applied successfully!');
console.log(`Cause: ${result.analysis?.causeType}`);
console.log(`Explanation: ${result.analysis?.explanation}`);
if (result.edits) {
console.log(`Files modified: ${result.edits.map((e) => e.filePath).join(', ')}`);
}
} else {
console.log(`Fix failed: ${result.error}`);
}Failure Sources
Read failure cases from different sources:
import { FileFailureSource, DatabaseFailureSource } from '@korvol/fixwright';
// File-based source - reads from a directory
const fileSource = new FileFailureSource('./failure-cases');
const failures = await fileSource.getPending();
// Database source - reads from a database
const dbSource = new DatabaseFailureSource(databaseConnection);
const failures = await dbSource.getPending();Git Integration
Manage git branches and commits:
import { GitManager } from '@korvol/fixwright';
const git = new GitManager({
repoPath: process.cwd(),
baseBranch: 'main',
});
// Create a fix branch
await git.createBranch('fix/login-selector');
// Stage and commit changes
await git.stageFiles(['src/login.ts']);
await git.commit('fix: update login selector');
// Push to remote
await git.push();PR Creation
Create pull requests with fixes:
import { PRCreator } from '@korvol/fixwright';
const prCreator = new PRCreator({
token: process.env.GITHUB_TOKEN,
owner: 'my-org',
repo: 'my-repo',
});
const prUrl = await prCreator.create({
title: 'fix: update login selector',
body: 'Automated fix for login page selector issue',
head: 'fix/login-selector',
base: 'main',
});
console.log(`PR created: ${prUrl}`);Configuration
AgentFixer Options
interface AgentFixerConfig {
// Claude model to use
model?: string; // default: 'claude-sonnet-4-20250514'
// Maximum conversation turns
maxTurns?: number; // default: 20
// Timeout in milliseconds
timeout?: number; // default: 300000 (5 min)
// Output verbosity
verbosity?: 'quiet' | 'normal' | 'verbose';
// Permission mode for file operations
permissionMode?: 'auto' | 'confirm' | 'deny';
}AgentFixer Events
const fixer = new AgentFixer(config);
// Text output from the agent
fixer.on('agent:text', (text: string) => {});
// Tool being used
fixer.on('agent:tool_use', (toolName: string, input: unknown) => {});
// Tool result
fixer.on('agent:tool_result', (toolName: string, result: unknown) => {});
// Error occurred
fixer.on('agent:error', (error: Error) => {});FailureCase Format
Fixwright expects failure cases in this format (produced by Stepwright's generateFailureCase):
interface FailureCase {
id: string;
status: 'pending' | 'in_progress' | 'fixed' | 'failed';
createdAt: string;
scriptInfo: {
name: string;
path: string;
repository: string;
baseBranch: string;
commit: string;
};
failureInfo: {
stepName: string;
stepIndex: number;
checkpoint?: string;
error: {
type: string;
message: string;
stack?: string;
};
sourceLocation?: {
file: string;
line: number;
column?: number;
};
};
artifacts: {
screenshot?: string;
dom?: string;
console?: string;
trace?: string;
video?: string;
};
executionContext: {
url: string;
title?: string;
viewport?: { width: number; height: number };
userAgent?: string;
timestamp: string;
};
}AgentFixResult
interface AgentFixResult {
success: boolean;
error?: string;
// Analysis of the failure
analysis?: {
causeType: 'selector' | 'timing' | 'navigation' | 'logic' | 'unknown';
explanation: string;
confidence: number;
};
// Edits applied
edits?: Array<{
filePath: string;
diff: string;
}>;
// Validation result
validation?: {
passed: boolean;
output?: string;
};
}Integration with Stepwright
┌─────────────────┐ ┌─────────────────┐
│ Stepwright │ │ Fixwright │
│ │ │ │
│ Runs scripts │ ── FailureCase ──▶│ Analyzes with │
│ Captures │ │ Claude AI │
│ failures │ │ Applies fixes │
│ │ │ Creates PRs │
└─────────────────┘ └─────────────────┘Example workflow:
import { Stepwright, generateFailureCase } from '@korvol/stepwright';
import { AgentFixer } from '@korvol/fixwright';
// 1. Run script
const result = await script.run();
// 2. If failed, generate failure case
if (!result.success && result.failedStep) {
const failureCase = generateFailureCase(result, {
scriptInfo: {
name: 'Login Script',
path: 'scripts/login.ts',
repository: 'my-org/my-repo',
baseBranch: 'main',
commit: 'abc123',
},
artifactPaths: {
screenshot: result.failedStep.artifacts.screenshot,
dom: result.failedStep.artifacts.dom,
},
});
// 3. Auto-fix with Fixwright
const fixer = new AgentFixer({
model: 'claude-sonnet-4-20250514',
verbosity: 'normal',
});
const fixResult = await fixer.fix(failureCase, process.cwd());
if (fixResult.success) {
console.log('Fix applied!');
}
}Environment Variables
# Required for AI fixing
ANTHROPIC_API_KEY=your-api-key
# Required for PR creation
GITHUB_TOKEN=your-github-tokenLicense
MIT
