CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-vorpal

Node's first framework for building immersive CLI apps.

Pending
Overview
Eval results
Files

ui.mddocs/

User Interface Control

Terminal UI management including show/hide prompt, logging, user interaction through prompts, and advanced UI redraw functionality.

Capabilities

Show Interface

Shows the Vorpal prompt in the terminal.

/**
 * Shows the vorpal prompt in the terminal
 * @returns Vorpal instance for chaining
 */
function show(): Vorpal;

Usage Example:

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

// Setup commands first
vorpal
  .command('hello', 'Says hello')
  .action(function(args, callback) {
    this.log('Hello World!');
    callback();
  });

// Show the interactive prompt
vorpal
  .delimiter('myapp$')
  .show();

Hide Interface

Hides the Vorpal prompt from the terminal.

/**
 * Hides the vorpal prompt from the terminal
 * @returns Vorpal instance for chaining
 */
function hide(): Vorpal;

Usage Example:

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

// Show the prompt initially
vorpal.show();

// Later, hide it during some operation
vorpal.hide();

// Processing something in background...
setTimeout(() => {
  console.log('Background task completed');
  // Show the prompt again
  vorpal.show();
}, 2000);

Logging

Logs output to the console through Vorpal's logging system.

/**
 * Logs output to console through Vorpal's logging system
 * @param args - Arguments to log (same as console.log)
 * @returns Vorpal instance for chaining
 */
function log(...args: any[]): Vorpal;

Usage Examples:

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

// Basic logging
vorpal.log('Hello, world!');

// Multiple arguments
vorpal.log('User:', 'john', 'Age:', 25);

// Logging objects
vorpal.log('Config:', { port: 3000, env: 'development' });

// In command actions
vorpal
  .command('status', 'Shows application status')
  .action(function(args, callback) {
    // Use this.log within command context
    this.log('Application is running');
    this.log('Status: OK');
    
    // Or use vorpal.log from outside
    callback();
  });

User Prompts

Prompts the user for input with configurable options.

/**
 * Prompts user for input
 * @param options - Prompt configuration object or array of prompts
 * @param userCallback - Optional callback function (if omitted, returns Promise)
 * @returns Promise when no callback provided
 */
function prompt(options?: PromptOptions | PromptOptions[], userCallback?: (result: any) => void): Promise<any>;

interface PromptOptions {
  type?: 'input' | 'password' | 'confirm' | 'list' | 'rawlist' | 'expand' | 'checkbox' | 'editor';
  name?: string;
  message?: string;
  default?: any;
  choices?: string[] | ChoiceOption[];
  validate?: (input: any) => boolean | string;
  filter?: (input: any) => any;
  when?: boolean | ((answers: any) => boolean);
}

interface ChoiceOption {
  name: string;
  value?: any;
  short?: string;
}

Usage Examples:

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

// Single input prompt with callback
vorpal.prompt({
  type: 'input',
  name: 'username',
  message: 'Enter your username:',
  default: 'guest'
}, function(result) {
  console.log('Username:', result.username);
});

// Promise-based prompting
vorpal.prompt({
  type: 'password',
  name: 'password',
  message: 'Enter your password:'
})
.then(function(result) {
  console.log('Password length:', result.password.length);
});

// Multiple prompts
vorpal.prompt([
  {
    type: 'input',
    name: 'name',
    message: 'What is your name?'
  },
  {
    type: 'list',
    name: 'color',
    message: 'What is your favorite color?',
    choices: ['Red', 'Blue', 'Green', 'Yellow']
  },
  {
    type: 'confirm',
    name: 'confirmed',
    message: 'Are you sure?',
    default: true
  }
])
.then(function(answers) {
  console.log('Name:', answers.name);
  console.log('Color:', answers.color);
  console.log('Confirmed:', answers.confirmed);
});

