Skip to main content
Glama
analyze-workflow.ts7.35 kB
/** * Developed by eBrook Group. * Copyright © 2026 eBrook Group (https://www.ebrook.com.tw) */ /** * Analyze workflow tool handler * Analyzes task workflow and provides insights */ import { ClickUpService } from "../services/clickup.js"; import { debug, error } from "../utils/logger.js"; import { sanitizeErrorResponse } from "../utils/error-sanitizer.js"; import type { AppConfig } from "../config/env.js"; import type { ClickUpTaskResponse } from "../types/index.js"; /** * Analyze workflow tool handler * @param task_id - ClickUp task ID * @param _config - Application configuration (unused) * @param click_up_service - ClickUp service instance * @returns Tool execution result */ export async function handleAnalyzeWorkflow( task_id: string, _config: AppConfig, click_up_service: ClickUpService ): Promise<{ content: Array<{ type: "text"; text: string }>; isError?: boolean }> { debug(`Analyzing workflow for task: ${task_id}`); // Fetch task from ClickUp const task_res = await click_up_service.getTask(task_id); debug(`ClickUp API response status: ${task_res.status}`); if (task_res.status !== 200) { // Sanitized error message for client const error_msg = `Failed to fetch task ${task_id}. ${sanitizeErrorResponse(task_res.status, task_res.body)}`; // Full error details only in logs debug(`Full API error response: ${JSON.stringify(task_res.body)}`); error(error_msg); return { content: [ { type: "text", text: error_msg, }, ], isError: true, }; } const task = task_res.body as ClickUpTaskResponse; debug(`Successfully fetched task: ${task.name}`); // Analyze workflow const analysis = click_up_service.analyzeTaskWorkflow(task); // Build formatted output const output_lines: string[] = []; output_lines.push("=".repeat(80)); output_lines.push(`📊 WORKFLOW ANALYSIS: ${analysis.task_name}`); output_lines.push("=".repeat(80)); output_lines.push(""); // Status and Progress output_lines.push("📈 STATUS & PROGRESS"); output_lines.push(` Current Status: ${analysis.current_status}`); output_lines.push(` Progress: ${analysis.progress_percentage}%`); const progress_bar = "█".repeat(Math.floor(analysis.progress_percentage / 5)) + "░".repeat(20 - Math.floor(analysis.progress_percentage / 5)); output_lines.push(` [${progress_bar}] ${analysis.progress_percentage}%`); output_lines.push(""); // Time Analysis output_lines.push("⏰ TIME ANALYSIS"); output_lines.push(` Created: ${new Date(analysis.time_analysis.created_at).toLocaleString()}`); output_lines.push(` Last Updated: ${new Date(analysis.time_analysis.last_updated).toLocaleString()}`); output_lines.push(` Days Since Creation: ${analysis.time_analysis.days_since_creation} days`); output_lines.push(` Days Since Update: ${analysis.time_analysis.days_since_update} days`); if (analysis.time_analysis.estimated_hours !== null) { output_lines.push(` Estimated Time: ${analysis.time_analysis.estimated_hours.toFixed(2)} hours`); } if (analysis.time_analysis.spent_hours !== null) { output_lines.push(` Time Spent: ${analysis.time_analysis.spent_hours.toFixed(2)} hours`); } if (analysis.time_analysis.remaining_hours !== null) { output_lines.push(` Remaining Time: ${analysis.time_analysis.remaining_hours.toFixed(2)} hours`); } output_lines.push(""); // Team Analysis output_lines.push("👥 TEAM ANALYSIS"); output_lines.push(` Creator: ${analysis.team_analysis.creator}`); if (analysis.team_analysis.assignees.length > 0) { output_lines.push(` Assignees (${analysis.team_analysis.assignees.length}):`); analysis.team_analysis.assignees.forEach((assignee, index) => { output_lines.push(` ${index + 1}. ${assignee}`); }); } else { output_lines.push(` Assignees: ⚠️ No assignees`); } output_lines.push(` Watchers: ${analysis.team_analysis.watchers_count}`); output_lines.push(""); // Dependency Analysis output_lines.push("🔗 DEPENDENCY ANALYSIS"); output_lines.push(` Depends On: ${analysis.dependency_analysis.depends_on_count} task(s)`); if (analysis.dependency_analysis.depends_on_tasks.length > 0) { analysis.dependency_analysis.depends_on_tasks.forEach((dep_id, index) => { output_lines.push(` ${index + 1}. Task ID: ${dep_id}`); }); } output_lines.push(` Blocked By: ${analysis.dependency_analysis.blocked_by_count} task(s)`); output_lines.push(` Blocking: ${analysis.dependency_analysis.blocking_count} task(s)`); output_lines.push(""); // Subtask Analysis output_lines.push("📝 SUBTASK ANALYSIS"); output_lines.push(` Total Subtasks: ${analysis.subtask_analysis.total_subtasks}`); if (analysis.subtask_analysis.total_subtasks > 0) { output_lines.push(` Completed: ${analysis.subtask_analysis.completed_subtasks}`); output_lines.push(` Pending: ${analysis.subtask_analysis.pending_subtasks}`); } output_lines.push(""); // Risk Factors if (analysis.risk_factors.length > 0) { output_lines.push("⚠️ RISK FACTORS"); analysis.risk_factors.forEach((risk, index) => { output_lines.push(` ${index + 1}. ${risk}`); }); output_lines.push(""); } else { output_lines.push("✅ NO RISK FACTORS IDENTIFIED"); output_lines.push(""); } // Recommendations if (analysis.recommendations.length > 0) { output_lines.push("💡 RECOMMENDATIONS"); analysis.recommendations.forEach((rec, index) => { output_lines.push(` ${index + 1}. ${rec}`); }); output_lines.push(""); } else { output_lines.push("✨ TASK IS WELL CONFIGURED"); output_lines.push(""); } // Overall Assessment output_lines.push("🎯 OVERALL ASSESSMENT"); const risk_level = analysis.risk_factors.length === 0 ? "LOW ✅" : analysis.risk_factors.length <= 2 ? "MEDIUM ⚠️" : "HIGH 🚨"; output_lines.push(` Risk Level: ${risk_level}`); output_lines.push(` Health Score: ${calculateHealthScore(analysis)}/100`); output_lines.push(""); output_lines.push("=".repeat(80)); // Return formatted result return { content: [ { type: "text", text: output_lines.join("\n"), }, { type: "text", text: `\n📊 Detailed Analysis (JSON):\n${JSON.stringify(analysis, null, 2)}`, }, ], isError: false, }; } /** * Calculate task health score based on analysis * @param analysis - Workflow analysis result * @returns Health score (0-100) */ function calculateHealthScore(analysis: import("../types/index.js").TaskWorkflowAnalysis): number { let score = 100; // Deduct points for risk factors score -= analysis.risk_factors.length * 10; // Deduct points for missing assignees if (analysis.team_analysis.assignees.length === 0) { score -= 15; } // Deduct points for stale updates if (analysis.time_analysis.days_since_update > 7) { score -= 10; } // Deduct points for dependencies score -= analysis.dependency_analysis.blocked_by_count * 5; // Bonus points for watchers score += Math.min(analysis.team_analysis.watchers_count * 2, 10); // Ensure score is within 0-100 range return Math.max(0, Math.min(100, score)); }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/tangbodie/clickup-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server