Skip to content

Interactive Prompts

dreamcli integrates interactive prompts into the flag resolution chain. Prompts activate only when needed and only in interactive contexts.

Per-Flag Prompts

ts
import { flag } from '@kjanat/dreamcli';

flag.string().prompt({ kind: 'input', message: 'Name?' });
flag
  .boolean()
  .prompt({ kind: 'confirm', message: 'Sure?' });
flag
  .enum(['a', 'b'])
  .prompt({ kind: 'select', message: 'Pick one' });
flag.array(flag.string()).prompt({
  kind: 'multiselect',
  message: 'Pick many',
  choices: [{ value: 'a' }, { value: 'b' }],
});

Prompts fire only if the flag wasn't resolved by CLI argv, env var, or config. Defaults apply only after prompts are skipped or unanswered.

For the exact non-interactive rules, cancellation fallthrough, and full precedence chain, see CLI Semantics.

Prompt Types

KindInputOutput
inputFree textstring
confirmYes/Noboolean
selectSingle choiceEnum value
multiselectMultiple choicesArray

Per-Command Interactive Resolver

For conditional prompts that depend on other resolved values:

ts
import { command, flag } from '@kjanat/dreamcli';

command('deploy')
  .flag('region', flag.enum(['us', 'eu', 'ap']))
  .flag('confirm', flag.boolean())
  .interactive(({ flags }) => ({
    region: !flags.region && {
      kind: 'select',
      message: 'Which region?',
    },
    confirm: flags.region === 'us' && {
      kind: 'confirm',
      message: 'Deploy to US prod?',
    },
  }));

The resolver receives partially resolved flags (after CLI/env/config) and returns prompt configs for any remaining values.

Non-Interactive Behavior

When stdin is not a TTY (CI, piped input), prompts are automatically skipped. Required flags that would have prompted instead produce a structured error with an actionable message.

Testing Prompts

ts
import {
  runCommand,
  createTestPrompter,
  PROMPT_CANCEL,
} from '@kjanat/dreamcli/testkit';

// Provide answers in order
const result = await runCommand(promptCmd, [], {
  answers: ['eu'],
});

// Simulate cancellation
const cancelled = await runCommand(promptCmd, [], {
  prompter: createTestPrompter([PROMPT_CANCEL]),
});

What's Next?

Released under the MIT License.