Events and Hooks
Events and Hooks
Fixwright emits events throughout the fixing process. Use these to monitor progress, log activity, and extend behavior.
Event Categories
Lifecycle Events
Control flow events for the overall process:
| Event | Description |
|---|---|
started | FixWright has started processing |
stopped | FixWright has stopped |
failure:received | New failure case received |
failure:completed | Failure case processing complete |
Attempt Events
Events for each fix attempt:
| Event | Description |
|---|---|
attempt:start | Fix attempt started |
attempt:analyzing | Analyzing the failure |
attempt:fixing | Applying a fix |
attempt:validating | Validating the fix |
attempt:success | Fix validated successfully |
attempt:failed | Fix attempt failed |
attempt:regression | Fix caused new failures |
attempt:new_error | Different error occurred |
Agent Events
Events from the Claude Agent:
| Event | Description |
|---|---|
agent:start | Agent started working |
agent:complete | Agent finished |
agent:message | Raw SDK message |
agent:error | Agent error |
agent:thinking | Agent thinking (verbose) |
agent:text | Agent text output (verbose) |
agent:tool_use | Tool invocation |
Tool Events (Verbose Mode)
Specific tool usage events:
| Event | Description |
|---|---|
agent:read | File read operation |
agent:edit | File edit operation |
agent:bash | Bash command |
agent:grep | Search operation |
agent:glob | Glob pattern match |
Result Events
| Event | Description |
|---|---|
pr:created | Pull request created |
error | Error occurred |
Using Events
Basic Event Handling
import { FixWright } from '@korvol/fixwright';
const fixwright = new FixWright(config);
// Lifecyclefixwright.on('started', () => console.log('FixWright started'));fixwright.on('stopped', () => console.log('FixWright stopped'));
// Failuresfixwright.on('failure:received', (failureCase) => { console.log('New failure:', failureCase.script.name);});
fixwright.on('failure:completed', (summary) => { console.log('Status:', summary.status); console.log('Attempts:', summary.attempts);});
// Attemptsfixwright.on('attempt:success', (attempt) => { console.log('Fixed!', attempt.proposedFix);});
fixwright.on('attempt:failed', (attempt) => { console.log('Failed:', attempt.error);});
// Resultsfixwright.on('pr:created', (prUrl) => { console.log('PR:', prUrl);});
fixwright.on('error', (error) => { console.error('Error:', error);});Monitoring Agent Activity
// Standard verbosityfixwright.setVerbosity('normal');
fixwright.on('agent:tool_use', (toolName, input) => { console.log(`Using ${toolName}:`, JSON.stringify(input).slice(0, 100));});
// Verbose mode for debuggingfixwright.setVerbosity('verbose');
fixwright.on('agent:thinking', (text) => { console.log('Thinking:', text.slice(0, 200));});
fixwright.on('agent:read', (info) => { console.log(`Read: ${info.filePath} (${info.linesRead} lines)`);});
fixwright.on('agent:edit', (info) => { console.log(`Edit: ${info.filePath}`); console.log(` - ${info.oldString.slice(0, 50)}...`); console.log(` + ${info.newString.slice(0, 50)}...`);});Event Data Structures
FixAttempt
interface FixAttempt { id: string; failureCaseId: string; attemptNumber: number; status: FixAttemptStatus; startedAt: Date; completedAt?: Date; analysis?: FailureAnalysis; proposedFix?: ProposedFix; validationResult?: ValidationResult; error?: string;}FixCompletionSummary
interface FixCompletionSummary { failureCaseId: string; status: 'fixed' | 'unfixable'; attempts: number; totalDuration: number; successfulAttempt?: FixAttempt; prNumber?: number; prUrl?: string; reason?: string; // If unfixable}EditInfo
interface EditInfo { filePath: string; oldString: string; newString: string; timestamp: Date;}Verbosity Levels
Control which events are emitted:
fixwright.setVerbosity('quiet');Events emitted:
- Lifecycle events (
started,stopped) - Result events (
pr:created,error) - Completion events (
failure:completed)
fixwright.setVerbosity('normal');Events emitted:
- All
quietevents - Attempt events (
attempt:*) - Tool usage (
agent:tool_use)
fixwright.setVerbosity('verbose');Events emitted:
- All
normalevents - Thinking (
agent:thinking) - Text output (
agent:text) - Specific tool events (
agent:read,agent:edit, etc.)
Common Patterns
Progress Logging
let currentAttempt = 0;
fixwright.on('attempt:start', (attempt) => { currentAttempt = attempt.attemptNumber; console.log(`\n=== Attempt ${currentAttempt} ===`);});
fixwright.on('attempt:analyzing', () => { console.log('[1/4] Analyzing failure...');});
fixwright.on('attempt:fixing', () => { console.log('[2/4] Applying fix...');});
fixwright.on('attempt:validating', () => { console.log('[3/4] Validating...');});
fixwright.on('attempt:success', () => { console.log('[4/4] Success!');});
fixwright.on('attempt:failed', (attempt) => { console.log(`[X] Attempt ${currentAttempt} failed: ${attempt.error}`);});Metrics Collection
const metrics = { totalFailures: 0, fixed: 0, unfixable: 0, totalAttempts: 0, totalDuration: 0, totalCost: 0,};
fixwright.on('failure:received', () => { metrics.totalFailures++;});
fixwright.on('attempt:start', () => { metrics.totalAttempts++;});
fixwright.on('agent:complete', (result) => { if (result.totalCostUsd) { metrics.totalCost += result.totalCostUsd; }});
fixwright.on('failure:completed', (summary) => { if (summary.status === 'fixed') { metrics.fixed++; } else { metrics.unfixable++; } metrics.totalDuration += summary.totalDuration;});
// Report metrics periodicallysetInterval(() => { console.log('Metrics:', metrics);}, 60000);Slack Notifications
async function notifySlack(message: string, color: string) { await fetch(process.env.SLACK_WEBHOOK!, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ attachments: [{ color, text: message, }], }), });}
fixwright.on('pr:created', (prUrl) => { notifySlack(`New fix PR created: ${prUrl}`, 'good');});
fixwright.on('failure:completed', (summary) => { if (summary.status === 'unfixable') { notifySlack( `Could not fix ${summary.failureCaseId}: ${summary.reason}`, 'danger' ); }});Debug Logging
import { writeFileSync, appendFileSync } from 'fs';
const logFile = `./logs/fixwright-${Date.now()}.log`;
function log(event: string, data: unknown) { const entry = { timestamp: new Date().toISOString(), event, data, }; appendFileSync(logFile, JSON.stringify(entry) + '\n');}
// Log all eventsconst events = [ 'started', 'stopped', 'failure:received', 'failure:completed', 'attempt:start', 'attempt:analyzing', 'attempt:fixing', 'attempt:validating', 'attempt:success', 'attempt:failed', 'agent:tool_use', 'pr:created', 'error',];
events.forEach(event => { fixwright.on(event as any, (...args) => { log(event, args); });});Error Handling
Catching All Errors
fixwright.on('error', (error) => { console.error('FixWright error:', error);
// Categorize errors if (error.message.includes('ANTHROPIC')) { console.error('API error - check your API key'); } else if (error.message.includes('git')) { console.error('Git error - check repository access'); } else if (error.message.includes('GitHub')) { console.error('GitHub error - check token permissions'); }});Graceful Shutdown
process.on('SIGINT', async () => { console.log('Shutting down...'); await fixwright.stop(); process.exit(0);});
process.on('uncaughtException', async (error) => { console.error('Uncaught exception:', error); await fixwright.stop(); process.exit(1);});Type-Safe Events
Events are fully typed:
import type { FixWrightEvents } from '@korvol/fixwright';
// TypeScript knows the event payload typesfixwright.on('attempt:success', (attempt) => { // attempt is typed as FixAttempt console.log(attempt.proposedFix?.filePath);});
fixwright.on('agent:edit', (info) => { // info is typed as EditInfo console.log(info.filePath);});Next Steps
- API Reference: FixWright - Full API documentation
- CI/CD Integration - Use events in pipelines
- Debugging Failures - Debug with events