mrkeyoor.com_
Sat 08 Aug 21:02 UTC
npmCLI & Toolingupdated 08 Aug 2026

@listr2/prompt-adapter-inquirer

@listr2/prompt-adapter-inquirer connects modern @inquirer/prompts functions to a running Listr2 task. Listr2 owns the terminal renderer, so calling an Inquirer prompt directly can fight with its spinner and line updates; this adapter redirects prompt output through the task, reports prompt state to the renderer, and supplies an AbortSignal for cancellation. It is not a prompt library by itself. You still install @inquirer/prompts, import input, select, confirm, or another prompt function, and invoke it through task.prompt(ListrInquirerPromptAdapter).run(...).

Verdict

Install this only as the narrow bridge between Listr2 11 and @inquirer/prompts; it is the recommended adapter for that exact stack. For a CLI without Listr2, call @inquirer/prompts directly and avoid the extra package and peer-version coupling.

API stability3/5The core call shape is small and typed: task.prompt(Adapter).run(promptFunction, config, context), plus cancel() and instance. Compatibility is tightly coupled to Listr2 majors, though. Version 4.2.5 pins listr2 to 11.0.0, version 4 dropped Node 20, and the package changelog contains frequent releases that mainly follow monorepo dependency changes.
Docs4/5The Listr2 prompt guide explains why an adapter is necessary, shows installation for npm, Yarn, and pnpm, provides current single-prompt and cancellation examples, warns against concurrent prompts, and documents non-TTY output behavior. The package README itself is only a pointer, and most prompt-specific options must be learned from the separate Inquirer documentation.
Maintenance5/5Version 4.2.5 was published in July 2026, the monorepo was pushed in August 2026, and the changelog shows repeated dependency updates and compatibility work throughout the year. The repository currently reports zero open issues and pull requests. Maintenance is active, though the adapter moves in lockstep with Listr2 and its Node support policy.
Ecosystem4/5The adapter records 4,682,900 weekly downloads because it sits between two established CLI projects, and it accepts @inquirer/prompts releases from major 3 through major 8. Its ecosystem is intentionally narrow: all prompt types come from Inquirer and all rendering behavior comes from Listr2, so there is little adapter-specific extension surface.

Use it if

  • Your CLI already uses Listr2 11 and needs interactive questions inside tasks without corrupting the live renderer
  • You want the actively maintained @inquirer/prompts functions while keeping prompt state visible to Listr2
  • You need a running prompt to be cancelled when a task is skipped or when your code calls the adapter's cancel method
  • You use TypeScript and want the chosen Inquirer prompt function to determine the config and return types
Skip it if

Setup reality

Install three pieces together: listr2@11.0.0, @listr2/prompt-adapter-inquirer@4.2.5, and a compatible @inquirer/prompts release. The adapter declares @inquirer/prompts >=3 <9 as an optional peer, so npm can install the adapter without the actual prompt functions; the missing package only becomes obvious when your import fails. It also pins listr2 to exactly 11.0.0, which makes routine independent upgrades capable of producing peer-dependency warnings. Node must be at least 22.13.0. The published entry point is ESM even for its require export, so treat this as modern module-oriented CLI code and test any CommonJS packaging setup. Inside a task, create the adapter with task.prompt(ListrInquirerPromptAdapter), then call run with an imported prompt function as the first argument and its options as the second. Do not call input() or select() directly because their stdout writes bypass Listr2's renderer. Keep the enclosing task async and await the answer. Set concurrent: false for any list that can prompt; simultaneous questions compete for the same keyboard and terminal lines. Cancellation rejects the Inquirer cancellable promise rather than returning a sentinel, so catch it only if cancellation is an expected branch. In CI, cron, Docker builds, and redirected stdin, provide flags or environment variables that bypass the question entirely. Prompt output is routed into Listr2's stream, but non-TTY renderers may print repeated updates and still look noisy.

Patterns

Ask for text inside a Listr taskprompt-for-input

import { input } from '@inquirer/prompts';
import { ListrInquirerPromptAdapter } from '@listr2/prompt-adapter-inquirer';
import { Listr } from 'listr2';

const tasks = new Listr([{
  title: 'Configure project',
  task: async (ctx, task) => {
    ctx.name = await task.prompt(ListrInquirerPromptAdapter).run(input, {
      message: 'Project name?',
    });
  },
}], { concurrent: false });

