clawbee 2.0.0 → 2.2.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.
package/lib/index.js ADDED
@@ -0,0 +1,42 @@
1
+ /**
2
+ * ClawBee - Your Personal AI, Endless Possibilities
3
+ * https://clawbee.pro
4
+ *
5
+ * Main library entry point
6
+ * Exports all modules for programmatic use
7
+ */
8
+
9
+ const { AIProvider, AVAILABLE_MODELS, DEFAULT_MODELS } = require('./ai/provider');
10
+ const { SkillManager, builtInSkills } = require('./skills/manager');
11
+ const { SystemCommands } = require('./automation/system');
12
+ const { BrowserAutomation, scrapeUrl } = require('./automation/browser');
13
+ const { TelegramBot } = require('./integrations/telegram');
14
+ const { DiscordBot } = require('./integrations/discord');
15
+ const { SlackBot } = require('./integrations/slack');
16
+ const { WhatsAppBot, formatWhatsAppId } = require('./integrations/whatsapp');
17
+
18
+ module.exports = {
19
+ // AI
20
+ AIProvider,
21
+ AVAILABLE_MODELS,
22
+ DEFAULT_MODELS,
23
+
24
+ // Skills
25
+ SkillManager,
26
+ builtInSkills,
27
+
28
+ // Automation
29
+ SystemCommands,
30
+ BrowserAutomation,
31
+ scrapeUrl,
32
+
33
+ // Integrations
34
+ TelegramBot,
35
+ DiscordBot,
36
+ SlackBot,
37
+ WhatsAppBot,
38
+ formatWhatsAppId,
39
+
40
+ // Version
41
+ version: '2.2.0'
42
+ };
@@ -0,0 +1,85 @@
1
+ /**
2
+ * ClawBee Discord Integration
3
+ * Real working Discord bot integration
4
+ */
5
+
6
+ const { Client, GatewayIntentBits, Partials } = require('discord.js');
7
+
8
+ class DiscordBot {
9
+ constructor(token) {
10
+ this.token = token;
11
+ this.client = new Client({
12
+ intents: [
13
+ GatewayIntentBits.Guilds,
14
+ GatewayIntentBits.GuildMessages,
15
+ GatewayIntentBits.MessageContent,
16
+ GatewayIntentBits.DirectMessages
17
+ ],
18
+ partials: [Partials.Channel, Partials.Message]
19
+ });
20
+ this.messageHandler = null;
21
+ }
22
+
23
+ async start(messageHandler) {
24
+ this.messageHandler = messageHandler;
25
+
26
+ this.client.on('ready', () => {
27
+ console.log(`🐝 Discord bot logged in as ${this.client.user.tag}`);
28
+ });
29
+
30
+ this.client.on('messageCreate', async (message) => {
31
+ // Ignore bot messages
32
+ if (message.author.bot) return;
33
+
34
+ // Check if bot is mentioned or in DM
35
+ const isMentioned = message.mentions.has(this.client.user);
36
+ const isDM = !message.guild;
37
+
38
+ if (!isMentioned && !isDM) return;
39
+
40
+ // Remove mention from message
41
+ let content = message.content.replace(/<@!?\d+>/g, '').trim();
42
+
43
+ if (!content) {
44
+ content = 'Hello!';
45
+ }
46
+
47
+ try {
48
+ await message.channel.sendTyping();
49
+
50
+ const response = await this.messageHandler(content, {
51
+ platform: 'discord',
52
+ channelId: message.channel.id,
53
+ username: message.author.username,
54
+ userId: message.author.id,
55
+ guildId: message.guild?.id
56
+ });
57
+
58
+ // Split long messages
59
+ if (response.length > 2000) {
60
+ const chunks = response.match(/.{1,2000}/g);
61
+ for (const chunk of chunks) {
62
+ await message.reply(chunk);
63
+ }
64
+ } else {
65
+ await message.reply(response);
66
+ }
67
+ } catch (error) {
68
+ await message.reply(`❌ Error: ${error.message}`);
69
+ }
70
+ });
71
+
72
+ await this.client.login(this.token);
73
+ }
74
+
75
+ stop() {
76
+ this.client.destroy();
77
+ }
78
+
79
+ async sendMessage(channelId, content) {
80
+ const channel = await this.client.channels.fetch(channelId);
81
+ return channel.send(content);
82
+ }
83
+ }
84
+
85
+ module.exports = { DiscordBot };
@@ -0,0 +1,72 @@
1
+ /**
2
+ * ClawBee Slack Integration
3
+ * Real working Slack bot integration
4
+ */
5
+
6
+ const { App } = require('@slack/bolt');
7
+
8
+ class SlackBot {
9
+ constructor(botToken, signingSecret, appToken) {
10
+ this.app = new App({
11
+ token: botToken,
12
+ signingSecret: signingSecret,
13
+ appToken: appToken,
14
+ socketMode: !!appToken
15
+ });
16
+ this.messageHandler = null;
17
+ }
18
+
19
+ async start(messageHandler) {
20
+ this.messageHandler = messageHandler;
21
+
22
+ // Listen for app mentions
23
+ this.app.event('app_mention', async ({ event, say }) => {
24
+ const text = event.text.replace(/<@[A-Z0-9]+>/g, '').trim();
25
+
26
+ try {
27
+ const response = await this.messageHandler(text, {
28
+ platform: 'slack',
29
+ channelId: event.channel,
30
+ userId: event.user,
31
+ threadTs: event.thread_ts || event.ts
32
+ });
33
+
34
+ await say({
35
+ text: response,
36
+ thread_ts: event.thread_ts || event.ts
37
+ });
38
+ } catch (error) {
39
+ await say({
40
+ text: `❌ Error: ${error.message}`,
41
+ thread_ts: event.thread_ts || event.ts
42
+ });
43
+ }
44
+ });
45
+
46
+ // Listen for direct messages
47
+ this.app.event('message', async ({ event, say }) => {
48
+ if (event.channel_type !== 'im' || event.bot_id) return;
49
+
50
+ try {
51
+ const response = await this.messageHandler(event.text, {
52
+ platform: 'slack',
53
+ channelId: event.channel,
54
+ userId: event.user
55
+ });
56
+
57
+ await say(response);
58
+ } catch (error) {
59
+ await say(`❌ Error: ${error.message}`);
60
+ }
61
+ });
62
+
63
+ await this.app.start();
64
+ console.log('🐝 Slack bot started');
65
+ }
66
+
67
+ async stop() {
68
+ await this.app.stop();
69
+ }
70
+ }
71
+
72
+ module.exports = { SlackBot };
@@ -0,0 +1,95 @@
1
+ /**
2
+ * ClawBee Telegram Integration
3
+ * Real working Telegram bot integration
4
+ */
5
+
6
+ const axios = require('axios');
7
+
8
+ class TelegramBot {
9
+ constructor(token) {
10
+ this.token = token;
11
+ this.baseUrl = `https://api.telegram.org/bot${token}`;
12
+ this.offset = 0;
13
+ this.running = false;
14
+ }
15
+
16
+ async getMe() {
17
+ const response = await axios.get(`${this.baseUrl}/getMe`);
18
+ return response.data.result;
19
+ }
20
+
21
+ async sendMessage(chatId, text, options = {}) {
22
+ const response = await axios.post(`${this.baseUrl}/sendMessage`, {
23
+ chat_id: chatId,
24
+ text: text,
25
+ parse_mode: options.parseMode || 'Markdown',
26
+ ...options
27
+ });
28
+ return response.data.result;
29
+ }
30
+
31
+ async getUpdates(timeout = 30) {
32
+ try {
33
+ const response = await axios.get(`${this.baseUrl}/getUpdates`, {
34
+ params: {
35
+ offset: this.offset,
36
+ timeout: timeout,
37
+ allowed_updates: ['message', 'callback_query']
38
+ },
39
+ timeout: (timeout + 10) * 1000
40
+ });
41
+
42
+ const updates = response.data.result;
43
+ if (updates.length > 0) {
44
+ this.offset = updates[updates.length - 1].update_id + 1;
45
+ }
46
+ return updates;
47
+ } catch (error) {
48
+ if (error.code !== 'ETIMEDOUT') {
49
+ throw error;
50
+ }
51
+ return [];
52
+ }
53
+ }
54
+
55
+ async startPolling(messageHandler) {
56
+ this.running = true;
57
+ console.log('🐝 Telegram bot started polling...');
58
+
59
+ while (this.running) {
60
+ try {
61
+ const updates = await this.getUpdates();
62
+
63
+ for (const update of updates) {
64
+ if (update.message && update.message.text) {
65
+ const chatId = update.message.chat.id;
66
+ const text = update.message.text;
67
+ const username = update.message.from.username || update.message.from.first_name;
68
+
69
+ try {
70
+ const response = await messageHandler(text, {
71
+ platform: 'telegram',
72
+ chatId,
73
+ username,
74
+ messageId: update.message.message_id
75
+ });
76
+
77
+ await this.sendMessage(chatId, response);
78
+ } catch (error) {
79
+ await this.sendMessage(chatId, `❌ Error: ${error.message}`);
80
+ }
81
+ }
82
+ }
83
+ } catch (error) {
84
+ console.error('Telegram polling error:', error.message);
85
+ await new Promise(resolve => setTimeout(resolve, 5000));
86
+ }
87
+ }
88
+ }
89
+
90
+ stop() {
91
+ this.running = false;
92
+ }
93
+ }
94
+
95
+ module.exports = { TelegramBot };
@@ -0,0 +1,247 @@
1
+ /**
2
+ * ClawBee WhatsApp Integration
3
+ * Real working WhatsApp integration using whatsapp-web.js
4
+ * Connects via QR code scanning
5
+ */
6
+
7
+ const qrcode = require('qrcode-terminal');
8
+ const fs = require('fs');
9
+ const path = require('os').homedir();
10
+
11
+ // Session directory for persistent login
12
+ const SESSION_DIR = `${path}/.local/share/clawbee/integrations/whatsapp`;
13
+
14
+ class WhatsAppBot {
15
+ constructor() {
16
+ this.client = null;
17
+ this.isReady = false;
18
+ this.messageHandler = null;
19
+ this.qrHandler = null;
20
+ this.statusHandler = null;
21
+ }
22
+
23
+ /**
24
+ * Initialize the WhatsApp client
25
+ */
26
+ async initialize() {
27
+ // Dynamic import for whatsapp-web.js (ES module compatibility)
28
+ const { Client, LocalAuth } = await import('whatsapp-web.js');
29
+
30
+ // Ensure session directory exists
31
+ if (!fs.existsSync(SESSION_DIR)) {
32
+ fs.mkdirSync(SESSION_DIR, { recursive: true });
33
+ }
34
+
35
+ this.client = new Client({
36
+ authStrategy: new LocalAuth({
37
+ dataPath: SESSION_DIR
38
+ }),
39
+ puppeteer: {
40
+ headless: true,
41
+ args: [
42
+ '--no-sandbox',
43
+ '--disable-setuid-sandbox',
44
+ '--disable-dev-shm-usage',
45
+ '--disable-accelerated-2d-canvas',
46
+ '--no-first-run',
47
+ '--no-zygote',
48
+ '--disable-gpu'
49
+ ]
50
+ }
51
+ });
52
+
53
+ return this;
54
+ }
55
+
56
+ /**
57
+ * Start the WhatsApp bot
58
+ * @param {Function} messageHandler - Function to handle incoming messages
59
+ * @param {Object} options - Additional options
60
+ */
61
+ async start(messageHandler, options = {}) {
62
+ if (!this.client) {
63
+ await this.initialize();
64
+ }
65
+
66
+ this.messageHandler = messageHandler;
67
+ this.qrHandler = options.onQR || null;
68
+ this.statusHandler = options.onStatus || null;
69
+
70
+ // QR Code event - display for scanning
71
+ this.client.on('qr', (qr) => {
72
+ console.log('\n🐝 Scan this QR code with WhatsApp:\n');
73
+ qrcode.generate(qr, { small: true });
74
+ console.log('\nOpen WhatsApp > Settings > Linked Devices > Link a Device\n');
75
+
76
+ if (this.qrHandler) {
77
+ this.qrHandler(qr);
78
+ }
79
+ });
80
+
81
+ // Ready event - successfully connected
82
+ this.client.on('ready', () => {
83
+ this.isReady = true;
84
+ console.log('🐝 WhatsApp client is ready!');
85
+
86
+ if (this.statusHandler) {
87
+ this.statusHandler('ready', 'WhatsApp connected successfully');
88
+ }
89
+ });
90
+
91
+ // Authentication success
92
+ this.client.on('authenticated', () => {
93
+ console.log('🐝 WhatsApp authenticated');
94
+
95
+ if (this.statusHandler) {
96
+ this.statusHandler('authenticated', 'Authentication successful');
97
+ }
98
+ });
99
+
100
+ // Authentication failure
101
+ this.client.on('auth_failure', (msg) => {
102
+ console.error('🐝 WhatsApp authentication failed:', msg);
103
+
104
+ if (this.statusHandler) {
105
+ this.statusHandler('auth_failure', msg);
106
+ }
107
+ });
108
+
109
+ // Disconnected event
110
+ this.client.on('disconnected', (reason) => {
111
+ this.isReady = false;
112
+ console.log('🐝 WhatsApp disconnected:', reason);
113
+
114
+ if (this.statusHandler) {
115
+ this.statusHandler('disconnected', reason);
116
+ }
117
+ });
118
+
119
+ // Message received event
120
+ this.client.on('message', async (message) => {
121
+ // Skip status updates and own messages
122
+ if (message.isStatus || message.fromMe) return;
123
+
124
+ const chat = await message.getChat();
125
+ const contact = await message.getContact();
126
+
127
+ const context = {
128
+ platform: 'whatsapp',
129
+ chatId: message.from,
130
+ chatName: chat.name || contact.pushname || contact.number,
131
+ username: contact.pushname || contact.name || contact.number,
132
+ isGroup: chat.isGroup,
133
+ messageId: message.id._serialized,
134
+ timestamp: message.timestamp,
135
+ hasMedia: message.hasMedia
136
+ };
137
+
138
+ // Only process text messages for now
139
+ if (message.body && this.messageHandler) {
140
+ try {
141
+ // Show typing indicator
142
+ await chat.sendStateTyping();
143
+
144
+ // Get AI response
145
+ const response = await this.messageHandler(message.body, context);
146
+
147
+ // Send response
148
+ await message.reply(response);
149
+ } catch (error) {
150
+ console.error('WhatsApp message handling error:', error);
151
+ await message.reply(`❌ Error: ${error.message}`);
152
+ }
153
+ }
154
+ });
155
+
156
+ // Initialize client
157
+ console.log('🐝 Initializing WhatsApp connection...');
158
+ await this.client.initialize();
159
+ }
160
+
161
+ /**
162
+ * Send a message to a specific chat
163
+ * @param {string} chatId - WhatsApp chat ID (number@c.us for contacts, number-id@g.us for groups)
164
+ * @param {string} content - Message content
165
+ */
166
+ async sendMessage(chatId, content) {
167
+ if (!this.isReady) {
168
+ throw new Error('WhatsApp client is not ready');
169
+ }
170
+
171
+ return this.client.sendMessage(chatId, content);
172
+ }
173
+
174
+ /**
175
+ * Get all chats
176
+ */
177
+ async getChats() {
178
+ if (!this.isReady) {
179
+ throw new Error('WhatsApp client is not ready');
180
+ }
181
+
182
+ return this.client.getChats();
183
+ }
184
+
185
+ /**
186
+ * Get contact info
187
+ * @param {string} contactId - Contact ID
188
+ */
189
+ async getContact(contactId) {
190
+ if (!this.isReady) {
191
+ throw new Error('WhatsApp client is not ready');
192
+ }
193
+
194
+ return this.client.getContactById(contactId);
195
+ }
196
+
197
+ /**
198
+ * Get current connection state
199
+ */
200
+ getState() {
201
+ return {
202
+ isReady: this.isReady,
203
+ state: this.client?.info?.wid ? 'connected' : 'disconnected',
204
+ phoneNumber: this.client?.info?.wid?.user || null,
205
+ platform: this.client?.info?.platform || null
206
+ };
207
+ }
208
+
209
+ /**
210
+ * Logout and clear session
211
+ */
212
+ async logout() {
213
+ if (this.client) {
214
+ await this.client.logout();
215
+ this.isReady = false;
216
+
217
+ // Clear session files
218
+ if (fs.existsSync(SESSION_DIR)) {
219
+ fs.rmSync(SESSION_DIR, { recursive: true, force: true });
220
+ }
221
+ }
222
+ }
223
+
224
+ /**
225
+ * Destroy client connection
226
+ */
227
+ async stop() {
228
+ if (this.client) {
229
+ await this.client.destroy();
230
+ this.client = null;
231
+ this.isReady = false;
232
+ }
233
+ }
234
+ }
235
+
236
+ /**
237
+ * Format phone number to WhatsApp ID
238
+ * @param {string} phoneNumber - Phone number with country code
239
+ * @returns {string} WhatsApp chat ID
240
+ */
241
+ function formatWhatsAppId(phoneNumber) {
242
+ // Remove any non-digit characters
243
+ const cleaned = phoneNumber.replace(/\D/g, '');
244
+ return `${cleaned}@c.us`;
245
+ }
246
+
247
+ module.exports = { WhatsAppBot, formatWhatsAppId };