@puberty-labs/bi-tch
Version:
BiTCH-MCP: Autonomous AI Coordination Platform - BETA: ZombieDust Protocol operational! Revolutionary AI-to-AI coordination with pure MCP integration. FOLLOW BETA RELEASES for latest features!
363 lines (312 loc) โข 10.1 kB
JavaScript
/**
* BitchNotifier - Sends notifications with attitude
*
* Handles system notifications for urgent bitch-messages,
* bitch-slaps, and other important workspace drama.
*
* Because sometimes you need to get someone's attention aggressively.
*/
const notifier = require('node-notifier');
const path = require('path');
const chalk = require('chalk');
const { BitchError } = require('./ErrorHandler');
class BitchNotifier {
constructor() {
this.isEnabled = true;
this.soundEnabled = true;
this.iconPath = this.getNotificationIcon();
}
/**
* Get the notification icon path
*/
getNotificationIcon() {
// In a real implementation, we'd bundle an icon file
// For now, we'll use the system default
return null;
}
/**
* Send a priority notification
*/
async sendPriorityNotification(targetWorkspace, message) {
if (!this.isEnabled) {
console.log(chalk.gray('๐ต Notifications disabled'));
return;
}
try {
const notificationData = {
title: `๐จ Urgent BiTCH Message`,
message: `From: ${targetWorkspace}\n${this.truncateMessage(message)}`,
icon: this.iconPath,
sound: this.soundEnabled ? 'Basso' : false,
timeout: 10,
actions: ['Reply', 'Ignore'],
dropdownLabel: 'BiTCH Actions',
closeLabel: 'Dismiss',
wait: false
};
await this.sendNotification(notificationData);
console.log(chalk.green('๐ Priority notification sent'));
} catch (error) {
console.log(chalk.yellow(`โ ๏ธ Failed to send priority notification: ${error.message}`));
}
}
/**
* Send a bitch-slap notification (maximum urgency)
*/
async sendBitchSlap(targetWorkspace, message) {
if (!this.isEnabled) {
console.log(chalk.gray('๐ต Notifications disabled'));
return;
}
try {
const slapMessages = [
'๐ BITCH-SLAP INCOMING!',
'๐ฅ WAKE UP CALL!',
'๐จ URGENT BITCH ALERT!',
'โก PRIORITY INTERRUPT!',
'๐ฅ EMERGENCY BITCH-UATION!'
];
const randomSlapTitle = slapMessages[Math.floor(Math.random() * slapMessages.length)];
const notificationData = {
title: randomSlapTitle,
message: `${targetWorkspace} needs your attention NOW!\n${this.truncateMessage(message)}`,
icon: this.iconPath,
sound: this.soundEnabled ? 'Funk' : false,
timeout: 15,
actions: ['Respond', 'Snooze'],
dropdownLabel: 'Emergency Actions',
closeLabel: 'I\'m awake!',
wait: false,
urgency: 'critical'
};
await this.sendNotification(notificationData);
// Send multiple notifications for maximum annoyance
setTimeout(() => {
this.sendNotification({
...notificationData,
title: '๐ Still waiting...',
message: 'Your BiTCH is getting impatient.',
timeout: 5
});
}, 3000);
console.log(chalk.red('๐ BITCH-SLAP notification delivered with maximum prejudice!'));
} catch (error) {
console.log(chalk.yellow(`โ ๏ธ Failed to send bitch-slap: ${error.message}`));
}
}
/**
* Send a regular message notification
*/
async sendMessageNotification(from, message, priority = false) {
if (!this.isEnabled) {
return;
}
try {
const title = priority ? '๐จ Priority BiTCH Message' : '๐จ New BiTCH Message';
const sound = priority ? 'Basso' : 'Blow';
const notificationData = {
title,
message: `From: ${from}\n${this.truncateMessage(message)}`,
icon: this.iconPath,
sound: this.soundEnabled ? sound : false,
timeout: priority ? 10 : 5,
actions: priority ? ['Reply', 'Mark Read'] : ['View'],
wait: false
};
await this.sendNotification(notificationData);
console.log(chalk.blue(`๐ Message notification sent (${priority ? 'priority' : 'normal'})`));
} catch (error) {
console.log(chalk.gray(`โ ๏ธ Failed to send message notification: ${error.message}`));
}
}
/**
* Send a workspace status notification
*/
async sendWorkspaceStatusNotification(status, details) {
if (!this.isEnabled) {
return;
}
try {
const statusEmojis = {
'connected': '๐ข',
'disconnected': '๐ด',
'error': '๐ฅ',
'warning': 'โ ๏ธ',
'info': '๐ก'
};
const notificationData = {
title: `${statusEmojis[status] || '๐'} BiTCH Workspace Status`,
message: details,
icon: this.iconPath,
sound: this.soundEnabled && status === 'error' ? 'Basso' : false,
timeout: 5,
wait: false
};
await this.sendNotification(notificationData);
} catch (error) {
console.log(chalk.gray(`โ ๏ธ Failed to send status notification: ${error.message}`));
}
}
/**
* Send a custom notification with BiTCH personality
*/
async sendCustomNotification(title, message, options = {}) {
if (!this.isEnabled) {
return;
}
try {
const bitchyTitles = {
'success': '๐ BiTCH Success (Shocking!)',
'error': '๐ฅ BiTCH Error (Typical)',
'warning': 'โ ๏ธ BiTCH Warning (Listen Up)',
'info': '๐ก BiTCH Info (Pay Attention)',
'reminder': 'โฐ BiTCH Reminder (Don\'t Forget)'
};
const finalTitle = bitchyTitles[options.type] || title;
const notificationData = {
title: finalTitle,
message: this.addBitchPersonality(message),
icon: this.iconPath,
sound: this.soundEnabled ? (options.sound || 'Blow') : false,
timeout: options.timeout || 5,
actions: options.actions || ['OK'],
wait: false,
...options
};
await this.sendNotification(notificationData);
} catch (error) {
console.log(chalk.gray(`โ ๏ธ Failed to send custom notification: ${error.message}`));
}
}
/**
* Send the actual notification using node-notifier
*/
async sendNotification(notificationData) {
return new Promise((resolve, reject) => {
notifier.notify(notificationData, (error, response) => {
if (error) {
reject(error);
} else {
resolve(response);
}
});
});
}
/**
* Truncate message for notification display
*/
truncateMessage(message, maxLength = 100) {
if (message.length <= maxLength) {
return message;
}
return message.substring(0, maxLength - 3) + '...';
}
/**
* Add BiTCH personality to notification messages
*/
addBitchPersonality(message) {
const personalityPhrases = [
'Just so you know',
'FYI',
'In case you care',
'Thought you should know',
'Breaking news',
'Update from your BiTCH'
];
const randomPhrase = personalityPhrases[Math.floor(Math.random() * personalityPhrases.length)];
return `${randomPhrase}: ${message}`;
}
/**
* Enable/disable notifications
*/
setEnabled(enabled) {
this.isEnabled = enabled;
console.log(chalk.cyan(`๐ Notifications ${enabled ? 'enabled' : 'disabled'}`));
}
/**
* Enable/disable notification sounds
*/
setSoundEnabled(enabled) {
this.soundEnabled = enabled;
console.log(chalk.cyan(`๐ Notification sounds ${enabled ? 'enabled' : 'disabled'}`));
}
/**
* Test notifications
*/
async testNotifications() {
try {
console.log(chalk.cyan('๐งช Testing BiTCH notifications...'));
// Test basic notification
await this.sendCustomNotification('BiTCH Test', 'If you can see this, notifications are working!', {
type: 'info',
timeout: 3
});
// Test priority notification
setTimeout(async () => {
await this.sendPriorityNotification('Test Workspace', 'This is a test priority message');
}, 2000);
// Test bitch-slap (if user confirms)
setTimeout(async () => {
console.log(chalk.yellow('โ ๏ธ Testing bitch-slap notification in 3 seconds...'));
setTimeout(async () => {
await this.sendBitchSlap('Test Workspace', 'This is a test bitch-slap (don\'t worry, it\'s just a test)');
}, 3000);
}, 4000);
console.log(chalk.green('โ
Notification test sequence initiated'));
} catch (error) {
throw new BitchError(`Notification test failed: ${error.message}`, 'NOTIFICATION_TEST_FAILED');
}
}
/**
* Get notification statistics
*/
getNotificationStats() {
// This would be implemented with actual tracking
return {
enabled: this.isEnabled,
soundEnabled: this.soundEnabled,
totalSent: 0,
prioritySent: 0,
bitchSlapsSent: 0,
lastSent: null,
platform: process.platform
};
}
/**
* Schedule a delayed notification
*/
async scheduleNotification(title, message, delayMs, options = {}) {
setTimeout(async () => {
try {
await this.sendCustomNotification(title, message, {
...options,
type: 'reminder'
});
} catch (error) {
console.log(chalk.gray(`โ ๏ธ Scheduled notification failed: ${error.message}`));
}
}, delayMs);
console.log(chalk.blue(`โฐ Notification scheduled for ${Math.round(delayMs / 1000)} seconds`));
}
/**
* Send a notification when BiTCH starts up
*/
async sendStartupNotification() {
if (!this.isEnabled) {
return;
}
const startupMessages = [
'BiTCH is ready to cause some drama!',
'Your workspace communication assistant is online.',
'Ready to facilitate some professional bitching.',
'BiTCH initialized. Let the workspace drama begin!',
'Communication bridge established. Start complaining!'
];
const randomMessage = startupMessages[Math.floor(Math.random() * startupMessages.length)];
await this.sendCustomNotification('BiTCH Online', randomMessage, {
type: 'success',
timeout: 3
});
}
}
module.exports = BitchNotifier;