App-karr

 view release on metacpan or  search on metacpan

lib/App/karr/Cmd/Pick.pm  view on Meta::CPAN

# ABSTRACT: Atomically find and claim the next available task

package App::karr::Cmd::Pick;
our $VERSION = '0.102';
use Moo;
use MooX::Cmd;
use MooX::Options (
  usage_string => 'USAGE: karr pick --claim NAME [--move STATUS] [--status LIST] [--tags LIST]',
);
use App::karr::Role::BoardAccess;
use App::karr::Role::Output;
use App::karr::Task;
use App::karr::Config;
use Time::Piece;

with 'App::karr::Role::BoardAccess', 'App::karr::Role::Output', 'App::karr::Role::ClaimTimeout';


option claim => (
  is => 'ro',
  format => 's',
  required => 1,
  doc => 'Agent name to claim the task for',
);

option status => (
  is => 'ro',
  format => 's',
  doc => 'Source status(es) to pick from (comma-separated)',
);

option move => (
  is => 'ro',
  format => 's',
  doc => 'Move picked task to this status',
);

option tags => (
  is => 'ro',
  format => 's',
  doc => 'Only pick tasks matching at least one tag',
);

sub execute {
  my ($self, $args_ref, $chain_ref) = @_;

  $self->sync_before;

  my $config = App::karr::Config->new(
    file => $self->board_dir->child('config.yml'),
  );

  my @tasks = $self->load_tasks;

  # Filter by status
  if ($self->status) {
    my %allowed = map { $_ => 1 } split /,/, $self->status;
    @tasks = grep { $allowed{$_->status} } @tasks;
  } else {
    # Exclude terminal statuses
    @tasks = grep { $_->status ne 'done' && $_->status ne 'archived' } @tasks;
  }

  # Exclude claimed tasks (unless claim expired)
  my $timeout = $self->_parse_timeout($config->claim_timeout);
  @tasks = grep {
    !$_->has_claimed_by || $self->_claim_expired($_, $timeout)
  } @tasks;

  # Exclude blocked
  @tasks = grep { !$_->has_blocked } @tasks;

  # Filter by tags
  if ($self->tags) {
    my %wanted = map { $_ => 1 } split /,/, $self->tags;
    @tasks = grep {



( run in 2.738 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )