life-todo

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

bot.js (2776B)


      1 const TelegramBot = require('node-telegram-bot-api');
      2 const claude = require('./claude');
      3 const todo = require('./todo');
      4 const git = require('./git');
      5 const state = require('./state');
      6 const { transcribeVoice } = require('./transcribe');
      7 
      8 const ALLOWED_USER_IDS = process.env.ALLOWED_USER_IDS
      9   ? process.env.ALLOWED_USER_IDS.split(',').map(id => parseInt(id.trim(), 10))
     10   : [];
     11 
     12 function isAllowed(userId) {
     13   if (ALLOWED_USER_IDS.length === 0) return true; // no whitelist configured
     14   return ALLOWED_USER_IDS.includes(userId);
     15 }
     16 
     17 function createBot(token) {
     18   const bot = new TelegramBot(token, { polling: true });
     19 
     20   bot.on('message', async (msg) => {
     21     const userId = msg.from.id;
     22     const chatId = msg.chat.id;
     23     let text = msg.text;
     24 
     25     if (!text && !msg.voice) return; // ignore stickers, photos, etc.
     26 
     27     if (!isAllowed(userId)) {
     28       await bot.sendMessage(chatId, 'Unauthorized.');
     29       return;
     30     }
     31 
     32     try {
     33       await bot.sendChatAction(chatId, 'typing');
     34 
     35       if (msg.voice) {
     36         text = await transcribeVoice(bot, msg.voice.file_id);
     37         console.log(`[user:${userId}] (voice) ${text}`);
     38       } else {
     39         console.log(`[user:${userId}] ${text}`);
     40       }
     41 
     42       const rotated = todo.rotateTodayIfStale();
     43       const currentToday = todo.readToday();
     44       const currentBacklog = todo.readBacklog();
     45       const history = state.load(userId);
     46 
     47       const result = await claude.chat(history, text, currentToday, currentBacklog, rotated);
     48       console.log(`[claude] ${result.reply}`);
     49 
     50       if (result.updatedToday !== currentToday) todo.writeToday(result.updatedToday);
     51       if (result.updatedBacklog !== currentBacklog) todo.writeBacklog(result.updatedBacklog);
     52 
     53       state.append(userId, 'user', text);
     54       state.append(userId, 'assistant', result.reply);
     55 
     56       const todayChanged = result.updatedToday !== currentToday;
     57       const backlogChanged = result.updatedBacklog !== currentBacklog;
     58       const commitMessage = (todayChanged || backlogChanged) && result.commitMessage
     59         ? result.commitMessage
     60         : 'Update conversation history';
     61       try {
     62         await git.commitAndPush(commitMessage);
     63       } catch (gitErr) {
     64         console.error('Git push failed:', gitErr.message);
     65       }
     66 
     67       await bot.sendMessage(chatId, result.reply, { parse_mode: 'Markdown' });
     68 
     69     } catch (err) {
     70       console.error('Error handling message:', err);
     71       await bot.sendMessage(chatId, 'Something went wrong — check the server logs.');
     72     }
     73   });
     74 
     75   bot.on('polling_error', (err) => {
     76     console.error('Polling error:', err.message);
     77   });
     78 
     79   console.log(`Bot started. Allowed users: ${ALLOWED_USER_IDS.length ? ALLOWED_USER_IDS.join(', ') : 'all (no whitelist)'}`);
     80   return bot;
     81 }
     82 
     83 module.exports = { createBot };