foliko 1.0.3 → 1.0.5

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.
@@ -26,7 +26,9 @@
26
26
  "Bash(node -e \":*)",
27
27
  "Bash(node -e \"\nconst { loadAgentConfig } = require\\('./plugins/default-plugins'\\);\nconst config = loadAgentConfig\\('D:/Date/20260321/app/.agent'\\);\nconsole.log\\('skillsDirs:', config.skillsDirs\\);\n\")",
28
28
  "Bash(cd D:/Code/vb-agent && pnpm install --shamefully-hoist 2>&1 | head -20)",
29
- "Bash(cd D:/Code/vb-agent && rm -rf node_modules && pnpm install)"
29
+ "Bash(cd D:/Code/vb-agent && rm -rf node_modules && pnpm install)",
30
+ "Bash(cd D:/Code/vb-agent && timeout 8 node test-tg.js 2>&1 || true)",
31
+ "Bash(cd D:/Code/vb-agent && timeout 10 node test-tg.js 2>&1 || true)"
30
32
  ]
31
33
  }
32
34
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "foliko",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "简约的插件化 Agent 框架",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -31,6 +31,7 @@
31
31
  "marked": "^11.2.0",
32
32
  "marked-terminal": "6",
33
33
  "node-cron": "^4.2.1",
34
+ "node-telegram-bot-api": "^0.67.0",
34
35
  "zod": "^3.24.0"
35
36
  }
36
37
  }