const ctx = await tasks.run();

Pass the imported prompt function to run; do not invoke input() directly while the Listr renderer owns stdout.

Confirm a destructive actionconfirm-action

import { confirm } from '@inquirer/prompts';

const approved = await task.prompt(ListrInquirerPromptAdapter).run(confirm, {
  message: 'Delete generated files?',
  default: false,
});

if (!approved) task.skip('Kept generated files');

Use a false default for destructive choices. Skipping the task also cancels an active prompt through the adapter.

Choose one item from a listselect-one

import { select } from '@inquirer/prompts';

const environment = await task.prompt(ListrInquirerPromptAdapter).run(select, {
  message: 'Deploy where?',
  choices: [
    { name: 'Development', value: 'dev' },
    { name: 'Staging', value: 'staging' },
    { name: 'Production', value: 'prod' },
  ],
});

The returned value is the choice value, not its display name.

Choose several itemsselect-many

import { checkbox } from '@inquirer/prompts';

const features = await task.prompt(ListrInquirerPromptAdapter).run(checkbox, {
  message: 'Enable features',
  choices: [
    { name: 'Linting', value: 'lint', checked: true },
    { name: 'Tests', value: 'test', checked: true },
    { name: 'Docker', value: 'docker' },
  ],
  required: true,
});

required prevents an empty submission; the answer is an array of choice values.

Read a masked secretread-password

import { password } from '@inquirer/prompts';

const token = await task.prompt(ListrInquirerPromptAdapter).run(password, {
  message: 'API token',
  mask: '*',
  validate: (value) => value.length > 10 || 'Token is too short',
});

Masking only hides terminal echo. Do not put the returned secret in task titles, output, debug logs, or Listr context that you later serialize.

Validate and transform textvalidate-input

import { input } from '@inquirer/prompts';

const slug = await task.prompt(ListrInquirerPromptAdapter).run(input, {
  message: 'Package slug',
  validate: (value) => /^[a-z0-9-]+$/.test(value) || 'Use lowercase letters, numbers, and hyphens',
  transformer: (value) => value.trim().toLowerCase(),
});

A transformer changes what is displayed while typing; normalize the final returned value yourself if storage must be canonical.

Ask for a numeric valueprompt-for-number

import { number } from '@inquirer/prompts';

const port = await task.prompt(ListrInquirerPromptAdapter).run(number, {
  message: 'Port',
  default: 3000,
  min: 1,
  max: 65535,
  required: true,
});

Use required when undefined is not valid; otherwise an empty answer can produce no number.

Search a long list of choicessearch-choices

import { search } from '@inquirer/prompts';

const project = await task.prompt(ListrInquirerPromptAdapter).run(search, {
  message: 'Choose a project',
  source: async (term = '') => projects
    .filter((item) => item.name.toLowerCase().includes(term.toLowerCase()))
    .map((item) => ({ name: item.name, value: item.id })),
});

Debounce network-backed source functions yourself so every keystroke does not become an API request.

Cancel a prompt after a deadlinecancel-prompt

import { input } from '@inquirer/prompts';

const prompt = task.prompt(ListrInquirerPromptAdapter);
const timer = setTimeout(() => prompt.cancel(), 30_000);

try {
  ctx.value = await prompt.run(input, { message: 'Value?' });
} finally {
  clearTimeout(timer);
}

cancel() aborts the Inquirer promise, so expect run() to reject. Always clear your timer after completion.

Avoid prompting in non-interactive runsbypass-in-ci

import { input } from '@inquirer/prompts';

const supplied = process.env.PROJECT_NAME;
if (supplied) {
  ctx.name = supplied;
} else if (!process.stdin.isTTY) {
  throw new Error('PROJECT_NAME is required without a TTY');
} else {
  ctx.name = await task.prompt(ListrInquirerPromptAdapter).run(input, {
    message: 'Project name?',
  });
}

The docs warn that prompts are meant for TTY terminals; fail clearly or accept flags and environment variables in automation.

Alternatives

PackageRegistryPick it when
@inquirer/promptsnpmUse it directly when your CLI does not have a Listr2 renderer competing for stdout
@listr2/prompt-adapter-enquirernpmUse it only for an existing Enquirer-based Listr2 command that cannot migrate yet
promptsnpmUse it for a small standalone prompt flow without Listr2 task integration