foliko 1.0.39 → 1.0.41

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.
@@ -9,343 +9,389 @@
9
9
 
10
10
  const { Plugin } = require('../src/core/plugin-base')
11
11
  const { z } = require('zod')
12
-
13
- module.exports = function(Plugin) {
14
- return class WeixinPlugin extends Plugin {
15
- constructor(config = {}) {
16
- super()
17
- this.name = 'weixin'
18
- this.version = '1.0.0'
19
- this.description = '微信对话插件,使用微信网页账号进行对话'
20
- this.priority = 80
21
- // 默认不启用,需要在 plugins.json 中设置 enabled: true
22
- this.enabled = false
23
- this.path=`.agent/data`
24
- this.systemPrompt='你是一个微信助手。回复内容不要使用markdown格式文本'
25
-
26
- this.config = {
27
- forceLogin: config.forceLogin || process.env.WEIXIN_FORCE_LOGIN === 'true',
28
- qrcodeTerminal: config.qrcodeTerminal !== false && process.env.WEIXIN_QRCODE_TERMINAL !== 'false',
29
- allowedUsers: config.allowedUsers || []
30
- }
31
-
32
- this._framework = null
33
- this._bot = null
34
- this._sessionPlugin = null
35
- this._sessionDeleteHandler = null
36
- this._sessionAgents = new Map() // userId -> Agent
37
- this._qrcodeTerminal = null
38
- this._origStderrWrite = null
39
- this._initialized = false
12
+ const { WeixinBot } = require('@chnak/weixin-bot')
13
+
14
+ class WeixinPlugin extends Plugin {
15
+ constructor(config = {}) {
16
+ super()
17
+ this.name = 'weixin'
18
+ this.version = '1.0.0'
19
+ this.description = '微信对话插件,使用微信网页账号进行对话'
20
+ this.priority = 80
21
+ // 默认不启用,需要在 plugins.json 中设置 enabled: true
22
+ this.enabled = false
23
+ this.path=`.agent/data`
24
+ this.systemPrompt='你是一个微信助手。回复内容不要使用markdown格式文本'
25
+
26
+ this.config = {
27
+ forceLogin: config.forceLogin || process.env.WEIXIN_FORCE_LOGIN === 'true',
28
+ qrcodeTerminal: config.qrcodeTerminal !== false && process.env.WEIXIN_QRCODE_TERMINAL !== 'false',
29
+ allowedUsers: config.allowedUsers || []
40
30
  }
41
31
 
42
- install(framework) {
43
- this._framework = framework
44
- return this
45
- }
32
+ this._framework = null
33
+ this._bot = null
34
+ this._sessionPlugin = null
35
+ this._sessionDeleteHandler = null
36
+ this._sessionAgents = new Map() // userId -> Agent
37
+ this._qrcodeTerminal = null
38
+ this._origStderrWrite = null
39
+ this._initialized = false
40
+ }
46
41
 
47
- async start(framework) {
48
- // 防止重复初始化
49
- if (this._initialized) return this
50
- this._initialized = true
42
+ install(framework) {
43
+ this._framework = framework
44
+ return this
45
+ }
51
46
 
52
- // 获取 SessionPlugin 引用
53
- this._sessionPlugin = framework.pluginManager.get('session')
47
+ async start(framework) {
48
+ // 防止重复初始化
49
+ if (this._initialized) return this
50
+ this._initialized = true
54
51
 
55
- // 监听 SessionPlugin 的会话删除事件
56
- if (this._sessionPlugin) {
57
- this._sessionDeleteHandler = (sessionId) => {
58
- // 只处理 weixin 会话的删除
59
- if (sessionId.startsWith('weixin_')) {
60
- console.log(`[WeChat] Session deleted: ${sessionId}`)
61
- }
52
+ // 获取 SessionPlugin 引用
53
+ this._sessionPlugin = framework.pluginManager.get('session')
54
+
55
+ // 监听 SessionPlugin 的会话删除事件
56
+ if (this._sessionPlugin) {
57
+ this._sessionDeleteHandler = (sessionId) => {
58
+ // 只处理 weixin 会话的删除
59
+ if (sessionId.startsWith('weixin_')) {
60
+ console.log(`[WeChat] Session deleted: ${sessionId}`)
62
61
  }
63
- this._sessionPlugin.on('session:deleted', this._sessionDeleteHandler)
64
62
  }
63
+ this._sessionPlugin.on('session:deleted', this._sessionDeleteHandler)
64
+ }
65
65
 
66
- // 异步初始化 Bot
67
- this._initBotAsync().catch(err => {
68
- console.error('[WeChat] Failed to initialize bot:', err.message)
66
+ // 监听定时提醒事件
67
+ if (this._framework) {
68
+ this._framework.on('scheduler:reminder', async (data) => {
69
+ console.log('[WeChat] Received scheduler reminder:', data)
70
+ await this._handleScheduledReminder(data)
69
71
  })
70
- return this
71
72
  }
72
73
 
73
- async _initBotAsync() {
74
+ // 异步初始化 Bot
75
+ this._initBotAsync().catch(err => {
76
+ console.error('[WeChat] Failed to initialize bot:', err.message)
77
+ })
78
+ return this
79
+ }
80
+
81
+ async _initBotAsync() {
74
82
 
75
- let WeixinBot
83
+ // 如果启用终端二维码渲染
84
+ if (this.config.qrcodeTerminal) {
76
85
  try {
77
- const module = await import('@chnak/weixin-bot')
78
- WeixinBot = module.WeixinBot
86
+ this._qrcodeTerminal = require('qrcode-terminal')
87
+ this._interceptQRCode()
79
88
  } catch (err) {
80
- console.warn('[WeChat] Failed to load @chnak/weixin-bot:', err.message)
81
- console.warn('[WeChat] Make sure @chnak/weixin-bot is installed: npm install @chnak/weixin-bot qrcode-terminal')
82
- return
89
+ console.warn('[WeChat] qrcode-terminal not installed:', err.message)
83
90
  }
91
+ }
84
92
 
85
- // 如果启用终端二维码渲染
86
- if (this.config.qrcodeTerminal) {
87
- try {
88
- this._qrcodeTerminal = require('qrcode-terminal')
89
- this._interceptQRCode()
90
- } catch (err) {
91
- console.warn('[WeChat] qrcode-terminal not installed:', err.message)
92
- }
93
- }
94
-
95
- this._bot = new WeixinBot({
96
- tokenPath:`${this.path}/${this.name}.json`,
97
- onError: (err) => {
98
- console.error('[WeChat] Error:', err instanceof Error ? err.stack ?? err.message : String(err))
99
- },
100
- })
101
-
102
- const loginOptions = { force: this.config.forceLogin }
103
- console.log('[WeChat]', this.config.forceLogin ? '强制重新扫码登录...' : '正在登录(已有凭证则自动跳过扫码)...')
93
+ this._bot = new WeixinBot({
94
+ tokenPath:`${this.path}/${this.name}.json`,
95
+ onError: (err) => {
96
+ console.error('[WeChat] Error:', err instanceof Error ? err.stack ?? err.message : String(err))
97
+ },
98
+ })
99
+
100
+ const loginOptions = { force: this.config.forceLogin }
101
+ console.log('[WeChat]', this.config.forceLogin ? '强制重新扫码登录...' : '正在登录(已有凭证则自动跳过扫码)...')
102
+
103
+ const creds = await this._bot.login(loginOptions)
104
+ console.log('[WeChat] 登录成功 — Bot ID:', creds.accountId)
105
+ console.log('[WeChat] 关联用户:', creds.userId)
106
+ console.log('[WeChat] API 地址:', creds.baseUrl)
107
+
108
+ // 注册消息处理
109
+ this._bot.onMessage(async (msg) => {
110
+ await this._handleMessage(msg)
111
+ })
112
+
113
+ // 启动Bot
114
+ await this._bot.run()
115
+ console.log('[WeChat] 开始接收微信消息')
116
+ }
104
117
 
105
- const creds = await this._bot.login(loginOptions)
106
- console.log('[WeChat] 登录成功 Bot ID:', creds.accountId)
107
- console.log('[WeChat] 关联用户:', creds.userId)
108
- console.log('[WeChat] API 地址:', creds.baseUrl)
118
+ /**
119
+ * 拦截 SDK stderr 输出,渲染二维码到终端
120
+ */
121
+ _interceptQRCode() {
122
+ if (!this._qrcodeTerminal) return
123
+
124
+ this._origStderrWrite = process.stderr.write.bind(process.stderr)
125
+ process.stderr.write = ((chunk, ...args) => {
126
+ const str = typeof chunk === 'string' ? chunk : chunk.toString()
127
+ // 检测到登录 URL,渲染二维码
128
+ if (str.startsWith('https://') && str.includes('qrcode=')) {
129
+ const url = str.trim()
130
+ this._qrcodeTerminal.generate(url, { small: true }, (qr) => {
131
+ this._origStderrWrite(qr + '\n')
132
+ })
133
+ }
134
+ return this._origStderrWrite(chunk, ...args)
135
+ })
136
+ }
109
137
 
110
- // 注册消息处理
111
- this._bot.onMessage(async (msg) => {
112
- await this._handleMessage(msg)
113
- })
138
+ /**
139
+ * 获取主Agent
140
+ */
141
+ _getMainAgent() {
142
+ if (this._framework._mainAgent) {
143
+ return this._framework._mainAgent
144
+ }
145
+ const agents = this._framework._agents || []
146
+ return agents.length > 0 ? agents[agents.length - 1] : null
147
+ }
114
148
 
115
- // 启动Bot
116
- await this._bot.run()
117
- console.log('[WeChat] 开始接收微信消息')
149
+ /**
150
+ * 获取或创建会话Agent
151
+ * 使用 SessionPlugin 统一管理会话历史
152
+ */
153
+ _getSessionAgent(userId) {
154
+ // 检查缓存
155
+ if (this._sessionAgents.has(userId)) {
156
+ const agent = this._sessionAgents.get(userId)
157
+ console.log('[WeChat] Reusing cached session agent for userId:', userId)
158
+ return { agent, sessionId: `weixin_${userId}` }
118
159
  }
119
160
 
120
- /**
121
- * 拦截 SDK stderr 输出,渲染二维码到终端
122
- */
123
- _interceptQRCode() {
124
- if (!this._qrcodeTerminal) return
125
-
126
- this._origStderrWrite = process.stderr.write.bind(process.stderr)
127
- process.stderr.write = ((chunk, ...args) => {
128
- const str = typeof chunk === 'string' ? chunk : chunk.toString()
129
- // 检测到登录 URL,渲染二维码
130
- if (str.startsWith('https://') && str.includes('qrcode=')) {
131
- const url = str.trim()
132
- this._qrcodeTerminal.generate(url, { small: true }, (qr) => {
133
- this._origStderrWrite(qr + '\n')
134
- })
135
- }
136
- return this._origStderrWrite(chunk, ...args)
161
+ // 创建新 agent
162
+ const agent = this._framework.createSessionAgent(`weixin_${userId}`, {
163
+ systemPrompt: this.systemPrompt
164
+ })
165
+ this._sessionAgents.set(userId, agent)
166
+ console.log('[WeChat] Created new session agent for userId:', userId)
167
+
168
+ // 使用 SessionPlugin 管理会话历史
169
+ if (this._sessionPlugin) {
170
+ const sessionId = `weixin_${userId}`
171
+ this._sessionPlugin.getOrCreateSession(sessionId, {
172
+ metadata: { platform: 'weixin', userId }
137
173
  })
138
174
  }
139
175
 
140
- /**
141
- * 获取主Agent
142
- */
143
- _getMainAgent() {
144
- if (this._framework._mainAgent) {
145
- return this._framework._mainAgent
146
- }
147
- const agents = this._framework._agents || []
148
- return agents.length > 0 ? agents[agents.length - 1] : null
176
+ console.log(`[WeChat] Session ready for user: ${userId}`)
177
+ return { agent, sessionId: `weixin_${userId}` }
178
+ }
179
+
180
+ /**
181
+ * 处理消息
182
+ */
183
+ async _handleMessage(msg) {
184
+ if (!msg || !msg.userId) return
185
+
186
+ const userId = msg.userId
187
+ // 从 SessionPlugin 获取历史消息数量
188
+ let messageCount = 0
189
+ if (this._sessionPlugin) {
190
+ const session = this._sessionPlugin.getSession(`weixin_${userId}`)
191
+ messageCount = session?.messages?.length || 0
149
192
  }
150
193
 
151
- /**
152
- * 获取或创建会话Agent
153
- * 使用 SessionPlugin 统一管理会话历史
154
- */
155
- _getSessionAgent(userId) {
156
- // 检查缓存
157
- if (this._sessionAgents.has(userId)) {
158
- const agent = this._sessionAgents.get(userId)
159
- console.log('[WeChat] Reusing cached session agent for userId:', userId)
160
- return { agent, sessionId: `weixin_${userId}` }
161
- }
194
+ console.log(`[WeChat] #${messageCount + 1} | 类型: ${msg.type} | 用户: ${userId}`)
195
+ console.log(`[WeChat] 内容: ${msg.text}`)
162
196
 
163
- // 创建新 agent
164
- const agent = this._framework.createSessionAgent(`weixin_${userId}`, {
165
- systemPrompt: this.systemPrompt
166
- })
167
- this._sessionAgents.set(userId, agent)
168
- console.log('[WeChat] Created new session agent for userId:', userId)
197
+ // 非文本消息暂不处理
198
+ if (msg.type !== 'text' || !msg.text) {
199
+ console.log('[WeChat] Unsupported message type or no text')
200
+ return
201
+ }
169
202
 
170
- // 使用 SessionPlugin 管理会话历史
171
- if (this._sessionPlugin) {
172
- const sessionId = `weixin_${userId}`
173
- this._sessionPlugin.getOrCreateSession(sessionId, {
174
- metadata: { platform: 'weixin', userId }
175
- })
176
- }
203
+ const text = msg.text.trim()
204
+ await this._processChat(userId, text, msg)
205
+ }
177
206
 
178
- console.log(`[WeChat] Session ready for user: ${userId}`)
179
- return { agent, sessionId: `weixin_${userId}` }
207
+ /**
208
+ * 处理对话
209
+ */
210
+ async _processChat(userId, text, originalMsg) {
211
+ const sessionInfo = this._getSessionAgent(userId)
212
+ if (!sessionInfo) {
213
+ console.error('[WeChat] No session agent available')
214
+ return
180
215
  }
181
216
 
182
- /**
183
- * 处理消息
184
- */
185
- async _handleMessage(msg) {
186
- if (!msg || !msg.userId) return
217
+ const { agent, sessionId } = sessionInfo
187
218
 
188
- const userId = msg.userId
189
- // SessionPlugin 获取历史消息数量
190
- let messageCount = 0
191
- if (this._sessionPlugin) {
192
- const session = this._sessionPlugin.getSession(`weixin_${userId}`)
193
- messageCount = session?.messages?.length || 0
194
- }
219
+ // 使用 SessionPlugin 添加用户消息到历史
220
+ if (this._sessionPlugin) {
221
+ this._sessionPlugin.addMessage(sessionId, { role: 'user', content: text })
222
+ }
195
223
 
196
- console.log(`[WeChat] #${messageCount + 1} | 类型: ${msg.type} | 用户: ${userId}`)
197
- console.log(`[WeChat] 内容: ${msg.text}`)
224
+ // 发送正在输入状态
225
+ try {
226
+ await this._bot.sendTyping(userId)
227
+ } catch { /* typing 失败不影响回复 */ }
198
228
 
199
- // 非文本消息暂不处理
200
- if (msg.type !== 'text' || !msg.text) {
201
- console.log('[WeChat] Unsupported message type or no text')
202
- return
203
- }
229
+ await new Promise((resolve) => setTimeout(resolve, 1000))
204
230
 
205
- const text = msg.text.trim()
206
- await this._processChat(userId, text, msg)
207
- }
231
+ try {
232
+ let fullResponse = ''
208
233
 
209
- /**
210
- * 处理对话
211
- */
212
- async _processChat(userId, text, originalMsg) {
213
- const sessionInfo = this._getSessionAgent(userId)
214
- if (!sessionInfo) {
215
- console.error('[WeChat] No session agent available')
216
- return
234
+ // 使用流式响应
235
+ for await (const chunk of agent.chatStream(text, {
236
+ sessionId: sessionId
237
+ })) {
238
+ if (chunk.type === 'text' && chunk.text) {
239
+ fullResponse += chunk.text
240
+ }
217
241
  }
218
242
 
219
- const { agent, sessionId } = sessionInfo
220
-
221
- // 使用 SessionPlugin 添加用户消息到历史
243
+ // 保存助手回复到历史(使用 SessionPlugin)
222
244
  if (this._sessionPlugin) {
223
- this._sessionPlugin.addMessage(sessionId, { role: 'user', content: text })
245
+ this._sessionPlugin.addMessage(sessionId, { role: 'assistant', content: fullResponse })
224
246
  }
225
247
 
226
- // 发送正在输入状态
227
- try {
228
- await this._bot.sendTyping(userId)
229
- } catch { /* typing 失败不影响回复 */ }
248
+ // 发送回复
249
+ if (fullResponse) {
250
+ await this._bot.reply(originalMsg, fullResponse)
251
+ console.log(`[WeChat] 回复成功 (${fullResponse.length} 字符)`)
252
+ } else {
253
+ await this._bot.reply(originalMsg, '抱歉,我没有收到有效的回复。')
254
+ }
230
255
 
231
- await new Promise((resolve) => setTimeout(resolve, 1000))
256
+ } catch (err) {
257
+ console.error('[WeChat] Chat error:', err)
258
+ await this._bot.reply(originalMsg, `发生错误:${err.message}`)
259
+ }
260
+ }
232
261
 
233
- try {
234
- let fullResponse = ''
235
-
236
- // 使用流式响应
237
- for await (const chunk of agent.chatStream(text, {
238
- sessionId: sessionId
239
- })) {
240
- if (chunk.type === 'text' && chunk.text) {
241
- fullResponse += chunk.text
242
- }
243
- }
262
+ /**
263
+ * 权限检查
264
+ */
265
+ _checkPermission(userId) {
266
+ if (!this.config.allowedUsers || this.config.allowedUsers.length === 0) {
267
+ return true
268
+ }
269
+ return this.config.allowedUsers.includes(userId)
270
+ }
244
271
 
245
- // 保存助手回复到历史(使用 SessionPlugin)
246
- if (this._sessionPlugin) {
247
- this._sessionPlugin.addMessage(sessionId, { role: 'assistant', content: fullResponse })
248
- }
272
+ /**
273
+ * 清除会话
274
+ */
275
+ _clearSession(userId) {
276
+ // 清除 SessionPlugin 中的会话(会触发 session:deleted 事件)
277
+ if (this._sessionPlugin) {
278
+ const sessionId = `weixin_${userId}`
279
+ this._sessionPlugin.deleteSession(sessionId)
280
+ }
281
+ }
249
282
 
250
- // 发送回复
251
- if (fullResponse) {
252
- await this._bot.reply(originalMsg, fullResponse)
253
- console.log(`[WeChat] 回复成功 (${fullResponse.length} 字符)`)
254
- } else {
255
- await this._bot.reply(originalMsg, '抱歉,我没有收到有效的回复。')
256
- }
283
+ /**
284
+ * 处理定时提醒
285
+ */
286
+ async _handleScheduledReminder(data) {
287
+ const { taskName, message, sessionId } = data
257
288
 
258
- } catch (err) {
259
- console.error('[WeChat] Chat error:', err)
260
- await this._bot.reply(originalMsg, `发生错误:${err.message}`)
261
- }
289
+ if (!this._bot) {
290
+ console.warn('[WeChat] Bot not ready, cannot send reminder')
291
+ return
262
292
  }
263
293
 
264
- /**
265
- * 权限检查
266
- */
267
- _checkPermission(userId) {
268
- if (!this.config.allowedUsers || this.config.allowedUsers.length === 0) {
269
- return true
270
- }
271
- return this.config.allowedUsers.includes(userId)
272
- }
294
+ // 构建提醒消息
295
+ const reminderText = `🔔 [${taskName}]\n\n${message}`
273
296
 
274
- /**
275
- * 清除会话
276
- */
277
- _clearSession(userId) {
278
- // 清除 SessionPlugin 中的会话(会触发 session:deleted 事件)
279
- if (this._sessionPlugin) {
280
- const sessionId = `weixin_${userId}`
281
- this._sessionPlugin.deleteSession(sessionId)
297
+ // 如果有 sessionId 是 weixin 类型的,发送到对应用户
298
+ if (sessionId && sessionId.startsWith('weixin_')) {
299
+ const userId = sessionId.replace('weixin_', '')
300
+ try {
301
+ await this._bot.sendText(userId, reminderText)
302
+ console.log(`[WeChat] Reminder sent to user ${userId}`)
303
+ } catch (err) {
304
+ console.error(`[WeChat] Failed to send reminder:`, err.message)
282
305
  }
306
+ return
283
307
  }
284
308
 
285
- /**
286
- * 获取插件状态
287
- */
288
- getStatus() {
289
- // SessionPlugin 获取 WeChat 相关会话
290
- let sessions = []
291
- if (this._sessionPlugin) {
292
- const allSessions = this._sessionPlugin.listSessions()
293
- sessions = allSessions
294
- .filter(s => s.id.startsWith('weixin_'))
295
- .map(s => ({
296
- userId: s.id.replace('weixin_', ''),
297
- historyLength: s.messageCount,
298
- lastActive: s.lastActive
299
- }))
300
- }
309
+ // 其他情况(包括 null 或其他 sessionId),发送到最近的 WeChat 会话
310
+ if (this._sessionPlugin) {
311
+ const allSessions = this._sessionPlugin.listSessions()
312
+ const weixinSessions = allSessions
313
+ .filter(s => s.id.startsWith('weixin_'))
314
+ .sort((a, b) => new Date(b.lastActive).getTime() - new Date(a.lastActive).getTime())
301
315
 
302
- return {
303
- connected: !!this._bot,
304
- sessionCount: sessions.length,
305
- sessions,
306
- config: {
307
- forceLogin: this.config.forceLogin,
308
- qrcodeTerminal: this.config.qrcodeTerminal
316
+ if (weixinSessions.length > 0) {
317
+ const userId = weixinSessions[0].id.replace('weixin_', '')
318
+ try {
319
+ await this._bot.sendText(userId, reminderText)
320
+ console.log(`[WeChat] Reminder sent to recent user ${userId}`)
321
+ } catch (err) {
322
+ console.error(`[WeChat] Failed to send reminder:`, err.message)
309
323
  }
324
+ } else {
325
+ console.warn('[WeChat] No WeChat session found to send reminder')
310
326
  }
311
327
  }
328
+ }
329
+
330
+ /**
331
+ * 获取插件状态
332
+ */
333
+ getStatus() {
334
+ // 从 SessionPlugin 获取 WeChat 相关会话
335
+ let sessions = []
336
+ if (this._sessionPlugin) {
337
+ const allSessions = this._sessionPlugin.listSessions()
338
+ sessions = allSessions
339
+ .filter(s => s.id.startsWith('weixin_'))
340
+ .map(s => ({
341
+ userId: s.id.replace('weixin_', ''),
342
+ historyLength: s.messageCount,
343
+ lastActive: s.lastActive
344
+ }))
345
+ }
312
346
 
313
- /**
314
- * 停止 Bot
315
- */
316
- stopBot() {
317
- if (this._bot) {
318
- this._bot.stop()
319
- this._bot = null
320
- console.log('[WeChat] Bot stopped')
347
+ return {
348
+ connected: !!this._bot,
349
+ sessionCount: sessions.length,
350
+ sessions,
351
+ config: {
352
+ forceLogin: this.config.forceLogin,
353
+ qrcodeTerminal: this.config.qrcodeTerminal
321
354
  }
322
355
  }
356
+ }
323
357
 
324
- reload(framework) {
325
- this._framework = framework
326
- this._initialized = false
327
- this.stopBot()
328
- this.start(framework)
358
+ /**
359
+ * 停止 Bot
360
+ */
361
+ stopBot() {
362
+ if (this._bot) {
363
+ this._bot.stop()
364
+ this._bot = null
365
+ console.log('[WeChat] Bot stopped')
329
366
  }
367
+ }
330
368
 
331
- uninstall(framework) {
332
- // 销毁所有 session agents
333
- for (const agent of this._sessionAgents.values()) {
334
- agent.destroy()
335
- }
336
- this._sessionAgents.clear()
369
+ reload(framework) {
370
+ this._framework = framework
371
+ this._initialized = false
372
+ this.stopBot()
373
+ this.start(framework)
374
+ }
337
375
 
338
- this.stopBot()
339
- if (this._sessionPlugin && this._sessionDeleteHandler) {
340
- this._sessionPlugin.off('session:deleted', this._sessionDeleteHandler)
341
- this._sessionDeleteHandler = null
342
- }
343
- this._sessionPlugin = null
344
- this._framework = null
345
- // 恢复 stderr
346
- if (this._origStderrWrite) {
347
- process.stderr.write = this._origStderrWrite
348
- }
376
+ uninstall(framework) {
377
+ // 销毁所有 session agents
378
+ for (const agent of this._sessionAgents.values()) {
379
+ agent.destroy()
380
+ }
381
+ this._sessionAgents.clear()
382
+
383
+ this.stopBot()
384
+ if (this._sessionPlugin && this._sessionDeleteHandler) {
385
+ this._sessionPlugin.off('session:deleted', this._sessionDeleteHandler)
386
+ this._sessionDeleteHandler = null
387
+ }
388
+ this._sessionPlugin = null
389
+ this._framework = null
390
+ // 恢复 stderr
391
+ if (this._origStderrWrite) {
392
+ process.stderr.write = this._origStderrWrite
349
393
  }
350
394
  }
351
395
  }
396
+
397
+ module.exports = { WeixinPlugin }