or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

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

tessl/npm-listr2

Terminal task list library for creating beautiful, interactive CLI interfaces with task management, rendering options, and error handling.

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/listr2@8.3.x

To install, run

npx @tessl/cli install tessl/npm-listr2@8.3.0

index.mddocs/

Listr2

Listr2 is a modern terminal task list library for Node.js that creates beautiful, interactive CLI interfaces. It provides multiple built-in renderers (default, verbose, silent, simple, test) with customizable themes and colors, supports nested task lists with concurrent and sequential execution modes, and includes comprehensive error handling and retry mechanisms with built-in progress indicators and spinners.

Package Information

  • Package Name: listr2
  • Package Type: npm
  • Language: TypeScript
  • Installation: npm install listr2

Core Imports

import { Listr } from "listr2";

For CommonJS:

const { Listr } = require("listr2");

Additional imports:

import { 
  Listr,
  ListrTaskState,
  ListrError,
  ListrEventManager,
  ListrTaskEventManager,
  EventManager,
  DefaultRenderer,
  SimpleRenderer,
  VerboseRenderer,
  PRESET_TIMER,
  PRESET_TIMESTAMP
} from "listr2";

Basic Usage

import { Listr } from "listr2";

const tasks = new Listr([
  {
    title: "Installing dependencies",
    task: () => {
      // Simulate async work
      return new Promise(resolve => setTimeout(resolve, 2000));
    }
  },
  {
    title: "Building project",
    task: (ctx, task) => {
      // Access task wrapper for output
      task.output = "Compiling TypeScript...";
      return new Promise(resolve => setTimeout(resolve, 3000));
    }
  },
  {
    title: "Running tests",
    task: () => {
      return new Promise(resolve => setTimeout(resolve, 1000));
    }
  }
]);

// Run the task list
try {
  await tasks.run();
  console.log("All tasks completed successfully!");
} catch (error) {
  console.error("Tasks failed:", error);
}

Architecture

Listr2 is built around several key components:

  • Listr Class: Main orchestrator that manages task execution, context sharing, and renderer coordination
  • Task System: Individual task management with state tracking, retry logic, and nested task support
  • Renderer System: Pluggable rendering engines for different output formats (TTY, non-TTY, testing)
  • Event Management: Observable-based event system for task state changes and lifecycle events
  • Context Sharing: Type-safe context object passed between tasks for data sharing
  • Error Handling: Comprehensive error collection and reporting with rollback capabilities

Capabilities

Core Task Management

Main Listr class for creating and executing task lists with context sharing, concurrent execution, and error handling.

class Listr<Ctx = ListrContext, Renderer = ListrPrimaryRendererValue, FallbackRenderer = ListrSecondaryRendererValue> {
  constructor(
    task: ListrTask<Ctx, Renderer, FallbackRenderer> | ListrTask<Ctx, Renderer, FallbackRenderer>[],
    options?: ListrBaseClassOptions<Ctx, Renderer, FallbackRenderer>,
    parentTask?: Task<any, Renderer, FallbackRenderer>
  );
  
  add(tasks: ListrTask<Ctx, Renderer>[] | ListrTask<Ctx, Renderer>): void;
  run(context?: Ctx): Promise<Ctx>;
  isRoot(): boolean;
  isSubtask(): boolean;
}

Task Management

Task Configuration and Lifecycle

Individual task definition, execution control, and lifecycle management including skip conditions, retry logic, and rollback functionality.

interface ListrTask<Ctx, Renderer, FallbackRenderer> {
  title?: string | any[];
  task: ListrTaskFn<Ctx, Renderer, FallbackRenderer>;
  enabled?: boolean | ((ctx: Ctx) => boolean | Promise<boolean>);
  skip?: boolean | string | ((ctx: Ctx) => boolean | string | Promise<boolean | string>);
  retry?: number | { tries: number; delay?: number };
  rollback?: ListrTaskFn<Ctx, Renderer, FallbackRenderer>;
  exitOnError?: boolean | ((ctx: Ctx) => boolean | Promise<boolean>);
}

type ListrTaskFn<Ctx, Renderer, FallbackRenderer> = (
  ctx: Ctx,
  task: TaskWrapper<Ctx, Renderer, FallbackRenderer>
) => void | ListrTaskResult<Ctx>;

Task Configuration

Rendering System

Multiple built-in renderers for different environments and use cases, with customizable options and TTY detection.

type ListrRendererValue = 'default' | 'simple' | 'verbose' | 'test' | 'silent' | ListrRendererFactory;

