or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

error-handling.mdevent-management.mdindex.mdrenderers.mdtask-configuration.mdtask-management.md
tile.json

event-management.mddocs/

0

# Event Management

1

2

Observable-based event system for monitoring task state changes, progress updates, lifecycle events, and custom event handling throughout task execution.

3

4

## Capabilities

5

6

### ListrEventManager

7

8

Global event manager for Listr-level events and cross-task communication.

9

10

```typescript { .api }

11

/**

12

* Global event manager for Listr-level events

13

* Extends the base EventManager with Listr-specific functionality

14

*/

15

class ListrEventManager extends EventManager {

16

/**

17

* Listen to Listr-level events

18

* @param event - Event name to listen for

19

* @param listener - Event handler function

20

*/

21

on(event: string, listener: (...args: any[]) => void): this;

22

23

/**

24

* Listen to event once

25

* @param event - Event name to listen for

26

* @param listener - Event handler function

27

*/

28

once(event: string, listener: (...args: any[]) => void): this;

29

30

/**

31

* Emit an event

32

* @param event - Event name to emit

33

* @param args - Arguments to pass to listeners

34

*/

35

emit(event: string, ...args: any[]): boolean;

36

37

/**

38

* Remove event listener

39

* @param event - Event name

40

* @param listener - Specific listener to remove

41

*/

42

off(event: string, listener: (...args: any[]) => void): this;

43

44

/**

45

* Remove all listeners for an event

46

* @param event - Event name

47

*/

48

removeAllListeners(event?: string): this;

49

}

50

```

51

52

### ListrTaskEventManager

53

54

Task-specific event manager for individual task lifecycle and state events.

55

56

```typescript { .api }

57

/**

58

* Task-specific event manager for individual task events

59

* Handles task lifecycle, state changes, and output events

60

*/

61

class ListrTaskEventManager extends EventManager {

62

/**

63

* Listen to task-specific events

64

* @param event - Task event type

65

* @param listener - Event handler function

66

*/

67

on(event: ListrTaskEventType, listener: (data: any) => void): this;

68

69

/**

70

* Listen to task event once

71

* @param event - Task event type

72

* @param listener - Event handler function

73

*/

74

once(event: ListrTaskEventType, listener: (data: any) => void): this;

75

76

/**

77

* Emit a task event

78

* @param event - Task event type

79

* @param data - Event data

80

*/

81

emit(event: ListrTaskEventType, data: any): boolean;

82

}

83

```

84

85

### Base EventManager

86

87

Generic event management functionality providing the foundation for all event handling.

88

89

```typescript { .api }

90

/**

91

* Generic base event manager

92

* Provides core event handling functionality

93

*/

94

class EventManager {

95

/**

96

* Add event listener

97

* @param event - Event name

98

* @param listener - Event handler function

99

*/

100

on(event: string, listener: (...args: any[]) => void): this;

101

102

/**

103

* Add one-time event listener

104

* @param event - Event name

105

* @param listener - Event handler function

106

*/

107

once(event: string, listener: (...args: any[]) => void): this;

108

109

/**

110

* Emit an event to all listeners

111

* @param event - Event name

112

* @param args - Arguments to pass to listeners

113

*/

114

emit(event: string, ...args: any[]): boolean;

115

116

/**

117

* Remove specific event listener

118

* @param event - Event name

119

* @param listener - Listener function to remove

120

*/

121

off(event: string, listener: (...args: any[]) => void): this;

122

123

/**

124

* Remove all listeners for an event or all events

125

* @param event - Optional specific event name

126

*/

127

removeAllListeners(event?: string): this;

128

129

/**

130

* Get array of listeners for an event

131

* @param event - Event name

132

*/

133

listeners(event: string): Function[];

134

135

/**

136

* Get count of listeners for an event

137

* @param event - Event name

138

*/

139

listenerCount(event: string): number;

140

}

141

```

142

143

### Task Event Types

144

145

Enumeration of all possible task-related events that can be monitored.

146

147

```typescript { .api }

148

/**

149

* Task event types for monitoring task lifecycle

150

*/

151

enum ListrTaskEventType {

152

/** Task title changed */

153

TITLE = 'TITLE',

154

/** Task state changed */

155

STATE = 'STATE',

156

/** Task enabled status changed */

157

ENABLED = 'ENABLED',

158

/** Subtask added or modified */

159

SUBTASK = 'SUBTASK',

160

/** Prompt started or updated */

161

PROMPT = 'PROMPT',

162

/** Task output updated */

163

OUTPUT = 'OUTPUT',

164

/** Task message updated */

165

MESSAGE = 'MESSAGE',

166

/** Task closed or completed */

167

CLOSED = 'CLOSED'

168

}

169

```

170

171

### Event Data Interfaces

172

173

Type definitions for event data structures passed to event handlers.

174

175

```typescript { .api }

176

/**

177

* Base event data structure

178

*/

179

interface ListrEvent {

180

/** Timestamp when event occurred */

181

timestamp: Date;

182

/** Task ID that generated the event */

183

taskId: string;

184

/** Event type */

185

type: ListrTaskEventType;

186

}

187

188

/**

189

* Task state change event data

190

*/

191

interface ListrTaskStateEvent extends ListrEvent {

192

type: ListrTaskEventType.STATE;

193

/** Previous task state */

194

previousState: ListrTaskState;

195

/** New task state */

196

newState: ListrTaskState;

197

/** Additional state metadata */

198

metadata?: Record<string, any>;

199

}

200

201

/**

202

* Task title change event data

203

*/

204

interface ListrTaskTitleEvent extends ListrEvent {

205

type: ListrTaskEventType.TITLE;

206

/** Previous title */

207

previousTitle?: string;

208

/** New title */

209

newTitle: string;

210

}

211

212

/**

213

* Task output event data

214

*/

215

interface ListrTaskOutputEvent extends ListrEvent {

216

type: ListrTaskEventType.OUTPUT;

217

/** Output content */

218

output: string;

219

/** Whether this is persistent output */

220

persistent?: boolean;

221

}

222

223

/**

224

* Task message event data

225

*/

226

interface ListrTaskMessageEvent extends ListrEvent {

227

type: ListrTaskEventType.MESSAGE;

228

/** Message content */

229

message: string;

230

/** Message level or type */

231

level?: 'info' | 'warn' | 'error';

232

}

233

```

234

235

**Usage Examples:**

236

237

### Basic Event Listening

238

239

```typescript

240

import { Listr, ListrTaskEventType } from "listr2";

241

242

const tasks = new Listr([

243

{

244

title: "Task with events",

245

task: async (ctx, task) => {

246

task.output = "Starting...";

247

await new Promise(resolve => setTimeout(resolve, 1000));

248

task.output = "Processing...";

249

await new Promise(resolve => setTimeout(resolve, 1000));

250

task.output = "Completed!";

251

}

252

}

253

]);

254

255

// Listen to task state changes

256

tasks.events.on('TASK_STATE_CHANGED', (event) => {

257

console.log(`Task ${event.taskId} changed from ${event.previousState} to ${event.newState}`);

258

});

259

260

// Listen to task output updates

261

tasks.events.on('TASK_OUTPUT_UPDATED', (event) => {

262

console.log(`Task ${event.taskId} output: ${event.output}`);

263

});

264

265

await tasks.run();

266

```

267

268

### Advanced Event Monitoring

269

270

