mcp-adr-analysis-server
Version:
MCP server for analyzing Architectural Decision Records and project architecture
668 lines • 26.9 kB
JavaScript
/**
* Enhanced error types for better user experience
*
* Provides structured error handling with actionable suggestions
* and contextual information to help users resolve issues.
*/
/**
* Enhanced base error class with comprehensive diagnostic information
*/
export class EnhancedError extends Error {
code;
severity;
suggestions;
diagnostics;
recoverable;
retryable;
constructor(message, code, options) {
super(message, { cause: options.cause });
this.name = this.constructor.name;
this.code = code;
this.severity = options.severity || 'medium';
this.suggestions = options.suggestions || [];
this.diagnostics = options.diagnostics;
this.recoverable = options.recoverable ?? true;
this.retryable = options.retryable ?? false;
}
/**
* Get formatted error message with diagnostic information
*/
getDetailedMessage() {
const lines = [
`${this.name}: ${this.message}`,
`Code: ${this.code}`,
`Severity: ${this.severity}`,
`Component: ${this.diagnostics.component}`,
`Operation: ${this.diagnostics.operation}`,
`Timestamp: ${this.diagnostics.timestamp.toISOString()}`,
];
if (this.diagnostics.context && Object.keys(this.diagnostics.context).length > 0) {
lines.push(`Context: ${JSON.stringify(this.diagnostics.context, null, 2)}`);
}
if (this.diagnostics.performanceMetrics) {
lines.push(`Performance: ${JSON.stringify(this.diagnostics.performanceMetrics, null, 2)}`);
}
if (this.suggestions.length > 0) {
lines.push('Suggestions:');
this.suggestions.forEach(s => {
lines.push(` - ${s.action}: ${s.description}`);
if (s.example) {
lines.push(` Example: ${s.example}`);
}
});
}
return lines.join('\n');
}
/**
* Convert error to structured object for logging
*/
toLogObject() {
return {
name: this.name,
message: this.message,
code: this.code,
severity: this.severity,
recoverable: this.recoverable,
retryable: this.retryable,
diagnostics: this.diagnostics,
suggestions: this.suggestions,
stack: this.stack,
cause: this.cause
? {
name: this.cause.name,
message: this.cause.message,
stack: this.cause.stack,
}
: undefined,
};
}
}
/**
* Operation Queue specific errors
*/
export class OperationQueueError extends EnhancedError {
constructor(message, code, diagnostics, options = {}) {
super(message, code, {
...options,
diagnostics: {
...diagnostics,
component: diagnostics.component || 'OperationQueue',
},
});
}
static queueOverflow(queueSize, maxSize, diagnostics) {
return new OperationQueueError(`Operation queue overflow: ${queueSize}/${maxSize} operations`, 'QUEUE_OVERFLOW', diagnostics, {
severity: 'high',
retryable: true,
suggestions: [
{
action: 'Reduce operation frequency',
description: 'Slow down the rate of operations being queued',
},
{
action: 'Increase queue size',
description: `Consider increasing maxQueueSize from ${maxSize} to handle peak loads`,
},
{
action: 'Enable backpressure',
description: 'Use backpressure handling to automatically throttle operations',
},
{
action: 'Check for stuck operations',
description: 'Verify that operations are completing and not hanging indefinitely',
},
],
});
}
static operationTimeout(operationId, timeoutMs, diagnostics) {
return new OperationQueueError(`Operation ${operationId} timed out after ${timeoutMs}ms`, 'OPERATION_TIMEOUT', diagnostics, {
severity: 'medium',
retryable: true,
suggestions: [
{
action: 'Increase timeout value',
description: `Consider increasing timeout from ${timeoutMs}ms for complex operations`,
},
{
action: 'Break down large operations',
description: 'Split complex operations into smaller, faster chunks',
},
{
action: 'Check system resources',
description: 'Verify system has adequate CPU and memory for the operation',
},
{
action: 'Review operation complexity',
description: 'Analyze if the operation can be optimized for better performance',
},
],
});
}
static concurrencyViolation(activeCount, maxConcurrency, diagnostics) {
return new OperationQueueError(`Concurrency limit exceeded: ${activeCount}/${maxConcurrency} active operations`, 'CONCURRENCY_VIOLATION', diagnostics, {
severity: 'high',
recoverable: false,
suggestions: [
{
action: 'Check semaphore implementation',
description: 'Verify that concurrency control is working correctly',
},
{
action: 'Review operation lifecycle',
description: 'Ensure operations are properly cleaned up when completed',
},
{
action: 'Increase concurrency limit',
description: `Consider increasing maxConcurrency from ${maxConcurrency} if system can handle it`,
},
],
});
}
static shutdownInProgress(diagnostics) {
return new OperationQueueError('Cannot queue operation: shutdown in progress', 'SHUTDOWN_IN_PROGRESS', diagnostics, {
severity: 'medium',
recoverable: false,
retryable: false,
suggestions: [
{
action: 'Wait for shutdown to complete',
description: 'Allow the current shutdown process to finish',
},
{
action: 'Create new queue instance',
description: 'Initialize a new operation queue after shutdown completes',
},
],
});
}
}
/**
* Data Consistency Checker specific errors
*/
export class DataConsistencyError extends EnhancedError {
constructor(message, code, diagnostics, options = {}) {
super(message, code, {
...options,
diagnostics: {
...diagnostics,
component: diagnostics.component || 'DataConsistencyChecker',
},
});
}
static validationFailure(validationType, affectedItems, diagnostics) {
return new DataConsistencyError(`Data validation failed for ${validationType}: ${affectedItems.length} items affected`, 'VALIDATION_FAILURE', diagnostics, {
severity: 'high',
recoverable: true,
suggestions: [
{
action: 'Review affected items',
description: `Check the ${affectedItems.length} items that failed validation`,
},
{
action: 'Run auto-fix if available',
description: 'Use auto-fix functionality to correct common issues',
},
{
action: 'Manual data correction',
description: 'Manually review and correct the data inconsistencies',
},
{
action: 'Restore from backup',
description: 'Consider restoring from a known good backup if corruption is extensive',
},
],
});
}
static metadataSyncFailure(taskCount, metadataCount, diagnostics) {
return new DataConsistencyError(`Metadata sync failure: ${taskCount} tasks vs ${metadataCount} metadata entries`, 'METADATA_SYNC_FAILURE', diagnostics, {
severity: 'medium',
recoverable: true,
suggestions: [
{
action: 'Regenerate metadata',
description: 'Rebuild metadata from current task data',
},
{
action: 'Remove orphaned metadata',
description: 'Clean up metadata entries without corresponding tasks',
},
{
action: 'Create missing metadata',
description: 'Generate metadata for tasks that are missing it',
},
],
});
}
static dateValidationFailure(invalidDates, diagnostics) {
return new DataConsistencyError(`Date validation failed: ${invalidDates.length} invalid dates found`, 'DATE_VALIDATION_FAILURE', diagnostics, {
severity: 'medium',
recoverable: true,
suggestions: [
{
action: 'Fix date formats',
description: 'Convert invalid dates to ISO 8601 format (YYYY-MM-DDTHH:mm:ss.sssZ)',
example: '2024-01-15T10:30:00.000Z',
},
{
action: 'Remove invalid dates',
description: 'Clear invalid date fields and let system set defaults',
},
{
action: 'Use date parsing utilities',
description: 'Implement robust date parsing to handle various formats',
},
],
});
}
static circularDependencyDetected(cycle, diagnostics) {
return new DataConsistencyError(`Circular dependency detected: ${cycle.join(' → ')}`, 'CIRCULAR_DEPENDENCY', diagnostics, {
severity: 'high',
recoverable: true,
suggestions: [
{
action: 'Break dependency cycle',
description: `Remove one dependency from the cycle: ${cycle.join(' → ')}`,
},
{
action: 'Restructure task relationships',
description: 'Consider using task hierarchy instead of dependencies',
},
{
action: 'Review task design',
description: 'Break down complex tasks to eliminate circular dependencies',
},
],
});
}
}
/**
* Enhanced error class for TODO management operations
*
* Provides structured error information with contextual suggestions
* to help users understand and resolve issues quickly.
*
* @example
* ```typescript
* try {
* await manager.updateTask({ taskId: "invalid", updates: {} });
* } catch (error) {
* if (error instanceof TodoManagerError) {
* console.log(`Error: ${error.message}`);
* console.log(`Code: ${error.code}`);
* error.suggestions.forEach(s => {
* console.log(`- ${s.action}: ${s.description}`);
* });
* }
* }
* ```
*/
export class TodoManagerError extends Error {
code;
field;
value;
validValues;
suggestions;
taskId;
suggestion;
constructor(message, code, options = {}) {
super(message);
this.name = 'TodoManagerError';
this.code = code;
if (options.field !== undefined)
this.field = options.field;
this.value = options.value;
if (options.validValues !== undefined)
this.validValues = options.validValues;
this.suggestions = options.suggestions || [];
if (options.taskId !== undefined)
this.taskId = options.taskId;
if (options.suggestion !== undefined)
this.suggestion = options.suggestion;
}
static projectPathNotFound(path) {
return new TodoManagerError(`Project path '${path}' does not exist or is not accessible`, 'PROJECT_PATH_NOT_FOUND', {
value: path,
suggestions: [
{
action: 'Check the PROJECT_PATH environment variable',
description: 'Ensure the path points to a valid directory',
},
{
action: 'Create the directory',
description: `Run: mkdir -p "${path}"`,
},
{
action: 'Run from the project root',
description: 'Make sure you are in the correct project directory',
},
],
});
}
/**
* Create a task not found error with helpful suggestions
*
* @param taskId - The task ID that could not be found
* @returns TodoManagerError with suggestions for finding the task
*/
static taskNotFound(taskId) {
return new TodoManagerError(`Task '${taskId}' not found`, 'TASK_NOT_FOUND', {
taskId,
suggestions: [
{
action: 'The task may have been deleted',
description: 'Check if the task was recently removed',
},
{
action: 'Use get_tasks to list all tasks',
description: 'Verify the task ID exists in the current list',
},
{
action: 'Search for the task using find_task',
description: 'The task might have a different ID than expected',
},
],
});
}
/**
* Create an invalid task ID error with format guidance
*
* @param taskId - The invalid task ID that was provided
* @returns TodoManagerError with suggestions for correct ID format
*/
static invalidTaskId(taskId) {
return new TodoManagerError(`Invalid task ID format: '${taskId}'`, 'INVALID_TASK_ID', {
value: taskId,
suggestions: [
{
action: 'Use find_task to search for tasks',
description: 'Search by title or description instead',
},
{
action: 'Use get_tasks with showFullIds: true',
description: 'Get the complete UUID for the task',
},
{
action: 'Check the task ID format',
description: 'Task IDs should be UUIDs or partial UUIDs (8+ characters)',
},
],
});
}
static invalidPriority(value, suggestedValue) {
const suggestionText = suggestedValue
? `Did you mean "${suggestedValue}"?`
: 'Use one of the valid priority values';
return new TodoManagerError(`Invalid priority '${value}'. Must be one of: low, medium, high, critical`, 'INVALID_PRIORITY', {
field: 'priority',
value,
validValues: ['low', 'medium', 'high', 'critical'],
suggestion: suggestionText,
suggestions: [
{
action: suggestionText,
description: suggestedValue
? `Replace '${value}' with '${suggestedValue}'`
: 'Choose from: low, medium, high, critical',
},
],
});
}
static taskHasDependencies(taskId, dependentTasks) {
return new TodoManagerError(`Cannot delete task '${taskId}' because it has active dependencies: ${dependentTasks.join(', ')}`, 'TASK_HAS_DEPENDENCIES', {
taskId,
value: dependentTasks,
suggestions: [
{
action: 'Complete or delete dependent tasks first',
description: 'Tasks that depend on this one must be handled first',
},
{
action: 'Use archiveTask instead of deleteTask',
description: 'Archiving preserves the task for reference while marking it inactive',
},
{
action: 'Remove dependencies from dependent tasks',
description: 'Update dependent tasks to remove this dependency',
},
],
});
}
/**
* Create a circular dependency error with resolution suggestions
*
* @param taskIds - Array of task IDs forming the circular dependency chain
* @returns TodoManagerError with suggestions for breaking the cycle
*/
static circularDependency(taskIds) {
const chain = taskIds.join(' → ');
return new TodoManagerError(`Circular dependency detected: ${chain}`, 'CIRCULAR_DEPENDENCY', {
value: taskIds,
suggestions: [
{
action: 'Remove one of the dependencies in the chain',
description: `Break the cycle by removing a dependency from: ${chain}`,
},
{
action: 'Restructure task relationships',
description: 'Consider breaking down tasks into smaller, independent units',
},
{
action: 'Use task hierarchy instead of dependencies',
description: 'Consider using parent-child relationships instead of dependencies',
},
],
});
}
static invalidDateFormat(date, field = 'date') {
return new TodoManagerError(`Invalid date format: '${date}'. Expected ISO 8601 format (YYYY-MM-DD or YYYY-MM-DDTHH:mm:ss.sssZ)`, 'INVALID_DATE_FORMAT', {
field,
value: date,
suggestions: [
{
action: 'Use ISO 8601 format',
description: 'Examples: "2024-01-15", "2024-01-15T10:30:00Z"',
example: '2024-01-15T10:30:00Z',
},
{
action: 'Use relative dates',
description: 'Examples: "today", "tomorrow", "+1 week", "+2 days"',
},
{
action: 'Check date validity',
description: 'Ensure the date exists (e.g., February 30th is invalid)',
},
],
});
}
static invalidStatus(value, suggestedValue) {
const suggestionText = suggestedValue
? `Did you mean "${suggestedValue}"?`
: 'Use one of the valid status values';
return new TodoManagerError(`Invalid status '${value}'. Must be one of: pending, in_progress, completed, blocked, cancelled`, 'INVALID_STATUS', {
field: 'status',
value,
validValues: ['pending', 'in_progress', 'completed', 'blocked', 'cancelled'],
suggestion: suggestionText,
suggestions: [
{
action: suggestionText,
description: suggestedValue
? `Replace '${value}' with '${suggestedValue}'`
: 'Choose from: pending, in_progress, completed, blocked, cancelled',
},
],
});
}
static requiredFieldMissing(field) {
return new TodoManagerError(`Required field '${field}' is missing`, 'REQUIRED_FIELD_MISSING', {
field,
suggestions: [
{
action: `Provide the '${field}' field`,
description: `The '${field}' field is required for this operation`,
},
],
});
}
static invalidFieldValue(field, value, expectedType) {
const typeInfo = expectedType ? ` (expected ${expectedType})` : '';
return new TodoManagerError(`Invalid value for field '${field}': '${value}'${typeInfo}`, 'INVALID_FIELD_VALUE', {
field,
value,
suggestions: [
{
action: `Check the '${field}' field value`,
description: expectedType
? `Expected type: ${expectedType}`
: 'Verify the field value is correct',
},
],
});
}
static taskAlreadyExists(taskId) {
return new TodoManagerError(`Task with ID '${taskId}' already exists`, 'TASK_ALREADY_EXISTS', {
taskId,
suggestions: [
{
action: 'Use update_task instead',
description: 'If you want to modify an existing task, use the update operation',
},
{
action: 'Generate a new task ID',
description: 'Create a new task with a unique ID',
},
{
action: 'Check if this is a duplicate',
description: 'Verify you are not accidentally creating the same task twice',
},
],
});
}
static bulkOperationPartialFailure(successful, failed, errors) {
return new TodoManagerError(`Bulk operation completed with ${successful} successes and ${failed} failures`, 'BULK_OPERATION_PARTIAL_FAILURE', {
value: { successful, failed, errors },
suggestions: [
{
action: 'Review failed operations',
description: 'Check the error details for each failed operation',
},
{
action: 'Retry failed operations individually',
description: 'Process failed items one by one to identify specific issues',
},
{
action: 'Use dry-run mode first',
description: 'Test bulk operations with dry-run to identify issues beforehand',
},
],
});
}
static operationNotSupported(operation) {
return new TodoManagerError(`Operation '${operation}' is not supported`, 'OPERATION_NOT_SUPPORTED', {
value: operation,
suggestions: [
{
action: 'Check available operations',
description: 'Use get_operations or check documentation for supported operations',
},
{
action: 'Check operation spelling',
description: 'Verify the operation name is spelled correctly',
},
],
});
}
static concurrencyConflict(taskId) {
return new TodoManagerError(`Concurrency conflict: Task '${taskId}' was modified by another operation`, 'CONCURRENCY_CONFLICT', {
taskId,
suggestions: [
{
action: 'Retry the operation',
description: 'The task may have been updated by another process',
},
{
action: 'Refresh task data',
description: 'Get the latest task data before making changes',
},
{
action: 'Use force update if necessary',
description: 'Override the conflict if you are sure about the changes',
},
],
});
}
static dataCorruption(details) {
return new TodoManagerError(`Data corruption detected: ${details}`, 'DATA_CORRUPTION', {
value: details,
suggestions: [
{
action: 'Restore from backup',
description: 'Use the most recent backup to restore data integrity',
},
{
action: 'Run data validation',
description: 'Check for and repair data inconsistencies',
},
{
action: 'Contact support',
description: 'If the issue persists, seek technical assistance',
},
],
});
}
static undoNotAvailable(reason) {
return new TodoManagerError(`Undo operation not available: ${reason}`, 'UNDO_NOT_AVAILABLE', {
value: reason,
suggestions: [
{
action: 'Check operation history',
description: 'Use get_undo_history to see available undo operations',
},
{
action: 'Manual recovery',
description: 'You may need to manually recreate or restore the desired state',
},
],
});
}
static searchQueryInvalid(query, reason) {
return new TodoManagerError(`Invalid search query '${query}': ${reason}`, 'SEARCH_QUERY_INVALID', {
value: query,
suggestions: [
{
action: 'Simplify the search query',
description: 'Try using simpler search terms',
},
{
action: 'Check regex syntax',
description: 'If using regex search, verify the pattern syntax',
},
{
action: 'Use fuzzy search instead',
description: 'Fuzzy search is more forgiving of typos and variations',
},
],
});
}
static multipleTasksFound(partialId, matches) {
return new TodoManagerError(`Multiple tasks found for '${partialId}': ${matches.join(', ')}`, 'MULTIPLE_TASKS_FOUND', {
value: partialId,
validValues: matches,
suggestions: [
{
action: 'Use a more specific ID',
description: 'Provide more characters to uniquely identify the task',
},
{
action: 'Use the full task ID',
description: 'Copy the complete UUID from the task list',
},
{
action: 'Use find_task to search by title',
description: 'Search by task title or description instead of ID',
},
],
});
}
}
//# sourceMappingURL=enhanced-errors.js.map