Skip to content

Interactive prompts for missing options #147

@toiroakr

Description

@toiroakr

Summary

Add support for interactive prompts that ask users for input when required options are not provided via command-line arguments or environment variables. This serves as an additional fallback layer in the value resolution chain.

Motivation

Many modern CLI tools provide interactive prompts to improve usability, especially for commands with many required options. Instead of failing with a validation error, the CLI can interactively guide the user to provide missing values.

This pattern is well-established in tools like npm init, gh repo create, and frameworks like @effect/cli (which provides Prompt.text, Prompt.confirm, Prompt.select, etc.).

Proposed Design

Value Resolution Order

Extend the existing fallback chain:

CLI argument > Environment variable > Interactive prompt > Default value

API

Add a prompt option to the arg() metadata:

const args = z.object({
  // Simple: auto-detect prompt type from Zod schema
  name: arg(z.string(), {
    description: "Your name",
    prompt: true,
  }),

  // completion type "file" is reused as prompt type
  input: arg(z.string(), {
    description: "Input file",
    completion: { type: "file", extensions: ["json", "yaml"] },
    prompt: true,  // → file prompt (inherited from completion.type)
  }),

  // completion type "directory" is reused as prompt type
  outputDir: arg(z.string(), {
    description: "Output directory",
    completion: { type: "directory" },
    prompt: true,  // → directory prompt (inherited from completion.type)
  }),

  // Prompt-specific type: password (hidden input)
  token: arg(z.string(), {
    description: "API token",
    prompt: { type: "password" },
  }),

  // Enum: auto-detected as select prompt
  format: arg(z.enum(["json", "yaml", "text"]), {
    description: "Output format",
    prompt: { message: "Which output format?" },
  }),

  // Explicit prompt type overrides completion type
  secret: arg(z.string(), {
    completion: { type: "file" },
    prompt: { type: "password" },  // overrides "file"
  }),
});

Prompt Type Resolution

The prompt type is resolved in the following priority order:

prompt.type (explicit) > completion.type (inherited) > Zod schema (auto-detected)

Auto-detection from Zod schema (when no explicit type):

Zod Schema Auto-detected Type Prompt Behavior
z.string() "text" Text input
z.number() / z.coerce.number() "text" Text input with numeric validation
z.boolean() "confirm" Confirm (y/N)
z.enum([...]) "select" Select from choices
z.array(z.enum([...])) "multiselect" Multi-select

Inherited from completion metadata:

Completion Type Prompt Behavior
"file" File path input (with extensions/matcher filter)
"directory" Directory path input

Prompt-specific types:

Prompt Type Prompt Behavior
"password" Hidden text input

Entry Point

Prompts should be available as a separate module to keep the core lightweight:

import { runMain } from "politty";
import { withPrompts } from "politty/prompt";
// or integrate via options in runMain/runCommand

Considerations

  • Non-interactive environments: When stdin is not a TTY (e.g., CI/CD, piped input), prompts should be skipped and normal validation errors should be raised
  • Separate module: To keep the core dependency-free, prompt functionality could live in politty/prompt with an optional dependency on a terminal input library
  • This feature is a prerequisite for Wizard Mode (see Wizard mode for guided command construction #148)

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions