UNPKG

cui-server

Version:

Web UI Agent Platform based on Claude Code

140 lines 4.88 kB
import { createLogger } from './logger.js'; import { ConfigService } from './config-service.js'; /** * Service for sending push notifications via ntfy.sh */ export class NotificationService { logger; configService; machineId = null; constructor() { this.logger = createLogger('NotificationService'); this.configService = ConfigService.getInstance(); } /** * Get machine ID from config */ getMachineId() { if (!this.machineId) { try { const config = this.configService.getConfig(); this.machineId = config.machine_id; } catch (error) { this.logger.error('Failed to get machine ID from config', error); this.machineId = 'unknown'; } } return this.machineId; } /** * Check if notifications are enabled */ async isEnabled() { const config = this.configService.getConfig(); return config.interface.notifications?.enabled ?? false; } /** * Get the ntfy URL from preferences */ async getNtfyUrl() { const config = this.configService.getConfig(); return config.interface.notifications?.ntfyUrl || 'https://ntfy.sh'; } /** * Send a notification for a permission request */ async sendPermissionNotification(request, sessionId, summary) { if (!(await this.isEnabled())) { this.logger.debug('Notifications disabled, skipping permission notification'); return; } try { const machineId = this.getMachineId(); const topic = `cui-${machineId}`; const ntfyUrl = await this.getNtfyUrl(); const notification = { title: 'CUI Permission Request', message: summary ? `${summary} - ${request.toolName}` : `${request.toolName} tool: ${JSON.stringify(request.toolInput).substring(0, 100)}...`, priority: 'default', tags: ['cui-permission'], sessionId: sessionId || 'unknown', streamingId: request.streamingId, permissionRequestId: request.id }; await this.sendNotification(ntfyUrl, topic, notification); this.logger.info('Permission notification sent', { requestId: request.id, toolName: request.toolName, topic }); } catch (error) { this.logger.error('Failed to send permission notification', error, { requestId: request.id }); } } /** * Send a notification when a conversation ends */ async sendConversationEndNotification(streamingId, sessionId, summary) { if (!(await this.isEnabled())) { this.logger.debug('Notifications disabled, skipping conversation end notification'); return; } try { const machineId = this.getMachineId(); const topic = `cui-${machineId}`; const ntfyUrl = await this.getNtfyUrl(); const notification = { title: 'Task Finished', message: summary || 'Task completed', priority: 'default', tags: ['cui-complete'], sessionId, streamingId }; await this.sendNotification(ntfyUrl, topic, notification); this.logger.info('Conversation end notification sent', { sessionId, streamingId, topic }); } catch (error) { this.logger.error('Failed to send conversation end notification', error, { sessionId, streamingId }); } } /** * Send a notification to ntfy */ async sendNotification(ntfyUrl, topic, notification) { const url = `${ntfyUrl}/${topic}`; const headers = { 'Title': notification.title, 'Priority': notification.priority, 'Tags': notification.tags.join(',') }; // Add custom headers for CUI metadata headers['X-CUI-SessionId'] = notification.sessionId; headers['X-CUI-StreamingId'] = notification.streamingId; if (notification.permissionRequestId) { headers['X-CUI-PermissionRequestId'] = notification.permissionRequestId; } const response = await fetch(url, { method: 'POST', headers, body: notification.message }); if (!response.ok) { throw new Error(`Ntfy returned ${response.status}: ${await response.text()}`); } } } //# sourceMappingURL=notification-service.js.map