woaru
Version:
Universal Project Setup Autopilot - Analyze and automatically configure development tools for ANY programming language
332 lines • 13.6 kB
JavaScript
import { EventEmitter } from 'events';
import chalk from 'chalk';
import notifier from 'node-notifier';
import axios from 'axios';
import { t } from '../config/i18n.js';
export class NotificationManager extends EventEmitter {
config;
notificationHistory = new Map();
cooldownMinutes = 5;
constructor(config) {
super();
this.config = config;
}
async notifyRecommendations(recommendations) {
if (recommendations.length === 0)
return;
// Group by priority
const critical = recommendations.filter(r => r.priority === 'critical');
const high = recommendations.filter(r => r.priority === 'high');
const other = recommendations.filter(r => r.priority === 'medium' || r.priority === 'low');
// Terminal notification
if (this.config.terminal) {
this.showTerminalNotification(critical, high, other);
}
// Desktop notification for critical
if (this.config.desktop && critical.length > 0) {
await this.showDesktopNotification(critical);
}
// Webhook
if (this.config.webhook) {
await this.sendWebhook('recommendations', recommendations);
}
}
async notifyIssues(issues) {
const criticalIssues = issues.filter(i => i.severity === 'critical');
if (criticalIssues.length > 0 && this.config.terminal) {
console.log(chalk.red('\n' + t('notification_manager.critical_issues_detected')));
criticalIssues.forEach(issue => {
console.log(chalk.red(` - ${issue.file}:${issue.line || '?'} - ${issue.message}`));
});
}
}
showTerminalNotification(critical, high, other) {
console.log(chalk.cyan('\n' + t('notification_manager.recommendations_update') + '\n'));
if (critical.length > 0) {
console.log(chalk.red(t('notification_manager.critical_priority')));
critical.forEach(rec => {
console.log(chalk.red(` ${rec.tool}: ${rec.reason}`));
if (rec.setupCommand) {
console.log(chalk.gray(` → ${rec.setupCommand}`));
}
});
console.log();
}
if (high.length > 0) {
console.log(chalk.yellow(t('notification_manager.high_priority')));
high.forEach(rec => {
console.log(chalk.yellow(` ${rec.tool}: ${rec.reason}`));
});
console.log();
}
if (other.length > 0) {
console.log(chalk.blue(t('notification_manager.suggestions_priority')));
other.forEach(rec => {
console.log(chalk.blue(` ${rec.tool}: ${rec.reason}`));
});
console.log();
}
console.log(chalk.gray(t('notification_manager.run_recommendations_details') + '\n'));
}
async showDesktopNotification(critical) {
// Check cooldown
const lastNotification = this.notificationHistory.get('desktop');
if (lastNotification) {
const minutesSince = (Date.now() - lastNotification.getTime()) / 1000 / 60;
if (minutesSince < this.cooldownMinutes) {
return;
}
}
const tools = critical.map(r => r.tool).join(', ');
notifier.notify({
title: t('notification_manager.desktop_critical_missing'),
message: t('notification_manager.desktop_missing_tools', { tools }),
sound: true,
wait: false,
});
this.notificationHistory.set('desktop', new Date());
}
async sendWebhook(type, data) {
if (!this.config.webhook)
return;
try {
await axios.post(this.config.webhook, {
type,
timestamp: new Date().toISOString(),
data,
});
}
catch (error) {
console.error(t('ai_provider_utils.failed_webhook'), error);
}
}
showProgress(message) {
if (this.config.terminal) {
console.log(chalk.gray(`⏳ ${message}`));
}
}
showSuccess(message) {
if (this.config.terminal) {
console.log(chalk.green(`✅ ${message}`));
}
}
showError(message) {
if (this.config.terminal) {
console.log(chalk.red(`❌ ${message}`));
}
if (this.config.desktop) {
notifier.notify({
title: t('notification_manager.desktop_error_title'),
message,
sound: true,
});
}
}
showCriticalQualityError(filePath, toolName, output) {
if (this.config.terminal) {
console.log(chalk.red('\n' + t('notification_manager.critical_quality_failed')));
console.log(chalk.red(t('notification_manager.quality_file', { file: filePath })));
console.log(chalk.red(t('notification_manager.quality_tool', { tool: toolName })));
console.log(chalk.red('─'.repeat(50)));
console.log(chalk.red(output));
console.log(chalk.red('─'.repeat(50)));
console.log(chalk.yellow(t('notification_manager.fix_before_continuing')));
console.log(chalk.gray(t('notification_manager.run_manually_detailed') + '\n'));
}
if (this.config.desktop) {
notifier.notify({
title: `🚨 ${toolName} Error`,
message: `Quality check failed in ${filePath}`,
sound: true,
wait: false,
});
}
}
showQualitySuccess(filePath, toolName) {
if (this.config.terminal) {
console.log(chalk.green(t('notification_manager.quality_passed', {
tool: toolName,
file: filePath,
})));
}
}
async notifyProductionAudits(audits) {
if (audits.length === 0)
return;
if (this.config.terminal) {
this.showProductionAuditsTerminal(audits);
}
// Desktop notification for critical production issues
const criticalAudits = audits.filter(audit => audit.priority === 'critical');
if (this.config.desktop && criticalAudits.length > 0) {
await this.showProductionAuditsDesktop(criticalAudits);
}
// Webhook
if (this.config.webhook) {
await this.sendWebhook('production_audits', audits);
}
}
showProductionAuditsTerminal(audits) {
console.log(chalk.cyan('\n' + t('notification_manager.production_readiness_audit') + '\n'));
// Group by priority
const critical = audits.filter(a => a.priority === 'critical');
const high = audits.filter(a => a.priority === 'high');
const medium = audits.filter(a => a.priority === 'medium');
const low = audits.filter(a => a.priority === 'low');
if (critical.length > 0) {
console.log(chalk.red.bold(t('notification_manager.critical_must_fix')));
critical.forEach(audit => {
console.log(chalk.red(` ${audit.message}`));
console.log(chalk.gray(` → ${audit.recommendation}`));
if (audit.packages?.length) {
console.log(chalk.gray(` 📦 ${audit.packages.join(', ')}`));
}
});
console.log();
}
if (high.length > 0) {
console.log(chalk.yellow.bold(t('notification_manager.high_should_fix')));
high.forEach(audit => {
console.log(chalk.yellow(` ${audit.message}`));
console.log(chalk.gray(` → ${audit.recommendation}`));
if (audit.packages?.length) {
console.log(chalk.gray(` 📦 ${audit.packages.join(', ')}`));
}
});
console.log();
}
if (medium.length > 0) {
console.log(chalk.blue.bold(t('notification_manager.medium_improvement')));
medium.forEach(audit => {
console.log(chalk.blue(` ${audit.message}`));
console.log(chalk.gray(` → ${audit.recommendation}`));
});
console.log();
}
if (low.length > 0) {
console.log(chalk.gray.bold(t('notification_manager.low_optional')));
low.forEach(audit => {
console.log(chalk.gray(` ${audit.message}`));
console.log(chalk.gray(` → ${audit.recommendation}`));
});
console.log();
}
console.log(chalk.cyan(t('notification_manager.run_audit_details') + '\n'));
}
async showProductionAuditsDesktop(criticalAudits) {
// Check cooldown
const lastNotification = this.notificationHistory.get('production_audit');
if (lastNotification) {
const minutesSince = (Date.now() - lastNotification.getTime()) / 1000 / 60;
if (minutesSince < this.cooldownMinutes) {
return;
}
}
const issues = criticalAudits.map(a => a.check).join(', ');
notifier.notify({
title: t('notification_manager.desktop_production_issues'),
message: t('notification_manager.desktop_production_missing', { issues }),
sound: true,
wait: false,
});
this.notificationHistory.set('production_audit', new Date());
}
showHealthScore(score, previous) {
if (!this.config.terminal)
return;
const bar = this.createProgressBar(score);
const color = score >= 80 ? chalk.green : score >= 60 ? chalk.yellow : chalk.red;
let message = color(t('notification_manager.health_score', { score, bar }));
if (previous !== undefined) {
const diff = score - previous;
if (diff > 0) {
message += chalk.green(' ' + t('notification_manager.health_score_up', { diff }));
}
else if (diff < 0) {
message += chalk.red(' ' +
t('notification_manager.health_score_down', {
diff: Math.abs(diff),
}));
}
}
console.log('\n' + message + '\n');
}
createProgressBar(percentage) {
const filled = Math.round(percentage / 10);
const empty = 10 - filled;
return '▓'.repeat(filled) + '░'.repeat(empty);
}
showWarning(message) {
if (this.config.terminal) {
console.log(chalk.yellow(`⚠️ ${message}`));
}
}
/**
* Shows prominent security alerts in the terminal
* @param severity - 'critical' or 'high'
* @param title - Main security issue title
* @param details - Additional details about the vulnerability
* @param action - Recommended action to fix
*/
showSecurityAlert(severity, title, details, action) {
if (!this.config.terminal)
return;
console.log(''); // Empty line for separation
if (severity === 'critical') {
// Critical alerts get the most prominent display
console.log(chalk.bgRed.white.bold(' ' + t('notification_manager.security_alert_title') + ' '));
console.log(chalk.red('═'.repeat(60)));
console.log(chalk.red.bold(title));
if (details) {
console.log(chalk.red(details));
}
if (action) {
console.log(chalk.yellow.bold('\n' + t('notification_manager.action_required', { action })));
}
console.log(chalk.red('═'.repeat(60)));
}
else {
// High severity alerts
console.log(chalk.bgYellow.black.bold(' ' + t('notification_manager.security_warning_title') + ' '));
console.log(chalk.yellow('─'.repeat(60)));
console.log(chalk.yellow.bold(title));
if (details) {
console.log(chalk.yellow(details));
}
if (action) {
console.log(chalk.cyan('\n' + t('notification_manager.recommended_action', { action })));
}
console.log(chalk.yellow('─'.repeat(60)));
}
console.log(''); // Empty line after
// Desktop notification for critical security issues
if (this.config.desktop && severity === 'critical') {
// Check cooldown
const lastSecurityNotification = this.notificationHistory.get('security_alert');
if (!lastSecurityNotification ||
(Date.now() - lastSecurityNotification.getTime()) / 1000 / 60 >=
this.cooldownMinutes) {
notifier.notify({
title: t('notification_manager.desktop_security_alert'),
message: title,
sound: true,
wait: false,
});
this.notificationHistory.set('security_alert', new Date());
}
}
// Webhook for security alerts
if (this.config.webhook) {
this.sendWebhook('security_alert', {
severity,
title,
details,
action,
timestamp: new Date().toISOString(),
}).catch(error => {
console.error(t('notification_manager.failed_security_webhook'), error);
});
}
}
}
//# sourceMappingURL=NotificationManager.js.map