botforje 0.0.1

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.
Files changed (84) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +381 -0
  3. package/dist/action/action.js +44 -0
  4. package/dist/action/catalog.js +40 -0
  5. package/dist/action/cooldown.js +60 -0
  6. package/dist/action/executor.js +23 -0
  7. package/dist/action/template.js +13 -0
  8. package/dist/action/types.js +2 -0
  9. package/dist/action/webhook.js +36 -0
  10. package/dist/actions/action.js +26 -0
  11. package/dist/actions/cooldown.js +66 -0
  12. package/dist/actions/request.js +40 -0
  13. package/dist/api/routes/auth.js +56 -0
  14. package/dist/api/routes/bots.js +51 -0
  15. package/dist/api/routes/config.js +24 -0
  16. package/dist/api/routes/health.js +15 -0
  17. package/dist/api/routes/index.js +14 -0
  18. package/dist/api/routes/messages.js +69 -0
  19. package/dist/api/routes/sessions.js +97 -0
  20. package/dist/api/routes/status.js +38 -0
  21. package/dist/api/server.js +153 -0
  22. package/dist/auth/service.js +102 -0
  23. package/dist/boot/fleet.js +207 -0
  24. package/dist/bot/bot.js +30 -0
  25. package/dist/bot/fleet.js +211 -0
  26. package/dist/bot/fuzzy.js +20 -0
  27. package/dist/bot/mapper.js +47 -0
  28. package/dist/bot/types.js +2 -0
  29. package/dist/bot/validation.js +38 -0
  30. package/dist/bot.js +31 -0
  31. package/dist/cli/create-bot.js +84 -0
  32. package/dist/cli.js +138 -0
  33. package/dist/commands/auth.js +200 -0
  34. package/dist/commands/create-bot.js +64 -0
  35. package/dist/commands/guide.js +563 -0
  36. package/dist/commands/lock.js +73 -0
  37. package/dist/commands/status.js +145 -0
  38. package/dist/commands/unlock.js +88 -0
  39. package/dist/commands/validate.js +19 -0
  40. package/dist/config/mapper.js +152 -0
  41. package/dist/config/schema.js +2 -0
  42. package/dist/config/validation.js +705 -0
  43. package/dist/config/watcher.js +145 -0
  44. package/dist/config/yaml.js +197 -0
  45. package/dist/fleet.js +247 -0
  46. package/dist/flow/executor.js +286 -0
  47. package/dist/flow/flow.js +2 -0
  48. package/dist/flow/mapper.js +72 -0
  49. package/dist/flow/state.js +115 -0
  50. package/dist/flow/types.js +2 -0
  51. package/dist/graph/executor.js +294 -0
  52. package/dist/graph/graph.js +2 -0
  53. package/dist/graph/state.js +118 -0
  54. package/dist/helpers/data.js +42 -0
  55. package/dist/helpers/fuzzy.js +30 -0
  56. package/dist/helpers/logger.js +89 -0
  57. package/dist/helpers/validation.js +38 -0
  58. package/dist/index.js +92 -0
  59. package/dist/messages/contracts.js +2 -0
  60. package/dist/messages/inbox.js +58 -0
  61. package/dist/messages/outbox.js +136 -0
  62. package/dist/services/auto-response.js +62 -0
  63. package/dist/services/cooldown.js +60 -0
  64. package/dist/services/fleet.js +207 -0
  65. package/dist/services/flow-executor.js +195 -0
  66. package/dist/services/flow-state.js +118 -0
  67. package/dist/services/inbox.js +50 -0
  68. package/dist/services/message-handler.js +78 -0
  69. package/dist/services/message-queue.js +138 -0
  70. package/dist/services/outbox.js +138 -0
  71. package/dist/services/session.js +118 -0
  72. package/dist/services/webhook.js +87 -0
  73. package/dist/utils/logger.js +89 -0
  74. package/dist/utils/webhook.js +36 -0
  75. package/dist/validation/validate.js +592 -0
  76. package/dist/whatsapp/client.js +293 -0
  77. package/dist/whatsapp/session.js +158 -0
  78. package/dist/whatsapp/types.js +109 -0
  79. package/dist/whatsapp/whatsapp.js +109 -0
  80. package/package.json +97 -0
  81. package/scripts/postinstall.js +45 -0
  82. package/scripts/preuninstall.js +48 -0
  83. package/scripts/setup-systemd.js +91 -0
  84. package/service/botforje.service.template +25 -0
