Complete API documentation for effect-cli-tui.
Interactive terminal user interface handler using @inquirer/prompts.
const tui = new TUIHandler()Display a text input prompt and return the user's input.
Parameters:
message: The prompt message to displayoptions.default: Optional default value if user presses enteroptions.validate: Optional validation function
Returns: Effect that resolves with the entered string
Errors: TUIError with reason 'RenderError'
Example:
import * as Effect from 'effect/Effect'
import { TUIHandler } from 'effect-cli-tui'
const getUsername = Effect.gen(function* (_) {
const tui = new TUIHandler()
const username = yield* _(
tui.prompt('Enter username:', {
default: 'guest'
})
)
return username
})
await Effect.runPromise(getUsername)Display a dropdown menu for selecting a single option.
Parameters:
message: The selection prompt messageoptions: Array ofSelectOptionobjects
Returns: Effect that resolves with the selected value
Errors:
TUIErrorwith reason'RenderError'if rendering failsTUIErrorwith reason'RenderError'if no options provided
Example:
const selectFramework = Effect.gen(function* (_) {
const tui = new TUIHandler()
const framework = yield* _(
tui.selectOption('Choose a framework:', [
{ label: 'React', value: 'react', description: 'A JavaScript library' },
{ label: 'Vue', value: 'vue', description: 'A JavaScript framework' },
{ label: 'Svelte', value: 'svelte', description: 'A compiler' }
])
)
console.log(`Selected: ${framework}`)
})Display checkboxes for selecting multiple options.
Parameters:
message: The selection prompt messageoptions: Array ofSelectOptionobjects
Returns: Effect that resolves with array of selected values
Errors:
TUIErrorwith reason'RenderError'if rendering failsTUIErrorwith reason'RenderError'if no options provided
Example:
const selectFeatures = Effect.gen(function* (_) {
const tui = new TUIHandler()
const features = yield* _(
tui.multiSelect('Select features:', [
{ label: 'TypeScript', value: 'ts' },
{ label: 'Testing', value: 'tests' },
{ label: 'Linting', value: 'lint' },
{ label: 'Pre-commit', value: 'husky' }
])
)
console.log(`Selected features:`, features)
})Display a yes/no confirmation prompt.
Parameters:
message: The confirmation message
Returns: Effect that resolves with boolean (true for yes, false for no)
Errors: TUIError with reason 'RenderError'
Example:
const confirmAction = Effect.gen(function* (_) {
const tui = new TUIHandler()
const confirmed = yield* _(
tui.confirm('Delete all files? (cannot be undone)')
)
if (confirmed) {
console.log('Deleting...')
// perform deletion
} else {
console.log('Cancelled')
}
})Display a styled message to the console.
Parameters:
message: The message to displaytype: Message type affecting styling'success': Green checkmark (✓)'error': Red cross (✗)'info': Blue info (ℹ)
Returns: Effect that resolves to void
Errors: None (always succeeds)
Example:
const displayMessages = Effect.gen(function* (_) {
const tui = new TUIHandler()
yield* _(tui.display('Operation started', 'info'))
try {
// do something
yield* _(tui.display('Operation successful!', 'success'))
} catch (err) {
yield* _(tui.display('Operation failed', 'error'))
}
})Execute CLI commands with Effect error handling and output capture.
const cli = new EffectCLI()Execute a command and capture its output.
Parameters:
command: The command to executeargs: Optional array of command argumentsoptions.cwd: Working directory (defaults toprocess.cwd())options.env: Environment variables to merge with current envoptions.timeout: Maximum execution time in milliseconds
Returns: Effect that resolves with CLIResult containing:
exitCode: Command exit codestdout: Standard output stringstderr: Standard error string
Errors: CLIError with reason:
'CommandFailed': Command exited with non-zero code'Timeout': Command exceeded timeout'NotFound': Command not found
Example:
const runBuild = Effect.gen(function* (_) {
const cli = new EffectCLI()
const result = yield* _(
cli.run('npm', ['run', 'build'], {
timeout: 60000,
cwd: '/path/to/project'
})
)
console.log('Build output:', result.stdout)
console.log('Exit code:', result.exitCode)
})Execute a command with output streamed directly to console (inherited stdio).
Parameters:
command: The command to executeargs: Optional array of command argumentsoptions.cwd: Working directoryoptions.env: Environment variablesoptions.timeout: Maximum execution time
Returns: Effect that resolves to void when command completes
Errors: CLIError with same reasons as run()
Example:
const streamInstall = Effect.gen(function* (_) {
const cli = new EffectCLI()
yield* _(
cli.stream('npm', ['install'], {
cwd: '/path/to/project'
})
)
console.log('Installation complete')
})interface SelectOption {
label: string // Display text shown to user
value: string // Value returned when selected
description?: string // Optional help text below label
}Example:
const options: SelectOption[] = [
{
label: 'TypeScript',
value: 'ts',
description: 'Add TypeScript support'
},
{
label: 'JavaScript',
value: 'js',
description: 'Keep as JavaScript'
}
]interface CLIResult {
exitCode: number // Command exit code
stdout: string // Standard output
stderr: string // Standard error
}Example:
const { exitCode, stdout, stderr } = yield* _(
cli.run('git', ['status'])
)
if (exitCode === 0) {
console.log(stdout)
} else {
console.error(stderr)
}interface CLIRunOptions {
cwd?: string // Working directory
env?: Record<string, string> // Environment variables
timeout?: number // Timeout in milliseconds
}Example:
const options: CLIRunOptions = {
cwd: '/home/user/project',
env: { NODE_ENV: 'production' },
timeout: 30000
}interface PromptOptions {
default?: string // Default value
validate?: (input: string) => boolean | string // Validation function
}Example:
const options: PromptOptions = {
default: 'localhost',
validate: (input) => {
if (input.length === 0) return 'Host cannot be empty'
return true
}
}Thrown by TUIHandler methods when prompts fail.
class TUIError {
_tag: 'TUIError'
reason: 'Cancelled' | 'ValidationFailed' | 'RenderError'
message: string
}Example:
const safePrompt = yield* _(
tui.prompt('Enter name:').pipe(
Effect.catchTag('TUIError', (error) => {
console.error(`Prompt failed: ${error.message}`)
return Effect.succeed('default')
})
)
)Thrown by EffectCLI methods when commands fail.
class CLIError {
_tag: 'CLIError'
reason: 'CommandFailed' | 'Timeout' | 'NotFound'
message: string
}Example:
const safeCLI = yield* _(
cli.run('npm', ['install']).pipe(
Effect.catchTag('CLIError', (error) => {
if (error.reason === 'NotFound') {
console.error('npm not found')
} else if (error.reason === 'Timeout') {
console.error('Installation took too long')
}
return Effect.succeed(null)
})
)
)import * as Effect from 'effect/Effect'
import { TUIHandler, EffectCLI } from 'effect-cli-tui'
const setupWizard = Effect.gen(function* (_) {
const tui = new TUIHandler()
const cli = new EffectCLI()
yield* _(tui.display('Welcome to Project Setup!', 'info'))
// Get project details
const name = yield* _(tui.prompt('Project name:'))
const template = yield* _(
tui.selectOption('Choose template:', [
{ label: 'Minimal', value: 'minimal' },
{ label: 'Full Stack', value: 'fullstack' }
])
)
const includeTests = yield* _(tui.confirm('Include tests?'))
// Confirm
const confirmed = yield* _(
tui.confirm(`Create ${name} with ${template}?`)
)
if (!confirmed) {
yield* _(tui.display('Setup cancelled', 'info'))
return
}
// Create project
yield* _(tui.display('Creating project...', 'info'))
yield* _(
cli.stream('npm', ['create', 'vite@latest', name, '--', '--template', template], {
timeout: 120000
})
)
yield* _(tui.display('Project created!', 'success'))
if (includeTests) {
yield* _(tui.display('Adding test setup...', 'info'))
yield* _(
cli.stream('npm', ['install', '-D', 'vitest'], {
cwd: name,
timeout: 60000
})
)
yield* _(tui.display('Tests configured!', 'success'))
}
yield* _(tui.display(`Project ready at: ./${name}`, 'success'))
})
Effect.runPromise(setupWizard)const workflow = Effect.gen(function* (_) {
const tui = new TUIHandler()
const inputs = []
for (let i = 0; i < 3; i++) {
const value = yield* _(
tui.prompt(`Step ${i + 1} - Enter value:`)
)
inputs.push(value)
}
yield* _(
tui.display(`Collected ${inputs.length} values`, 'success')
)
return inputs
})const robustPrompt = (message: string) =>
tui.prompt(message).pipe(
Effect.retry({
times: 3,
schedule: Effect.exponentialBackoff(100)
}),
Effect.catchTag('TUIError', () =>
Effect.succeed('default value')
)
)