@hyperfrontend/questions
v0.2.0
Published
Terminal prompting library with composable, functional API for text, select, confirm, and multiselect prompts
Downloads
219
Maintainers
Readme
@hyperfrontend/questions
Terminal prompting library with composable, functional API for text, select, confirm, and multiselect prompts
• 👉 See documentation
What is @hyperfrontend/questions?
A terminal prompting library built on functional programming principles. Create interactive CLI experiences with composable, type-safe prompts that return structured outcomes.
Key Features
- Pure Functions — Every prompt is a pure function returning
Promise<PromptOutcome<T>>, making results predictable and easily testable - Composable API — Build complex interactive flows by combining simple prompt functions
- Type-Safe — Full TypeScript support with discriminated unions for prompt outcomes
- Zero External Dependencies — Uses only Node.js built-ins and
@hyperfrontendutilities - Searchable Multiselect — Type-to-filter functionality for large option lists
Architecture Highlights
Each prompt follows a functional state machine pattern:
- Immutable State — All prompt state is frozen; updates create new state objects
- Explicit Outcomes — Prompts return either
{ result: 'submitted', value: T }or{ result: 'cancelled', value: undefined } - Terminal Abstraction — Low-level I/O is encapsulated in a
Terminalinterface for testability
Why Use @hyperfrontend/questions?
When building CLI tools, you need interactive prompts that are:
- Predictable — Know exactly what a prompt returns, always
- Composable — Chain prompts without callback hell
- Cancellable — Handle Ctrl+C gracefully with structured cancellation
- Lightweight — No large dependency trees for simple prompts
This library provides all four while staying true to functional programming principles.
Installation
npm install @hyperfrontend/questionsQuick Start
import { text, confirm, select, multiselect, PromptResult } from '@hyperfrontend/questions'
// Text input
const nameResult = await text({
message: 'What is your name?',
validate: (value) => (value.length < 2 ? 'Name too short' : undefined),
})
if (nameResult.result === PromptResult.Submitted) {
console.log(`Hello, ${nameResult.value}!`)
}
// Text input with a live label — `renderMessage` is recomputed on every keystroke
import { style } from '@hyperfrontend/questions'
await text({
message: 'Title:',
renderMessage: (value) => {
const left = 72 - value.length
return `Title (${left >= 0 ? style.green(`${left} left`) : style.red(`${-left} over`)}):`
},
})
// Confirmation
const continueResult = await confirm({
message: 'Continue?',
initial: true,
})
// Single select
const colorResult = await select({
message: 'Pick a color:',
choices: [
{ label: 'Red', value: 'red' },
{ label: 'Green', value: 'green', hint: 'recommended' },
{ label: 'Blue', value: 'blue' },
],
})
// Multiselect with search
const featuresResult = await multiselect({
message: 'Select features:',
choices: [
{ label: 'TypeScript', value: 'ts' },
{ label: 'ESLint', value: 'eslint' },
{ label: 'Prettier', value: 'prettier' },
],
searchable: true,
min: 1,
})API Overview
| Function | Description |
| -------------- | ----------------------------------------------------------------------------- |
| text | Free-form text input with optional validation and live-updating labels |
| confirm | Yes/no confirmation prompt |
| select | Single selection from a list of choices |
| multiselect | Multiple selections with optional search |
| style | ANSI colour helpers (green, yellow, red, cyan, bold, dim, gray) |
| PromptResult | Discriminated union: 'submitted' \| 'cancelled' |
All prompts return Promise<PromptOutcome<T>> where:
type PromptOutcome<T> = { result: 'submitted'; value: T } | { result: 'cancelled'; value: undefined }Compatibility
| Environment | Supported | | -------------- | --------- | | Node.js >= 18 | ✅ | | TTY Terminal | ✅ | | Tree Shakeable | ✅ |