package/dist/bot.js ADDED
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createBot = createBot;
4
+ exports.registerChannel = registerChannel;
5
+ exports.createDefaultSettings = createDefaultSettings;
6
+ const validation_1 = require("./config/validation");
7
+ function createBot(props) {
8
+ (0, validation_1.validateId)(props.id, 'Bot');
9
+ return {
10
+ id: props.id,
11
+ phone: props.phone,
12
+ settings: props.settings,
13
+ graph: props.graph || '',
14
+ };
15
+ }
16
+ function registerChannel(bot, channel) {
17
+ bot.channel = channel;
18
+ return bot;
19
+ }
20
+ function createDefaultSettings() {
21
+ // TODO: simulateTyping, typingDelay, readReceipts are reserved for future implementation
22
+ return {
23
+ simulateTyping: true,
24
+ typingDelay: 1000,
25
+ queueDelay: 1000,
26
+ readReceipts: true,
27
+ ignoreGroups: true,
28
+ allowedSenders: [],
29
+ ignoredSenders: [],
30
+ };
31
+ }
@@ -0,0 +1,84 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.runCreateBot = runCreateBot;
7
+ const inquirer_1 = __importDefault(require("inquirer"));
8
+ const crypto_1 = require("crypto");
9
+ const qrcode_terminal_1 = __importDefault(require("qrcode-terminal"));
10
+ const client_1 = require("../whatsapp/client");
11
+ const yaml_1 = require("../config/yaml");
12
+ async function runCreateBot(configPath) {
13
+ if (configPath)
14
+ (0, yaml_1.setConfigPath)(configPath);
15
+ console.log('Welcome to WWeb BotForge!');
16
+ console.log('Let\'s create a new WhatsApp bot...\n');
17
+ try {
18
+ const answers = await inquirer_1.default.prompt([
19
+ {
20
+ type: 'input',
21
+ name: 'botName',
22
+ message: 'What would you like to name your bot?',
23
+ validate: (input) => {
24
+ if (input.trim().length === 0) {
25
+ return 'Bot name cannot be empty';
26
+ }
27
+ return true;
28
+ },
29
+ },
30
+ ]);
31
+ const botName = answers.botName.trim();
32
+ const botId = generateBotId(botName);
33
+ console.log(`\nGenerated bot ID: ${botId}`);
34
+ console.log(`Bot name: ${botName}`);
35
+ const initializer = new client_1.WhatsAppInitializer(botId);
36
+ let phoneNumber;
37
+ initializer.onQRCode((qr) => {
38
+ console.log('\nScan this QR code with WhatsApp to link your account:');
39
+ qrcode_terminal_1.default.generate(qr, { small: true });
40
+ });
41
+ initializer.onAuthSuccess((phone) => {
42
+ console.log('\nWhatsApp account linked successfully!');
43
+ console.log(`Connected to WhatsApp with phone: ${phone}`);
44
+ phoneNumber = phone;
45
+ });
46
+ initializer.onAuthFailure((error) => {
47
+ console.error('\nAuthentication failed:', error.message);
48
+ process.exit(1);
49
+ });
50
+ console.log('\nInitializing WhatsApp Web client...');
51
+ await initializer.initialize();
52
+ await new Promise((resolve) => {
53
+ const checkInterval = setInterval(() => {
54
+ if (phoneNumber) {
55
+ clearInterval(checkInterval);
56
+ resolve();
57
+ }
58
+ }, 1000);
59
+ });
60
+ const botConfig = {
61
+ settings: {
62
+ queue_delay: 1000,
63
+ ignore_groups: true,
64
+ ignored_senders: ['status@broadcast'],
65
+ },
66
+ };
67
+ await (0, yaml_1.addBotConfig)(botId, botConfig, configPath);
68
+ console.log(`\nAdded new bot: ${botName} (${botId})`);
69
+ console.log(`Connected to WhatsApp with phone: ${phoneNumber}`);
70
+ console.log(`\nBot configuration saved to ${(0, yaml_1.getConfigPath)()}`);
71
+ console.log(`\nYour bot "${botName}" (${botId}) is now ready to use!`);
72
+ console.log('\nTo start using your bot, run: npm start');
73
+ await initializer.destroy();
74
+ process.exit(0);
75
+ }
76
+ catch (error) {
77
+ console.error('\nError creating bot:', error);
78
+ process.exit(1);
79
+ }
80
+ }
81
+ function generateBotId(name) {
82
+ const hash = (0, crypto_1.createHash)('md5').update(name.toLowerCase()).digest('hex');
83
+ return `bot-${hash.substring(0, 8)}`;
84
+ }
package/dist/cli.js ADDED
@@ -0,0 +1,138 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ Object.defineProperty(exports, "__esModule", { value: true });
37
+ const commander_1 = require("commander");
38
+ const child_process_1 = require("child_process");
39
+ const path = __importStar(require("path"));
40
+ const fs = __importStar(require("fs"));
41
+ const fleet_1 = require("./fleet");
42
+ const outbox_1 = require("./messages/outbox");
43
+ const server_1 = require("./api/server");
44
+ const yaml_1 = require("./config/yaml");
45
+ const watcher_1 = require("./config/watcher");
46
+ const logger_1 = require("./helpers/logger");
47
+ const client_1 = require("./whatsapp/client");
48
+ const guide_1 = require("./commands/guide");
49
+ const validate_1 = require("./commands/validate");
50
+ const auth_1 = require("./commands/auth");
51
+ const status_1 = require("./commands/status");
52
+ const lock_1 = require("./commands/lock");
53
+ const unlock_1 = require("./commands/unlock");
54
+ const packageJsonPath = path.join(__dirname, '..', 'package.json');
55
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
56
+ const program = new commander_1.Command();
57
+ program
58
+ .name('botforje')
59
+ .description('CLI tool for creating and managing WhatsApp bots')
60
+ .version(packageJson.version)
61
+ .option('-c, --config <path>', `Path to config file (default: ${(0, yaml_1.getDefaultConfigPath)()})`);
62
+ program
63
+ .command('setup')
64
+ .description('Setup/repair systemd service')
65
+ .action(() => {
66
+ const setupScript = path.join(__dirname, '..', 'scripts', 'setup-systemd.js');
67
+ (0, child_process_1.execSync)(`node ${setupScript}`, { stdio: 'inherit' });
68
+ });
69
+ program
70
+ .command('guide')
71
+ .description('Show AI agent configuration guide')
72
+ .action(() => (0, guide_1.runGuide)());
73
+ program
74
+ .command('validate')
75
+ .description('Validate bot configuration')
76
+ .action(() => (0, validate_1.runValidate)(program.opts().config));
77
+ program
78
+ .command('daemon')
79
+ .alias('start')
80
+ .description('Start the WhatsApp bot daemon')
81
+ .action(async () => {
82
+ await runDaemon(program.opts().config);
83
+ });
84
+ program
85
+ .command('auth')
86
+ .description('Authenticate a bot session via QR code')
87
+ .argument('<botId>', 'Bot ID to authenticate')
88
+ .action(async (botId) => {
89
+ await (0, auth_1.runAuth)(botId, program.opts().config);
90
+ });
91
+ program
92
+ .command('lock')
93
+ .description('Enable API auth protection and generate a key')
94
+ .option('-k, --key <value>', 'Supply your own key (32+ characters)')
95
+ .action(async (options) => {
96
+ await (0, lock_1.runLock)(options.key, program.opts().config);
97
+ });
98
+ program
99
+ .command('unlock')
100
+ .description('Disable API auth protection')
101
+ .option('-k, --key <value>', 'Current auth key (will prompt if omitted)')
102
+ .action(async (options) => {
103
+ await (0, unlock_1.runUnlock)(options.key, program.opts().config);
104
+ });
105
+ program
106
+ .command('status')
107
+ .description('Show all bots and their session status')
108
+ .action(async () => {
109
+ await (0, status_1.runStatus)(program.opts().config);
110
+ });
111
+ async function runDaemon(configPath) {
112
+ if (configPath)
113
+ (0, yaml_1.setConfigPath)(configPath);
114
+ const configFile = await (0, yaml_1.loadConfig)(configPath);
115
+ if (configFile) {
116
+ (0, logger_1.setGlobalLogger)(configFile);
117
+ (0, client_1.setGlobalConfig)(configFile);
118
+ }
119
+ const logger = (0, logger_1.getLogger)();
120
+ logger.info('Botforje - Starting bots...');
121
+ const outboxService = new outbox_1.OutboxService();
122
+ const fleet = new fleet_1.BotFleet(outboxService);
123
+ const configWatcher = new watcher_1.ConfigWatcher(fleet);
124
+ configWatcher.start();
125
+ const bots = await fleet.start(configFile);
126
+ const address = configFile?.address || '127.0.0.1';
127
+ const authService = fleet.getAuthService();
128
+ if (address !== '127.0.0.1' && !authService.isLocked()) {
129
+ logger.warn('API is exposed on a non-local address. Run `botforje lock` to enable auth protection.');
130
+ }
131
+ if (configFile?.port) {
132
+ const apiPort = configFile.port;
133
+ const apiServer = new server_1.ApiServer(outboxService, bots, authService, apiPort, fleet, configWatcher, address);
134
+ await apiServer.start();
135
+ }
136
+ logger.info('Botforje Daemon is running');
137
+ }
138
+ program.parse();
@@ -0,0 +1,200 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.runAuth = runAuth;
40
+ const http = __importStar(require("http"));
41
+ const qrcode_terminal_1 = __importDefault(require("qrcode-terminal"));
42
+ const yaml_1 = require("../config/yaml");
43
+ async function getApiBase(configPath) {
44
+ try {
45
+ if (configPath)
46
+ (0, yaml_1.setConfigPath)(configPath);
47
+ const config = await (0, yaml_1.loadConfig)(configPath);
48
+ const apiPort = config.port || 3000;
49
+ return `http://localhost:${apiPort}`;
50
+ }
51
+ catch {
52
+ return 'http://localhost:3000';
53
+ }
54
+ }
55
+ async function apiRequest(method, path, apiBase, body) {
56
+ return new Promise((resolve, reject) => {
57
+ const urlObj = new URL(path, apiBase);
58
+ const options = {
59
+ hostname: urlObj.hostname,
60
+ port: urlObj.port,
61
+ path: urlObj.pathname,
62
+ method,
63
+ headers: { 'Content-Type': 'application/json' },
64
+ };
65
+ const req = http.request(options, (res) => {
66
+ let data = '';
67
+ res.on('data', (chunk) => { data += chunk; });
68
+ res.on('end', () => {
69
+ try {
70
+ resolve({ status: res.statusCode, data: JSON.parse(data) });
71
+ }
72
+ catch {
73
+ resolve({ status: res.statusCode, data });
74
+ }
75
+ });
76
+ });
77
+ req.on('error', (err) => {
78
+ if (err.code === 'ECONNREFUSED') {
79
+ reject(new Error('Daemon is not running. Start it with: botforje daemon'));
80
+ }
81
+ else {
82
+ reject(err);
83
+ }
84
+ });
85
+ if (body)
86
+ req.write(JSON.stringify(body));
87
+ req.end();
88
+ });
89
+ }
90
+ function subscribeToSSE(urlStr, onEvent) {
91
+ return new Promise((resolve, reject) => {
92
+ const urlObj = new URL(urlStr);
93
+ const options = {
94
+ hostname: urlObj.hostname,
95
+ port: urlObj.port,
96
+ path: urlObj.pathname,
97
+ method: 'GET',
98
+ headers: { Accept: 'text/event-stream' },
99
+ };
100
+ const req = http.request(options, (res) => {
101
+ if (res.statusCode !== 200) {
102
+ let data = '';
103
+ res.on('data', (chunk) => { data += chunk; });
104
+ res.on('end', () => reject(new Error(`SSE error ${res.statusCode}: ${data}`)));
105
+ return;
106
+ }
107
+ let buffer = '';
108
+ res.on('data', (chunk) => {
109
+ buffer += chunk.toString();
110
+ const parts = buffer.split('\n\n');
111
+ buffer = parts.pop() || '';
112
+ for (const part of parts) {
113
+ const lines = part.split('\n');
114
+ let eventType = 'message';
115
+ let data = '';
116
+ for (const line of lines) {
117
+ if (line.startsWith('event: '))
118
+ eventType = line.slice(7).trim();
119
+ else if (line.startsWith('data: '))
120
+ data = line.slice(6);
121
+ }
122
+ if (data) {
123
+ try {
124
+ onEvent(eventType, JSON.parse(data));
125
+ }
126
+ catch {
127
+ onEvent(eventType, data);
128
+ }
129
+ }
130
+ }
131
+ });
132
+ res.on('end', resolve);
133
+ res.on('error', reject);
134
+ });
135
+ req.on('error', (err) => {
136
+ if (err.code === 'ECONNREFUSED') {
137
+ reject(new Error('Daemon is not running. Start it with: botforje daemon'));
138
+ }
139
+ else {
140
+ reject(err);
141
+ }
142
+ });
143
+ req.end();
144
+ });
145
+ }
146
+ async function runAuth(botId, configPath) {
147
+ try {
148
+ if (configPath)
149
+ (0, yaml_1.setConfigPath)(configPath);
150
+ const apiBase = await getApiBase(configPath);
151
+ console.log(`\nAuthenticating bot: ${botId}`);
152
+ console.log('Contacting daemon...\n');
153
+ const result = await apiRequest('POST', `/api/sessions/${botId}`, apiBase);
154
+ if (result.status === 409) {
155
+ console.log(`Bot "${botId}" is already authenticated.`);
156
+ return;
157
+ }
158
+ if (result.status !== 200) {
159
+ console.error(`Error: ${result.data?.error || 'Unknown error'}`);
160
+ process.exit(1);
161
+ }
162
+ const state = result.data?.session?.state;
163
+ if (state === 'connected') {
164
+ console.log(`Bot "${botId}" is already connected!`);
165
+ return;
166
+ }
167
+ console.log('Waiting for QR code...');
168
+ console.log('(The QR code refreshes every 30 seconds if not scanned)\n');
169
+ let hasShownQR = false;
170
+ await subscribeToSSE(`${apiBase}/api/sessions/${botId}/events`, (eventType, data) => {
171
+ switch (eventType) {
172
+ case 'qr':
173
+ if (!hasShownQR) {
174
+ console.log('Scan this QR code with WhatsApp to link your account:\n');
175
+ hasShownQR = true;
176
+ }
177
+ qrcode_terminal_1.default.generate(data, { small: true });
178
+ break;
179
+ case 'ready':
180
+ console.log('\nBot authenticated successfully!');
181
+ process.exit(0);
182
+ case 'auth_failure':
183
+ console.error(`\nAuthentication failed: ${data}`);
184
+ process.exit(1);
185
+ case 'disconnected':
186
+ console.log(`\nSession disconnected: ${data}`);
187
+ break;
188
+ }
189
+ });
190
+ }
191
+ catch (error) {
192
+ if (error.message?.includes('Daemon is not running')) {
193
+ console.error(`\n${error.message}`);
194
+ }
195
+ else {
196
+ console.error(`\nError: ${error.message || error}`);
197
+ }
198
+ process.exit(1);
199
+ }
200
+ }
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.runCreateBot = runCreateBot;
7
+ const inquirer_1 = __importDefault(require("inquirer"));
8
+ const yaml_1 = require("../config/yaml");
9
+ const validation_1 = require("../helpers/validation");
10
+ async function runCreateBot(configPath) {
11
+ if (configPath)
12
+ (0, yaml_1.setConfigPath)(configPath);
13
+ console.log('Welcome to WWeb BotForge!');
14
+ console.log('Let\'s create a new WhatsApp bot...\n');
15
+ try {
16
+ const answers = await inquirer_1.default.prompt([
17
+ {
18
+ type: 'input',
19
+ name: 'botId',
20
+ message: 'Enter bot name identifier:',
21
+ validate: (input) => {
22
+ const sanitized = input.trim().toLowerCase();
23
+ if (sanitized.length === 0) {
24
+ return 'Bot name cannot be empty';
25
+ }
26
+ try {
27
+ (0, validation_1.validateId)(sanitized, 'Bot');
28
+ }
29
+ catch (e) {
30
+ return e.message;
31
+ }
32
+ return true;
33
+ },
34
+ },
35
+ {
36
+ type: 'confirm',
37
+ name: 'authenticateNow',
38
+ message: 'Do you want to authenticate now? (daemon must be running)',
39
+ default: false,
40
+ },
41
+ ]);
42
+ const botId = answers.botId.trim().toLowerCase();
43
+ const botConfig = {
44
+ settings: {
45
+ queue_delay: 1000,
46
+ ignore_groups: true,
47
+ ignored_senders: ['status@broadcast'],
48
+ },
49
+ };
50
+ await (0, yaml_1.addBotConfig)(botId, botConfig, configPath);
51
+ console.log(`\nAdded bot: ${botId}`);
52
+ console.log(`Bot configuration saved.`);
53
+ if (answers.authenticateNow) {
54
+ console.log(`\nTo authenticate, run: botforge auth ${botId}`);
55
+ console.log('(Make sure the daemon is running first)');
56
+ }
57
+ console.log(`\nEdit ${(0, yaml_1.getConfigPath)()} to add flows and actions.`);
58
+ console.log('Then run: botforge daemon');
59
+ }
60
+ catch (error) {
61
+ console.error('\nError creating bot:', error);
62
+ process.exit(1);
63
+ }
64
+ }