// Validation example
vorpal.prompt({
  type: 'input',
  name: 'email',
  message: 'Enter your email:',
  validate: function(input) {
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    if (!emailRegex.test(input)) {
      return 'Please enter a valid email address';
    }
    return true;
  }
})
.then(function(result) {
  console.log('Valid email:', result.email);
});

// Using within command actions
vorpal
  .command('setup', 'Interactive setup')
  .action(function(args, callback) {
    const self = this;
    
    self.prompt([
      {
        type: 'input',
        name: 'appName',
        message: 'Application name:'
      },
      {
        type: 'list',
        name: 'environment',
        message: 'Select environment:',
        choices: ['development', 'staging', 'production']
      }
    ], function(result) {
      self.log(`Setting up ${result.appName} for ${result.environment}`);
      callback();
    });
  });

Conditional Prompts

Advanced prompting with conditional logic:

vorpal.prompt([
  {
    type: 'confirm',
    name: 'needsDatabase',
    message: 'Do you need a database?'
  },
  {
    type: 'list',
    name: 'databaseType',
    message: 'Select database type:',
    choices: ['MySQL', 'PostgreSQL', 'MongoDB', 'SQLite'],
    when: function(answers) {
      return answers.needsDatabase;
    }
  },
  {
    type: 'input',
    name: 'databaseUrl',
    message: 'Database connection URL:',
    when: function(answers) {
      return answers.needsDatabase;
    },
    validate: function(input) {
      if (!input.trim()) {
        return 'Database URL is required';
      }
      return true;
    }
  }
])
.then(function(answers) {
  if (answers.needsDatabase) {
    console.log(`Using ${answers.databaseType} at ${answers.databaseUrl}`);
  } else {
    console.log('No database configured');
  }
});

Complete UI Example

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

// Setup interactive CLI with rich UI
vorpal
  .delimiter('myapp$')
  .banner('Welcome to My Application v1.0.0')
  .command('configure', 'Interactive configuration')
  .action(function(args, callback) {
    const self = this;
    
    self.log('Starting configuration wizard...');
    
    self.prompt([
      {
        type: 'input',
        name: 'name',
        message: 'Project name:',
        default: 'my-project'
      },
      {
        type: 'list',
        name: 'framework',
        message: 'Select framework:',
        choices: [
          { name: 'Express.js', value: 'express' },
          { name: 'Koa.js', value: 'koa' },
          { name: 'Fastify', value: 'fastify' }
        ]
      },
      {
        type: 'checkbox',
        name: 'features',
        message: 'Select features:',
        choices: [
          'Authentication',
          'Database',
          'Caching',
          'Logging',
          'Testing'
        ]
      },
      {
        type: 'confirm',
        name: 'proceed',
        message: 'Proceed with configuration?',
        default: true
      }
    ], function(result) {
      if (result.proceed) {
        self.log('Configuration saved:');
        self.log('- Name:', result.name);
        self.log('- Framework:', result.framework);
        self.log('- Features:', result.features.join(', '));
      } else {
        self.log('Configuration cancelled');
      }
      callback();
    });
  });

// Show the interface
vorpal.show();

Advanced UI Methods

Prompt Pause and Resume

Controls prompt state for complex user interactions.

/**
 * Pauses active prompt, returning the value of what had been typed so far
 * @returns Current prompt input string or false if no active prompt
 */
function pause(): string | false;

/**
 * Resumes active prompt with optional text to fill prompt with
 * @param val - Optional text to fill prompt with on resume
 * @returns UI instance for chaining
 */
function resume(val?: string): UI;

Usage Example:

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

vorpal
  .command('interactive', 'Interactive command with pause/resume')
  .action(function(args, callback) {
    const self = this;
    
    // Start a prompt
    self.prompt({
      type: 'input',
      name: 'data',
      message: 'Enter some data (will be paused):'
    }, function(result) {
      self.log('Final result:', result.data);
      callback();
    });
    
    // Pause the prompt after 2 seconds
    setTimeout(() => {
      const currentInput = vorpal.ui.pause();
      self.log('Prompt paused. Current input:', currentInput);
      
      // Do some processing...
      setTimeout(() => {
        self.log('Resuming prompt...');
        vorpal.ui.resume(currentInput + ' [processed]');
      }, 1000);
    }, 2000);
  });

