Acme-Claude-Shell

 view release on metacpan or  search on metacpan

lib/Acme/Claude/Shell/Hooks.pm  view on Meta::CPAN


    # Tool name pattern - matches mcp__shell-tools__execute_command
    my $execute_cmd_pattern = 'execute_command$';
    # Match any tool from our shell-tools server
    my $any_shell_tool = 'shell-tools__';

    # Track session start time
    $session->{_session_start} //= time();
    $session->{_tool_count} //= 0;
    $session->{_tool_errors} //= 0;

    return {
        # PreToolUse: Audit logging - track what tools Claude wants to use
        PreToolUse => [
            Claude::Agent::Hook::Matcher->new(
                matcher => $any_shell_tool,
                hooks   => [sub {
                    my ($input, $tool_use_id, $context) = @_;

                    my $tool_name = $input->{tool_name} // 'unknown';
                    my $tool_input = $input->{tool_input} // {};

                    # Extract short tool name (after mcp__shell-tools__)
                    my $short_name = $tool_name;
                    $short_name =~ s/^mcp__shell-tools__//;

                    # Log tool usage in verbose mode
                    if ($session->{verbose}) {
                        if ($session->colorful) {
                            status('info', "Tool: $short_name");
                        }
                        else {
                            print "[Tool] $short_name\n";
                        }
                    }

                    # Track in audit log if enabled
                    if ($session->{audit_log}) {
                        push @{$session->{_audit_log} //= []}, {
                            time       => time(),
                            tool       => $short_name,
                            input      => $tool_input,
                            tool_use_id => $tool_use_id,
                        };
                    }

                    return Claude::Agent::Hook::Result->proceed();
                }],
            ),
        ],

        # PostToolUse: Stop spinner after command execution and track stats
        PostToolUse => [
            Claude::Agent::Hook::Matcher->new(
                matcher => $execute_cmd_pattern,
                hooks   => [sub {
                    my ($input, $tool_use_id, $context) = @_;
                    # Stop the execution spinner
                    if ($session->_spinner) {
                        stop_spinner($session->_spinner);
                        $session->_spinner(undef);
                    }
                    # Track tool usage
                    $session->{_tool_count}++;
                    return Claude::Agent::Hook::Result->proceed();
                }],
            ),
        ],

        # PostToolUseFailure: Handle tool failures gracefully
        PostToolUseFailure => [
            Claude::Agent::Hook::Matcher->new(
                matcher => $any_shell_tool,
                hooks   => [sub {
                    my ($input, $tool_use_id, $context) = @_;

                    my $tool_name = $input->{tool_name} // 'unknown';
                    my $error = $input->{error} // 'Unknown error';

                    # Extract short tool name
                    my $short_name = $tool_name;
                    $short_name =~ s/^mcp__shell-tools__//;

                    # Track error count
                    $session->{_tool_errors}++;

                    # Show error to user
                    if ($session->colorful) {
                        status('error', "Tool '$short_name' failed: $error");
                    }
                    else {
                        print "[ERROR] Tool '$short_name' failed: $error\n";
                    }

                    return Claude::Agent::Hook::Result->proceed();
                }],
            ),
        ],

        # Stop: Show session statistics when the agent stops
        Stop => [
            Claude::Agent::Hook::Matcher->new(
                matcher => '.*',  # Match any stop reason
                hooks   => [sub {
                    my ($input, $tool_use_id, $context) = @_;

                    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";
                    }



( run in 1.459 second using v1.01-cache-2.11-cpan-d80b1682f3f )