apexbot 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,186 @@
1
+ "use strict";
2
+ /**
3
+ * Telegram Channel - Bot API integration via grammY
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.TelegramChannel = void 0;
7
+ const grammy_1 = require("grammy");
8
+ const eventBus_1 = require("../core/eventBus");
9
+ class TelegramChannel {
10
+ name = 'telegram';
11
+ status = 'disconnected';
12
+ bot;
13
+ config;
14
+ botUsername = '';
15
+ constructor(config) {
16
+ this.config = {
17
+ allowGroups: true,
18
+ requireMention: true,
19
+ ...config,
20
+ };
21
+ this.bot = new grammy_1.Bot(config.botToken);
22
+ this.setupHandlers();
23
+ }
24
+ setupHandlers() {
25
+ // Get bot info on start
26
+ this.bot.api.getMe().then(me => {
27
+ this.botUsername = me.username || '';
28
+ console.log(`[Telegram] Bot username: @${this.botUsername}`);
29
+ });
30
+ // Handle all messages
31
+ this.bot.on('message:text', async (ctx) => {
32
+ const userId = ctx.from?.id;
33
+ const chatId = ctx.chat.id;
34
+ const isGroup = ctx.chat.type === 'group' || ctx.chat.type === 'supergroup';
35
+ const text = ctx.message.text;
36
+ // Check if allowed
37
+ if (this.config.allowedUsers && this.config.allowedUsers.length > 0) {
38
+ if (!this.config.allowedUsers.includes(userId)) {
39
+ // Silent ignore or send access denied
40
+ return;
41
+ }
42
+ }
43
+ // In groups, check for mention
44
+ if (isGroup && this.config.requireMention) {
45
+ const mentioned = text.toLowerCase().includes(`@${this.botUsername.toLowerCase()}`) ||
46
+ ctx.message.reply_to_message?.from?.id === ctx.me.id;
47
+ if (!mentioned) {
48
+ return; // Ignore messages without mention
49
+ }
50
+ }
51
+ // Clean text (remove bot mention)
52
+ const cleanText = text.replace(new RegExp(`@${this.botUsername}`, 'gi'), '').trim();
53
+ // Emit message event
54
+ (0, eventBus_1.emit)('channel:message', {
55
+ channel: 'telegram',
56
+ from: chatId.toString(),
57
+ text: cleanText,
58
+ id: ctx.message.message_id.toString(),
59
+ isGroup,
60
+ groupId: isGroup ? chatId.toString() : undefined,
61
+ timestamp: ctx.message.date * 1000,
62
+ });
63
+ });
64
+ // Handle media
65
+ this.bot.on('message:photo', async (ctx) => {
66
+ const photo = ctx.message.photo[ctx.message.photo.length - 1]; // Highest resolution
67
+ const fileId = photo.file_id;
68
+ (0, eventBus_1.emit)('channel:message', {
69
+ channel: 'telegram',
70
+ from: ctx.chat.id.toString(),
71
+ text: ctx.message.caption || '',
72
+ media: [{ type: 'image', url: fileId }],
73
+ id: ctx.message.message_id.toString(),
74
+ isGroup: ctx.chat.type !== 'private',
75
+ timestamp: ctx.message.date * 1000,
76
+ });
77
+ });
78
+ // Handle voice/audio
79
+ this.bot.on('message:voice', async (ctx) => {
80
+ (0, eventBus_1.emit)('channel:message', {
81
+ channel: 'telegram',
82
+ from: ctx.chat.id.toString(),
83
+ text: '[Voice message]',
84
+ media: [{ type: 'voice', url: ctx.message.voice.file_id }],
85
+ id: ctx.message.message_id.toString(),
86
+ isGroup: ctx.chat.type !== 'private',
87
+ timestamp: ctx.message.date * 1000,
88
+ });
89
+ });
90
+ // Slash commands
91
+ this.bot.command('start', async (ctx) => {
92
+ await ctx.reply('👋 *Welcome to ApexBot!*\n\n' +
93
+ 'I\'m your personal AI assistant. Just send me a message!\n\n' +
94
+ 'Commands:\n' +
95
+ '/status - Check bot status\n' +
96
+ '/new - Start fresh conversation\n' +
97
+ '/help - Show help', { parse_mode: 'Markdown' });
98
+ });
99
+ this.bot.command('status', async (ctx) => {
100
+ (0, eventBus_1.emit)('channel:message', {
101
+ channel: 'telegram',
102
+ from: ctx.chat.id.toString(),
103
+ text: '/status',
104
+ id: ctx.message.message_id.toString(),
105
+ isGroup: ctx.chat.type !== 'private',
106
+ });
107
+ });
108
+ this.bot.command('new', async (ctx) => {
109
+ (0, eventBus_1.emit)('channel:message', {
110
+ channel: 'telegram',
111
+ from: ctx.chat.id.toString(),
112
+ text: '/new',
113
+ id: ctx.message.message_id.toString(),
114
+ isGroup: ctx.chat.type !== 'private',
115
+ });
116
+ });
117
+ }
118
+ async connect() {
119
+ this.status = 'connecting';
120
+ (0, eventBus_1.emit)('channel:status', { channel: 'telegram', status: 'connecting' });
121
+ try {
122
+ await this.bot.start({
123
+ onStart: () => {
124
+ this.status = 'connected';
125
+ (0, eventBus_1.emit)('channel:status', { channel: 'telegram', status: 'connected' });
126
+ console.log('[Telegram] Connected and polling');
127
+ },
128
+ });
129
+ }
130
+ catch (e) {
131
+ this.status = 'error';
132
+ (0, eventBus_1.emit)('channel:status', { channel: 'telegram', status: 'error', data: e });
133
+ throw e;
134
+ }
135
+ }
136
+ async disconnect() {
137
+ this.bot.stop();
138
+ this.status = 'disconnected';
139
+ (0, eventBus_1.emit)('channel:status', { channel: 'telegram', status: 'disconnected' });
140
+ }
141
+ async send(to, text, replyTo) {
142
+ const chatId = parseInt(to, 10);
143
+ const options = { parse_mode: 'Markdown' };
144
+ if (replyTo) {
145
+ options.reply_to_message_id = parseInt(replyTo, 10);
146
+ }
147
+ // Split long messages
148
+ const maxLength = 4096;
149
+ if (text.length <= maxLength) {
150
+ await this.bot.api.sendMessage(chatId, text, options);
151
+ }
152
+ else {
153
+ // Split at paragraph or sentence boundaries
154
+ const chunks = this.splitMessage(text, maxLength);
155
+ for (const chunk of chunks) {
156
+ await this.bot.api.sendMessage(chatId, chunk, options);
157
+ }
158
+ }
159
+ }
160
+ splitMessage(text, maxLength) {
161
+ const chunks = [];
162
+ let remaining = text;
163
+ while (remaining.length > 0) {
164
+ if (remaining.length <= maxLength) {
165
+ chunks.push(remaining);
166
+ break;
167
+ }
168
+ // Find a good split point
169
+ let splitAt = remaining.lastIndexOf('\n\n', maxLength);
170
+ if (splitAt < maxLength / 2) {
171
+ splitAt = remaining.lastIndexOf('\n', maxLength);
172
+ }
173
+ if (splitAt < maxLength / 2) {
174
+ splitAt = remaining.lastIndexOf('. ', maxLength);
175
+ }
176
+ if (splitAt < maxLength / 2) {
177
+ splitAt = maxLength;
178
+ }
179
+ chunks.push(remaining.slice(0, splitAt));
180
+ remaining = remaining.slice(splitAt).trim();
181
+ }
182
+ return chunks;
183
+ }
184
+ }
185
+ exports.TelegramChannel = TelegramChannel;
186
+ exports.default = TelegramChannel;