Prompt Cancellation

Cancels the currently active prompt.

/**
 * Cancels the active prompt
 * @returns UI instance for chaining
 */
function cancel(): UI;

Usage Example:

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

vorpal
  .command('cancelable', 'A command with cancelable prompt')
  .action(function(args, callback) {
    const self = this;
    
    // Start a prompt
    self.prompt({
      type: 'input',
      name: 'data',
      message: 'Enter data (will auto-cancel in 5s):'
    })
    .then(result => {
      self.log('Data entered:', result.data);
    })
    .catch(err => {
      self.log('Prompt was cancelled');
    })
    .finally(() => {
      callback();
    });
    
    // Auto-cancel after 5 seconds
    setTimeout(() => {
      self.log('Auto-cancelling prompt...');
      vorpal.ui.cancel();
    }, 5000);
  });

UI Redraw Methods

Advanced terminal output control for dynamic content updates.

/**
 * Writes over existing logging, useful for progress indicators
 * @param str - Content to write over existing output
 * @returns UI instance for chaining
 */
function redraw(str: string): UI;

/**
 * Clears all redraw content permanently
 * @returns UI instance for chaining
 */
function redraw.clear(): UI;

/**
 * Makes current redraw content permanent
 * @returns UI instance for chaining
 */
function redraw.done(): UI;

Usage Examples:

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

vorpal
  .command('progress', 'Shows a progress indicator')
  .action(function(args, callback) {
    const self = this;
    let progress = 0;
    const total = 100;
    
    const interval = setInterval(() => {
      progress += 10;
      const percentage = Math.round((progress / total) * 100);
      const bar = '█'.repeat(Math.floor(percentage / 5)) + 
                  '░'.repeat(20 - Math.floor(percentage / 5));
      
      // Update the same line with progress
      vorpal.ui.redraw(`Progress: [${bar}] ${percentage}%`);
      
      if (progress >= total) {
        clearInterval(interval);
        // Make the final progress permanent
        vorpal.ui.redraw.done();
        self.log('Process completed!');
        callback();
      }
    }, 200);
  });

vorpal
  .command('loading', 'Shows a loading spinner')
  .action(function(args, callback) {
    const self = this;
    const spinner = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
    let i = 0;
    
    const interval = setInterval(() => {
      vorpal.ui.redraw(`Loading ${spinner[i % spinner.length]} Please wait...`);
      i++;
    }, 100);
    
    // Simulate work
    setTimeout(() => {
      clearInterval(interval);
      // Clear the loading message
      vorpal.ui.redraw.clear();
      self.log('Loading completed!');
      callback();
    }, 3000);
  });

vorpal
  .command('live-data', 'Shows live updating data')
  .action(function(args, callback) {
    const self = this;
    let counter = 0;
    
    self.log('Starting live data feed (Ctrl+C to stop):');
    
    const interval = setInterval(() => {
      const timestamp = new Date().toLocaleTimeString();
      const data = {
        counter: ++counter,
        timestamp: timestamp,
        random: Math.floor(Math.random() * 1000)
      };
      
      // Update the display with current data
      vorpal.ui.redraw(JSON.stringify(data, null, 2));
    }, 1000);
    
    // Handle cancellation
    const originalCancel = self.cancel;
    self.cancel = function() {
      clearInterval(interval);
      vorpal.ui.redraw.clear();
      self.log('Live data feed stopped');
      if (originalCancel) originalCancel.call(self);
      callback();
    };
    
    // Auto-stop after 10 seconds for demo
    setTimeout(() => {
      clearInterval(interval);
      vorpal.ui.redraw.done(); // Keep the last data visible
      self.log('Live data feed ended');
      callback();
    }, 10000);
  });

