foliko 1.0.63 → 1.0.64
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/cli/src/commands/chat.js +17 -4
- package/examples/basic.js +110 -110
- package/examples/mcp-example.js +53 -53
- package/examples/skill-example.js +49 -49
- package/examples/test-mcp.js +79 -79
- package/examples/test-reload.js +61 -61
- package/package.json +1 -1
- package/plugins/ai-plugin.js +1 -2
- package/plugins/ambient-agent-plugin.js +844 -1059
- package/plugins/email.js +103 -138
- package/plugins/file-system-plugin.js +30 -0
- package/plugins/scheduler-plugin.js +11 -11
- package/src/core/agent.js +1 -1
- package/src/core/framework.js +3 -3
- package/src/executors/executor-base.js +58 -58
- package/test-server.js +25 -25
- package/test.txt +3 -3
package/plugins/email.js
CHANGED
|
@@ -44,19 +44,19 @@ class EmailPlugin extends Plugin {
|
|
|
44
44
|
return this
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
if (process.env.IMAP_USER && process.env.IMAP_PASS) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
} else {
|
|
58
|
-
|
|
59
|
-
}
|
|
47
|
+
// if (process.env.IMAP_USER && process.env.IMAP_PASS) {
|
|
48
|
+
// console.log('[Email] Auto-starting email watch...')
|
|
49
|
+
// this._startEmailWatch({
|
|
50
|
+
// interval: 60,
|
|
51
|
+
// host: process.env.IMAP_HOST,
|
|
52
|
+
// port: parseInt(process.env.IMAP_PORT) || 993,
|
|
53
|
+
// user: process.env.IMAP_USER,
|
|
54
|
+
// password: process.env.IMAP_PASS,
|
|
55
|
+
// box: 'INBOX'
|
|
56
|
+
// })
|
|
57
|
+
// } else {
|
|
58
|
+
// console.log('[Email] IMAP credentials not configured, skipping auto-start')
|
|
59
|
+
// }
|
|
60
60
|
return this
|
|
61
61
|
}
|
|
62
62
|
|
|
@@ -148,6 +148,19 @@ class EmailPlugin extends Plugin {
|
|
|
148
148
|
}
|
|
149
149
|
})
|
|
150
150
|
|
|
151
|
+
// 删除邮件
|
|
152
|
+
this._framework.registerTool({
|
|
153
|
+
name: 'email_delete',
|
|
154
|
+
description: '删除邮件(标记为已删除,然后永久删除)',
|
|
155
|
+
inputSchema: z.object({
|
|
156
|
+
messageId: z.string().describe('邮件UID或序列号'),
|
|
157
|
+
box: z.string().optional().describe('邮箱文件夹,默认INBOX')
|
|
158
|
+
}),
|
|
159
|
+
execute: async (args) => {
|
|
160
|
+
return this._deleteEmail(args)
|
|
161
|
+
}
|
|
162
|
+
})
|
|
163
|
+
|
|
151
164
|
// 配置邮箱连接
|
|
152
165
|
this._framework.registerTool({
|
|
153
166
|
name: 'email_configure',
|
|
@@ -188,126 +201,6 @@ class EmailPlugin extends Plugin {
|
|
|
188
201
|
return this._handleEmailWatch(args)
|
|
189
202
|
}
|
|
190
203
|
})
|
|
191
|
-
|
|
192
|
-
// 自动回复邮件
|
|
193
|
-
// this._framework.registerTool({
|
|
194
|
-
// name: 'email_auto_reply',
|
|
195
|
-
// description: '自动分析邮件内容并发送回复(无需用户确认)',
|
|
196
|
-
// inputSchema: z.object({
|
|
197
|
-
// to: z.string().describe('收件人邮箱地址'),
|
|
198
|
-
// subject: z.string().describe('原始邮件主题'),
|
|
199
|
-
// body: z.string().describe('原始邮件内容'),
|
|
200
|
-
// from: z.string().optional().describe('发件人邮箱地址(可选)'),
|
|
201
|
-
// prompt: z.string().optional().describe('自定义提示词,用于指导AI生成回复内容')
|
|
202
|
-
// }),
|
|
203
|
-
// execute: async (args) => {
|
|
204
|
-
// return this._handleAutoReply(args)
|
|
205
|
-
// }
|
|
206
|
-
// })
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
/**
|
|
210
|
-
* 处理自动回复
|
|
211
|
-
*/
|
|
212
|
-
async _handleAutoReply(args) {
|
|
213
|
-
let { to, subject, body, from, _event, prompt } = args
|
|
214
|
-
|
|
215
|
-
// 如果没有直接参数,尝试从 _event 提取
|
|
216
|
-
if (!to && !subject && !body && _event) {
|
|
217
|
-
const email = _event.data?.email || _event.email || {}
|
|
218
|
-
from = email.from?.text || email.from || ''
|
|
219
|
-
to = email.to?.text || email.to || ''
|
|
220
|
-
subject = email.subject || ''
|
|
221
|
-
body = email.text || email.body || ''
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
// 检查必要参数
|
|
225
|
-
if (!from && !to) {
|
|
226
|
-
return { success: false, error: '缺少收件人地址' }
|
|
227
|
-
}
|
|
228
|
-
if (!body) {
|
|
229
|
-
return { success: false, error: '缺少邮件内容' }
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
try {
|
|
233
|
-
// 获取活跃的 Agent
|
|
234
|
-
const agent = this._getActiveAgent()
|
|
235
|
-
if (!agent) {
|
|
236
|
-
return { success: false, error: 'No active agent found' }
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
// 构建提示让 LLM 生成回复
|
|
240
|
-
const finalPrompt = prompt || `你是一封邮件自动回复助手。请根据以下邮件内容,生成一封专业的回复邮件。
|
|
241
|
-
|
|
242
|
-
【原始邮件】
|
|
243
|
-
发件人: ${from || to}
|
|
244
|
-
主题: ${subject}
|
|
245
|
-
内容:
|
|
246
|
-
${body}
|
|
247
|
-
|
|
248
|
-
【要求】
|
|
249
|
-
1. 回复内容要针对邮件中的问题或内容进行回复
|
|
250
|
-
2. 语言要专业、礼貌、简洁
|
|
251
|
-
3. 只输出邮件正文内容,不要额外解释
|
|
252
|
-
4. 回复语言应与原邮件一致(如果原邮件是中文,则用中文回复)`
|
|
253
|
-
|
|
254
|
-
// 等待 Agent 生成回复(带超时保护)
|
|
255
|
-
const timeoutPromise = new Promise((_, reject) => {
|
|
256
|
-
setTimeout(() => reject(new Error('AI回复生成超时(30秒)')), 30000)
|
|
257
|
-
})
|
|
258
|
-
|
|
259
|
-
const replyPromise = agent.pushMessage(finalPrompt, { maxSteps: 3 })
|
|
260
|
-
const replyResult = await Promise.race([replyPromise, timeoutPromise])
|
|
261
|
-
|
|
262
|
-
// 提取回复内容
|
|
263
|
-
let replyContent = ''
|
|
264
|
-
if (typeof replyResult === 'string') {
|
|
265
|
-
replyContent = replyResult.trim()
|
|
266
|
-
} else if (replyResult && replyResult.content) {
|
|
267
|
-
replyContent = replyResult.content.trim()
|
|
268
|
-
} else if (replyResult && replyResult.message) {
|
|
269
|
-
replyContent = replyResult.message.trim()
|
|
270
|
-
} else {
|
|
271
|
-
replyContent = JSON.stringify(replyResult).trim()
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
// 去掉思考过程标签
|
|
275
|
-
replyContent = replyContent.replace(/<think>[\s\S]*?<\/think>/g, '').trim()
|
|
276
|
-
|
|
277
|
-
if (!replyContent || replyContent.length < 5) {
|
|
278
|
-
return { success: false, error: 'AI未能生成有效的回复内容' }
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
// 发送回复邮件
|
|
282
|
-
const sendResult = await this._sendEmail({
|
|
283
|
-
to: from || to,
|
|
284
|
-
subject: `Re: ${subject}`,
|
|
285
|
-
body: replyContent
|
|
286
|
-
})
|
|
287
|
-
|
|
288
|
-
if (sendResult.success) {
|
|
289
|
-
return {
|
|
290
|
-
success: true,
|
|
291
|
-
message: `自动回复已发送至 ${from || to}`,
|
|
292
|
-
replyContent
|
|
293
|
-
}
|
|
294
|
-
} else {
|
|
295
|
-
return { success: false, error: sendResult.error || '发送失败' }
|
|
296
|
-
}
|
|
297
|
-
} catch (err) {
|
|
298
|
-
return { success: false, error: err.message }
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
/**
|
|
303
|
-
* 获取活跃的 Agent
|
|
304
|
-
*/
|
|
305
|
-
_getActiveAgent() {
|
|
306
|
-
if (this._framework._mainAgent) {
|
|
307
|
-
return this._framework._mainAgent
|
|
308
|
-
}
|
|
309
|
-
const agents = this._framework._agents || []
|
|
310
|
-
return agents.length > 0 ? agents[agents.length - 1] : null
|
|
311
204
|
}
|
|
312
205
|
|
|
313
206
|
/**
|
|
@@ -316,10 +209,10 @@ ${body}
|
|
|
316
209
|
async _handleEmailWatch(args) {
|
|
317
210
|
args={
|
|
318
211
|
...args,
|
|
319
|
-
host: process.env.IMAP_HOST,
|
|
320
|
-
port: parseInt(process.env.IMAP_PORT) || 993,
|
|
321
|
-
user: process.env.IMAP_USER,
|
|
322
|
-
password: process.env.IMAP_PASS
|
|
212
|
+
host: config.host || process.env.IMAP_HOST,
|
|
213
|
+
port: config.port || parseInt(process.env.IMAP_PORT) || 993,
|
|
214
|
+
user: config.user || process.env.IMAP_USER,
|
|
215
|
+
password: config.password || process.env.IMAP_PASS
|
|
323
216
|
}
|
|
324
217
|
|
|
325
218
|
const { action, interval, host, port, user, password, box } = args
|
|
@@ -514,7 +407,7 @@ ${body}
|
|
|
514
407
|
// 发送事件通知
|
|
515
408
|
this._emitEmailReceived(email)
|
|
516
409
|
|
|
517
|
-
console.log(`[Email] New email received: ${email.subject}`)
|
|
410
|
+
//console.log(`[Email] New email received: ${email.subject}`)
|
|
518
411
|
cleanup()
|
|
519
412
|
resolve({ success: true, newEmails: newEmails.length, email })
|
|
520
413
|
} else {
|
|
@@ -757,6 +650,40 @@ ${body}
|
|
|
757
650
|
}
|
|
758
651
|
}
|
|
759
652
|
|
|
653
|
+
async _deleteEmail(args) {
|
|
654
|
+
try {
|
|
655
|
+
const Imap = require('imap-mkl')
|
|
656
|
+
|
|
657
|
+
const imapConfig = {
|
|
658
|
+
user: args.user || process.env.IMAP_USER,
|
|
659
|
+
password: args.password || process.env.IMAP_PASS,
|
|
660
|
+
host: args.host || process.env.IMAP_HOST,
|
|
661
|
+
port: args.port || parseInt(process.env.IMAP_PORT) || 993,
|
|
662
|
+
tls: true,
|
|
663
|
+
tlsOptions: { rejectUnauthorized: false },
|
|
664
|
+
id: {
|
|
665
|
+
name: process.env.IMAP_CLIENT_NAME || 'FolikoAgent',
|
|
666
|
+
version: process.env.IMAP_CLIENT_VERSION || '1.0.0',
|
|
667
|
+
vendor: process.env.IMAP_CLIENT_VENDOR || 'Foliko',
|
|
668
|
+
'support-email': process.env.IMAP_CLIENT_SUPPORT_EMAIL || 'unknown@example.com'
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
const box = args.box || 'INBOX'
|
|
673
|
+
await this._moveToTrash(imapConfig, box, args.messageId)
|
|
674
|
+
|
|
675
|
+
return {
|
|
676
|
+
success: true,
|
|
677
|
+
message: '邮件已删除'
|
|
678
|
+
}
|
|
679
|
+
} catch (error) {
|
|
680
|
+
return {
|
|
681
|
+
success: false,
|
|
682
|
+
error: error.message
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
|
|
760
687
|
_fetchEmails(imapConfig, box, limit, unreadOnly, searchCriteria) {
|
|
761
688
|
return new Promise((resolve, reject) => {
|
|
762
689
|
const Imap = require('imap-mkl')
|
|
@@ -924,6 +851,44 @@ ${body}
|
|
|
924
851
|
})
|
|
925
852
|
}
|
|
926
853
|
|
|
854
|
+
_moveToTrash(imapConfig, box, messageId) {
|
|
855
|
+
return new Promise((resolve, reject) => {
|
|
856
|
+
const Imap = require('imap-mkl')
|
|
857
|
+
const imap = new Imap(imapConfig)
|
|
858
|
+
|
|
859
|
+
const cleanup = () => {
|
|
860
|
+
try { imap.end() } catch (e) {}
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
imap.on('ready', () => {
|
|
864
|
+
imap.openBox(box, true, (err) => {
|
|
865
|
+
if (err) {
|
|
866
|
+
cleanup()
|
|
867
|
+
return reject(err)
|
|
868
|
+
}
|
|
869
|
+
// 标记邮件为已删除
|
|
870
|
+
imap.addFlags(messageId, '\\Deleted', (err) => {
|
|
871
|
+
if (err) {
|
|
872
|
+
cleanup()
|
|
873
|
+
return reject(err)
|
|
874
|
+
}
|
|
875
|
+
// 执行 expunge 永久删除
|
|
876
|
+
imap.expunge((err) => {
|
|
877
|
+
cleanup()
|
|
878
|
+
if (err) reject(err)
|
|
879
|
+
else resolve()
|
|
880
|
+
})
|
|
881
|
+
})
|
|
882
|
+
})
|
|
883
|
+
})
|
|
884
|
+
|
|
885
|
+
imap.on('error', (err) => reject(err))
|
|
886
|
+
imap.on('end', () => {})
|
|
887
|
+
|
|
888
|
+
imap.connect()
|
|
889
|
+
})
|
|
890
|
+
}
|
|
891
|
+
|
|
927
892
|
uninstall(framework) {
|
|
928
893
|
// 停止邮件监控
|
|
929
894
|
if (this._watchInterval) {
|
|
@@ -394,6 +394,36 @@ class FileSystemPlugin extends Plugin {
|
|
|
394
394
|
}
|
|
395
395
|
})
|
|
396
396
|
|
|
397
|
+
// 发送通知
|
|
398
|
+
framework.registerTool({
|
|
399
|
+
name: 'notification_send',
|
|
400
|
+
description: '发送系统通知,仅发送给当前聊天会话,通知会显示给用户或在下次对话时呈现',
|
|
401
|
+
inputSchema: z.object({
|
|
402
|
+
title: z.string().describe('通知标题'),
|
|
403
|
+
message: z.string().describe('通知内容'),
|
|
404
|
+
source: z.string().optional().describe('通知来源标识,默认 file-system')
|
|
405
|
+
}),
|
|
406
|
+
execute: async (args, framework) => {
|
|
407
|
+
const { title, message, source = 'file-system' } = args
|
|
408
|
+
try {
|
|
409
|
+
// 获取当前执行上下文中的 sessionId,只发送到当前会话
|
|
410
|
+
const ctx = framework.getExecutionContext()
|
|
411
|
+
const sessionId = ctx?.sessionId || null
|
|
412
|
+
|
|
413
|
+
framework.emit('notification', {
|
|
414
|
+
title,
|
|
415
|
+
message,
|
|
416
|
+
source,
|
|
417
|
+
sessionId,
|
|
418
|
+
timestamp: new Date().toISOString()
|
|
419
|
+
})
|
|
420
|
+
return { success: true, message: '通知已发送' }
|
|
421
|
+
} catch (error) {
|
|
422
|
+
return { success: false, error: error.message }
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
})
|
|
426
|
+
|
|
397
427
|
return this
|
|
398
428
|
}
|
|
399
429
|
}
|
|
@@ -203,7 +203,7 @@ class SchedulerPlugin extends Plugin {
|
|
|
203
203
|
return bTime - aTime
|
|
204
204
|
})
|
|
205
205
|
targetSessionId = sessions[0].id
|
|
206
|
-
console.log(`[Scheduler] Auto-detected active session: ${targetSessionId}`)
|
|
206
|
+
//console.log(`[Scheduler] Auto-detected active session: ${targetSessionId}`)
|
|
207
207
|
}
|
|
208
208
|
}
|
|
209
209
|
}
|
|
@@ -534,12 +534,12 @@ class SchedulerPlugin extends Plugin {
|
|
|
534
534
|
* 执行任务
|
|
535
535
|
*/
|
|
536
536
|
async _executeTask(task) {
|
|
537
|
-
console.log(`[Scheduler] Executing task: ${task.name} (${task.id})`)
|
|
538
|
-
console.log(`[Scheduler] Message: ${task.message}`)
|
|
539
|
-
if (task.sessionId) {
|
|
540
|
-
|
|
541
|
-
}
|
|
542
|
-
console.log(`[Scheduler] LLM mode: ${task.llm ? 'enabled' : 'disabled'}`)
|
|
537
|
+
// console.log(`[Scheduler] Executing task: ${task.name} (${task.id})`)
|
|
538
|
+
// console.log(`[Scheduler] Message: ${task.message}`)
|
|
539
|
+
// if (task.sessionId) {
|
|
540
|
+
// console.log(`[Scheduler] Target session: ${task.sessionId}`)
|
|
541
|
+
// }
|
|
542
|
+
// console.log(`[Scheduler] LLM mode: ${task.llm ? 'enabled' : 'disabled'}`)
|
|
543
543
|
|
|
544
544
|
task.lastRun = new Date()
|
|
545
545
|
task.runCount++
|
|
@@ -569,9 +569,9 @@ class SchedulerPlugin extends Plugin {
|
|
|
569
569
|
responseText = result.text
|
|
570
570
|
}
|
|
571
571
|
|
|
572
|
-
if (responseText) {
|
|
573
|
-
|
|
574
|
-
}
|
|
572
|
+
// if (responseText) {
|
|
573
|
+
// console.log(`\n🔔 [定时提醒] ${responseText}\n`)
|
|
574
|
+
// }
|
|
575
575
|
|
|
576
576
|
// 发送统一的通知事件
|
|
577
577
|
this._framework.emit('notification', {
|
|
@@ -584,7 +584,7 @@ class SchedulerPlugin extends Plugin {
|
|
|
584
584
|
})
|
|
585
585
|
} else {
|
|
586
586
|
// 直接显示模式:只显示提醒,不发 LLM
|
|
587
|
-
console.log(`\n🔔 [定时提醒] ${task.message}\n`)
|
|
587
|
+
//console.log(`\n🔔 [定时提醒] ${task.message}\n`)
|
|
588
588
|
|
|
589
589
|
// 发送统一的通知事件
|
|
590
590
|
this._framework.emit('notification', {
|
package/src/core/agent.js
CHANGED
|
@@ -29,7 +29,7 @@ class Agent extends EventEmitter {
|
|
|
29
29
|
this.baseURL = config.baseURL
|
|
30
30
|
this.provider = config.provider || 'deepseek'
|
|
31
31
|
this.providerOptions = config.providerOptions || {}
|
|
32
|
-
|
|
32
|
+
|
|
33
33
|
// 原始 system prompt
|
|
34
34
|
this._originalPrompt = config.systemPrompt || '你是一个智能助手。当用户提出问题或任务时,你会主动分析需求,选择合适的工具来获取信息或执行操作。你善于将复杂任务拆解为多个步骤,通过工具协作完成。'
|
|
35
35
|
|
package/src/core/framework.js
CHANGED
|
@@ -215,7 +215,7 @@ class Framework extends EventEmitter {
|
|
|
215
215
|
name: `session_${sessionId}`,
|
|
216
216
|
...config
|
|
217
217
|
}
|
|
218
|
-
|
|
218
|
+
|
|
219
219
|
// 如果没有提供 AI 相关参数,从 AI 插件获取
|
|
220
220
|
if (!agentConfig.apiKey) {
|
|
221
221
|
const aiPlugin = this.pluginManager.get('ai')
|
|
@@ -223,10 +223,10 @@ class Framework extends EventEmitter {
|
|
|
223
223
|
agentConfig.apiKey = aiPlugin.config.apiKey
|
|
224
224
|
agentConfig.provider = agentConfig.provider || aiPlugin.config.provider
|
|
225
225
|
agentConfig.model = agentConfig.model || aiPlugin.config.model
|
|
226
|
-
agentConfig.baseURL = agentConfig.baseURL || aiPlugin.config.baseURL
|
|
227
|
-
agentConfig.providerOptions||aiPlugin.config.providerOptions||{}
|
|
226
|
+
agentConfig.baseURL = agentConfig.baseURL || aiPlugin.config.baseURL
|
|
228
227
|
}
|
|
229
228
|
}
|
|
229
|
+
|
|
230
230
|
const agent = new Agent(this, agentConfig)
|
|
231
231
|
this._agents.push(agent)
|
|
232
232
|
|
|
@@ -1,58 +1,58 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Executor 基类
|
|
3
|
-
* 执行器的基类,定义执行器接口
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const { EventEmitter } = require('../utils/event-emitter')
|
|
7
|
-
|
|
8
|
-
class ExecutorBase extends EventEmitter {
|
|
9
|
-
/**
|
|
10
|
-
* @param {string} name - 执行器名称
|
|
11
|
-
*/
|
|
12
|
-
constructor(name) {
|
|
13
|
-
super()
|
|
14
|
-
this.name = name
|
|
15
|
-
this._enabled = true
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* 执行
|
|
20
|
-
* @param {Object} params - 执行参数
|
|
21
|
-
* @returns {Promise<any>}
|
|
22
|
-
*/
|
|
23
|
-
async execute(params) {
|
|
24
|
-
throw new Error('execute() must be implemented')
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* 启用执行器
|
|
29
|
-
*/
|
|
30
|
-
enable() {
|
|
31
|
-
this._enabled = true
|
|
32
|
-
return this
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* 禁用执行器
|
|
37
|
-
*/
|
|
38
|
-
disable() {
|
|
39
|
-
this._enabled = false
|
|
40
|
-
return this
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* 是否启用
|
|
45
|
-
*/
|
|
46
|
-
isEnabled() {
|
|
47
|
-
return this._enabled
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* 销毁
|
|
52
|
-
*/
|
|
53
|
-
destroy() {
|
|
54
|
-
this.removeAllListeners()
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
module.exports = { ExecutorBase }
|
|
1
|
+
/**
|
|
2
|
+
* Executor 基类
|
|
3
|
+
* 执行器的基类,定义执行器接口
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const { EventEmitter } = require('../utils/event-emitter')
|
|
7
|
+
|
|
8
|
+
class ExecutorBase extends EventEmitter {
|
|
9
|
+
/**
|
|
10
|
+
* @param {string} name - 执行器名称
|
|
11
|
+
*/
|
|
12
|
+
constructor(name) {
|
|
13
|
+
super()
|
|
14
|
+
this.name = name
|
|
15
|
+
this._enabled = true
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* 执行
|
|
20
|
+
* @param {Object} params - 执行参数
|
|
21
|
+
* @returns {Promise<any>}
|
|
22
|
+
*/
|
|
23
|
+
async execute(params) {
|
|
24
|
+
throw new Error('execute() must be implemented')
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* 启用执行器
|
|
29
|
+
*/
|
|
30
|
+
enable() {
|
|
31
|
+
this._enabled = true
|
|
32
|
+
return this
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* 禁用执行器
|
|
37
|
+
*/
|
|
38
|
+
disable() {
|
|
39
|
+
this._enabled = false
|
|
40
|
+
return this
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* 是否启用
|
|
45
|
+
*/
|
|
46
|
+
isEnabled() {
|
|
47
|
+
return this._enabled
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* 销毁
|
|
52
|
+
*/
|
|
53
|
+
destroy() {
|
|
54
|
+
this.removeAllListeners()
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
module.exports = { ExecutorBase }
|
package/test-server.js
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
const { serve } = require('@hono/node-server');
|
|
2
|
-
const { Hono } = require('hono');
|
|
3
|
-
|
|
4
|
-
const app = new Hono();
|
|
5
|
-
|
|
6
|
-
// 简单路由
|
|
7
|
-
app.get('/test', (c) => {
|
|
8
|
-
console.log('Handler called');
|
|
9
|
-
return c.json({ message: 'Hello World' });
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
const server = serve({
|
|
13
|
-
fetch: app.fetch,
|
|
14
|
-
port: 3001
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
server.on('request', (req) => {
|
|
18
|
-
console.log('Request:', req.method, req.url);
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
server.on('error', (err) => {
|
|
22
|
-
console.error('Server error:', err);
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
console.log('Server started on port 3001');
|
|
1
|
+
const { serve } = require('@hono/node-server');
|
|
2
|
+
const { Hono } = require('hono');
|
|
3
|
+
|
|
4
|
+
const app = new Hono();
|
|
5
|
+
|
|
6
|
+
// 简单路由
|
|
7
|
+
app.get('/test', (c) => {
|
|
8
|
+
console.log('Handler called');
|
|
9
|
+
return c.json({ message: 'Hello World' });
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
const server = serve({
|
|
13
|
+
fetch: app.fetch,
|
|
14
|
+
port: 3001
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
server.on('request', (req) => {
|
|
18
|
+
console.log('Request:', req.method, req.url);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
server.on('error', (err) => {
|
|
22
|
+
console.error('Server error:', err);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
console.log('Server started on port 3001');
|
package/test.txt
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
Hello from static resource test!
|
|
2
|
-
This is a test file for verifying static resource serving.
|
|
3
|
-
Timestamp: 2026-03-24
|
|
1
|
+
Hello from static resource test!
|
|
2
|
+
This is a test file for verifying static resource serving.
|
|
3
|
+
Timestamp: 2026-03-24
|