/** * Comprehensive Task Management Commands * Integrates with TodoWrite/TodoRead for coordination and Memory for persistence */ import { Command } from 'commander'; import chalk from 'chalk'; import { TaskEngine, WorkflowTask, TaskFilter, TaskSort, Workflow, ResourceRequirement, TaskSchedule } from "./engine.ts"; import { generateId } from "../utils/helpers.ts"; export interface TaskCommandContext { taskEngine: TaskEngine; memoryManager?: any; logger?: any; } /** * Task Create Command - Create tasks with dependencies, priority, scheduling, resource requirements */ export function createTaskCreateCommand(context: TaskCommandContext): Command { return new Command('create') .description('Create a new task with comprehensive options') .argument('', 'Task type (e.g., research, development, analysis)') .argument('', 'Task description') .option('-p, --priority ', 'Task priority (0-100)', '50') .option('-d, --dependencies ', 'Comma-separated dependency task IDs') .option('--dep-type ', 'Dependency type: finish-to-start, start-to-start, finish-to-finish, start-to-finish', 'finish-to-start') .option('--dep-lag ', 'Dependency lag in milliseconds', '0') .option('-a, --assign ', 'Assign to specific agent') .option('-t, --tags ', 'Comma-separated tags') .option('--timeout ', 'Task timeout in milliseconds', '300000') .option('--estimated-duration ', 'Estimated duration in milliseconds') .option('--max-retries ', 'Maximum retry attempts', '3') .option('--retry-backoff ', 'Retry backoff in milliseconds', '1000') .option('--retry-multiplier ', 'Retry backoff multiplier', '2') .option('--rollback ', 'Rollback strategy: previous-checkpoint, initial-state, custom', 'previous-checkpoint') .option('--start-time ', 'Scheduled start time (ISO format)') .option('--deadline ', 'Task deadline (ISO format)') .option('--recurring ', 'Recurring interval: daily, weekly, monthly') .option('--recurring-count ', 'Number of recurrences') .option('--timezone ', 'Timezone for scheduling') .option('--cpu ', 'CPU resource requirement') .option('--memory ', 'Memory resource requirement (MB)') .option('--disk ', 'Disk resource requirement (MB)') .option('--network ', 'Network resource requirement (Mbps)') .option('--exclusive-resources', 'Require exclusive access to resources') .option('--input ', 'Task input as JSON string') .option('--dry-run', 'Show what would be created without creating') .action(async (type: string, description: string, options: any) => { try { console.log(chalk.hex("#0066CC")('πŸ”§ Creating new task...')); // Parse dependencies const dependencies = options.dependencies ? options.dependencies.split(',').map((depId: string) => ({ taskId: depId.trim(), type: options.depType, lag: parseInt(options.depLag) })) : []; // Parse resource requirements const resourceRequirements: ResourceRequirement[] = []; if (options.cpu) { resourceRequirements.push({ resourceId: 'cpu', type: 'cpu', amount: parseFloat(options.cpu), unit: 'cores', exclusive: options.exclusiveResources, priority: parseInt(options.priority) }); } if (options.memory) { resourceRequirements.push({ resourceId: 'memory', type: 'memory', amount: parseFloat(options.memory), unit: 'MB', exclusive: options.exclusiveResources, priority: parseInt(options.priority) }); } if (options.disk) { resourceRequirements.push({ resourceId: 'disk', type: 'disk', amount: parseFloat(options.disk), unit: 'MB', exclusive: options.exclusiveResources, priority: parseInt(options.priority) }); } if (options.network) { resourceRequirements.push({ resourceId: 'network', type: 'network', amount: parseFloat(options.network), unit: 'Mbps', exclusive: options.exclusiveResources, priority: parseInt(options.priority) }); } // Parse schedule let schedule: TaskSchedule | undefined; if (options.startTime || options.deadline || options.recurring) { schedule = { startTime: options.startTime ? new Date(options.startTime) : undefined, deadline: options.deadline ? new Date(options.deadline) : undefined, timezone: options.timezone, recurring: options.recurring ? { interval: options.recurring, count: options.recurringCount ? parseInt(options.recurringCount) : undefined } : undefined }; } const taskData: Partial = { type, description, priority: parseInt(options.priority), dependencies, resourceRequirements, schedule, assignedAgent: options.assign, tags: options.tags ? options.tags.split(',').map((t: string) => t.trim()) : [], timeout: parseInt(options.timeout), estimatedDurationMs: options.estimatedDuration ? parseInt(options.estimatedDuration) : undefined, retryPolicy: { maxAttempts: parseInt(options.maxRetries), backoffMs: parseInt(options.retryBackoff), backoffMultiplier: parseFloat(options.retryMultiplier) }, rollbackStrategy: options.rollback, input: options.input ? JSON.parse(options.input) : {} }; if (options.dryRun) { console.log(chalk.hex("#FFAA00")('πŸ” Dry run - Task configuration:')); console.log(JSON.stringify(taskData, null, 2)); return; } // Create task using TodoWrite for coordination if (context.memoryManager) { // Store task creation in memory for coordination await context.memoryManager.store('task:creation', { action: 'create_task', taskData, timestamp: new Date(), requestedBy: 'cli' }); } const task = await context.taskEngine.createTask(taskData); console.log(chalk.hex("#00AA00")('βœ… Task created successfully:')); console.log(chalk.cyan(`πŸ“ ID: ${task.id}`)); console.log(chalk.cyan(`🎯 Type: ${task.type}`)); console.log(chalk.cyan(`πŸ“„ Description: ${task.description}`)); console.log(chalk.cyan(`⚑ Priority: ${task.priority}`)); console.log(chalk.cyan(`🏷️ Tags: ${task.tags.join(', ')}`)); if (task.assignedAgent) { console.log(chalk.cyan(`πŸ‘€ Assigned to: ${task.assignedAgent}`)); } if (task.dependencies.length > 0) { console.log(chalk.cyan(`πŸ”— Dependencies: ${task.dependencies.map(d => d.taskId).join(', ')}`)); } if (task.schedule) { console.log(chalk.cyan(`πŸ“… Schedule:`)); if (task.schedule.startTime) console.log(chalk.cyan(` ⏰ Start: ${task.schedule.startTime.toISOString()}`)); if (task.schedule.deadline) console.log(chalk.cyan(` ⏳ Deadline: ${task.schedule.deadline.toISOString()}`)); } if (resourceRequirements.length > 0) { console.log(chalk.cyan(`πŸ’» Resources: ${resourceRequirements.map(r => `${r.type}:${r.amount}${r.unit}`).join(', ')}`)); } console.log(chalk.hex("#0066CC")(`\nπŸ’‘ Use 'task status ${task.id}' to monitor progress`)); } catch (error) { console.error(chalk.hex("#FF0000")('❌ Error creating task:'), error instanceof Error ? error.message : error); } }); } /** * Task List Command - Display tasks with filtering, sorting, dependency visualization */ export function createTaskListCommand(context: TaskCommandContext): Command { return new Command('list') .description('List tasks with filtering, sorting, and visualization options') .option('-s, --status ', 'Filter by status (pending,queued,running,completed,failed,cancelled)') .option('-a, --agent ', 'Filter by assigned agent') .option('-p, --priority ', 'Filter by priority range (e.g., 50-100)') .option('-t, --tags ', 'Filter by tags (comma-separated)') .option('--created-after ', 'Filter tasks created after date (ISO format)') .option('--created-before ', 'Filter tasks created before date (ISO format)') .option('--due-before ', 'Filter tasks due before date (ISO format)') .option('--search ', 'Search in description, type, and tags') .option('--sort ', 'Sort by field: createdAt, priority, deadline, status, estimatedDuration', 'createdAt') .option('--sort-dir ', 'Sort direction: asc, desc', 'desc') .option('--limit ', 'Limit number of results', '50') .option('--offset ', 'Offset for pagination', '0') .option('--format ', 'Output format: table, json, tree', 'table') .option('--show-dependencies', 'Show dependency relationships') .option('--show-progress', 'Show progress bars') .option('--show-metrics', 'Show performance metrics') .action(async (options: any) => { try { console.log(chalk.hex("#0066CC")('πŸ“‹ Listing tasks...')); // Build filter const filter: TaskFilter = {}; if (options.status) { filter.status = options.status.split(','); } if (options.agent) { filter.assignedAgent = [options.agent]; } if (options.priority) { const [min, max] = options.priority.split('-').map((p: string) => parseInt(p)); filter.priority = { min, max: max || min }; } if (options.tags) { filter.tags = options.tags.split(',').map((t: string) => t.trim()); } if (options.createdAfter) { filter.createdAfter = new Date(options.createdAfter); } if (options.createdBefore) { filter.createdBefore = new Date(options.createdBefore); } if (options.dueBefore) { filter.dueBefore = new Date(options.dueBefore); } if (options.search) { filter.search = options.search; } // Build sort const sort: TaskSort = { field: options.sort, direction: options.sortDir }; // Get tasks const result = await context.taskEngine.listTasks( filter, sort, parseInt(options.limit), parseInt(options.offset) ); if (result.tasks.length === 0) { console.log(chalk.hex("#FFAA00")('πŸ“­ No tasks found matching criteria')); return; } // Store query in memory for coordination if (context.memoryManager) { await context.memoryManager.store('task:query:latest', { filter, sort, results: result.total, timestamp: new Date() }); } console.log(chalk.hex("#00AA00")(`βœ… Found ${result.total} tasks (showing ${result.tasks.length})`)); if (options.format === 'json') { console.log(JSON.stringify(result, null, 2)); } else if (options.format === 'tree' && options.showDependencies) { displayTaskTree(result.tasks); } else { displayTaskTable(result.tasks, { showProgress: options.showProgress, showMetrics: options.showMetrics, showDependencies: options.showDependencies }); } if (result.hasMore) { console.log(chalk.hex("#0066CC")(`\nπŸ’‘ Use --offset ${parseInt(options.offset) + parseInt(options.limit)} to see more results`)); } } catch (error) { console.error(chalk.hex("#FF0000")('❌ Error listing tasks:'), error instanceof Error ? error.message : error); } }); } /** * Task Status Command - Detailed task status with progress tracking, performance metrics */ export function createTaskStatusCommand(context: TaskCommandContext): Command { return new Command('status') .description('Get detailed task status with progress and metrics') .argument('', 'Task ID to check status') .option('--show-logs', 'Show execution logs') .option('--show-checkpoints', 'Show task checkpoints') .option('--show-metrics', 'Show performance metrics') .option('--show-dependencies', 'Show dependency status') .option('--show-resources', 'Show resource allocation') .option('--watch', 'Watch for status changes (refresh every 5s)') .option('--format ', 'Output format: detailed, json, compact', 'detailed') .action(async (taskId: string, options: any) => { try { const displayStatus = async () => { const status = await context.taskEngine.getTaskStatus(taskId); if (!status) { console.log(chalk.hex("#FF0000")(`❌ Task ${taskId} not found`)); return false; } // Store status check in memory if (context.memoryManager) { await context.memoryManager.store(`task:status:${taskId}`, { ...status, checkedAt: new Date(), checkedBy: 'cli' }); } if (options.format === 'json') { console.log(JSON.stringify(status, null, 2)); return true; } console.clear(); console.log(chalk.hex("#0066CC")(`πŸ“Š Task Status: ${taskId}`)); console.log(''.padEnd(60, '=')); const task = status.task; // Basic info console.log(chalk.cyan(`πŸ“ Type: ${task.type}`)); console.log(chalk.cyan(`πŸ“„ Description: ${task.description}`)); console.log(chalk.cyan(`πŸ“Š Status: ${getStatusIcon(task.status)} ${task.status.toUpperCase()}`)); console.log(chalk.cyan(`⚑ Priority: ${task.priority}`)); console.log(chalk.cyan(`🏷️ Tags: ${task.tags.join(', ') || 'None'}`)); if (task.assignedAgent) { console.log(chalk.cyan(`πŸ‘€ Assigned to: ${task.assignedAgent}`)); } // Progress if (task.progressPercentage > 0) { const progressBar = createProgressBar(task.progressPercentage); console.log(chalk.cyan(`πŸ“ˆ Progress: ${progressBar} ${task.progressPercentage.toFixed(1)}%`)); } // Timing console.log(chalk.cyan(`⏰ Created: ${task.createdAt.toLocaleString()}`)); if (task.startedAt) { console.log(chalk.cyan(`πŸš€ Started: ${task.startedAt.toLocaleString()}`)); } if (task.completedAt) { console.log(chalk.cyan(`βœ… Completed: ${task.completedAt.toLocaleString()}`)); } if (task.schedule?.deadline) { const isOverdue = task.schedule.deadline < new Date() && task.status !== 'completed'; console.log(chalk.cyan(`⏳ Deadline: ${task.schedule.deadline.toLocaleString()} ${isOverdue ? chalk.hex("#FF0000")('(OVERDUE)') : ''}`)); } // Duration if (task.estimatedDurationMs) { console.log(chalk.cyan(`⏱️ Estimated: ${formatDuration(task.estimatedDurationMs)}`)); } if (task.actualDurationMs) { console.log(chalk.cyan(`⏱️ Actual: ${formatDuration(task.actualDurationMs)}`)); } // Dependencies if (options.showDependencies && status.dependencies.length > 0) { console.log(chalk.hex("#FFAA00")('\nπŸ”— Dependencies:')); for (const dep of status.dependencies) { const icon = dep.satisfied ? 'βœ…' : '⏳'; console.log(` ${icon} ${dep.task.id}: ${dep.task.description} (${dep.task.status})`); } } // Dependents if (options.showDependencies && status.dependents.length > 0) { console.log(chalk.hex("#FFAA00")('\n⬆️ Dependents:')); for (const dep of status.dependents) { console.log(` πŸ“‹ ${dep.id}: ${dep.description} (${dep.status})`); } } // Resources if (options.showResources && status.resourceStatus.length > 0) { console.log(chalk.hex("#FFAA00")('\nπŸ’» Resources:')); for (const resource of status.resourceStatus) { const icon = resource.allocated ? 'πŸ”’' : resource.available ? 'βœ…' : '❌'; console.log(` ${icon} ${resource.required.type}: ${resource.required.amount}${resource.required.unit}`); } } // Checkpoints if (options.showCheckpoints && task.checkpoints.length > 0) { console.log(chalk.hex("#FFAA00")('\nπŸ“ Checkpoints:')); for (const checkpoint of task.checkpoints) { console.log(` πŸ“Œ ${checkpoint.timestamp.toLocaleString()}: ${checkpoint.description}`); } } // Metrics if (options.showMetrics && status.execution) { console.log(chalk.hex("#FFAA00")('\nπŸ“Š Performance Metrics:')); const metrics = status.execution.metrics; console.log(` πŸ’» CPU: ${metrics.cpuUsage.toFixed(2)}%`); console.log(` 🧠 Memory: ${(metrics.memoryUsage / 1024 / 1024).toFixed(2)} MB`); console.log(` πŸ’Ύ Disk I/O: ${(metrics.diskIO / 1024 / 1024).toFixed(2)} MB`); console.log(` 🌐 Network I/O: ${(metrics.networkIO / 1024 / 1024).toFixed(2)} MB`); } // Logs if (options.showLogs && status.execution?.logs.length) { console.log(chalk.hex("#FFAA00")('\nπŸ“ Recent Logs:')); const recentLogs = status.execution.logs.slice(-5); for (const log of recentLogs) { const levelColor = getLogLevelColor(log.level); console.log(` ${log.timestamp.toLocaleTimeString()} ${levelColor(log.level.toUpperCase())}: ${log.message}`); } } // Error info if (task.error) { console.log(chalk.hex("#FF0000")('\n❌ Error:')); console.log(chalk.hex("#FF0000")(` ${task.error.message}`)); } console.log(''.padEnd(60, '=')); console.log(chalk.hex("#0066CC")(`πŸ”„ Last updated: ${new Date().toLocaleTimeString()}`)); return true; }; if (options.watch) { console.log(chalk.hex("#0066CC")('πŸ‘€ Watching task status (press Ctrl+C to stop)...')); const interval = setInterval(async () => { const success = await displayStatus(); if (!success) { clearInterval(interval); } }, 5000); // Initial display await displayStatus(); // Handle Ctrl+C process.on('SIGINT', () => { clearInterval(interval); console.log(chalk.hex("#FFAA00")('\nπŸ‘‹ Stopped watching')); process.exit(0); }); } else { await displayStatus(); } } catch (error) { console.error(chalk.hex("#FF0000")('❌ Error getting task status:'), error instanceof Error ? error.message : error); } }); } /** * Task Cancel Command - Safe task cancellation with rollback and cleanup */ export function createTaskCancelCommand(context: TaskCommandContext): Command { return new Command('cancel') .description('Cancel a task with optional rollback and cleanup') .argument('', 'Task ID to cancel') .option('-r, --reason ', 'Cancellation reason', 'User requested') .option('--no-rollback', 'Skip rollback to previous checkpoint') .option('--force', 'Force cancellation even if task is completed') .option('--cascade', 'Cancel dependent tasks as well') .option('--dry-run', 'Show what would be cancelled without cancelling') .action(async (taskId: string, options: any) => { try { console.log(chalk.hex("#0066CC")(`⏹️ Preparing to cancel task: ${taskId}`)); const status = await context.taskEngine.getTaskStatus(taskId); if (!status) { console.log(chalk.hex("#FF0000")(`❌ Task ${taskId} not found`)); return; } const task = status.task; if (task.status === 'completed' && !options.force) { console.log(chalk.hex("#FFAA00")(`⚠️ Task ${taskId} is already completed. Use --force to cancel anyway.`)); return; } if (task.status === 'cancelled') { console.log(chalk.hex("#FFAA00")(`⚠️ Task ${taskId} is already cancelled`)); return; } console.log(chalk.cyan(`πŸ“‹ Task: ${task.description}`)); console.log(chalk.cyan(`πŸ“Š Current status: ${task.status}`)); console.log(chalk.cyan(`πŸ“ˆ Progress: ${task.progressPercentage.toFixed(1)}%`)); if (options.cascade && status.dependents.length > 0) { console.log(chalk.cyan(`πŸ”— Will also cancel ${status.dependents.length} dependent tasks:`)); for (const dep of status.dependents) { console.log(` πŸ“‹ ${dep.id}: ${dep.description}`); } } if (!options.noRollback && task.checkpoints.length > 0) { console.log(chalk.cyan(`πŸ”„ Will rollback to previous checkpoint (${task.checkpoints.length} available)`)); } if (options.dryRun) { console.log(chalk.hex("#FFAA00")('πŸ” Dry run - no actual cancellation performed')); return; } // Store cancellation request in memory for coordination if (context.memoryManager) { await context.memoryManager.store(`task:cancellation:${taskId}`, { taskId, reason: options.reason, rollback: !options.noRollback, cascade: options.cascade, requestedAt: new Date(), requestedBy: 'cli' }); } console.log(chalk.hex("#FFAA00")('⏳ Cancelling task...')); await context.taskEngine.cancelTask( taskId, options.reason, !options.noRollback ); console.log(chalk.hex("#00AA00")(`βœ… Task ${taskId} cancelled successfully`)); console.log(chalk.cyan(`πŸ“ Reason: ${options.reason}`)); if (!options.noRollback && task.checkpoints.length > 0) { console.log(chalk.hex("#00AA00")('πŸ”„ Rollback completed')); } if (options.cascade && status.dependents.length > 0) { console.log(chalk.hex("#0066CC")('πŸ”— Cancelling dependent tasks...')); for (const dep of status.dependents) { try { await context.taskEngine.cancelTask(dep.id, `Parent task ${taskId} was cancelled`); console.log(chalk.hex("#00AA00")(` βœ… Cancelled: ${dep.id}`)); } catch (error) { console.log(chalk.hex("#FF0000")(` ❌ Failed to cancel: ${dep.id} - ${error}`)); } } } } catch (error) { console.error(chalk.hex("#FF0000")('❌ Error cancelling task:'), error instanceof Error ? error.message : error); } }); } /** * Task Workflow Command - Workflow execution engine with parallel processing */ export function createTaskWorkflowCommand(context: TaskCommandContext): Command { return new Command('workflow') .description('Execute and manage workflows with parallel processing') .addCommand( new Command('create') .description('Create a new workflow') .argument('', 'Workflow name') .option('-d, --description ', 'Workflow description') .option('-f, --file ', 'Load workflow from JSON file') .option('--max-concurrent ', 'Maximum concurrent tasks', '10') .option('--strategy ', 'Parallelism strategy: breadth-first, depth-first, priority-based', 'priority-based') .option('--error-handling ', 'Error handling: fail-fast, continue-on-error, retry-failed', 'fail-fast') .option('--max-retries ', 'Maximum workflow retries', '3') .action(async (name: string, options: any) => { try { console.log(chalk.hex("#0066CC")(`πŸ”§ Creating workflow: ${name}`)); let workflowData: Partial = { name, description: options.description, parallelism: { maxConcurrent: parseInt(options.maxConcurrent), strategy: options.strategy }, errorHandling: { strategy: options.errorHandling, maxRetries: parseInt(options.maxRetries) } }; if (options.file) { const fs = await import('node:fs/promises'); const fileContent = await fs.readFile(options.file, 'utf8'); const fileData = JSON.parse(fileContent); workflowData = { ...workflowData, ...fileData }; } const workflow = await context.taskEngine.createWorkflow(workflowData); console.log(chalk.hex("#00AA00")('βœ… Workflow created successfully:')); console.log(chalk.cyan(`πŸ“ ID: ${workflow.id}`)); console.log(chalk.cyan(`πŸ“„ Name: ${workflow.name}`)); console.log(chalk.cyan(`πŸ“‹ Tasks: ${workflow.tasks.length}`)); console.log(chalk.cyan(`⚑ Max concurrent: ${workflow.parallelism.maxConcurrent}`)); console.log(chalk.cyan(`🎯 Strategy: ${workflow.parallelism.strategy}`)); } catch (error) { console.error(chalk.hex("#FF0000")('❌ Error creating workflow:'), error instanceof Error ? error.message : error); } }) ) .addCommand( new Command('execute') .description('Execute a workflow') .argument('', 'Workflow ID to execute') .option('--variables ', 'Workflow variables as JSON') .option('--dry-run', 'Show execution plan without executing') .option('--monitor', 'Monitor execution progress') .action(async (workflowId: string, options: any) => { try { console.log(chalk.hex("#0066CC")(`πŸš€ Executing workflow: ${workflowId}`)); // This would need access to workflow storage // For now, showing the structure if (options.dryRun) { console.log(chalk.hex("#FFAA00")('πŸ” Dry run - execution plan would be shown here')); return; } if (options.monitor) { console.log(chalk.hex("#0066CC")('πŸ‘€ Monitoring workflow execution...')); // Would implement real-time monitoring } console.log(chalk.hex("#00AA00")('βœ… Workflow execution started')); } catch (error) { console.error(chalk.hex("#FF0000")('❌ Error executing workflow:'), error instanceof Error ? error.message : error); } }) ) .addCommand( new Command('visualize') .description('Visualize workflow dependency graph') .argument('', 'Workflow ID to visualize') .option('--format ', 'Output format: ascii, dot, json', 'ascii') .option('--output ', 'Output file (for dot/json formats)') .action(async (workflowId: string, options: any) => { try { console.log(chalk.hex("#0066CC")(`πŸ“Š Visualizing workflow: ${workflowId}`)); // Get dependency graph if available const dependencyGraph = (context.taskEngine as any).getDependencyGraph?.() || null; if (options.format === 'json') { const output = JSON.stringify(dependencyGraph, null, 2); if (options.output) { const fs = await import('node:fs/promises'); await fs.writeFile(options.output, output); console.log(chalk.hex("#00AA00")(`πŸ’Ύ Graph saved to: ${options.output}`)); } else { console.log(output); } } else if (options.format === 'ascii') { displayDependencyGraph(dependencyGraph); } } catch (error) { console.error(chalk.hex("#FF0000")('❌ Error visualizing workflow:'), error instanceof Error ? error.message : error); } }) ); } // Helper functions for display function getStatusIcon(status: string): string { switch (status) { case 'pending': return '⏳'; case 'queued': return 'πŸ“‹'; case 'running': return 'πŸƒ'; case 'completed': return 'βœ…'; case 'failed': return '❌'; case 'cancelled': return '⏹️'; default: return '❓'; } } function createProgressBar(percentage: number, width: number = 20): string { const filled = Math.round((percentage / 100) * width); const empty = width - filled; return chalk.hex("#00AA00")('β–ˆ'.repeat(filled)) + chalk.gray('β–‘'.repeat(empty)); } function formatDuration(ms: number): string { const seconds = Math.floor(ms / 1000); const minutes = Math.floor(seconds / 60); const hours = Math.floor(minutes / 60); if (hours > 0) return `${hours}h ${minutes % 60}m`; if (minutes > 0) return `${minutes}m ${seconds % 60}s`; return `${seconds}s`; } function getLogLevelColor(level: string): any { switch (level) { case 'debug': return chalk.gray; case 'info': return chalk.blue; case 'warn': return chalk.yellow; case 'error': return chalk.red; default: return chalk.white; } } function displayTaskTable(tasks: WorkflowTask[], options: any): void { console.log(chalk.hex("#FFAA00")('\nπŸ“‹ Tasks:')); console.log('─'.repeat(80)); for (const task of tasks) { const statusIcon = getStatusIcon(task.status); const progress = options.showProgress && task.progressPercentage > 0 ? ` ${createProgressBar(task.progressPercentage, 10)} ${task.progressPercentage.toFixed(0)}%` : ''; console.log(`${statusIcon} ${task.id.substring(0, 8)} | ${task.type.padEnd(12)} | ${task.description.substring(0, 30).padEnd(30)} | P:${task.priority}${progress}`); } } function displayTaskTree(tasks: WorkflowTask[]): void { console.log(chalk.hex("#FFAA00")('\n🌳 Task Dependency Tree:')); // Implementation would show hierarchical view of dependencies console.log('Tree visualization would be implemented here'); } function displayDependencyGraph(graph: { nodes: any[]; edges: any[] }): void { console.log(chalk.hex("#FFAA00")('\nπŸ•ΈοΈ Dependency Graph:')); console.log(`πŸ“Š Nodes: ${graph.nodes.length}, Edges: ${graph.edges.length}`); // Simple ASCII representation for (const node of graph.nodes) { const incoming = graph.edges.filter(e => e.to === node.id); const outgoing = graph.edges.filter(e => e.from === node.id); const prefix = incoming.length > 0 ? '← ' : ' '; const suffix = outgoing.length > 0 ? ' β†’' : ' '; console.log(`${prefix}${getStatusIcon(node.status)} ${node.id} (${node.label})${suffix}`); } }