Claude-Agent
view release on metacpan or search on metacpan
lib/Claude/Agent/Hook/Executor.pm view on Meta::CPAN
package Claude::Agent::Hook::Executor;
use 5.020;
use strict;
use warnings;
use Claude::Agent::Logger '$log';
use Types::Common -types;
use Scalar::Util qw(blessed);
use Try::Tiny;
use Future;
use Claude::Agent::Hook;
use Claude::Agent::Hook::Context;
use Claude::Agent::Hook::Result;
use Marlin
'hooks' => sub { {} }, # Event name => arrayref of matchers
'session_id==.', # Read-write, set after init message
'cwd?',
'loop?'; # Optional IO::Async::Loop for async hooks
=head1 NAME
Claude::Agent::Hook::Executor - Executes Perl hooks for Claude Agent SDK
=head1 SYNOPSIS
use Claude::Agent::Hook::Executor;
use Claude::Agent::Hook::Matcher;
my $executor = Claude::Agent::Hook::Executor->new(
hooks => {
PreToolUse => [
Claude::Agent::Hook::Matcher->new(
matcher => 'Bash',
hooks => [sub {
my ($input, $tool_use_id, $context) = @_;
if ($input->{tool_input}{command} =~ /rm -rf/) {
return Claude::Agent::Hook::Result->deny(
reason => 'Dangerous command blocked',
);
}
return Claude::Agent::Hook::Result->proceed();
}],
),
],
},
session_id => $session_id,
);
# Execute pre-tool-use hooks
my $result = $executor->run_pre_tool_use($tool_name, $tool_input, $tool_use_id);
if ($result->{decision} eq 'deny') {
# Block the tool
}
=head1 DESCRIPTION
This module executes Perl hook callbacks when tool use events occur.
It intercepts tool calls in the Query layer and runs matching hooks.
=head1 ATTRIBUTES
=head2 hooks
HashRef of hook event names to arrayrefs of L<Claude::Agent::Hook::Matcher> objects.
=head2 session_id
Current session ID (set after init message).
=head2 cwd
Current working directory.
=head2 loop
Optional IO::Async::Loop for async hook execution.
=head1 METHODS
=head2 run_pre_tool_use
my $future = $executor->run_pre_tool_use($tool_name, $tool_input, $tool_use_id);
Execute PreToolUse hooks for a tool call. Returns a Future that resolves to a hashref with:
{
decision => 'continue' | 'allow' | 'deny',
reason => 'optional reason',
updated_input => { ... }, # for 'allow' decision
}
=cut
sub run_pre_tool_use {
my ($self, $tool_name, $tool_input, $tool_use_id) = @_;
return $self->_run_hooks(
( run in 0.735 second using v1.01-cache-2.11-cpan-75ffa21a3d4 )