@@ -28,11 +28,12 @@ class AIPlugin extends Plugin {
28
28
 
29
29
  install(framework) {
30
30
  this._framework = framework
31
+ this._initAIClient()
31
32
  return this
32
33
  }
33
34
 
34
35
  start(framework) {
35
- this._initAIClient()
36
+ // AI client 已在 install 中初始化
36
37
  return this
37
38
  }
38
39
 
@@ -212,6 +212,25 @@ async function bootstrapDefaults(framework, config = {}) {
212
212
  console.log('[Bootstrap] AI Plugin loaded')
213
213
  }
214
214
 
215
+ // 1.5 创建主 Agent(供 Telegram 等需要绑定 Agent 的插件使用)
216
+ if (!framework._mainAgent && aiConfig.provider) {
217
+ const { Agent } = require('../src/core/agent')
218
+ const aiPlugin = framework.pluginManager.get('ai')
219
+ const aiClient = aiPlugin ? aiPlugin.getAIClient() : null
220
+ console.log('[Bootstrap] Creating Main Agent - aiClient:', !!aiClient)
221
+
222
+ framework._mainAgent = new Agent(framework, {
223
+ name: 'MainAgent',
224
+ systemPrompt: '你是一个有帮助的AI助手。',
225
+ model: aiConfig.model,
226
+ provider: aiConfig.provider,
227
+ apiKey: aiConfig.apiKey,
228
+ baseURL: aiConfig.baseURL
229
+ })
230
+ framework._agents.push(framework._mainAgent)
231
+ console.log('[Bootstrap] Main Agent created, has _chatHandler:', !!framework._mainAgent._chatHandler)
232
+ }
233
+
215
234
  // 2. Storage 存储插件
216
235
  if (!framework.pluginManager.has('storage')) {
217
236
  const { StoragePlugin } = require('./storage-plugin')
@@ -351,6 +370,20 @@ async function bootstrapDefaults(framework, config = {}) {
351
370
  console.log('[Bootstrap] Python Plugin Loader already loaded, skipping')
352
371
  }
353
372
 
373
+ // 12.6 Telegram 插件(如果配置了Token)
374
+ if (!framework.pluginManager.has('telegram')) {
375
+ const telegramToken = process.env.TELEGRAM_BOT_TOKEN || agentConfig.telegram?.botToken
376
+ if (telegramToken) {
377
+ const { Plugin } = require('../src/core/plugin-base')
378
+ const createTelegramPlugin = require('./telegram-plugin')
379
+ const TelegramPlugin = createTelegramPlugin(Plugin)
380
+ await framework.loadPlugin(new TelegramPlugin({ botToken: telegramToken }))
381
+ console.log('[Bootstrap] Telegram Plugin loaded')
382
+ }
383
+ } else {
384
+ console.log('[Bootstrap] Telegram Plugin already loaded, skipping')
385
+ }
386
+
354
387
  // 13. 加载自定义插件
355
388
  await loadCustomPlugins(framework, agentConfig)
356
389
 
@@ -0,0 +1,510 @@
1
+ /**
2
+ * Telegram 插件 v2
3
+ * 支持绑定主Agent进行持续对话
4
+ *
5
+ * 配置:
6
+ * - botToken: Telegram Bot Token (必需)
7
+ * - allowedChats: 允许的聊天ID数组
8
+ * - groupMode: 是否启用群组模式
9
+ * - prefix: 命令前缀
10
+ */
11
+
12
+ const { Plugin } = require('../src/core/plugin-base')
13
+ const { z } = require('zod')
14
+
15
+ // 转义 MarkdownV2 特殊字符
16
+ function escapeMarkdown(text) {
17
+ if (!text) return ''
18
+ // MarkdownV2 需要转义的字符
19
+ return text.replace(/([\_*\[\]()~`>#+\-=|{}.!])/g, '\\$1')
20
+ }
21
+
22
+ module.exports = function(Plugin) {
23
+ return class TelegramPlugin extends Plugin {
24
+ constructor(config = {}) {
25
+ super()
26
+ this.name = 'telegram'
27
+ this.version = '2.0.0'
28
+ this.description = 'Telegram 对话插件,绑定主Agent进行持续对话'
29
+ this.priority = 80
30
+
31
+ this.config = {
32
+ botToken: config.botToken || process.env.TELEGRAM_BOT_TOKEN,
33
+ allowedChats: config.allowedChats || [],
34
+ groupMode: config.groupMode || false,
35
+ prefix: config.prefix || '/',
36
+ systemPrompt: config.systemPrompt || '你是一个有帮助的AI助手。'
37
+ }
38
+
39
+ this._framework = null
40
+ this._bot = null
41
+ this._sessions = new Map() // chatId -> { agent, history, lastActive }
42
+ this._streamingMessages = new Map() // chatId -> messageId
43
+ }
44
+
45
+ install(framework) {
46
+ this._framework = framework
47
+ return this
48
+ }
49
+
50
+ start(framework) {
51
+ if (!this.config.botToken) {
52
+ console.warn('[Telegram] No bot token. Set TELEGRAM_BOT_TOKEN env var.')
53
+ return this
54
+ }
55
+
56
+ this._initBot()
57
+ return this
58
+ }
59
+
60
+ _initBot() {
61
+ try {
62
+ // 添加 .agent/node_modules 到搜索路径
63
+ // const path = require('path')
64
+ // const agentNodeModules = path.join(process.cwd(), '.agent', 'node_modules')
65
+ // if (!module.paths.includes(agentNodeModules)) {
66
+ // module.paths.unshift(agentNodeModules)
67
+ // }
68
+
69
+ const TelegramBot = require('node-telegram-bot-api')
70
+ this._bot = new TelegramBot(this.config.botToken, { polling: true })
71
+
72
+ console.log('[Telegram] Bot started successfully')
73
+
74
+ // 注册菜单命令
75
+ this._bot.setMyCommands([
76
+ { command: 'start', description: '显示帮助信息' },
77
+ { command: 'clear', description: '清除对话历史' },
78
+ { command: 'history', description: '查看对话状态' }
79
+ ]).then(() => {
80
+ console.log('[Telegram] Commands registered')
81
+ }).catch((err) => {
82
+ console.error('[Telegram] Failed to register commands:', err.message)
83
+ })
84
+
85
+ // 监听消息
86
+ this._bot.on('message', (msg) => this._handleMessage(msg))
87
+
88
+ // 监听编辑消息
89
+ this._bot.on('edit_message', (msg) => this._handleEdit(msg))
90
+
91
+ // 监听回调
92
+ this._bot.on('callback_query', (query) => this._handleCallback(query))
93
+
94
+ // 监听错误
95
+ this._bot.on('polling_error', (err) => {
96
+ console.error('[Telegram] Polling error:', err.message)
97
+ })
98
+
99
+ this._bot.on('error', (err) => {
100
+ console.error('[Telegram] Bot error:', err.message)
101
+ })
102
+
103
+ // 监听 Agent 创建事件,确保在 Agent 创建后能正确获取
104
+ if (this._framework) {
105
+ this._framework.on('agent:created', (agent) => {
106
+ console.log('[Telegram] New agent created:', agent.name)
107
+ })
108
+ }
109
+
110
+ } catch (err) {
111
+ console.error('[Telegram] Failed to initialize bot:', err.message)
112
+ }
113
+ }
114
+
115
+ /**
116
+ * 获取主Agent
117
+ */
118
+ _getMainAgent() {
119
+ console.log('[Telegram] _getMainAgent called')
120
+ console.log('[Telegram] _framework:', !!this._framework)
121
+ console.log('[Telegram] _framework._mainAgent:', !!this._framework?._mainAgent)
122
+ console.log('[Telegram] _framework._agents:', this._framework?._agents?.length || 0)
123
+
124
+ if (this._framework._mainAgent) {
125
+ console.log('[Telegram] returning _mainAgent')
126
+ return this._framework._mainAgent
127
+ }
128
+ const agents = this._framework._agents || []
129
+ console.log('[Telegram] returning last agent:', agents.length > 0 ? agents[agents.length - 1].name : 'none')
130
+ return agents.length > 0 ? agents[agents.length - 1] : null
131
+ }
132
+
133
+ /**
134
+ * 获取或创建会话Agent
135
+ */
136
+ _getSessionAgent(chatId) {
137
+ console.log('[Telegram] _getSessionAgent called for chatId:', chatId)
138
+ let session = this._sessions.get(chatId)
139
+
140
+ if (!session) {
141
+ const mainAgent = this._getMainAgent()
142
+ console.log('[Telegram] mainAgent:', !!mainAgent, mainAgent?.name)
143
+ if (!mainAgent) {
144
+ console.log('[Telegram] ERROR: mainAgent is null!')
145
+ return null
146
+ }
147
+
148
+ // 创建会话Agent(复用主Agent的配置)
149
+ session = {
150
+ agent: mainAgent,
151
+ history: [], // 对话历史
152
+ lastActive: new Date()
153
+ }
154
+ this._sessions.set(chatId, session)
155
+ console.log(`[Telegram] New session created for: ${chatId}`)
156
+ }
157
+
158
+ return session
159
+ }
160
+
161
+ /**
162
+ * 处理消息
163
+ */
164
+ async _handleMessage(msg) {
165
+ if (!msg || !msg.chat) return
166
+
167
+ const chatId = msg.chat.id.toString()
168
+
169
+ // 处理图片消息
170
+ if (msg.photo) {
171
+ await this._handlePhoto(msg)
172
+ return
173
+ }
174
+
175
+ // 处理文档消息
176
+ if (msg.document) {
177
+ await this._handleDocument(msg)
178
+ return
179
+ }
180
+
181
+ if (!msg.text) return
182
+
183
+ const text = msg.text.trim()
184
+
185
+ // 命令处理
186
+ if (text.startsWith(this.config.prefix)) {
187
+ await this._handleCommand(msg)
188
+ return
189
+ }
190
+
191
+ // 群组模式检查
192
+ if (msg.chat.type === 'group' || msg.chat.type === 'supergroup') {
193
+ if (!this.config.groupMode) return
194
+ }
195
+
196
+ // 权限检查
197
+ if (!this._checkPermission(chatId)) {
198
+ await this._sendMessage(chatId, '抱歉,您没有权限使用此 Bot。', msg.message_id)
199
+ return
200
+ }
201
+
202
+ // 处理对话
203
+ await this._processChat(chatId, text, msg.message_id)
204
+ }
205
+
206
+ /**
207
+ * 处理命令
208
+ */
209
+ async _handleCommand(msg) {
210
+ const chatId = msg.chat.id.toString()
211
+ const text = msg.text.trim()
212
+ const parts = text.split(' ')
213
+ const command = parts[0].substring(1)
214
+ const args = parts.slice(1).join(' ')
215
+
216
+ switch (command.toLowerCase()) {
217
+ case 'start':
218
+ await this._sendMessage(chatId,
219
+ '👋 欢迎使用 AI 助手!\n\n' +
220
+ '直接发送消息即可与我对话,我会尽力帮助您。\n\n' +
221
+ '可用命令:\n' +
222
+ '/start - 显示帮助\n' +
223
+ '/clear - 清除对话历史\n' +
224
+ '/history - 查看历史消息数',
225
+ msg.message_id)
226
+ break
227
+
228
+ case 'clear':
229
+ this._clearSession(chatId)
230
+ await this._sendMessage(chatId, '✅ 对话历史已清除', msg.message_id)
231
+ break
232
+
233
+ case 'history':
234
+ const session = this._sessions.get(chatId)
235
+ await this._sendMessage(chatId,
236
+ `📊 当前状态\n\n会话数:${this._sessions.size}\n` +
237
+ `历史消息:${session?.history.length || 0}\n` +
238
+ `最后活跃:${session?.lastActive?.toLocaleString() || '无'}`,
239
+ msg.message_id)
240
+ break
241
+
242
+ default:
243
+ // 未识别命令,作为普通消息处理
244
+ await this._processChat(chatId, text, msg.message_id)
245
+ }
246
+ }
247
+
248
+ /**
249
+ * 处理对话
250
+ */
251
+ async _processChat(chatId, text, replyToMessageId) {
252
+ console.log('[Telegram] _processChat called, chatId:', chatId, 'text:', text.substring(0, 50))
253
+ const session = this._getSessionAgent(chatId)
254
+ console.log('[Telegram] session:', !!session)
255
+ if (!session) {
256
+ await this._sendMessage(chatId, '❌ AI 服务未初始化', replyToMessageId)
257
+ return
258
+ }
259
+
260
+ // 添加用户消息到历史
261
+ session.history.push({ role: 'user', content: text })
262
+ session.lastActive = new Date()
263
+
264
+ // 发送思考中消息
265
+ let thinkingMsg
266
+ try {
267
+ thinkingMsg = await this._bot.sendMessage(chatId, '🤔 思考中...', {
268
+ reply_to_message_id: replyToMessageId
269
+ })
270
+ } catch (err) {
271
+ console.error('[Telegram] Send thinking error:', err.message)
272
+ return
273
+ }
274
+
275
+ try {
276
+ let fullResponse = ''
277
+ const chatIdStr = `telegram_${chatId}`
278
+
279
+ // 使用流式响应
280
+ for await (const chunk of session.agent.chatStream(text, {
281
+ sessionId: chatIdStr
282
+ })) {
283
+ // chatStream 返回 { type: 'text', text } 或 { type: 'tool-call', toolName, args }
284
+ if (chunk.type === 'text' && chunk.text) {
285
+ fullResponse += chunk.text
286
+
287
+ // 定期更新消息
288
+ if (fullResponse.length % 100 === 0) {
289
+ try {
290
+ await this._bot.editMessageText(`📝 ${fullResponse}▌`, {
291
+ chat_id: chatId,
292
+ message_id: thinkingMsg.message_id
293
+ })
294
+ } catch (e) {
295
+ // 忽略编辑错误
296
+ }
297
+ }
298
+ }
299
+ }
300
+
301
+ // 保存助手回复到历史
302
+ session.history.push({ role: 'assistant', content: fullResponse })
303
+
304
+ // 发送最终回复(转义 Markdown 特殊字符)
305
+ const safeResponse = fullResponse || '抱歉,我没有收到有效的回复。'
306
+ await this._bot.editMessageText(safeResponse, {
307
+ chat_id: chatId,
308
+ message_id: thinkingMsg.message_id,
309
+ parse_mode: 'MarkdownV2'
310
+ })
311
+
312
+ } catch (err) {
313
+ console.error('[Telegram] Chat error:', err)
314
+ await this._bot.editMessageText(`❌ 发生错误:${err.message}`, {
315
+ chat_id: chatId,
316
+ message_id: thinkingMsg.message_id
317
+ })
318
+ }
319
+ }
320
+
321
+ /**
322
+ * 处理编辑消息
323
+ */
324
+ async _handleEdit(msg) {
325
+ // 支持编辑后重新处理
326
+ }
327
+
328
+ /**
329
+ * 处理回调查询
330
+ */
331
+ async _handleCallback(query) {
332
+ await this._bot.answerCallbackQuery(query.id, {
333
+ text: '处理中...'
334
+ })
335
+ }
336
+
337
+ /**
338
+ * 权限检查
339
+ */
340
+ _checkPermission(chatId) {
341
+ if (this.config.allowedChats.length === 0) return true
342
+ return this.config.allowedChats.includes(chatId)
343
+ }
344
+
345
+ /**
346
+ * 处理图片消息
347
+ */
348
+ async _handlePhoto(msg) {
349
+ const chatId = msg.chat.id.toString()
350
+ const caption = msg.caption?.trim() || ''
351
+
352
+ // 权限检查
353
+ if (!this._checkPermission(chatId)) {
354
+ await this._sendMessage(chatId, '抱歉,您没有权限使用此 Bot。', msg.message_id)
355
+ return
356
+ }
357
+
358
+ // 获取最大尺寸的图片
359
+ const photo = msg.photo[msg.photo.length - 1]
360
+ console.log(`[Telegram] Photo received, file_id: ${photo.file_id}`)
361
+
362
+ try {
363
+ // 下载图片
364
+ const filePath = await this._downloadFile(photo.file_id, '.jpg', 'telegram_images')
365
+ console.log(`[Telegram] Photo saved: ${filePath}`)
366
+
367
+ const savedMsg = `收到图片${caption ? ': ' + caption : ''}\n已保存至: ${filePath}`
368
+ await this._sendMessage(chatId, savedMsg, msg.message_id)
369
+
370
+ // TODO: 调用 AI 视觉能力分析图片
371
+ // await this._analyzeImage(chatId, filePath, caption)
372
+ } catch (err) {
373
+ console.error('[Telegram] Failed to save photo:', err.message)
374
+ await this._sendMessage(chatId, '图片保存失败: ' + err.message, msg.message_id)
375
+ }
376
+ }
377
+
378
+ /**
379
+ * 处理文档消息
380
+ */
381
+ async _handleDocument(msg) {
382
+ const chatId = msg.chat.id.toString()
383
+ const fileName = msg.document.file_name || '未命名文件'
384
+ const caption = msg.caption?.trim() || ''
385
+
386
+ // 权限检查
387
+ if (!this._checkPermission(chatId)) {
388
+ await this._sendMessage(chatId, '抱歉,您没有权限使用此 Bot。', msg.message_id)
389
+ return
390
+ }
391
+
392
+ console.log(`[Telegram] Document received: ${fileName}, file_id: ${msg.document.file_id}`)
393
+
394
+ try {
395
+ // 根据文件扩展名确定保存目录和扩展名
396
+ const ext = fileName.includes('.') ? fileName.split('.').pop() : 'bin'
397
+ const filePath = await this._downloadFile(msg.document.file_id, ext, 'telegram_documents')
398
+ console.log(`[Telegram] Document saved: ${filePath}`)
399
+
400
+ const savedMsg = `收到文件: ${fileName}\n已保存至: ${filePath}${caption ? '\n\n说明: ' + caption : ''}`
401
+ await this._sendMessage(chatId, savedMsg, msg.message_id)
402
+ } catch (err) {
403
+ console.error('[Telegram] Failed to save document:', err.message)
404
+ await this._sendMessage(chatId, '文件保存失败: ' + err.message, msg.message_id)
405
+ }
406
+ }
407
+
408
+ /**
409
+ * 下载文件
410
+ * @param {string} fileId - Telegram 文件 ID
411
+ * @param {string} ext - 文件扩展名
412
+ * @param {string} subDir - 子目录名
413
+ * @returns {Promise<string>} 保存的文件路径
414
+ */
415
+ async _downloadFile(fileId, ext, subDir) {
416
+ return new Promise((resolve, reject) => {
417
+ const path = require('path')
418
+ const fs = require('fs')
419
+
420
+ // 创建保存目录
421
+ const saveDir = path.join(process.cwd(), '.agent', 'data', subDir)
422
+ if (!fs.existsSync(saveDir)) {
423
+ fs.mkdirSync(saveDir, { recursive: true })
424
+ }
425
+
426
+ // 生成文件名
427
+ const fileName = `${Date.now()}_${Math.random().toString(36).substring(7)}.${ext}`
428
+ const filePath = path.join(saveDir, fileName)
429
+
430
+ // 下载文件
431
+ this._bot.downloadFile(fileId, saveDir)
432
+ .then((savedPath) => {
433
+ // 重命名为期望的文件名
434
+ const finalPath = path.join(saveDir, fileName)
435
+ if (savedPath !== finalPath) {
436
+ fs.renameSync(savedPath, finalPath)
437
+ }
438
+ resolve(finalPath)
439
+ })
440
+ .catch(reject)
441
+ })
442
+ }
443
+
444
+ /**
445
+ * 清除会话
446
+ */
447
+ _clearSession(chatId) {
448
+ const session = this._sessions.get(chatId)
449
+ if (session && session.agent) {
450
+ session.agent.clearHistory?.()
451
+ }
452
+ this._sessions.delete(chatId)
453
+ }
454
+
455
+ /**
456
+ * 发送消息
457
+ */
458
+ async _sendMessage(chatId, text, replyToMessageId = null) {
459
+ if (!this._bot) return
460
+ return this._bot.sendMessage(chatId, text, {
461
+ reply_to_message_id: replyToMessageId,
462
+ })
463
+ }
464
+
465
+ /**
466
+ * 获取插件状态
467
+ */
468
+ getStatus() {
469
+ return {
470
+ connected: !!this._bot,
471
+ sessionCount: this._sessions.size,
472
+ sessions: Array.from(this._sessions.entries()).map(([chatId, session]) => ({
473
+ chatId,
474
+ historyLength: session.history.length,
475
+ lastActive: session.lastActive
476
+ })),
477
+ config: {
478
+ groupMode: this.config.groupMode,
479
+ prefix: this.config.prefix,
480
+ allowedChatsCount: this.config.allowedChats.length
481
+ }
482
+ }
483
+ }
484
+
485
+ /**
486
+ * 停止 Bot
487
+ */
488
+ stopBot() {
489
+ if (this._bot) {
490
+ this._bot.stopPolling()
491
+ this._bot = null
492
+ console.log('[Telegram] Bot stopped')
493
+ }
494
+ }
495
+
496
+ reload(framework) {
497
+ this._framework = framework
498
+ if (this.config.botToken) {
499
+ this.stopBot()
500
+ this._initBot()
501
+ }
502
+ }
503
+
504
+ uninstall(framework) {
505
+ this.stopBot()
506
+ this._sessions.clear()
507
+ this._framework = null
508
+ }
509
+ }
510
+ }
package/test-tg-bot.js ADDED
@@ -0,0 +1,42 @@
1
+ require('dotenv').config();
2
+ const { Framework } = require('./src');
3
+
4
+ async function main() {
5
+ console.log('Starting test...\n');
6
+
7
+ const framework = new Framework({ debug: false });
8
+
9
+ await framework.bootstrap({
10
+ agentDir: process.cwd() + '/.agent',
11
+ aiConfig: {
12
+ provider: process.env.FOLIKO_PROVIDER || 'minimax',
13
+ model: process.env.FOLIKO_MODEL || 'MiniMax-M2.7',
14
+ baseURL: process.env.FOLIKO_BASE_URL || 'https://api.minimaxi.com/v1',
15
+ apiKey: process.env.MINIMAX_API_KEY || process.env.DEEPSEEK_API_KEY
16
+ }
17
+ });
18
+
19
+ // 检查主 Agent
20
+ const mainAgent = framework._mainAgent;
21
+ console.log('Main Agent:', mainAgent ? mainAgent.name : 'NOT FOUND');
22
+ console.log('Agent apiKey:', mainAgent?.apiKey ? 'set' : 'NOT SET');
23
+ console.log('Agent _chatHandler:', mainAgent?._chatHandler ? 'exists' : 'NOT EXISTS');
24
+ console.log('Agent _chatHandler._aiClient:', mainAgent?._chatHandler?._aiClient ? 'exists' : 'NOT EXISTS');
25
+
26
+ // 检查 Telegram 插件
27
+ const tgPlugin = framework.pluginManager.get('telegram');
28
+ console.log('\nTelegram Plugin:', tgPlugin ? 'loaded' : 'NOT LOADED');
29
+
30
+ if (tgPlugin) {
31
+ console.log('Telegram _bot:', tgPlugin._bot ? 'exists' : 'NOT EXISTS');
32
+ }
33
+
34
+ console.log('\n========================================');
35
+ console.log('Bot is running. Send a message to test!');
36
+ console.log('========================================\n');
37
+
38
+ // 保持运行
39
+ await new Promise(() => {});
40
+ }
41
+
42
+ main().catch(console.error);