Acme-Claude-Shell
view release on metacpan or search on metacpan
bin/acme_claude_shell view on Meta::CPAN
sub show_help {
my $c = $opts{'color'};
if ($c) {
print colored(['bold', 'cyan'], "\n Acme::Claude::Shell"), " - AI-powered interactive shell\n\n";
} else {
print "\n Acme::Claude::Shell - AI-powered interactive shell\n\n";
}
print_section("Usage", $c);
print " acme_claude_shell [options]\n";
print " acme_claude_shell -c \"find all large log files\"\n\n";
print_section("Options", $c);
print_opt("-n, --dry-run", "Preview mode - show commands without executing", $c);
print_opt("-u, --unsafe", "Disable safety confirmations for dangerous commands", $c);
print_opt("--no-color", "Disable colored output", $c);
print_opt("-d, --directory DIR", "Set working directory (default: current)", $c);
print_opt("-c, --command CMD", "Run single command and exit (use '-' for stdin)", $c);
print_opt("-m, --model MODEL", "Claude model to use (e.g., claude-opus-4-5)", $c);
print_opt("-h, --help", "Show this help", $c);
print_opt("-v, --version", "Show version", $c);
print "\n";
print_section("Examples", $c);
print " acme_claude_shell # Start interactive shell\n";
print " acme_claude_shell --dry-run # Preview mode\n";
print " acme_claude_shell -d /var/log # Start in specific directory\n";
print " acme_claude_shell -c \"list perl files\" # Single command\n";
print " acme_claude_shell -m claude-opus-4-5 # Use a specific model\n";
print " echo \"list files\" | acme_claude_shell -c - # Piped input\n\n";
print_section("Interactive Commands", $c);
print " help Show help inside the shell\n";
print " history Show executed command history\n";
print " clear Clear the screen\n";
print " exit Exit the shell (or 'quit')\n\n";
print_section("Example Session", $c);
if ($c) {
print colored(['green'], " acme_claude_shell> "), "find all perl files larger than 10k\n";
print colored(['cyan'], " Thinking...\n");
print " I'll find .pl and .pm files over 10KB:\n\n";
print colored(['cyan'], " i "), "Command: find . -name '*.p[lm]' -size +10k\n\n";
print " Action:\n";
print " [", colored(['cyan'], "a"), "] Approve and run\n";
print " [", colored(['cyan'], "d"), "] Dry-run (show only)\n";
print " [", colored(['cyan'], "e"), "] Edit command\n";
print " [", colored(['cyan'], "x"), "] Cancel\n";
bin/acme_claude_shell view on Meta::CPAN
print " (Claude remembers the previous files...)\n\n";
} else {
print " acme_claude_shell> find all perl files larger than 10k\n";
print " Thinking...\n";
print " I'll find .pl and .pm files over 10KB:\n";
print " Command: find . -name '*.p[lm]' -size +10k\n";
print " > a\n";
print " ./lib/Acme/Claude/Shell.pm\n\n";
}
print_section("SDK Features Demonstrated", $c);
print " This module showcases all Claude::Agent SDK features:\n";
print " - query() Single-shot commands (-c option)\n";
print " - session() Multi-turn context (interactive mode)\n";
print " - MCP tools Custom shell execution tools\n";
print " - Hooks Safety confirmation before running\n";
print " - Dry-run Preview without executing\n";
print " - IO::Async Non-blocking spinners\n";
print " - CLI utils Colored output, menus, spinners\n\n";
}
sub show_version {
my $c = $opts{'color'};
if ($c) {
print colored(['bold', 'cyan'], "Acme::Claude::Shell"), " version $VERSION\n";
} else {
print "Acme::Claude::Shell version $VERSION\n";
}
}
sub print_section {
my ($title, $color) = @_;
if ($color) {
print colored(['bold', 'yellow'], "$title:\n");
} else {
print "$title:\n";
}
}
sub print_opt {
my ($opt, $desc, $color) = @_;
lib/Acme/Claude/Shell/Hooks.pm view on Meta::CPAN
my $duration = time() - ($session->{_session_start} // time());
my $tool_count = $session->{_tool_count} // 0;
my $tool_errors = $session->{_tool_errors} // 0;
my $history_count = scalar(@{$session->_history // []});
if ($session->colorful) {
print "\n";
print colored(['cyan'], "â" x 40) . "\n";
status('info', "Session Statistics");
printf " Duration: %.1f seconds\n", $duration;
printf " Tools used: %d\n", $tool_count;
printf " Tool errors: %d\n", $tool_errors if $tool_errors > 0;
printf " Commands in history: %d\n", $history_count;
print colored(['cyan'], "â" x 40) . "\n";
}
else {
print "\n--- Session Statistics ---\n";
printf "Duration: %.1f seconds\n", $duration;
printf "Tools used: %d\n", $tool_count;
printf "Tool errors: %d\n", $tool_errors if $tool_errors > 0;
printf "Commands in history: %d\n", $history_count;
print "--------------------------\n";
}
return Claude::Agent::Hook::Result->proceed();
}],
),
],
t/03-dangerous-patterns.t view on Meta::CPAN
# Test the dangerous command pattern detection in Tools.pm
# We need to access the internal _check_dangerous function
# Since it's not exported, we'll test it by loading the module and using
# the package namespace
use_ok('Acme::Claude::Shell::Tools');
# Get access to the dangerous patterns check
# This tests the module's internal security patterns
package Acme::Claude::Shell::Tools;
package main;
# Define the same patterns for testing purposes
my @DANGEROUS_PATTERNS = (
{ pattern => qr/\brm\s+(-[rf]+|--recursive|--force)/i,
reason => 'Recursive or forced file deletion' },
{ pattern => qr/\bsudo\b/,
reason => 'Superuser command' },
( run in 0.615 second using v1.01-cache-2.11-cpan-39bf76dae61 )