workspaceId = $this->resolveWorkspaceId(); if ($this->workspaceId === null) { $this->error('Workspace context required. Use --workspace=ID or ensure user is authenticated.'); return 1; } $action = $this->argument('action'); return match ($action) { 'list', 'ls' => $this->listTasks(), 'add', 'new' => $this->addTask(), 'done', 'complete' => $this->completeTask(), 'start', 'wip' => $this->startTask(), 'remove', 'rm', 'delete' => $this->removeTask(), 'show' => $this->showTask(), default => $this->showHelp(), }; } /** * Resolve workspace ID from option or authenticated user. */ protected function resolveWorkspaceId(): ?int { // Explicit workspace option takes precedence if ($workspaceOption = $this->option('workspace')) { return (int) $workspaceOption; } // Fall back to authenticated user's default workspace $user = auth()->user(); if ($user && method_exists($user, 'defaultHostWorkspace')) { $workspace = $user->defaultHostWorkspace(); return $workspace?->id; } return null; } protected function listTasks(): int { $query = Task::forWorkspace($this->workspaceId); $status = $this->option('status'); if ($status && $status !== 'all') { $query->where('status', $status); } elseif (! $status) { $query->active(); // Default: show active only } if ($category = $this->option('category')) { $query->where('category', $category); } $tasks = $query->orderByRaw("FIELD(priority, 'urgent', 'high', 'normal', 'low')") ->orderByRaw("FIELD(status, 'in_progress', 'pending', 'done')") ->limit($this->option('limit')) ->get(); if ($tasks->isEmpty()) { $this->info('No tasks found.'); return 0; } $this->newLine(); foreach ($tasks as $task) { $line = sprintf( ' %s %s #%d %s', $task->status_badge, $task->priority_badge, $task->id, $task->title ); if ($task->category) { $line .= " [{$task->category}]"; } if ($task->file_ref) { $ref = basename($task->file_ref); if ($task->line_ref) { $ref .= ":{$task->line_ref}"; } $line .= " ($ref)"; } $this->line($line); } $this->newLine(); $pending = Task::forWorkspace($this->workspaceId)->pending()->count(); $inProgress = Task::forWorkspace($this->workspaceId)->inProgress()->count(); $this->comment(" {$pending} pending, {$inProgress} in progress"); return 0; } protected function addTask(): int { $title = $this->option('title'); if (! $title) { $title = $this->ask('Task title'); } if (! $title) { $this->error('Title is required'); return 1; } $task = Task::create([ 'workspace_id' => $this->workspaceId, 'title' => $title, 'description' => $this->option('desc'), 'priority' => $this->option('priority'), 'category' => $this->option('category'), 'file_ref' => $this->option('file'), 'line_ref' => $this->option('line'), 'status' => 'pending', ]); $this->info("Created task #{$task->id}: {$task->title}"); return 0; } protected function completeTask(): int { $task = $this->findTask('complete'); if (! $task) { return 1; } $task->update(['status' => 'done']); $this->info("Completed: {$task->title}"); return 0; } protected function startTask(): int { $task = $this->findTask('start'); if (! $task) { return 1; } $task->update(['status' => 'in_progress']); $this->info("Started: {$task->title}"); return 0; } protected function removeTask(): int { $task = $this->findTask('remove'); if (! $task) { return 1; } $title = $task->title; $task->delete(); $this->info("Removed: {$title}"); return 0; } protected function showTask(): int { $task = $this->findTask('show'); if (! $task) { return 1; } $this->newLine(); $this->line(" #{$task->id} {$task->title}"); $this->line(" Status: {$task->status}"); $this->line(" Priority: {$task->priority}"); if ($task->category) { $this->line(" Category: {$task->category}"); } if ($task->description) { $this->newLine(); $this->line(" {$task->description}"); } if ($task->file_ref) { $this->newLine(); $ref = $task->file_ref; if ($task->line_ref) { $ref .= ":{$task->line_ref}"; } $this->comment(" File: {$ref}"); } $this->newLine(); $this->comment(" Created: {$task->created_at->diffForHumans()}"); return 0; } /** * Find a task by ID, scoped to the current workspace. */ protected function findTask(string $action): ?Task { $id = $this->option('id'); if (! $id) { $id = $this->ask("Task ID to {$action}"); } if (! $id) { $this->error('Task ID is required'); return null; } // Always scope by workspace to prevent data leakage $task = Task::forWorkspace($this->workspaceId)->where('id', $id)->first(); if (! $task) { $this->error("Task #{$id} not found"); return null; } return $task; } protected function showHelp(): int { $this->newLine(); $this->line(' Task Manager'); $this->newLine(); $this->line(' Usage:'); $this->line(' php artisan task list List active tasks'); $this->line(' php artisan task add --title="Fix bug" Add a task'); $this->line(' php artisan task start --id=1 Start working on task'); $this->line(' php artisan task done --id=1 Complete a task'); $this->line(' php artisan task show --id=1 Show task details'); $this->line(' php artisan task remove --id=1 Remove a task'); $this->newLine(); $this->line(' Options:'); $this->line(' --workspace=ID Workspace ID (required if not authenticated)'); $this->line(' --priority=urgent|high|normal|low'); $this->line(' --category=feature|bug|task|docs'); $this->line(' --file=path/to/file.php --line=42'); $this->line(' --status=pending|in_progress|done|all'); $this->newLine(); return 0; } }