```typescript

271

import { Listr, ListrTaskEventType, ListrTaskState } from "listr2";

272

273

interface MonitoringContext {

274

startTime: Date;

275

completedTasks: number;

276

failedTasks: number;

277

}

278

279

const tasks = new Listr<MonitoringContext>([

280

{

281

title: "Task 1",

282

task: () => new Promise(resolve => setTimeout(resolve, 1000))

283

},

284

{

285

title: "Task 2",

286

task: () => new Promise((resolve, reject) => {

287

setTimeout(() => Math.random() > 0.5 ? resolve(undefined) : reject(new Error("Random failure")), 1000);

288

})

289

},

290

{

291

title: "Task 3",

292

task: () => new Promise(resolve => setTimeout(resolve, 1000))

293

}

294

]);

295

296

// Track task completion statistics

297

tasks.events.on('TASK_STATE_CHANGED', (event) => {

298

if (event.newState === ListrTaskState.COMPLETED) {

299

console.log(`βœ… Task completed: ${event.taskId}`);

300

} else if (event.newState === ListrTaskState.FAILED) {

301

console.log(`❌ Task failed: ${event.taskId}`);

302

} else if (event.newState === ListrTaskState.STARTED) {

303

console.log(`πŸ”„ Task started: ${event.taskId}`);

304

}

305

});

306

307

// Monitor overall progress

308

let totalTasks = 0;

309

let completedTasks = 0;

310

311

tasks.events.on('TASK_CREATED', () => totalTasks++);

312

tasks.events.on('TASK_STATE_CHANGED', (event) => {

313

if (event.newState === ListrTaskState.COMPLETED || event.newState === ListrTaskState.SKIPPED) {

314

completedTasks++;

315

console.log(`Progress: ${completedTasks}/${totalTasks} tasks completed`);

316

}

317

});

318

319

const result = await tasks.run({

320

startTime: new Date(),

321

completedTasks: 0,

322

failedTasks: 0

323

});

324

```

325

326

### Custom Event Emitters

327

328

```typescript

329

import { Listr } from "listr2";

330

331

const tasks = new Listr([

332

{

333

title: "Task with custom events",

334

task: async (ctx, task) => {

335

// Emit custom events through the task's event manager

336

task.events.emit('CUSTOM_PROGRESS', { progress: 0, message: "Starting..." });

337

338

for (let i = 1; i <= 5; i++) {

339

await new Promise(resolve => setTimeout(resolve, 500));

340

task.events.emit('CUSTOM_PROGRESS', {

341

progress: i * 20,

342

message: `Step ${i}/5 completed`

343

});

344

task.output = `Progress: ${i * 20}%`;

345

}

346

347

task.events.emit('CUSTOM_COMPLETE', {

348

duration: Date.now() - startTime,

349

result: "success"

350

});

351

}

352

}

353

]);

354

355

// Listen to custom events

356

tasks.events.on('CUSTOM_PROGRESS', (data) => {

357

console.log(`Custom progress: ${data.progress}% - ${data.message}`);

358

});

359

360

tasks.events.on('CUSTOM_COMPLETE', (data) => {

361

console.log(`Custom completion: ${data.result} (took ${data.duration}ms)`);

362

});

363

364

const startTime = Date.now();

365

await tasks.run();

366

```

367

368

### Event-Based Task Coordination

369

370

```typescript

371

import { Listr } from "listr2";

372

373

interface SharedContext {

374

phase1Complete: boolean;

375

phase2Data?: any;

376

finalResults?: any[];

377

}

378

379

const tasks = new Listr<SharedContext>([

380

{

381

title: "Phase 1: Preparation",

382

task: async (ctx, task) => {

383

task.output = "Preparing data...";

384

await new Promise(resolve => setTimeout(resolve, 1000));

385

386

ctx.phase1Complete = true;

387

388

// Emit event to signal phase 1 completion

389

task.events.emit('PHASE_1_COMPLETE', {

390

timestamp: new Date(),

391

data: "preparation-data"

392

});

393

394

task.output = "Phase 1 completed";

395

}

396

},

397

{

398

title: "Phase 2: Processing",

399

task: async (ctx, task) => {

400

// Wait for phase 1 to complete

401

if (!ctx.phase1Complete) {

402

await new Promise(resolve => {

403

task.events.once('PHASE_1_COMPLETE', resolve);

404

});

405

}

406

407

task.output = "Processing data...";

408

await new Promise(resolve => setTimeout(resolve, 1500));

409

410

ctx.phase2Data = { processed: true, items: 10 };

411

412

task.events.emit('PHASE_2_COMPLETE', ctx.phase2Data);

413

task.output = "Phase 2 completed";

414

}

415

},

416

{

417

title: "Phase 3: Finalization",

418

task: async (ctx, task) => {

419

// Wait for phase 2 data

420

if (!ctx.phase2Data) {

421

await new Promise(resolve => {

422

task.events.once('PHASE_2_COMPLETE', (data) => {

423

ctx.phase2Data = data;

424

resolve(undefined);

425

});

426

});

427

}

428

429

task.output = "Finalizing results...";

430

await new Promise(resolve => setTimeout(resolve, 800));

431

432

ctx.finalResults = Array.from({ length: ctx.phase2Data.items }, (_, i) => `result-${i}`);

433

task.output = `Finalized ${ctx.finalResults.length} results`;

434

}

435

}

436

]);

437

438

await tasks.run({ phase1Complete: false });

439

```

