Skip to content
Back to skills

Testdriver Events

ASecurity

Listen to SDK lifecycle events with wildcard support

  • 243 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 6, 2026
ai-agentsjavascripttypescriptgojavaawsgitapi

Works with

  • terminal
  • cli
  • api

Security analysis

A100/100

Scanned September 22, 2026

npx -y skills add testdriverai/testdriverai --skill testdriver-events --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Testdriver Events?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Testdriver Events
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/testdriverai-testdriver-events/badge)](https://www.skillsdirectory.com/skills/testdriverai-testdriver-events)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: testdriver:events
description: Listen to SDK lifecycle events with wildcard support
---
<!-- Generated from events.mdx. DO NOT EDIT. -->

## Overview

TestDriver uses [EventEmitter2](https://github.com/EventEmitter2/EventEmitter2) for its event system. Events use a namespace pattern with colons. They permit wildcard listeners.

Use the emitter through `testdriver.emitter`:

```javascript
testdriver.emitter.on('command:start', (data) => {
  console.log(`Running: ${data.command}`);
});
```

### Configuration

The internal emitter is created with:

```javascript
new EventEmitter2({
  wildcard: true,
  delimiter: ':',
  maxListeners: 20,
  verboseMemoryLeak: false,
  ignoreErrors: false,
});
```

### Wildcard Listeners

Use `*` to match one level. Use `**` to match many levels:

```javascript
// Match all log events
testdriver.emitter.on('log:*', (message) => {
  console.log(message);
});

// Match all events in any namespace
testdriver.emitter.on('**', (...args) => {
  console.log('Event:', this.event, args);
});
```

## Event Reference

### Command Events

Emitted during the execution of SDK commands (`click`, `type`, `find`, etc.).

| Event | Payload |
|---|---|
| `command:start` | `{ command, depth, data, timestamp, sourcePosition }` |
| `command:success` | `{ command, depth, data, duration, response, timestamp, sourcePosition }` |
| `command:error` | `{ command, depth, data, error, duration, timestamp, sourcePosition }` |
| `command:status` | `{ command, status: "executing", data, depth, timestamp }` |
| `command:progress` | `{ command, status: "completed", timing, data, depth, timestamp }` |

```javascript
testdriver.emitter.on('command:start', ({ command, data }) => {
  console.log(`Starting ${command}`, data);
});

testdriver.emitter.on('command:error', ({ command, error, duration }) => {
  console.error(`${command} failed after ${duration}ms: ${error}`);
});
```

### Step Events

Emitted for each AI reasoning step within a command.

| Event | Payload |
|---|---|
| `step:start` | `{ stepIndex, prompt, commandCount, timestamp, sourcePosition }` |
| `step:success` | `{ stepIndex, prompt, commandCount, duration, timestamp, sourcePosition }` |
| `step:error` | `{ stepIndex, prompt, error, duration?, timestamp, sourcePosition? }` |

```javascript
testdriver.emitter.on('step:start', ({ stepIndex, prompt }) => {
  console.log(`Step ${stepIndex}: ${prompt}`);
});
```

### Test Events

Emitted when a test file execution starts.

| Event | Payload |
|---|---|
| `test:start` | `{ filePath, timestamp }` |
| `test:success` | *Emitted on test completion* |
| `test:error` | *Emitted on test failure* |

### Log Events

Emitted for all log output from the SDK.

| Event | Payload |
|---|---|
| `log:log` | `(message: string)` — general log message |
| `log:warn` | `(message: string)` — warning message |
| `log:debug` | `(message: string)` — debug output (only when `VERBOSE`/`DEBUG`/`TD_DEBUG` env set) |
| `log:info` | `(message: string)` — informational message |
| `log:error` | `(message: string)` — error message |
| `log:narration` | `(message: string, overwrite?: boolean)` — in-place status line |
| `log:markdown` | `(markdown: string)` — full static markdown content |
| `log:markdown:start` | `(streamId: string)` — begin streaming markdown |
| `log:markdown:chunk` | `(streamId: string, chunk: string)` — incremental chunk |
| `log:markdown:end` | `(streamId: string)` — end streaming markdown |

```javascript
// Capture all logs
testdriver.emitter.on('log:*', function (message) {
  console.log(`[${this.event}]`, message);
});
```

### Screen Capture Events

Emitted during screenshot capture.

| Event | Payload |
|---|---|
| `screen-capture:start` | `{ scale, silent, display }` |
| `screen-capture:end` | `{ scale, silent, display }` |
| `screen-capture:error` | `{ error, scale, silent, display }` |

### Sandbox Events

Emitted for sandbox WebSocket lifecycle and communication.

| Event | Payload |
|---|---|
| `sandbox:connected` | *No payload* — WebSocket connection established |
| `sandbox:authenticated` | `{ traceId }` — authentication successful |
| `sandbox:error` | `(err: Error \| string)` — connection or sandbox error |
| `sandbox:sent` | `(message: object)` — WebSocket message sent |
| `sandbox:received` | *No payload* — successful message reply received |
| `sandbox:progress` | `{ step, message }` — sandbox setup progress |

```javascript
testdriver.emitter.on('sandbox:connected', () => {
  console.log('Connected to sandbox');
});

testdriver.emitter.on('sandbox:progress', ({ step, message }) => {
  console.log(`Sandbox: [${step}] ${message}`);
});
```

### Redraw Events

Emitted during screen stability detection. See [Redraw](/redraw) for more details.

| Event | Payload |
|---|---|
| `redraw:status` | `{ redraw: { enabled, settled, hasChangedFromInitial, consecutiveFramesStable, diffFromInitial, diffFromLast, text }, network: { enabled, settled, rxBytes, txBytes, text }, timeout: { isTimeout, elapsed, max, text } }` |
| `redraw:complete` | `{ screenSettled, hasChangedFromInitial, consecutiveFramesStable, networkSettled, isTimeout, timeElapsed }` |

```javascript
testdriver.emitter.on('redraw:complete', (result) => {
  if (result.isTimeout) {
    console.warn('Redraw timed out after', result.timeElapsed, 'ms');
  }
});
```

### File Events

Emitted during file load/save operations in the agent.

| Event | Payload |
|---|---|
| `file:start` | `{ operation: "load" \| "save" \| "run", filePath, timestamp }` |
| `file:stop` | `{ operation, filePath, duration, success, sourceMap?, reason?, timestamp }` |
| `file:load` | `{ filePath, size, timestamp }` |
| `file:save` | `{ filePath, size, timestamp }` |
| `file:diff` | `{ filePath, diff: { patches, sourceMaps, summary: { additions, deletions, modifications } }, timestamp }` |
| `file:error` | `{ operation, filePath, error, duration?, timestamp }` |

### Error Events

Emitted for errors at various severity levels.

| Event | Payload |
|---|---|
| `error:fatal` | `(error: string \| Error)` — terminates the process |
| `error:general` | `(message: string)` — non-fatal error |
| `error:sandbox` | `(err: Error \| string)` — sandbox/WebSocket error |

```javascript
testdriver.emitter.on('error:*', function (err) {
  console.error(`[${this.event}]`, err);
});
```

### SDK Events

Emitted for API request lifecycle.

| Event | Payload |
|---|---|
| `sdk:request` | `{ path }` — outgoing API request |
| `sdk:response` | `{ path }` — API response received |
| `sdk:retry` | `{ path, attempt, error, delayMs }` — request retry |

### Other Events

| Event | Payload |
|---|---|
| `exit` | `(exitCode: number)` — `0` for success, `1` for failure |
| `status` | `(message: string)` — general status updates |
| `mouse-click` | `{ x, y, button, click, double }` — mouse click performed |
| `terminal:stdout` | Terminal stdout output |
| `terminal:stderr` | Terminal stderr output |

## Practical Examples

### Custom Test Reporter

```javascript
const results = [];

testdriver.emitter.on('command:success', ({ command, duration }) => {
  results.push({ command, duration, status: 'pass' });
});

testdriver.emitter.on('command:error', ({ command, duration, error }) => {
  results.push({ command, duration, status: 'fail', error });
});

// After test completes
afterAll(() => {
  console.table(results);
});
```

### Progress Monitoring

```javascript
testdriver.emitter.on('step:start', ({ stepIndex, prompt }) => {
  process.stdout.write(`\r  Step ${stepIndex}: ${prompt}`);
});

testdriver.emitter.on('command:progress', ({ command, timing }) => {
  process.stdout.write(`\r  ${command} completed in ${timing}ms`);
});
```

### Debug Logging

```javascript
// Log every event (verbose)
testdriver.emitter.on('**', function (...args) {
  console.debug(`[EVENT] ${this.event}`, ...args);
});
```

## Types

```typescript
interface CommandStartEvent {
  command: string;
  depth: number;
  data: Record<string, any>;
  timestamp: number;
  sourcePosition: SourcePosition;
}

interface CommandSuccessEvent {
  command: string;
  depth: number;
  data: Record<string, any>;
  duration: number;
  response: any;
  timestamp: number;
  sourcePosition: SourcePosition;
}

interface CommandErrorEvent {
  command: string;
  depth: number;
  data: Record<string, any>;
  error: string;
  duration: number;
  timestamp: number;
  sourcePosition: SourcePosition;
}

interface StepStartEvent {
  stepIndex: number;
  prompt: string;
  commandCount: number;
  timestamp: number;
  sourcePosition: SourcePosition;
}

interface StepSuccessEvent {
  stepIndex: number;
  prompt: string;
  commandCount: number;
  duration: number;
  timestamp: number;
  sourcePosition: SourcePosition;
}

interface RedrawStatusEvent {
  redraw: {
    enabled: boolean;
    settled: boolean;
    hasChangedFromInitial: boolean;
    consecutiveFramesStable: number;
    diffFromInitial: number;
    diffFromLast: number;
    text: string;
  };
  network: {
    enabled: boolean;
    settled: boolean;
    rxBytes: number;
    txBytes: number;
    text: string;
  };
  timeout: {
    isTimeout: boolean;
    elapsed: number;
    max: number;
    text: string;
  };
}

interface RedrawCompleteEvent {
  screenSettled: boolean;
  hasChangedFromInitial: boolean;
  consecutiveFramesStable: number;
  networkSettled: boolean;
  isTimeout: boolean;
  timeElapsed: number;
}

interface SandboxProgressEvent {
  step: string;
  message: string;
}

interface SourcePosition {
  file: string;
  line: number;
  column: number;
}
```

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.