claude-code-remote-remake/claude-hook-notify.js

168 lines
6.3 KiB
JavaScript

#!/usr/bin/env node
/**
* Claude Hook Notification Script
* Called by Claude Code hooks to send Telegram notifications
*/
const path = require('path');
const fs = require('fs');
const dotenv = require('dotenv');
// Load environment variables from the project directory
const projectDir = path.dirname(__filename);
const envPath = path.join(projectDir, '.env');
console.log('🔍 Hook script started from:', process.cwd());
console.log('📁 Script location:', __filename);
console.log('🔧 Looking for .env at:', envPath);
if (fs.existsSync(envPath)) {
console.log('✅ .env file found, loading...');
dotenv.config({ path: envPath });
} else {
console.error('❌ .env file not found at:', envPath);
console.log('📂 Available files in script directory:');
try {
const files = fs.readdirSync(projectDir);
console.log(files.join(', '));
} catch (error) {
console.error('Cannot read directory:', error.message);
}
process.exit(1);
}
const TelegramChannel = require('./src/channels/telegram/telegram');
const DesktopChannel = require('./src/channels/local/desktop');
const EmailChannel = require('./src/channels/email/smtp');
async function sendHookNotification() {
try {
console.log('🔔 Claude Hook: Sending notifications...');
// Get notification type from command line argument
const notificationType = process.argv[2] || 'completed';
const channels = [];
const results = [];
// Configure Desktop channel (always enabled for sound)
const desktopChannel = new DesktopChannel({
completedSound: 'Glass',
waitingSound: 'Tink'
});
channels.push({ name: 'Desktop', channel: desktopChannel });
// Configure Telegram channel if enabled
if (process.env.TELEGRAM_ENABLED === 'true' && process.env.TELEGRAM_BOT_TOKEN) {
const telegramConfig = {
botToken: process.env.TELEGRAM_BOT_TOKEN,
chatId: process.env.TELEGRAM_CHAT_ID,
groupId: process.env.TELEGRAM_GROUP_ID
};
if (telegramConfig.botToken && (telegramConfig.chatId || telegramConfig.groupId)) {
const telegramChannel = new TelegramChannel(telegramConfig);
channels.push({ name: 'Telegram', channel: telegramChannel });
}
}
// Configure Email channel if enabled
if (process.env.EMAIL_ENABLED === 'true' && process.env.SMTP_USER) {
const emailConfig = {
smtp: {
host: process.env.SMTP_HOST,
port: parseInt(process.env.SMTP_PORT),
secure: process.env.SMTP_SECURE === 'true',
auth: {
user: process.env.SMTP_USER,
pass: process.env.SMTP_PASS
}
},
from: process.env.EMAIL_FROM,
fromName: process.env.EMAIL_FROM_NAME,
to: process.env.EMAIL_TO
};
if (emailConfig.smtp.host && emailConfig.smtp.auth.user && emailConfig.to) {
const emailChannel = new EmailChannel(emailConfig);
channels.push({ name: 'Email', channel: emailChannel });
}
}
// Get current working directory and tmux session
const currentDir = process.cwd();
const projectName = path.basename(currentDir);
// Try to get current tmux session
let tmuxSession = process.env.TMUX_SESSION || 'claude-real';
try {
const { execSync } = require('child_process');
const sessionOutput = execSync('tmux display-message -p "#S"', {
encoding: 'utf8',
stdio: ['ignore', 'pipe', 'ignore']
}).trim();
if (sessionOutput) {
tmuxSession = sessionOutput;
}
} catch (error) {
// Not in tmux or tmux not available, use default
}
// Create notification
const notification = {
type: notificationType,
title: `Claude ${notificationType === 'completed' ? 'Task Completed' : 'Waiting for Input'}`,
message: `Claude has ${notificationType === 'completed' ? 'completed a task' : 'is waiting for input'}`,
project: projectName
// Don't set metadata here - let TelegramChannel extract real conversation content
};
console.log(`📱 Sending ${notificationType} notification for project: ${projectName}`);
console.log(`🖥️ Tmux session: ${tmuxSession}`);
// Send notifications to all configured channels
for (const { name, channel } of channels) {
try {
console.log(`📤 Sending to ${name}...`);
const result = await channel.send(notification);
results.push({ name, success: result });
if (result) {
console.log(`${name} notification sent successfully!`);
} else {
console.log(`❌ Failed to send ${name} notification`);
}
} catch (error) {
console.error(`${name} notification error:`, error.message);
results.push({ name, success: false, error: error.message });
}
}
// Report overall results
const successful = results.filter(r => r.success).length;
const total = results.length;
if (successful > 0) {
console.log(`\n✅ Successfully sent notifications via ${successful}/${total} channels`);
if (results.some(r => r.name === 'Telegram' && r.success)) {
console.log('📋 You can now send new commands via Telegram');
}
} else {
console.log('\n❌ All notification channels failed');
process.exit(1);
}
} catch (error) {
console.error('❌ Hook notification error:', error.message);
process.exit(1);
}
}
// Show usage if no arguments
if (process.argv.length < 2) {
console.log('Usage: node claude-hook-notify.js [completed|waiting]');
process.exit(1);
}
sendHookNotification();