440

441

### Error Event Handling

442

443

```typescript

444

import { Listr, ListrTaskState } from "listr2";

445

446

const tasks = new Listr([

447

{

448

title: "Potentially failing task",

449

retry: 3,

450

task: async (ctx, task) => {

451

if (Math.random() < 0.7) {

452

throw new Error("Simulated failure");

453

}

454

return "Success";

455

}

456

}

457

]);

458

459

// Handle error events

460

tasks.events.on('TASK_ERROR', (event) => {

461

console.log(`Task error: ${event.error.message}`);

462

console.log(`Will retry: ${event.willRetry}`);

463

console.log(`Retry count: ${event.retryCount}`);

464

});

465

466

// Handle retry events

467

tasks.events.on('TASK_RETRY', (event) => {

468

console.log(`Retrying task: ${event.taskId} (attempt ${event.attempt})`);

469

});

470

471

// Handle state changes for detailed error tracking

472

tasks.events.on('TASK_STATE_CHANGED', (event) => {

473

if (event.newState === ListrTaskState.FAILED) {

474

console.log(`Task failed permanently: ${event.taskId}`);

475

} else if (event.newState === ListrTaskState.RETRY) {

476

console.log(`Task entering retry state: ${event.taskId}`);

477

}

478

});

479

480

try {

481

await tasks.run();

482

} catch (error) {

483

console.log("Task list failed:", error.message);

484

}

485

```

486

487

## Types

488

489

```typescript { .api }

490

/**

491

* Event listener function type

492

*/

493

type EventListener = (...args: any[]) => void;

494

495

/**

496

* Event map interface for type-safe event handling

497

*/

498

interface ListrEventMap {

499

/** Task state changed */

500

[ListrTaskEventType.STATE]: ListrTaskStateEvent;

501

/** Task title changed */

502

[ListrTaskEventType.TITLE]: ListrTaskTitleEvent;

503

/** Task output updated */

504

[ListrTaskEventType.OUTPUT]: ListrTaskOutputEvent;

505

/** Task message updated */

506

[ListrTaskEventType.MESSAGE]: ListrTaskMessageEvent;

507

/** Task enabled status changed */

508

[ListrTaskEventType.ENABLED]: { taskId: string; enabled: boolean };

509

/** Subtask event */

510

[ListrTaskEventType.SUBTASK]: { taskId: string; subtask: any };

511

/** Prompt event */

512

[ListrTaskEventType.PROMPT]: { taskId: string; prompt: any };

513

/** Task closed */

514

[ListrTaskEventType.CLOSED]: { taskId: string; timestamp: Date };

515

}

516

517

/**

518

* Task event map interface for task-specific events

519

*/

520

interface ListrTaskEventMap {

521

/** Task was created */

522

TASK_CREATED: { taskId: string; title: string };

523

/** Task state changed */

524

TASK_STATE_CHANGED: ListrTaskStateEvent;

525

/** Task encountered an error */

526

TASK_ERROR: { taskId: string; error: Error; willRetry: boolean; retryCount: number };

527

/** Task is retrying */

528

TASK_RETRY: { taskId: string; attempt: number; maxAttempts: number };

529

/** Task output was updated */

530

TASK_OUTPUT_UPDATED: ListrTaskOutputEvent;

531

}

532

```