@manybot/manybot 5.1.0 → 5.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 CHANGED
@@ -6,7 +6,7 @@
6
6
  ![npm 9+](https://img.shields.io/badge/npm-9+-CB3837?logo=npm&logoColor=white)
7
7
  ![GPL v3](https://img.shields.io/badge/License-GPL--v3-blue.svg)
8
8
  ![Linux](https://img.shields.io/badge/Linux%20%7C%20Windows-lightgrey)
9
- ![whatsapp-web.js](https://img.shields.io/badge/WhatsApp-25D366?logo=whatsapp&logoColor=white)
9
+ ![Baileys](https://img.shields.io/badge/WhatsApp-25D366?logo=whatsapp&logoColor=white)
10
10
 
11
11
  </div>
12
12
 
@@ -27,9 +27,9 @@ npm install -g @manybot/manyplug
27
27
  manybot
28
28
  ```
29
29
 
30
- On first run, a configuration file is created at `~/.manybot/manybot.conf`. Edit it to set up your preferences and list the plugins you want to load.
30
+ On first run, a configuration file is created at `~/.manybot/manybot.toml`. Edit it to set up your preferences.
31
31
 
32
- For detailed setup instructions, see the **[documentation](https://manybot.stxerr.dev/docs/)**.
32
+ For detailed setup instructions, see the **[documentation](https://manybot.org/docs/)**.
33
33
 
34
34
  ## Plugins
35
35
 
@@ -39,16 +39,14 @@ ManyBot's functionality comes from plugins. Install them with ManyPlug:
39
39
  manyplug install <plugin-name>
40
40
  ```
41
41
 
42
- Browse available plugins at **[manybot.stxerr.dev/plugins](https://manybot.stxerr.dev/plugins/)**.
43
-
44
- Want to build your own? The plugin API lets you add commands and features without touching the bot's core - *documentation coming soon*.
42
+ Browse available plugins at **[manybot.org/plugins](https://manybot.org/plugins/)**.
45
43
 
46
44
  ## Contributing
47
45
 
48
46
  All kinds of contributions are welcome:
49
47
 
50
48
  - **Bug reports and feature requests**: open an issue on GitHub or Codeberg
51
- - **Code**: pull requests are welcome on [GitHub](https://github.com/many-bot/manybot) or [Codeberg](https://codeberg.org/many-bot/manybot); patches by email (`devel+manybot@stxerr.dev`) are also accepted - subscribe to the mailing list [here](https://list.stxerr.dev).
49
+ - **Code**: pull requests are welcome on [GitHub](https://github.com/many-bot/manybot) or [Codeberg](https://codeberg.org/many-bot/manybot); patches by email (`devel+manybot.org`) are also accepted - subscribe to the mailing list [here](https://list.stxerr.dev).
52
50
  - **Plugins**: submit your plugin to [manyplug-repo](https://github.com/many-bot/manyplug-repo), which has instructions on how to do it
53
51
  - **Anything else**: suggestions, translations, documentation fixes - reach out by email or open an issue
54
52
 
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "name": "SyntaxError!",
6
6
  "email": "me@stxerr.dev"
7
7
  },
8
- "version": "5.1.0",
8
+ "version": "5.2.0",
9
9
  "license": "GPL-3.0-only",
10
10
  "private": false,
11
11
  "engines": {
@@ -17,40 +17,49 @@
17
17
  },
18
18
  "type": "module",
19
19
  "bin": {
20
- "manybot": "./src/main.js"
20
+ "manybot": "dist/main.js"
21
21
  },
22
22
  "files": [
23
- "src/client",
24
- "src/config.js",
25
- "src/download",
26
- "src/i18n",
27
- "src/kernel",
28
- "src/locales",
29
- "src/logger",
30
- "src/main.js",
31
- "src/utils",
23
+ "dist/",
32
24
  "README.md",
33
- "README_EN.md",
34
- "latest",
35
25
  "LICENSE"
36
26
  ],
27
+ "scripts": {
28
+ "build": "tsc && node -e \"fs.mkdirSync('dist/locales', { recursive: true }); fs.cpSync('src/locales', 'dist/locales', { recursive: true });\"",
29
+ "start": "node dist/main.js",
30
+ "typecheck": "tsc --noEmit"
31
+ },
32
+ "devDependencies": {
33
+ "@types/better-sqlite3": "^7.6.12",
34
+ "@types/node": "^22.0.0",
35
+ "tsx": "^4.19.2",
36
+ "typescript": "^5.7.3"
37
+ },
37
38
  "dependencies": {
39
+ "@clack/prompts": "^0.10.0",
40
+ "@hapi/boom": "^10.0.1",
41
+ "@whiskeysockets/baileys": "^6.7.23",
42
+ "better-sqlite3": "^12.11.1",
43
+ "node-cron": "^4.6.0",
38
44
  "node-webpmux": "^3.2.1",
45
+ "pino": "^10.3.1",
39
46
  "qrcode-terminal": "^0.12.0",
40
- "smol-toml": "^1.7.0",
41
- "tar": "^7.5.16",
42
- "whatsapp-web.js": "^1.24.0"
47
+ "smol-toml": "^1.7.0"
43
48
  },
44
49
  "imports": {
45
- "#client/*": "./src/client/*.js",
46
- "#kernel/*": "./src/kernel/*.js",
47
- "#manyapi": "./src/kernel/pluginApi.js",
48
- "#sendguard": "./src/kernel/sendGuard.js",
49
- "#logger": "./src/logger/logger.js",
50
- "#utils/*": "./src/utils/*.js",
51
- "#i18n": "./src/i18n/index.js",
52
- "#download": "./src/download/queue.js",
53
- "#config": "./src/config.js",
54
- "#main": "./src/main.js"
50
+ "#drivers/*": "./dist/drivers/*",
51
+ "#core/*": "./dist/core/*",
52
+ "#client/*": "./dist/client/*",
53
+ "#kernel/*": "./dist/kernel/*",
54
+ "#manyapi": "./dist/kernel/pluginApi.js",
55
+ "#settingsdb": "./dist/kernel/settingsDb.js",
56
+ "#sendguard": "./dist/kernel/sendGuard.js",
57
+ "#logger": "./dist/logger/logger.js",
58
+ "#utils/*": "./dist/utils/*",
59
+ "#i18n": "./dist/i18n/index.js",
60
+ "#download": "./dist/download/queue.js",
61
+ "#config": "./dist/config.js",
62
+ "#main": "./dist/main.js",
63
+ "#types": "./dist/types.js"
55
64
  }
56
65
  }
@@ -1,57 +0,0 @@
1
- const C = {
2
- reset: "\x1b[0m",
3
- bold: "\x1b[1m",
4
-
5
- blue: "\x1b[94m",
6
- magenta: "\x1b[95m",
7
- cyan: "\x1b[96m",
8
- gray: "\x1b[90m",
9
- yellow: "\x1b[93m",
10
- };
11
-
12
- import { readFileSync } from "fs";
13
- import { fileURLToPath } from "url";
14
- import path from "path";
15
-
16
- const __filename = fileURLToPath(import.meta.url);
17
- const __dirname = path.dirname(__filename);
18
-
19
- const v = JSON.parse(
20
- readFileSync(
21
- path.join(__dirname, "../../package.json"),
22
- "utf8"
23
- )
24
- ).version;
25
-
26
- export function printBanner() {
27
- const banner = [
28
- ` _ _ `,
29
- ` | | | | `,
30
- ` _ __ ___ __ _ _ __ _ _| |__ ___ | |_`,
31
- `| '_ \` _ \\ / _\` | '_ \\| | | | '_ \\ / _ \\| __`,
32
- `| | | | | | (_| | | | | |_| | |_) | (_) | |_`,
33
- `|_| |_| |_|\\__,_|_| |_|\\__, |_.__/ \\___/ \\__`,
34
- ` __/ | `,
35
- ` ${v} |___/ `
36
- ];
37
-
38
- console.log(`${C.bold}${C.blue}`);
39
- console.log(banner.join("\n"));
40
- console.log(C.reset);
41
-
42
- console.log(
43
- ` made with ${C.magenta}<3${C.reset} by ${C.bold}${C.cyan}SyntaxError!${C.reset} ${C.gray}<me@stxerr.dev>${C.reset}`
44
- );
45
-
46
- console.log();
47
-
48
- console.log(
49
- ` ${C.gray}website${C.reset} : ${C.yellow}https://manybot.stxerr.dev${C.reset}`
50
- );
51
-
52
- console.log(
53
- ` ${C.gray}github ${C.reset} : ${C.yellow}https://github.com/many-bot${C.reset}`
54
- );
55
-
56
- console.log();
57
- }
@@ -1,185 +0,0 @@
1
- /* whatsappClient
2
- *
3
- * Initialize client and connect to WhatsApp
4
- *
5
- * if PHONE_NUMBER is set on config, it will request a verficiation code
6
- * but if it is not, it will display a QR Code on the screen to scan using your phone
7
- *
8
- * */
9
-
10
- import pkg from "whatsapp-web.js";
11
- import fs from "fs";
12
- import path from "path";
13
- import { fileURLToPath } from "url";
14
- import { PHONE_NUMBER, CLIENT_ID } from "#config";
15
- import { logger } from "#logger";
16
- import qrcode from "qrcode-terminal";
17
- import { t } from "#i18n"
18
- import { CONFIG_DIR } from "#config";
19
- import { extract } from "tar";
20
- import { pipeline } from "node:stream/promises";
21
- import { Readable } from "node:stream";
22
- import { Transform } from "node:stream";
23
- const os = process.platform;
24
-
25
- const __filename = fileURLToPath(import.meta.url);
26
- const __dirname = path.dirname(__filename);
27
-
28
- const DATA_PATH = path.join(CONFIG_DIR, "sessions");
29
-
30
- const chromeDir = path.join(CONFIG_DIR, "chrome");
31
-
32
- const bins = {
33
- linux: "chrome",
34
- win32: "chrome.exe"
35
- }
36
-
37
- const chrome = path.join(chromeDir, bins[os]);
38
-
39
- if (!fs.existsSync(chrome)) {
40
- try {
41
- logger.warn(t("errors.chromeNotFound"));
42
- const tmpDir = "/tmp/manybot-chrome";
43
- const tmpPath = path.join(tmpDir, "chrome.tar.gz");
44
- const urls = {
45
- linux: "https://api.manybot.stxerr.dev/download-chrome-linux",
46
- win32: "https://api.manybot.stxerr.dev/download-chrome-win"
47
- }
48
-
49
- const url = urls[os];
50
- if (!url) throw new Error(t("errors.OSNotSupported", { os }));
51
-
52
- fs.mkdirSync(tmpDir, { recursive: true });
53
-
54
- const res = await fetch(url);
55
- if (!res.ok) throw new Error(`HTTP ${res.status}`);
56
-
57
- const expected = Number(res.headers.get("content-length"));
58
- let received = 0;
59
- const frames = ["|","/","-","\\"];
60
- let frame = 0;
61
- let spinner;
62
-
63
- const file = fs.createWriteStream(tmpPath);
64
-
65
- spinner = setInterval(() => {
66
- const pct = expected
67
- ? ` ${Math.floor((received / expected) * 100)}%`
68
- : ` ${(received / 1024 / 1024).toFixed(1)}MB`;
69
- process.stderr.write(`\r${frames[frame++ % frames.length]} Baixando Chrome...${pct}`);
70
- }, 80);
71
-
72
- const counter = new Transform({
73
- transform(chunk, _enc, cb) {
74
- received += chunk.length;
75
- cb(null, chunk);
76
- }
77
- });
78
-
79
- try {
80
- await pipeline(
81
- Readable.fromWeb(res.body),
82
- counter,
83
- file
84
- );
85
- } finally {
86
- clearInterval(spinner);
87
- process.stderr.write("\r\x1b[2K");
88
- }
89
-
90
- if (expected && received !== expected) {
91
- throw new Error("Download incompleto");
92
- }
93
-
94
- await extract({ file: tmpPath, cwd: CONFIG_DIR, gzip: true });
95
- } catch (err) {
96
- throw new Error(t("errors.couldNotDownloadChrome") + err.message);
97
- }
98
-
99
- }
100
- export const { Client, LocalAuth, MessageMedia } = pkg;
101
-
102
- // -- Instance --------------------------------------------------
103
- const clientOptions = {
104
- authStrategy: new LocalAuth({
105
- clientId: CLIENT_ID,
106
- dataPath: DATA_PATH
107
- }),
108
- puppeteer: {
109
- executablePath: chrome,
110
- headless: true,
111
- args: [
112
- '--no-sandbox',
113
- '--disable-setuid-sandbox'
114
- ],
115
- },
116
- };
117
-
118
- // -- Qr Handle --------------------------------------------------
119
- export function handleQR(qr) {
120
- logger.info(t("system.qrScan"));
121
- qrcode.generate(qr, { small: true });
122
- }
123
-
124
- // -- Handle pairing code ---------------------------------------
125
- export function handlePairingCode(code) {
126
- logger.info(t("system.pairingCodeTitle"));
127
- logger.info(t("system.pairingCodeValue", { code: code }));
128
- logger.info(t("system.pairingCodeInstructions"));
129
- }
130
-
131
- // -- Phone Number Validation ------------------------------------
132
- const AUTH_STATE_PATH = path.join(__dirname, `../../.auth_${CLIENT_ID}.json`);
133
-
134
- // Validates if phone string has 10-15 characters
135
- function isValidPhoneNumber(phone) {
136
- if (!phone || typeof phone !== 'string') return false;
137
- const phoneRegex = /^\d{10,15}$/;
138
- return phoneRegex.test(phone);
139
- }
140
-
141
- // Checks if phone number changed since last authentication
142
- function hasPhoneNumberChanged(currentPhone) {
143
- try {
144
- if (!fs.existsSync(AUTH_STATE_PATH)) return false;
145
- const state = JSON.parse(fs.readFileSync(AUTH_STATE_PATH, 'utf8'));
146
- const storedPhone = state.phoneNumber || null;
147
- return storedPhone !== currentPhone;
148
- } catch {
149
- return false;
150
- }
151
- }
152
-
153
- // Saves phone number to auth state file
154
- function savePhoneNumber(phone) {
155
- try {
156
- fs.writeFileSync(AUTH_STATE_PATH, JSON.stringify({ phoneNumber: phone, savedAt: new Date().toISOString() }));
157
- } catch {
158
- return false;
159
- }
160
- }
161
-
162
- // Check if phone number changed and force re-authentication if needed
163
- if (PHONE_NUMBER && hasPhoneNumberChanged(PHONE_NUMBER)) {
164
- // Delete auth folder to force fresh authentication
165
- const authPath = path.join(__dirname, `../../.wwebjs_auth/session-${CLIENT_ID}`);
166
- if (fs.existsSync(authPath)) {
167
- fs.rmSync(authPath, { recursive: true, force: true });
168
- }
169
- }
170
-
171
- // Add phone number pairing if PHONE_NUMBER is configured and valid
172
- if (PHONE_NUMBER) {
173
- if (isValidPhoneNumber(PHONE_NUMBER)) {
174
- clientOptions.pairWithPhoneNumber = {
175
- phoneNumber: PHONE_NUMBER,
176
- showNotification: true,
177
- };
178
- }
179
- savePhoneNumber(PHONE_NUMBER);
180
- }
181
-
182
- export const client = new Client(clientOptions);
183
-
184
-
185
- export default client;
package/src/config.js DELETED
@@ -1,288 +0,0 @@
1
- /**
2
- * config.js
3
- *
4
- * Loads config from up to four files, merged in strict precedence order:
5
- *
6
- * defaults < legacy .conf < TOML
7
- *
8
- * Legacy files (frozen — no new keys):
9
- * ~/.manybot/manybot.conf
10
- * ~/.manybot/manyplug.conf
11
- *
12
- * TOML files (all new features go here):
13
- * ~/.manybot/manybot.toml
14
- * ~/.manybot/manyplug.toml
15
- *
16
- * The final CONFIG object always has the same shape regardless of which
17
- * files are present. Plugins must never see a structural difference.
18
- */
19
-
20
- import fs from "fs/promises";
21
- import os from "os";
22
- import path from "path";
23
- import { parse as parseToml } from "smol-toml";
24
- import { logger } from "#logger";
25
-
26
- // ---------------------------------------------------------------------------
27
- // Paths
28
- // ---------------------------------------------------------------------------
29
-
30
- export const CONFIG_DIR = path.join(os.homedir(), ".manybot");
31
-
32
- /** @deprecated Use TOML_CONFIG_FILE. Frozen — no new keys. */
33
- export const CONFIG_FILE = path.join(CONFIG_DIR, "manybot.conf");
34
- /** @deprecated Use TOML_PLUGIN_FILE. Frozen — no new keys. */
35
- export const PLUGIN_FILE = path.join(CONFIG_DIR, "manyplug.conf");
36
-
37
- export const TOML_CONFIG_FILE = path.join(CONFIG_DIR, "manybot.toml");
38
- export const TOML_PLUGIN_FILE = path.join(CONFIG_DIR, "manyplug.toml");
39
-
40
- // ---------------------------------------------------------------------------
41
- // Legacy .conf parser (frozen — do not extend)
42
- // ---------------------------------------------------------------------------
43
-
44
- function parseValue(value) {
45
- value = value.trim();
46
- if (
47
- (value.startsWith('"') && value.endsWith('"')) ||
48
- (value.startsWith("'") && value.endsWith("'"))
49
- ) {
50
- value = value.slice(1, -1);
51
- }
52
- if (value === "true") return true;
53
- if (value === "false") return false;
54
- return value;
55
- }
56
-
57
- function stripInlineComment(line) {
58
- let result = "";
59
- let quote = null;
60
- for (let i = 0; i < line.length; i++) {
61
- const ch = line[i];
62
- if ((ch === '"' || ch === "'") && line[i - 1] !== "\\") {
63
- if (quote === ch) quote = null;
64
- else if (!quote) quote = ch;
65
- }
66
- if (ch === "#" && !quote) break;
67
- result += ch;
68
- }
69
- return result.trim();
70
- }
71
-
72
- function parseConf(raw) {
73
- const lines = raw.split(/\r?\n/);
74
- const mergedLines = [];
75
- let insideList = false;
76
- let buffer = "";
77
-
78
- for (let line of lines) {
79
- line = stripInlineComment(line);
80
- if (!line) continue;
81
-
82
- if (!insideList) {
83
- if (/=\s*\[$/.test(line)) {
84
- insideList = true;
85
- buffer = line;
86
- } else {
87
- mergedLines.push(line);
88
- }
89
- } else {
90
- buffer += " " + line;
91
- if (line.includes("]")) {
92
- mergedLines.push(buffer);
93
- buffer = "";
94
- insideList = false;
95
- }
96
- }
97
- }
98
-
99
- const config = {};
100
- for (const line of mergedLines) {
101
- const idx = line.indexOf("=");
102
- if (idx === -1) continue;
103
- const key = line.slice(0, idx).trim();
104
- let value = line.slice(idx + 1).trim();
105
-
106
- if (value.startsWith("[") && value.endsWith("]")) {
107
- config[key] = value
108
- .slice(1, -1)
109
- .split(",")
110
- .map(v => parseValue(v))
111
- .filter(v => v !== "");
112
- continue;
113
- }
114
- config[key] = parseValue(value);
115
- }
116
- return config;
117
- }
118
-
119
- // ---------------------------------------------------------------------------
120
- // TOML migration
121
- // ---------------------------------------------------------------------------
122
-
123
- function escapeTomlString(s) {
124
- return s
125
- .replaceAll("\\", "\\\\")
126
- .replaceAll('"', '\\"');
127
- }
128
-
129
- function toToml(obj) {
130
- return Object.entries(obj)
131
- .map(([k, v]) => {
132
- if (Array.isArray(v))
133
- return `${k} = [${v.map(JSON.stringify).join(", ")}]`;
134
-
135
- if (v == null || v === "")
136
- return `${k} = ""`;
137
-
138
- return typeof v === "string"
139
- ? `${k} = "${escapeTomlString(v)}"`
140
- : `${k} = ${v}`;
141
- })
142
- .join("\n") + "\n";
143
- }
144
-
145
- async function migrateLegacyIfNeeded() {
146
- if (await fileExists(TOML_CONFIG_FILE))
147
- return;
148
-
149
- const migrate = async (src, dest, omit = []) => {
150
- const raw = await readFileSafe(src);
151
- if (!raw) return false;
152
-
153
- const cfg = parseConf(raw);
154
-
155
- for (const k of omit)
156
- delete cfg[k];
157
-
158
- await fs.writeFile(dest, toToml(cfg), "utf8");
159
- await fs.rename(src, `${src}.bak`);
160
-
161
- return true;
162
- };
163
-
164
- const migrated =
165
- await migrate(CONFIG_FILE, TOML_CONFIG_FILE, ["PLUGINS"]) ||
166
- await migrate(PLUGIN_FILE, TOML_PLUGIN_FILE);
167
-
168
- if (migrated)
169
- logger.success("Config migrated to TOML");
170
- }
171
-
172
- // ---------------------------------------------------------------------------
173
- // File helpers
174
- // ---------------------------------------------------------------------------
175
-
176
- async function fileExists(file) {
177
- try { await fs.stat(file); return true; }
178
- catch { return false; }
179
- }
180
-
181
- async function readFileSafe(file) {
182
- try {
183
- return await fs.readFile(file, "utf-8");
184
- } catch (err) {
185
- if (err.code !== "ENOENT") logger.warn(`Error reading ${file}: ${err.message}`);
186
- return null;
187
- }
188
- }
189
-
190
- // ---------------------------------------------------------------------------
191
- // Bootstrap: ensure at least one config file exists
192
- // ---------------------------------------------------------------------------
193
-
194
- const DEFAULT_TOML =
195
- `# ManyBot configuration file
196
- # See https://manybot.stxerr.dev/docs/config to learn more
197
-
198
- CLIENT_ID = "manybot"
199
- CMD_PREFIX = "!"
200
- CHATS = []
201
- LANGUAGE = "en"
202
- PHONE_NUMBER = ""
203
- `;
204
-
205
- await fs.mkdir(CONFIG_DIR, { recursive: true });
206
-
207
- await migrateLegacyIfNeeded();
208
-
209
- if (!await fileExists(TOML_CONFIG_FILE)) {
210
- logger.warn(`Creating ${TOML_CONFIG_FILE}`);
211
- await fs.writeFile(TOML_CONFIG_FILE, DEFAULT_TOML);
212
- }
213
-
214
- // ---------------------------------------------------------------------------
215
- // Layer 1 — tOML
216
- // ---------------------------------------------------------------------------
217
-
218
- const legacyLayer = {};
219
-
220
- // ---------------------------------------------------------------------------
221
- // Layer 2 — TOML (all new features land here)
222
- // ---------------------------------------------------------------------------
223
-
224
- let tomlLayer = {};
225
-
226
- async function loadToml(file, label) {
227
- const raw = await readFileSafe(file);
228
- if (raw === null) return {};
229
- try {
230
- return parseToml(raw);
231
- } catch (err) {
232
- logger.warn(`Error parsing ${label}: ${err.message}`);
233
- return {};
234
- }
235
- }
236
-
237
- tomlLayer = {
238
- ...await loadToml(TOML_CONFIG_FILE, "manybot.toml"),
239
- ...await loadToml(TOML_PLUGIN_FILE, "manyplug.toml"),
240
- };
241
-
242
- // ---------------------------------------------------------------------------
243
- // Merge + normalize
244
- //
245
- // Normalization runs once on the final merged object so both legacy and TOML
246
- // layers are treated identically. Add new normalization rules here only.
247
- // ---------------------------------------------------------------------------
248
-
249
- const DEFAULTS = {
250
- CMD_PREFIX: "!",
251
- CLIENT_ID: "manybot",
252
- CHATS: [],
253
- PLUGINS: [],
254
- LANGUAGE: "en",
255
- PHONE_NUMBER: null,
256
- };
257
-
258
- function normalize(cfg) {
259
- // Empty string and absent PHONE_NUMBER are both treated as null so plugins
260
- // can always do a simple truthiness check regardless of config source.
261
- if (cfg.PHONE_NUMBER === "") cfg.PHONE_NUMBER = null;
262
- return cfg;
263
- }
264
-
265
- export const CONFIG = normalize({
266
- ...DEFAULTS,
267
- ...legacyLayer, // legacy .conf overrides defaults
268
- ...tomlLayer, // TOML overrides legacy .conf
269
- });
270
-
271
- // ---------------------------------------------------------------------------
272
- // Named exports — identical shape regardless of config source
273
- // ---------------------------------------------------------------------------
274
-
275
- export const CLIENT_ID = CONFIG.CLIENT_ID;
276
- export const CMD_PREFIX = CONFIG.CMD_PREFIX;
277
- export const CHATS = CONFIG.CHATS;
278
- export const PLUGINS = CONFIG.PLUGINS;
279
- export const LANGUAGE = CONFIG.LANGUAGE;
280
- export const PHONE_NUMBER = CONFIG.PHONE_NUMBER;
281
-
282
- export const PATHS = {
283
- HOME: CONFIG_DIR,
284
- CONFIG_FILE,
285
- PLUGIN_FILE,
286
- TOML_CONFIG_FILE,
287
- TOML_PLUGIN_FILE,
288
- };