interface ListrBaseClassOptions<Ctx, Renderer, FallbackRenderer> {
  renderer?: Renderer;
  fallbackRenderer?: FallbackRenderer;
  rendererOptions?: ListrGetRendererOptions<ListrGetRendererClassFromValue<Renderer>>;
  fallbackRendererOptions?: ListrGetRendererOptions<ListrGetRendererClassFromValue<FallbackRenderer>>;
  fallbackRendererCondition?: boolean | (() => boolean);
  silentRendererCondition?: boolean | (() => boolean);
}

Renderers

Event Management

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

class ListrEventManager extends EventManager {
  // Inherits all EventManager functionality
}

class ListrTaskEventManager extends EventManager {
  // Inherits all EventManager functionality  
}

enum ListrTaskEventType {
  TITLE = 'TITLE',
  STATE = 'STATE', 
  ENABLED = 'ENABLED',
  SUBTASK = 'SUBTASK',
  PROMPT = 'PROMPT',
  OUTPUT = 'OUTPUT',
  MESSAGE = 'MESSAGE',
  CLOSED = 'CLOSED'
}

Event Management

Error Handling and States

Comprehensive error handling system with task state management, error collection modes, and rollback capabilities.

class ListrError<Ctx> extends Error {
  public path: string[];
  public ctx: Ctx;
  constructor(error: Error, type: ListrErrorTypes, task: Task);
}

enum ListrTaskState {
  WAITING = 'WAITING',
  STARTED = 'STARTED',
  COMPLETED = 'COMPLETED', 
  FAILED = 'FAILED',
  SKIPPED = 'SKIPPED',
  ROLLING_BACK = 'ROLLING_BACK',
  ROLLED_BACK = 'ROLLED_BACK',
  RETRY = 'RETRY',
  PAUSED = 'PAUSED',
  PROMPT = 'PROMPT',
  PROMPT_COMPLETED = 'PROMPT_COMPLETED',
  PROMPT_FAILED = 'PROMPT_FAILED'
}

enum ListrErrorTypes {
  WILL_RETRY = 'WILL_RETRY',
  WILL_ROLLBACK = 'WILL_ROLLBACK',
  HAS_FAILED_TO_ROLLBACK = 'HAS_FAILED_TO_ROLLBACK',
  HAS_FAILED = 'HAS_FAILED',
  HAS_FAILED_WITHOUT_ERROR = 'HAS_FAILED_WITHOUT_ERROR'
}

Error Handling

Presets and Utilities

Built-in formatting presets for timestamps and timers, plus utility functions for environment detection and UI formatting.

// Timer preset for displaying elapsed time
const PRESET_TIMER: PresetTimer;
type PresetTimer = LoggerFieldFn<[number]>;

interface RendererPresetTimer {
  /** Show duration for the tasks */
  timer?: PresetTimer;
}

// Timestamp preset for displaying current time
const PRESET_TIMESTAMP: PresetTimestamp;
type PresetTimestamp = LoggerFieldFn;

interface RendererPresetTimestamp {
  /** Show timestamp for each event that has been logged */
  timestamp?: PresetTimestamp;
}

interface LoggerFieldFn<Args extends any[] = any[]> {
  /** The value of the given field */
  field: ((...args: Args) => string) | string;
  /** Condition to display the given field */
  condition?: ((...args: Args) => boolean) | boolean;
  /** Formatting/coloring of the field */
  format?: (...args: Args) => LoggerFormat;
  /** Args to pass to other functions whenever this field is triggered */
  args?: Args;
}

type LoggerFormat = (message?: string) => string;

// Utility functions
function getRenderer<Renderer extends ListrRendererValue, FallbackRenderer extends ListrRendererValue>(options: {
  renderer: Renderer;
  rendererOptions: ListrGetRendererOptions<Renderer>;
  fallbackRenderer: FallbackRenderer;
  fallbackRendererOptions: ListrGetRendererOptions<FallbackRenderer>;
  fallbackRendererCondition?: boolean | (() => boolean);
  silentRendererCondition?: boolean | (() => boolean);
}): SupportedRenderer<ListrRendererFactory>;
function getRendererClass(renderer: ListrRendererValue): ListrRendererFactory;

Common Types

type ListrContext = Record<PropertyKey, any>;

type ListrTaskResult<Ctx> = 
  | string 
  | Promise<any> 
  | Listr<Ctx, any, any>
  | ReadableLike
  | ObservableLike<any>;

interface ObservableLike<T> {
  subscribe: (observer: ObserverLike<T>) => unknown;
}

