Claude-Agent
view release on metacpan or search on metacpan
"Crypt::URandom" : "0.54",
"File::Which" : "1.27",
"Future::AsyncAwait" : "0.60",
"IO::Async" : "0.80",
"JSON::Lines" : "1.10",
"Log::Any" : "1.710",
"Marlin" : "0.007000",
"Term::Choose" : "1.7",
"Term::ProgressSpinner" : "1.02",
"Term::ReadKey" : "2.38",
"Try::Tiny" : "0.30",
"Type::Tiny" : "2.0",
"Types::Common" : "2.0",
"namespace::clean" : "0.27",
"perl" : "5.020"
}
},
"test" : {
"requires" : {
"Test::Deep" : "1.0",
"Test::Exception" : "0.43",
Crypt::URandom: '0.54'
File::Which: '1.27'
Future::AsyncAwait: '0.60'
IO::Async: '0.80'
JSON::Lines: '1.10'
Log::Any: '1.710'
Marlin: '0.007000'
Term::Choose: '1.7'
Term::ProgressSpinner: '1.02'
Term::ReadKey: '2.38'
Try::Tiny: '0.30'
Type::Tiny: '2.0'
Types::Common: '2.0'
namespace::clean: '0.27'
perl: '5.020'
resources:
repository: https://github.com/lnation/Claude-Agent.git
version: '0.13'
x_serialization_backend: 'CPAN::Meta::YAML version 0.018'
Makefile.PL view on Meta::CPAN
'Test::Exception' => '0.43',
'Test::Deep' => '1.0',
},
PREREQ_PM => {
'Marlin' => '0.007000',
'JSON::Lines' => '1.10',
'IO::Async' => '0.80',
'Future::AsyncAwait' => '0.60',
'Type::Tiny' => '2.0',
'Types::Common' => '2.0',
'Try::Tiny' => '0.30',
'File::Which' => '1.27',
'Const::XS' => '1.03',
'namespace::clean' => '0.27',
'Crypt::URandom' => '0.54',
'Log::Any' => '1.710',
# CLI utilities (Claude::Agent::CLI)
'Term::Choose' => '1.7',
'Term::ReadKey' => '2.38',
'Term::ProgressSpinner' => '1.02',
},
- Valid Anthropic API key or Claude subscription
DEPENDENCIES
- Marlin (fast Moo-compatible OO)
- IO::Async
- Future::AsyncAwait
- Cpanel::JSON::XS
- JSON::Lines
- Types::Common
- Try::Tiny
- File::Which
INSTALLATION
To install this module, run the following commands:
perl Makefile.PL
make
make test
make install
examples/09-error-handling.pl view on Meta::CPAN
#
use 5.020;
use strict;
use warnings;
use lib 'lib';
use Claude::Agent qw(query);
use Claude::Agent::Options;
use Claude::Agent::Error;
use Try::Tiny;
# Example 1: Handle CLI not found
say "Example 1: Handling CLI errors";
say "-" x 50;
try {
my $options = Claude::Agent::Options->new(
allowed_tools => ['Read'],
permission_mode => 'bypassPermissions',
);
lib/Claude/Agent/Error.pm view on Meta::CPAN
use Marlin
'message!' => Str;
=head1 NAME
Claude::Agent::Error - Exception classes for Claude Agent SDK
=head1 SYNOPSIS
use Claude::Agent::Error;
use Try::Tiny;
try {
# ... code that might fail ...
}
catch {
if ($_->isa('Claude::Agent::Error::CLINotFound')) {
die "Please install Claude CLI first";
}
};
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?',
lib/Claude/Agent/Hook/Matcher.pm view on Meta::CPAN
package Claude::Agent::Hook::Matcher;
use 5.020;
use strict;
use warnings;
use Claude::Agent::Logger '$log';
use Scalar::Util qw(blessed);
use Try::Tiny;
use Future;
use Types::Common -types;
use Marlin
'matcher', # Regex pattern for tool names (optional)
'hooks' => sub { [] }, # ArrayRef of coderefs
'timeout' => sub { 60 }; # Timeout in seconds
=head1 NAME
Claude::Agent::Hook::Matcher - Hook matcher for Claude Agent SDK
lib/Claude/Agent/Hook/Matcher.pm view on Meta::CPAN
my $pattern = $self->matcher;
# If it's a simple string (no regex metacharacters), do exact match
# Use quotemeta to reliably detect plain strings vs regex patterns
if ($pattern eq quotemeta($pattern)) {
return $tool_name eq $pattern;
}
# Otherwise treat as regex with timeout protection against ReDoS
# Use Try::Tiny with finally to ensure alarm is always cleared
my $result;
try {
# Validate pattern length to mitigate ReDoS
if (length($pattern) > 1000) {
die "Pattern too long\n";
}
# Detect potentially dangerous ReDoS patterns (works on all platforms)
# Look for nested quantifiers like (a+)+ or (a*)*
if ($pattern =~ /\([^)]*[+*][^)]*\)[+*]/ ||
lib/Claude/Agent/MCP/SDKRunner.pm view on Meta::CPAN
use 5.020;
use strict;
use warnings;
use Claude::Agent::Logger '$log';
use IO::Socket::UNIX;
use IO::Async::Loop;
use IO::Async::Stream;
use JSON::Lines;
use Try::Tiny;
=head1 NAME
Claude::Agent::MCP::SDKRunner - MCP server runner for SDK tools
=head1 DESCRIPTION
This module implements the MCP server protocol and forwards tool calls
to the parent Perl process via a Unix socket. It is spawned as a child
process by the Claude CLI.
lib/Claude/Agent/MCP/SDKServer.pm view on Meta::CPAN
use strict;
use warnings;
use Claude::Agent::Logger '$log';
use Errno qw(ENOENT);
use IO::Socket::UNIX;
use JSON::Lines;
use File::Temp qw(tempdir);
use File::Spec;
use Cwd qw(abs_path);
use Try::Tiny;
=head1 NAME
Claude::Agent::MCP::SDKServer - Socket-based MCP server for SDK tools
=head1 DESCRIPTION
This module manages the IPC between the Perl SDK and the MCP server runner.
It creates a Unix socket, spawns the runner as a stdio MCP server, and
handles tool call requests from the runner by executing the local handlers.
lib/Claude/Agent/Query.pm view on Meta::CPAN
return;
},
)
};
use IO::Async::Loop;
use IO::Async::Process;
use Future;
use Future::AsyncAwait;
use JSON::Lines;
use Try::Tiny;
use File::Which qw(which);
use File::Spec;
use Claude::Agent::Options;
use Claude::Agent::Message;
use Claude::Agent::Error;
use Claude::Agent::MCP::SDKServer;
use Claude::Agent::Hook::Executor;
use Claude::Agent::DryRun qw(create_dry_run_hooks);
t/10-errors.t view on Meta::CPAN
isa_ok($@, 'Claude::Agent::Error', 'PermissionDenied can be caught as Error');
eval { die $hook_error };
isa_ok($@, 'Claude::Agent::Error', 'HookError can be caught as Error');
# Test throw() class method
eval { Claude::Agent::Error::CLINotFound->throw(message => 'not found') };
isa_ok($@, 'Claude::Agent::Error::CLINotFound', 'throw() creates and dies with error');
# Test using errors in try/catch pattern
use Try::Tiny;
my $caught_type;
try {
die Claude::Agent::Error::CLINotFound->new(message => 'not found');
}
catch {
if ($_->isa('Claude::Agent::Error::CLINotFound')) {
$caught_type = 'cli_not_found';
}
elsif ($_->isa('Claude::Agent::Error')) {
( run in 2.504 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )