or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

commands.mdconfiguration.mdevents.mdexecution.mdextensions.mdindex.mdstorage.mdui.md

events.mddocs/

0

# Event Handling

1

2

Event system with hooks, pipes, and signal handling for advanced CLI behaviors.

3

4

## Capabilities

5

6

### Signal Handling

7

8

Registers a handler for SIGINT (Ctrl+C) signals.

9

10

```javascript { .api }

11

/**

12

* Registers a SIGINT handler function

13

* @param fn - Function to call when SIGINT is received

14

* @returns Vorpal instance for chaining

15

*/

16

function sigint(fn: () => void): Vorpal;

17

```

18

19

**Usage Example:**

20

21

```javascript

22

const vorpal = require('vorpal')();

23

24

// Handle Ctrl+C gracefully

25

vorpal

26

.sigint(function() {

27

console.log('\nReceived SIGINT. Cleaning up...');

28

29

// Cleanup operations

30

// Save data, close connections, etc.

31

32

process.exit(0);

33

})

34

.delimiter('myapp$')

35

.show();

36

```

37

38

### Output Piping

39

40

Intercepts all stdout logging through a custom function.

41

42

```javascript { .api }

43

/**

44

* Pipes all stdout through a custom function

45

* @param fn - Function to process output before display

46

* @returns Vorpal instance for chaining

47

*/

48

function pipe(fn: (output: string) => string): Vorpal;

49

```

50

51

**Usage Examples:**

52

53

```javascript

54

const vorpal = require('vorpal')();

55

56

// Log all output to file

57

const fs = require('fs');

58

const logStream = fs.createWriteStream('app.log', { flags: 'a' });

59

60

vorpal

61

.pipe(function(output) {

62

// Log to file with timestamp

63

logStream.write(`[${new Date().toISOString()}] ${output}\n`);

64

65

// Return output to display normally

66

return output;

67

});

68

69

// Transform output (e.g., add color, formatting)

70

vorpal

71

.pipe(function(output) {

72

// Add timestamp prefix to all output

73

return `[${new Date().toLocaleTimeString()}] ${output}`;

74

});

75

76

// Filter sensitive information

77

vorpal

78

.pipe(function(output) {

79

// Remove sensitive data from logs

80

return output.replace(/password=\w+/gi, 'password=***');

81

});

82

```

83

84

### Stdout Hooking

85

86

Hooks into stdout and passes it through a function.

87

88

```javascript { .api }

89

/**

90

* Hooks stdout and passes it through a function

91

* @param fn - Optional function to process stdout

92

* @returns Vorpal instance for chaining

93

*/

94

function hook(fn?: (output: string) => void): Vorpal;

95

```

96

97

**Usage Example:**

98

99

```javascript

100

const vorpal = require('vorpal')();

101

102

// Monitor all stdout output

103

vorpal

104

.hook(function(output) {

105

// Send output to monitoring service

106

console.error(`[MONITOR] ${output}`); // Use stderr to avoid recursion

107

108

// Count output lines

109

if (!global.outputStats) {

110

global.outputStats = { lines: 0, chars: 0 };

111

}

112

global.outputStats.lines++;

113

global.outputStats.chars += output.length;

114

});

115

116

// Example command that generates output

117

vorpal

118

.command('test-output', 'Generate test output')

119

.action(function(args, callback) {

120

this.log('Line 1');

121

this.log('Line 2');

122

this.log('Line 3');

123

callback();

124

});

125

```

126

127

### Custom Help Handler

128

129

Registers a custom help handler for the application.

130

131

```javascript { .api }

132

/**

133

* Registers a custom help handler

134

* @param fn - Function to handle help requests

135

* @returns undefined

136

*/

137

function help(fn: (cmd?: string) => void): undefined;

138

```

139

140

**Usage Example:**

141

142

```javascript

143

const vorpal = require('vorpal')();

144

145

// Custom help system

146

vorpal

147

.help(function(cmd) {

148

if (cmd) {

149

// Help for specific command

150

console.log(`Custom help for command: ${cmd}`);

151

152

const command = this.find(cmd);

153

if (command) {

154

console.log(`Description: ${command.description()}`);

155

console.log(`Usage: ${command.usage()}`);

156

} else {

157

console.log(`Command '${cmd}' not found`);

158

}

159

} else {

160

// General help

161

console.log('=== My CLI Application Help ===');

162

console.log('Available commands:');

163

164

this.commands.forEach(command => {

165

if (!command._hidden) {

166

console.log(` ${command._name} - ${command.description()}`);

167

}

168

});

169

170

console.log('\nUse "help <command>" for specific command help');

171

}

172

});

173

```