interface ReadableLike {
  readable: boolean;
  read: (size?: number) => string | Buffer;
  on: (eventName: 'data' | 'error' | 'end', listener: (data: Buffer | string) => void) => unknown;
}

enum ListrEnvironmentVariables {
  FORCE_UNICODE = 'LISTR_FORCE_UNICODE',
  FORCE_TTY = 'LISTR_FORCE_TTY', 
  DISABLE_COLOR = 'NO_COLOR',
  FORCE_COLOR = 'FORCE_COLOR'
}

// Helper types for renderer-related generics
type ListrGetRendererClassFromValue<T extends ListrRendererValue> = 
  T extends ListrRendererFactory ? T : 
  T extends 'default' ? typeof DefaultRenderer :
  T extends 'simple' ? typeof SimpleRenderer :
  T extends 'verbose' ? typeof VerboseRenderer :
  T extends 'test' ? typeof TestRenderer :
  T extends 'silent' ? typeof SilentRenderer :
  never;

type ListrGetRendererOptions<T extends ListrRendererFactory> = 
  T extends { rendererOptions: infer R } ? R : Record<PropertyKey, any>;

type ListrGetRendererTaskOptions<T extends ListrRendererFactory> = 
  T extends { rendererTaskOptions: infer R } ? R : Record<PropertyKey, any>;

type ListrRendererFactory = new (
  tasks: Task[],
  options: Record<PropertyKey, any>,
  events?: ListrEventManager
) => ListrRenderer;

interface SupportedRenderer<Renderer extends ListrRendererFactory> {
  renderer: Renderer;
  options?: ListrGetRendererOptions<Renderer>;
  selection: ListrRendererSelection;
}

enum ListrRendererSelection {
  PRIMARY = 'PRIMARY',
  SECONDARY = 'SECONDARY',
  SILENT = 'SILENT'
}

// Renderer class declarations
declare class ListrRenderer {
  static rendererOptions: Record<PropertyKey, any>;
  static rendererTaskOptions: Record<PropertyKey, any>;
  static nonTTY: boolean;
  constructor(tasks: Task[], options: Record<PropertyKey, any>, events?: ListrEventManager);
  render(): void | Promise<void>;
  end(err?: Error): void;
}

declare class DefaultRenderer extends ListrRenderer {
  static nonTTY: false;
}

declare class SimpleRenderer extends ListrRenderer {
  static nonTTY: true;
}

declare class VerboseRenderer extends ListrRenderer {
  static nonTTY: true;
}

declare class TestRenderer extends ListrRenderer {}

declare class SilentRenderer extends ListrRenderer {}

declare abstract class ListrPromptAdapter {
  constructor(task: Task<any, any, any>, wrapper: TaskWrapper<any, any, any>);
  protected reportStarted(): void;
  protected reportFailed(): void;
  protected reportCompleted(): void;
  protected restoreState(): void;
  public abstract run<T = any>(...args: any[]): T | Promise<T>;
}

// Core task classes
declare class Task<Ctx, Renderer, FallbackRenderer> {
  public id: string;
  public state: ListrTaskState;
  public title?: string;
  public output?: string;
  public subtasks: Task<Ctx, Renderer, FallbackRenderer>[];
  public retry?: ListrTaskRetry;
  public message: ListrTaskMessage;
  public prompt: ListrTaskPrompt;
  public listr: Listr<Ctx, any, any>;
  check(ctx: Ctx): Promise<boolean>;
  isPending(): boolean;
  isRunning(): boolean;
  isCompleted(): boolean;
  isFailed(): boolean;
  isSkipped(): boolean;
  isRetrying(): boolean;
  isRollingBack(): boolean;
  isRolledBack(): boolean;
  pause(time: number): Promise<void>;
}

declare class TaskWrapper<Ctx, Renderer, FallbackRenderer> {
  title: string | any[];
  output: string | any[];
  newListr(task: ListrTask<Ctx, Renderer> | ListrTask<Ctx, Renderer>[], options?: ListrBaseClassOptions<Ctx, any, any>): Listr<Ctx, any, any>;
  report(error: Error, type?: ListrErrorTypes): void;
  skip(message?: string): void;
  isRetrying(): Task['retry'];
  prompt<T extends ListrPromptAdapter = ListrPromptAdapter>(
    adapter: new (task: Task<Ctx, Renderer, FallbackRenderer>, wrapper: TaskWrapper<Ctx, Renderer, FallbackRenderer>) => T
  ): T;
  stdout(type?: ListrTaskEventType.OUTPUT | ListrTaskEventType.PROMPT): NodeJS.WritableStream;
}