Claude-Agent
view release on metacpan or search on metacpan
lib/Claude/Agent/CLI.pm view on Meta::CPAN
my $_term;
sub _term {
$_term //= Term::ReadLine->new('Claude::Agent');
}
=head1 FUNCTIONS
=head2 Spinners
=head3 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();
});
=cut
sub with_spinner {
my ($message, $code) = @_;
my $ps = Term::ProgressSpinner->new();
$ps->message("{spinner} $message");
$ps->start(100); # Indeterminate mode
my $result = $code->();
$ps->finish();
status('success', $message);
return $result;
}
=head3 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");
=cut
my $_active_spinner;
sub start_spinner {
my ($message, $loop, %opts) = @_;
# Extract our options vs Term::ProgressSpinner options
my $interval = delete $opts{interval} // 0.1;
# Build spinner options with defaults
my %spinner_opts = (
spinner => $opts{spinner} // 'dots',
spinner_color => $opts{spinner_color} // 'cyan',
message => $opts{message} // "{spinner} $message",
);
# Pass through any additional Term::ProgressSpinner options
for my $key (qw(terminal_line terminal_height output)) {
$spinner_opts{$key} = $opts{$key} if defined $opts{$key};
}
$_active_spinner = Term::ProgressSpinner->new(%spinner_opts);
if ($loop) {
# Async mode - spinner animates via IO::Async timer
$_active_spinner->start_async($loop, interval => $interval);
} else {
# Non-async mode - start and draw once
$_active_spinner->start(1);
$_active_spinner->draw($_active_spinner);
}
return $_active_spinner;
}
=head3 stop_spinner
stop_spinner($spinner, $success_message);
Stop a spinner started with start_spinner. Optionally display a success message.
=cut
lib/Claude/Agent/CLI.pm view on Meta::CPAN
=cut
sub divider {
my ($char, $width) = @_;
$char //= '-';
$width //= 60;
print $char x $width, "\n";
}
=head3 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");
=cut
sub status {
my ($type, $message) = @_;
my %colors = (
success => 'green',
error => 'red',
warning => 'yellow',
info => 'cyan',
);
my %icons = (
success => "\x{2713}", # Check mark
error => "\x{2717}", # X mark
warning => "\x{26A0}", # Warning sign
info => "\x{2139}", # Info symbol
);
my $color = $colors{$type} // 'white';
my $icon = $icons{$type} // '*';
print colored([$color], "$icon $message"), "\n";
}
=head2 Terminal Control
=head3 clear_line
clear_line();
Clear the current line (useful for updating spinner messages).
=cut
sub clear_line {
print "\r\033[K";
}
=head3 move_up
move_up($n);
Move cursor up N lines.
=cut
sub move_up {
my ($n) = @_;
$n //= 1;
print "\033[${n}A";
}
=head1 DEPENDENCIES
=over 4
=item * Term::ANSIColor (core module)
=item * Term::ReadLine (core module)
=item * Term::Choose
=item * Term::ReadKey (recommended, used by Term::Choose)
=item * Term::ProgressSpinner
=back
=head1 AUTHOR
LNATION, C<< <email at lnation.org> >>
=head1 LICENSE AND COPYRIGHT
This software is Copyright (c) 2026 by LNATION.
This is free software, licensed under:
The Artistic License 2.0 (GPL Compatible)
=cut
1;
( run in 0.897 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )