NAME
Claude::Agent::CLI - Terminal UI utilities for interactive CLI applications
SYNOPSIS
use Claude::Agent::CLI qw(:all);
# Spinners
my $result = with_spinner("Processing...", sub {
# Long-running operation
return $data;
});
# Async spinners with IO::Async
use IO::Async::Loop;
my $loop = IO::Async::Loop->new;
my $spinner = start_spinner("Processing...", $loop);
my $result = await $async_operation;
stop_spinner($spinner, "Processing complete");
# Prompts
my $name = prompt("Enter your name", "Anonymous");
my $continue = ask_yn("Continue?", "y");
my $choice = menu("Select action", [
{ key => 'a', label => 'Add' },
{ key => 'd', label => 'Delete' },
]);
# Interactive selection using Term::Choose (keyboard navigation)
my $selected = choose_from(\@options, prompt => "Pick one:");
my @selected = choose_multiple(\@options, prompt => "Pick several:");
# Display utilities
header("My Application");
divider();
status('success', "Operation completed");
status('error', "Something went wrong");
DESCRIPTION
Provides shared utilities for interactive terminal features including:
Spinners using Term::ProgressSpinner (with IO::Async support)
Input prompts using Term::ReadLine
Interactive keyboard-navigable selection using Term::Choose
Colored output using Term::ANSIColor
Terminal control utilities
EXPORTS
Nothing is exported by default. Use :all for everything, or import specific functions.
Export Tags
:all - All functions
:spinner - with_spinner, start_spinner, stop_spinner
:prompt - prompt, ask_yn, menu, select_option, choose_from, choose_multiple
:display - header, divider, status
:term - clear_line, move_up
FUNCTIONS
Spinners
with_spinner
my $result = with_spinner($message, $code);
Display a spinner while executing code. Returns the result of the code block. Note: This is for synchronous code. For async operations, use start_spinner/stop_spinner.
my $data = with_spinner("Loading...", sub {
return load_data();
});
start_spinner
my $spinner = start_spinner($message, $loop, %opts);
Start an async spinner for long-running operations. Returns the spinner object. Call stop_spinner($spinner) when the operation completes.
When an IO::Async loop is provided, the spinner animates automatically. Without a loop, the spinner displays but doesn't animate (useful for quick operations).
Options:
spinner - Spinner style (default: 'dots')
Available: dots, bar, around, pipe, moon, circle,
color_circle, color_circles, color_square, color_squares,
earth, circle_half, clock, pong, material
spinner_color - Color for spinner (default: 'cyan')
Available: black, red, green, yellow, blue, magenta, cyan, white
Also: bright_* variants, and "color on_background" combinations
message - Custom message format (default: "{spinner} $message")
Placeholders: {spinner}, {elapsed}, {percent}, etc.
interval - Animation interval in seconds (default: 0.1)
terminal_line - Skip STDIN cursor query by providing line number
use IO::Async::Loop;
my $loop = IO::Async::Loop->new;
# Simple usage
my $spinner = start_spinner("Processing...", $loop);
# Customized spinner
my $spinner = start_spinner("Loading...", $loop,
spinner => 'moon',
spinner_color => 'yellow',
interval => 0.2,
);
my $result = await $async_operation;
stop_spinner($spinner, "Processing complete");
stop_spinner
stop_spinner($spinner, $success_message);
Stop a spinner started with start_spinner. Optionally display a success message.
Prompts
prompt
my $answer = prompt($message, $default);
Prompt the user for text input with an optional default value.
ask_yn
my $yes = ask_yn($message, $default);
Ask a yes/no question. Returns true for yes, false for no. Default is 'y' if not specified.
if (ask_yn("Continue?", "y")) {
# User said yes
}
menu
my $choice = menu($title, $options);
Display a menu with keyed options using Term::Choose for keyboard navigation. Returns the selected key.
my $action = menu("Action", [
{ key => 'a', label => 'Approve' },
{ key => 'r', label => 'Revise' },
{ key => 's', label => 'Skip' },
]);
select_option
my $selected = select_option($options, %args);
Display options for selection using Term::Choose with keyboard navigation. Returns the selected option text, or undef if "Custom" was selected (when allow_custom => 1).
my $outline = select_option(\@outlines, allow_custom => 1);
if (!defined $outline) {
# User wants to enter custom text
$outline = prompt("Enter custom outline:");
}
choose_from
my $selected = choose_from($options, %args);
Interactive selection using Term::Choose with keyboard navigation. Users can use arrow keys, vim keys (hjkl), or Ctrl-F to search.
Options: prompt - Header text to display inline_prompt - Prompt shown inline with selection layout - 1 for columns (default), 2 for single column return_index - Return index instead of value (default: 0) mouse - Enable mouse support (default: 0)
my $title = choose_from(\@titles, prompt => "Select a title:");
choose_multiple
my @selected = choose_multiple($options, %args);
Interactive multi-selection using Term::Choose. Users press SpaceBar to mark items and Enter to confirm.
my @features = choose_multiple(
[qw(feature1 feature2 feature3)],
prompt => "Select features to enable:",
preselected => [0, 2], # Pre-select first and third
);
Display
header
header($text);
Display a styled header with border lines.
divider
divider($char, $width);
Print a divider line. Defaults to '-' x 60.
status
status($type, $message);
Print a status message with appropriate color and icon. Types: success, error, warning, info
status('success', "File saved");
status('error', "Operation failed");
status('warning', "Disk space low");
status('info', "Processing 10 items");
Terminal Control
clear_line
clear_line();
Clear the current line (useful for updating spinner messages).
move_up
move_up($n);
Move cursor up N lines.
DEPENDENCIES
Term::ANSIColor (core module)
Term::ReadLine (core module)
Term::Choose
Term::ReadKey (recommended, used by Term::Choose)
Term::ProgressSpinner
AUTHOR
LNATION, <email at lnation.org>
LICENSE AND COPYRIGHT
This software is Copyright (c) 2026 by LNATION.
This is free software, licensed under:
The Artistic License 2.0 (GPL Compatible)