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/README.md +238 -55
- package/bin/clawbee.js +1256 -130
- package/lib/ai/provider.js +377 -0
- package/lib/automation/browser.js +154 -0
- package/lib/automation/system.js +193 -0
- package/lib/index.js +42 -0
- package/lib/integrations/discord.js +85 -0
- package/lib/integrations/slack.js +72 -0
- package/lib/integrations/telegram.js +95 -0
- package/lib/integrations/whatsapp.js +247 -0
- package/lib/skills/manager.js +301 -0
- package/package.json +23 -16
- package/src/core/clawbee.ts +0 -124
- package/src/core/config.ts +0 -88
- package/src/core/memory.ts +0 -98
- package/src/index.ts +0 -14
- package/src/skills/manager.ts +0 -89
- package/src/types.ts +0 -73
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 };
|