pgit-cli
Version:
Private file tracking with dual git repositories
299 lines • 12.5 kB
JavaScript
import chalk from 'chalk';
import { BaseError } from './base.error.js';
import { MIN_NODE_VERSION } from '../types/config.types.js';
/**
* Enhanced error handler with recovery suggestions and user guidance
*/
export class EnhancedErrorHandler {
/**
* Handle error with enhanced output and recovery suggestions
*/
static handleError(error, context) {
console.log(); // Add spacing
if (error instanceof BaseError) {
this.handleBaseError(error, context);
}
else if (error instanceof Error) {
this.handleGenericError(error, context);
}
else {
this.handleUnknownError(error, context);
}
this.displayTroubleshootingTips(context);
}
/**
* Handle BaseError instances with specific recovery suggestions
*/
static handleBaseError(error, context) {
console.error(chalk.red.bold('❌ Error'));
console.error(chalk.red(` ${error.message}`));
if (error.details) {
console.error(chalk.gray(` Details: ${error.details}`));
}
if (context?.command) {
console.error(chalk.gray(` Command: ${context.command}`));
}
// Get recovery suggestions based on error type
const suggestions = this.getRecoverySuggestions(error, context);
if (suggestions.length > 0) {
console.log();
console.log(chalk.yellow.bold('💡 Recovery Suggestions:'));
suggestions.forEach((suggestion, index) => {
console.log(` ${index + 1}. ${chalk.cyan(suggestion.action)}`);
console.log(` ${chalk.gray(suggestion.description)}`);
if (suggestion.command) {
console.log(` ${chalk.green('Run:')} ${chalk.white(suggestion.command)}`);
}
});
}
if (error.recoverable) {
console.log();
console.log(chalk.yellow('⚠️ This error might be recoverable. Try the suggestions above.'));
}
if (process.env['NODE_ENV'] === 'development' && error.stack) {
console.log();
console.log(chalk.gray('Debug Stack Trace:'));
console.error(chalk.gray(error.stack));
}
}
/**
* Handle generic Error instances
*/
static handleGenericError(error, context) {
console.error(chalk.red.bold('❌ Unexpected Error'));
console.error(chalk.red(` ${error.message}`));
if (context?.command) {
console.error(chalk.gray(` Command: ${context.command}`));
}
// Provide generic recovery suggestions
const suggestions = this.getGenericRecoverySuggestions(error, context);
if (suggestions.length > 0) {
console.log();
console.log(chalk.yellow.bold('💡 General Suggestions:'));
suggestions.forEach((suggestion, index) => {
console.log(` ${index + 1}. ${chalk.cyan(suggestion.action)}`);
console.log(` ${chalk.gray(suggestion.description)}`);
if (suggestion.command) {
console.log(` ${chalk.green('Run:')} ${chalk.white(suggestion.command)}`);
}
});
}
if (process.env['NODE_ENV'] === 'development' && error.stack) {
console.log();
console.log(chalk.gray('Debug Stack Trace:'));
console.error(chalk.gray(error.stack));
}
}
/**
* Handle unknown error types
*/
static handleUnknownError(error, context) {
console.error(chalk.red.bold('❌ Unknown Error'));
console.error(chalk.red(` ${String(error)}`));
if (context?.command) {
console.error(chalk.gray(` Command: ${context.command}`));
}
console.log();
console.log(chalk.yellow.bold('💡 General Suggestions:'));
console.log(` 1. ${chalk.cyan('Check your input parameters')}`);
console.log(` ${chalk.gray('Ensure all required arguments are provided correctly')}`);
console.log(` 2. ${chalk.cyan('Verify system requirements')}`);
console.log(` ${chalk.gray(`Make sure Node.js version is >= ${MIN_NODE_VERSION} and git is available`)}`);
console.log(` 3. ${chalk.cyan('Run system diagnostics')}`);
console.log(` ${chalk.green('Run:')} ${chalk.white('private status -v')}`);
}
/**
* Get recovery suggestions based on error type and code
*/
static getRecoverySuggestions(error, _context) {
const suggestions = [];
switch (error.code) {
case 'NOT_INITIALIZED':
suggestions.push({
action: 'Initialize private git tracking',
command: 'private init',
description: 'Set up private file tracking in the current directory',
});
break;
case 'PATH_NOT_FOUND':
suggestions.push({
action: 'Check file path',
description: 'Verify the file or directory exists and the path is correct',
});
suggestions.push({
action: 'List directory contents',
command: 'ls -la',
description: 'See all files and directories in the current location',
});
break;
case 'ALREADY_TRACKED':
suggestions.push({
action: 'Check tracked files',
command: 'private status',
description: 'See which files are currently being tracked privately',
});
suggestions.push({
action: 'Remove from tracking',
command: 'private cleanup --force',
description: 'Remove the file from private tracking if needed',
});
break;
case 'SYMLINK_NOT_SUPPORTED':
suggestions.push({
action: 'Check platform support',
description: 'Symbolic links may not be supported on this platform or require elevated permissions',
});
if (process.platform === 'win32') {
suggestions.push({
action: 'Enable Developer Mode (Windows)',
description: 'Go to Settings > Update & Security > For developers > Developer Mode',
});
}
break;
case 'GIT_OPERATION_FAILED':
suggestions.push({
action: 'Check git installation',
command: 'git --version',
description: 'Verify git is installed and accessible',
});
suggestions.push({
action: 'Check repository health',
command: 'private status -v',
description: 'Diagnose potential repository issues',
});
suggestions.push({
action: 'Run system repair',
command: 'private cleanup -v',
description: 'Attempt to repair any repository issues',
});
break;
case 'FILESYSTEM_ERROR':
suggestions.push({
action: 'Check file permissions',
description: 'Ensure you have read/write access to the files and directories',
});
suggestions.push({
action: 'Check disk space',
command: 'df -h .',
description: 'Verify there is sufficient disk space available',
});
break;
case 'CONFIG_VALIDATION_FAILED':
suggestions.push({
action: 'Reset configuration',
command: 'private init --force',
description: 'Reinitialize private git tracking with fresh configuration',
});
suggestions.push({
action: 'Manual cleanup',
description: 'Remove .private-config.json and reinitialize',
});
break;
default:
// Generic suggestions for unknown error codes
suggestions.push({
action: 'Run diagnostics',
command: 'private status -v',
description: 'Check the overall health of your private git setup',
});
suggestions.push({
action: 'Try system repair',
command: 'private cleanup -v',
description: 'Attempt automatic repair of common issues',
});
break;
}
return suggestions;
}
/**
* Get generic recovery suggestions for non-BaseError instances
*/
static getGenericRecoverySuggestions(error, _context) {
const suggestions = [];
// Check for common error patterns
if (error.message.includes('ENOENT')) {
suggestions.push({
action: 'Check file or directory exists',
description: 'The specified path was not found',
});
}
else if (error.message.includes('EACCES') || error.message.includes('EPERM')) {
suggestions.push({
action: 'Check file permissions',
description: 'You may not have sufficient permissions to access this file/directory',
});
}
else if (error.message.includes('ENOSPC')) {
suggestions.push({
action: 'Free up disk space',
description: 'The disk appears to be full',
});
}
else if (error.message.includes('git')) {
suggestions.push({
action: 'Check git installation',
command: 'git --version',
description: 'Verify git is properly installed and configured',
});
}
// Always add general suggestions
suggestions.push({
action: 'Run system diagnostics',
command: 'private status -v',
description: 'Check the health of your private git setup',
});
return suggestions;
}
/**
* Display general troubleshooting tips
*/
static displayTroubleshootingTips(_context) {
console.log();
console.log(chalk.blue.bold('🔧 General Troubleshooting Tips:'));
console.log(' • Run ' + chalk.white('private status -v') + ' to check system health');
console.log(' • Use ' + chalk.white('private cleanup -v') + ' to repair common issues');
console.log(' • Check ' + chalk.white('private --help') + ' for command usage');
console.log(' • Ensure you are in a git repository directory');
console.log(' • Verify file paths are relative to the current directory');
if (process.platform === 'win32') {
console.log(' • On Windows, ensure Developer Mode is enabled for symbolic links');
}
console.log();
console.log(chalk.gray('For more help, visit the documentation or file an issue.'));
}
/**
* Create error context from command information
*/
static createContext(command, args, workingDir) {
return {
command,
args,
workingDir: workingDir || process.cwd(),
timestamp: new Date(),
environment: {
NODE_ENV: process.env['NODE_ENV'] || 'production',
PLATFORM: process.platform,
NODE_VERSION: process.version,
},
};
}
/**
* Format error for logging
*/
static formatForLog(error, context) {
const timestamp = new Date().toISOString();
const errorInfo = error instanceof Error
? {
name: error.name,
message: error.message,
stack: error.stack,
}
: { message: String(error) };
return JSON.stringify({
timestamp,
context,
error: errorInfo,
}, null, 2);
}
}
//# sourceMappingURL=enhanced.error-handler.js.map