174

175

### Application Exit

176

177

Exits the application with optional cleanup.

178

179

```javascript { .api }

180

/**

181

* Exits the application

182

* @param options - Exit options (code, cleanup, etc.)

183

* @returns undefined

184

*/

185

function exit(options: ExitOptions): undefined;

186

187

interface ExitOptions {

188

code?: number; // Exit code (default: 0)

189

cleanup?: boolean; // Whether to run cleanup (default: true)

190

force?: boolean; // Force exit without confirmation (default: false)

191

}

192

```

193

194

**Usage Example:**

195

196

```javascript

197

const vorpal = require('vorpal')();

198

199

vorpal

200

.command('shutdown', 'Shutdown the application')

201

.option('-f, --force', 'Force shutdown without confirmation')

202

.action(function(args, callback) {

203

const force = args.options.force;

204

205

if (force) {

206

this.log('Force shutdown initiated...');

207

this.parent.exit({ code: 0, force: true });

208

} else {

209

this.prompt({

210

type: 'confirm',

211

name: 'confirm',

212

message: 'Are you sure you want to shutdown?',

213

default: false

214

}, (result) => {

215

if (result.confirm) {

216

this.log('Shutting down...');

217

this.parent.exit({ code: 0, cleanup: true });

218

} else {

219

this.log('Shutdown cancelled');

220

callback();

221

}

222

});

223

}

224

});

225

```

226

227

## Event System

228

229

Vorpal extends EventEmitter and emits various events during operation.

230

231

### Vorpal Events

232

233

```javascript { .api }

234

// Event types emitted by Vorpal

235

interface VorpalEvents {

236

'keypress': (key: KeyPress) => void;

237

'command_registered': (command: Command) => void;

238

'client_prompt_submit': (data: PromptData) => void;

239

'client_command_error': (error: Error, command: string) => void;

240

'client_command_executed': (command: string, args: any) => void;

241

'client_command_cancelled': (command: string) => void;

242

'mode_exit': (mode: string) => void;

243

'vorpal_exit': (code: number) => void;

244

}

245

246

interface KeyPress {

247

sequence: string;

248

name: string;

249

ctrl: boolean;

250

meta: boolean;

251

shift: boolean;

252

}

253

254

interface PromptData {

255

command: string;

256

args: any;

257

}

258

```

259

260

**Event Handling Examples:**

261

262

```javascript

263

const vorpal = require('vorpal')();

264

265

// Listen for command executions

266

vorpal.on('client_command_executed', function(command, args) {

267

console.log(`Command executed: ${command}`);

268

console.log('Arguments:', args);

269

});

270

271

// Listen for errors

272

vorpal.on('client_command_error', function(error, command) {

273

console.error(`Error in command ${command}:`, error.message);

274

275

// Log to file, send to monitoring service, etc.

276

logError(command, error);

277

});

278

279

// Listen for command registrations

280

vorpal.on('command_registered', function(command) {

281

console.log(`New command registered: ${command._name}`);

282

});

283

284

// Listen for key presses

285

vorpal.on('keypress', function(key) {

286

if (key.name === 'tab') {

287

console.log('Tab key pressed for autocomplete');

288

}

289

});

290

291

// Listen for application exit

292

vorpal.on('vorpal_exit', function(code) {

293

console.log(`Application exiting with code: ${code}`);

294

295

// Cleanup operations

296

closeConnections();

297

saveState();

298

});

299

300

// Listen for mode changes

301

vorpal.on('mode_exit', function(mode) {

302

console.log(`Exited mode: ${mode}`);

303

});

304

```

305

306

### Session Events

307

308

Session instances also emit events:

309

310

```javascript

311

const vorpal = require('vorpal')();

312

313

// Listen to session events

314

vorpal.session.on('vorpal_command_cancel', function() {

315

console.log('Command was cancelled');

316

});

317

```

318

319

## Advanced Event Patterns

320

321

### Event-Driven Command Logging

322

323