Dynamic Status Display

Advanced example combining multiple UI methods:

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

vorpal
  .command('system-monitor', 'Shows real-time system information')
  .action(function(args, callback) {
    const self = this;
    const os = require('os');
    
    self.log('System Monitor Started (press any key to stop)');
    
    let monitoring = true;
    const interval = setInterval(() => {
      if (!monitoring) return;
      
      const cpuUsage = process.cpuUsage();
      const memUsage = process.memoryUsage();
      const uptime = process.uptime();
      
      const display = [
        '=== System Monitor ===',
        `Uptime: ${Math.floor(uptime)}s`,
        `CPU User: ${(cpuUsage.user / 1000000).toFixed(2)}ms`,
        `CPU System: ${(cpuUsage.system / 1000000).toFixed(2)}ms`,
        `Memory RSS: ${(memUsage.rss / 1024 / 1024).toFixed(2)}MB`,
        `Memory Heap: ${(memUsage.heapUsed / 1024 / 1024).toFixed(2)}MB`,
        `Memory External: ${(memUsage.external / 1024 / 1024).toFixed(2)}MB`,
        '=====================',
        'Press any key to stop monitoring...'
      ].join('\n');
      
      vorpal.ui.redraw(display);
    }, 1000);
    
    // Wait for any key press
    process.stdin.setRawMode(true);
    process.stdin.resume();
    process.stdin.once('data', () => {
      monitoring = false;
      clearInterval(interval);
      
      process.stdin.setRawMode(false);
      process.stdin.pause();
      
      vorpal.ui.redraw.clear();
      self.log('System monitoring stopped');
      callback();
    });
  });

UI Best Practices

Responsive Prompts

Handle different terminal sizes and capabilities:

vorpal
  .command('responsive-ui', 'Shows responsive UI elements')
  .action(function(args, callback) {
    const self = this;
    const terminalWidth = process.stdout.columns || 80;
    const narrow = terminalWidth < 60;
    
    if (narrow) {
      // Simplified UI for narrow terminals
      self.prompt([
        {
          type: 'input',
          name: 'name',
          message: 'Name:'
        },
        {
          type: 'confirm',
          name: 'proceed',
          message: 'OK?'
        }
      ], function(result) {
        self.log('Done:', result.name);
        callback();
      });
    } else {
      // Full UI for wider terminals
      self.prompt([
        {
          type: 'input',
          name: 'fullName',
          message: 'Please enter your full name:'
        },
        {
          type: 'list',
          name: 'role',
          message: 'Select your role:',
          choices: ['Administrator', 'Developer', 'User', 'Guest']
        },
        {
          type: 'confirm',
          name: 'proceed',
          message: 'Proceed with these settings?'
        }
      ], function(result) {
        self.log('Configuration complete:');
        self.log('Name:', result.fullName);
        self.log('Role:', result.role);
        callback();
      });
    }
  });

Error Recovery

Handle UI errors gracefully:

vorpal
  .command('robust-ui', 'UI with error handling')
  .action(function(args, callback) {
    const self = this;
    
    function safePrompt(options, retryCount = 0) {
      const maxRetries = 3;
      
      self.prompt(options)
        .then(result => {
          self.log('Success:', result);
          callback();
        })
        .catch(err => {
          if (retryCount < maxRetries) {
            self.log(`Error occurred, retrying... (${retryCount + 1}/${maxRetries})`);
            setTimeout(() => {
              safePrompt(options, retryCount + 1);
            }, 1000);
          } else {
            self.log('Max retries exceeded. Operation failed.');
            callback(err);
          }
        });
    }
    
    safePrompt({
      type: 'input',
      name: 'data',
      message: 'Enter data:'
    });
  });

Install with Tessl CLI

npx tessl i tessl/npm-vorpal

docs

commands.md

configuration.md

events.md

execution.md

extensions.md

index.md

storage.md

ui.md

tile.json