feat(05-02): add task CLI commands

- Add `cw task list --plan <planId>` command
  - Display tasks as table: name, status, type, priority
  - Show count of pending/in_progress/completed/blocked
- Add `cw task get <taskId>` command
  - Display full task details: id, name, description, type, priority, status, order, timestamps
- Add `cw task status <taskId> <status>` command
  - Validate status is one of: pending, in_progress, completed, blocked
  - Confirm status update
This commit is contained in:
Lukas May
2026-01-30 20:34:57 +01:00
parent f54ec5e07e
commit 586f7caa7a

View File

@@ -231,11 +231,93 @@ export function createCli(serverHandler?: (port?: number) => Promise<void>): Com
} }
}); });
program // Task command group
const taskCommand = program
.command('task') .command('task')
.description('Manage tasks') .description('Manage tasks');
.action(() => {
console.log('cw task: not implemented'); // cw task list --plan <planId>
taskCommand
.command('list')
.description('List tasks for a plan')
.requiredOption('--plan <planId>', 'Plan ID to list tasks for')
.action(async (options: { plan: string }) => {
try {
const client = createDefaultTrpcClient();
const tasks = await client.listTasks.query({ planId: options.plan });
if (tasks.length === 0) {
console.log('No tasks found for this plan');
return;
}
// Count by status
const pending = tasks.filter(t => t.status === 'pending' || t.status === 'pending_approval').length;
const inProgress = tasks.filter(t => t.status === 'in_progress').length;
const completed = tasks.filter(t => t.status === 'completed').length;
const blocked = tasks.filter(t => t.status === 'blocked').length;
console.log('Tasks:');
console.log('');
for (const task of tasks) {
const statusLabel = task.status === 'in_progress' ? 'IN_PROGRESS' : task.status.toUpperCase();
const priorityLabel = task.priority === 'high' ? '[HIGH]' : task.priority === 'low' ? '[low]' : '';
console.log(` ${task.order}. ${task.name} [${statusLabel}] ${task.type} ${priorityLabel}`);
}
console.log('');
console.log(`Summary: ${pending} pending, ${inProgress} in progress, ${completed} completed, ${blocked} blocked`);
} catch (error) {
console.error('Failed to list tasks:', (error as Error).message);
process.exit(1);
}
});
// cw task get <taskId>
taskCommand
.command('get <taskId>')
.description('Get task details by ID')
.action(async (taskId: string) => {
try {
const client = createDefaultTrpcClient();
const task = await client.getTask.query({ id: taskId });
console.log(`Task: ${task.name}`);
console.log(` ID: ${task.id}`);
console.log(` Plan: ${task.planId}`);
console.log(` Description: ${task.description ?? '(none)'}`);
console.log(` Type: ${task.type}`);
console.log(` Priority: ${task.priority}`);
console.log(` Status: ${task.status}`);
console.log(` Order: ${task.order}`);
console.log(` Created: ${task.createdAt}`);
console.log(` Updated: ${task.updatedAt}`);
} catch (error) {
console.error('Failed to get task:', (error as Error).message);
process.exit(1);
}
});
// cw task status <taskId> <status>
taskCommand
.command('status <taskId> <status>')
.description('Update task status (pending, in_progress, completed, blocked)')
.action(async (taskId: string, status: string) => {
const validStatuses = ['pending', 'in_progress', 'completed', 'blocked'];
if (!validStatuses.includes(status)) {
console.error(`Invalid status: ${status}`);
console.error(`Valid statuses: ${validStatuses.join(', ')}`);
process.exit(1);
}
try {
const client = createDefaultTrpcClient();
const task = await client.updateTaskStatus.mutate({
id: taskId,
status: status as 'pending' | 'in_progress' | 'completed' | 'blocked',
});
console.log(`Task '${task.name}' status updated to: ${task.status}`);
} catch (error) {
console.error('Failed to update task status:', (error as Error).message);
process.exit(1);
}
}); });
return program; return program;