```javascript

324

const vorpal = require('vorpal')();

325

const fs = require('fs');

326

327

// Setup comprehensive logging

328

const logFile = 'command-log.json';

329

const commandLog = [];

330

331

vorpal.on('client_command_executed', function(command, args) {

332

const logEntry = {

333

timestamp: new Date().toISOString(),

334

command: command,

335

args: args,

336

success: true

337

};

338

339

commandLog.push(logEntry);

340

fs.writeFileSync(logFile, JSON.stringify(commandLog, null, 2));

341

});

342

343

vorpal.on('client_command_error', function(error, command) {

344

const logEntry = {

345

timestamp: new Date().toISOString(),

346

command: command,

347

error: error.message,

348

success: false

349

};

350

351

commandLog.push(logEntry);

352

fs.writeFileSync(logFile, JSON.stringify(commandLog, null, 2));

353

});

354

355

// Command to view logs

356

vorpal

357

.command('logs [count]', 'Show recent command logs')

358

.action(function(args, callback) {

359

const count = parseInt(args.count) || 10;

360

const recentLogs = commandLog.slice(-count);

361

362

this.log(`Last ${count} commands:`);

363

recentLogs.forEach((entry, index) => {

364

const status = entry.success ? '✓' : '✗';

365

this.log(`${index + 1}. ${status} ${entry.timestamp} - ${entry.command}`);

366

if (!entry.success) {

367

this.log(` Error: ${entry.error}`);

368

}

369

});

370

371

callback();

372

});

373

```

374

375

### Plugin Event System

376

377

```javascript

378

// Create event-driven plugin system

379

function createEventPlugin(vorpal) {

380

const pluginEvents = {};

381

382

// Register plugin event listeners

383

vorpal.pluginOn = function(event, listener) {

384

if (!pluginEvents[event]) {

385

pluginEvents[event] = [];

386

}

387

pluginEvents[event].push(listener);

388

};

389

390

// Emit plugin events

391

vorpal.pluginEmit = function(event, ...args) {

392

if (pluginEvents[event]) {

393

pluginEvents[event].forEach(listener => {

394

try {

395

listener(...args);

396

} catch (error) {

397

console.error(`Plugin event error:`, error);

398

}

399

});

400

}

401

};

402

403

// Hook into command execution

404

vorpal.on('client_command_executed', function(command, args) {

405

vorpal.pluginEmit('command:executed', command, args);

406

});

407

408

vorpal.on('client_command_error', function(error, command) {

409

vorpal.pluginEmit('command:error', error, command);

410

});

411

}

412

413

// Usage

414

const vorpal = require('vorpal')();

415

createEventPlugin(vorpal);

416

417

// Plugin that listens to events

418

vorpal.pluginOn('command:executed', function(command, args) {

419

if (command.startsWith('db:')) {

420

console.log('Database command executed:', command);

421

}

422

});

423

424

vorpal.pluginOn('command:error', function(error, command) {

425

if (command.startsWith('api:')) {

426

console.log('API command failed:', error.message);

427

// Maybe retry or show helpful message

428

}

429

});

430

```

431

432

### Real-time Status Updates

433

434

```javascript

435

const vorpal = require('vorpal')();

436

437

// Status monitoring with events

438

let systemStatus = {

439

uptime: 0,

440

commandsExecuted: 0,

441

errors: 0,

442

lastCommand: null

443

};

444

445

// Update status on events

446

vorpal.on('client_command_executed', function(command, args) {

447

systemStatus.commandsExecuted++;

448

systemStatus.lastCommand = {

449

command: command,

450

timestamp: new Date(),

451

args: args

452

};

453

});

454

455

vorpal.on('client_command_error', function(error, command) {

456

systemStatus.errors++;

457

});

458

459

// Periodic status updates

460

setInterval(() => {

461

systemStatus.uptime += 1;

462

}, 1000);

463

464

vorpal

465

.command('status', 'Show system status')

466

.action(function(args, callback) {

467

this.log('System Status:');

468

this.log(` Uptime: ${systemStatus.uptime} seconds`);

469

this.log(` Commands executed: ${systemStatus.commandsExecuted}`);

470

this.log(` Errors: ${systemStatus.errors}`);

471

472

if (systemStatus.lastCommand) {

473

this.log(` Last command: ${systemStatus.lastCommand.command} at ${systemStatus.lastCommand.timestamp.toLocaleTimeString()}`);

474

}

475

476

callback();

477

});

478

```

479

480

## Complete Event-Driven Example

481

482

```javascript

483

const vorpal = require('vorpal')();

484

const fs = require('fs');

485

const path = require('path');

486

487

// Setup comprehensive event handling

488

class CLIEventSystem {

489

constructor(vorpal) {

490

this.vorpal = vorpal;

491

this.logPath = path.join(process.cwd(), 'cli-events.log');

492

this.stats = {

493

sessionsStarted: 0,

494

commandsExecuted: 0,

495

errors: 0,

496

startTime: new Date()

497

};

498

499

this.setupEventHandlers();

500

}

501

502

setupEventHandlers() {

503

// Log all events to file

504

this.vorpal.on('client_command_executed', (command, args) => {

505

this.logEvent('command_executed', { command, args });

506

this.stats.commandsExecuted++;

507

});

508

509

this.vorpal.on('client_command_error', (error, command) => {

510

this.logEvent('command_error', { command, error: error.message });

511

this.stats.errors++;

512

});

513

514

this.vorpal.on('command_registered', (command) => {

515

this.logEvent('command_registered', { name: command._name });

516

});

517

518

this.vorpal.on('keypress', (key) => {

519

if (key.ctrl && key.name === 'c') {

520

this.logEvent('sigint_received', {});

521

}

522

});

523

524

this.vorpal.on('vorpal_exit', (code) => {

525

this.logEvent('application_exit', { code, uptime: this.getUptime() });

526

});

527

528

// Custom graceful shutdown

529

this.vorpal.sigint(() => {

530

console.log('\n\nGraceful shutdown initiated...');

531

this.logEvent('graceful_shutdown', { stats: this.stats });

532

533

console.log('Event log saved to:', this.logPath);

534

process.exit(0);

535

});

536

}

537

538

logEvent(type, data) {

539

const logEntry = {

540

timestamp: new Date().toISOString(),

541

type: type,

542

data: data

543

};

544

545

fs.appendFileSync(this.logPath, JSON.stringify(logEntry) + '\n');

546

}

547

548

getUptime() {

549

return Math.floor((new Date() - this.stats.startTime) / 1000);

550

}

551

552

getStats() {

553

return {

554

...this.stats,

555

uptime: this.getUptime()

556

};

557

}

558

}

559

560

// Initialize event system

561

const eventSystem = new CLIEventSystem(vorpal);

562

563

// Commands that work with the event system

564

vorpal

565

.command('events:stats', 'Show event statistics')

566

.action(function(args, callback) {

567

const stats = eventSystem.getStats();

568

569

this.log('CLI Event Statistics:');

570

this.log(` Uptime: ${stats.uptime} seconds`);

571

this.log(` Commands executed: ${stats.commandsExecuted}`);

572

this.log(` Errors: ${stats.errors}`);

573

this.log(` Session started: ${stats.startTime.toLocaleString()}`);

574

575

callback();

576

});

577

578

vorpal

579

.command('events:log [lines]', 'Show recent event log entries')

580

.action(function(args, callback) {

581

const lines = parseInt(args.lines) || 10;

582

583

try {

584

const logContent = fs.readFileSync(eventSystem.logPath, 'utf8');

585

const logLines = logContent.trim().split('\n').slice(-lines);

586

587

this.log(`Last ${lines} events:`);

588

logLines.forEach((line, index) => {

589

try {

590

const entry = JSON.parse(line);

591

this.log(`${index + 1}. [${entry.timestamp}] ${entry.type}: ${JSON.stringify(entry.data)}`);

592

} catch (e) {

593

this.log(`${index + 1}. Invalid log entry: ${line}`);

594

}

595

});

596

} catch (error) {

597

this.log('Error reading event log:', error.message);

598

}

599

600

callback();

601

});

602

603

// Custom output piping for enhanced logging

604

vorpal.pipe(function(output) {

605

// Add session info to all output

606

const sessionInfo = `[Session ${eventSystem.stats.sessionsStarted}]`;

607

return `${sessionInfo} ${output}`;

608

});

609

610

// Start the CLI

611

eventSystem.stats.sessionsStarted++;

612

eventSystem.logEvent('session_started', { pid: process.pid });

613

614

vorpal

615

.delimiter('events$')

616

.show();

617

```