foliko 1.1.93 → 2.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.
- package/.claude/settings.local.json +2 -1
- package/CLAUDE.md +56 -30
- package/REFACTORING_PLAN.md +645 -0
- package/docs/architecture.md +131 -0
- package/docs/migration.md +57 -0
- package/docs/public-api.md +138 -0
- package/docs/usage.md +385 -0
- package/examples/ambient-example.js +20 -137
- package/examples/basic.js +21 -48
- package/examples/bootstrap.js +16 -74
- package/examples/mcp-example.js +6 -29
- package/examples/skill-example.js +6 -19
- package/examples/workflow.js +8 -56
- package/package.json +8 -4
- package/plugins/README.md +49 -0
- package/plugins/{ambient-agent → ambient}/EventWatcher.js +1 -1
- package/plugins/{ambient-agent → ambient}/ExplorerLoop.js +3 -3
- package/plugins/{ambient-agent → ambient}/GoalManager.js +2 -2
- package/plugins/ambient/README.md +14 -0
- package/plugins/{ambient-agent → ambient}/Reflector.js +1 -1
- package/plugins/{ambient-agent → ambient}/StateStore.js +1 -1
- package/plugins/{ambient-agent → ambient}/index.js +2 -2
- package/plugins/{ai-plugin.js → core/ai/index.js} +14 -30
- package/plugins/{audit-plugin.js → core/audit/index.js} +3 -30
- package/plugins/{coordinator-plugin.js → core/coordinator/index.js} +3 -35
- package/plugins/core/default/bootstrap.js +224 -0
- package/plugins/core/default/config.js +222 -0
- package/plugins/core/default/index.js +58 -0
- package/plugins/core/mcp/index.js +1 -0
- package/plugins/{python-plugin-loader.js → core/python-loader/index.js} +7 -187
- package/plugins/{rules-plugin.js → core/rules/index.js} +121 -64
- package/plugins/{scheduler-plugin.js → core/scheduler/index.js} +12 -114
- package/plugins/{session-plugin.js → core/session/index.js} +9 -73
- package/{src/capabilities/skill-manager.js → plugins/core/skill-manager/index.js} +64 -18
- package/plugins/{storage-plugin.js → core/storage/index.js} +5 -29
- package/plugins/{subagent-plugin.js → core/sub-agent/index.js} +10 -171
- package/plugins/{think-plugin.js → core/think/index.js} +24 -91
- package/{src/capabilities/workflow-engine.js → plugins/core/workflow/index.js} +87 -85
- package/plugins/default-plugins.js +6 -720
- package/plugins/{data-splitter-plugin.js → executors/data-splitter/index.js} +9 -83
- package/plugins/{extension-executor-plugin.js → executors/extension/index.js} +13 -97
- package/plugins/{python-executor-plugin.js → executors/python/index.js} +6 -31
- package/plugins/{shell-executor-plugin.js → executors/shell/index.js} +2 -5
- package/plugins/install/README.md +9 -0
- package/plugins/{install-plugin.js → install/index.js} +3 -3
- package/plugins/{file-system-plugin.js → io/file-system/index.js} +34 -236
- package/plugins/{web-plugin.js → io/web/index.js} +11 -113
- package/plugins/memory/README.md +13 -0
- package/plugins/{memory-plugin.js → memory/index.js} +4 -18
- package/plugins/messaging/email/README.md +19 -0
- package/plugins/{email → messaging/email}/index.js +3 -3
- package/plugins/{feishu-plugin.js → messaging/feishu/index.js} +4 -4
- package/plugins/{qq-plugin.js → messaging/qq/index.js} +6 -17
- package/plugins/{telegram-plugin.js → messaging/telegram/index.js} +4 -4
- package/plugins/{weixin-plugin.js → messaging/weixin/index.js} +16 -16
- package/plugins/{plugin-manager-plugin.js → plugin-manager/index.js} +36 -180
- package/plugins/{tools-plugin.js → tools/index.js} +68 -116
- package/plugins/trading/README.md +15 -0
- package/plugins/{gate-trading.js → trading/index.js} +8 -8
- package/{examples → sandbox}/test-concurrent-chat.js +2 -2
- package/{examples → sandbox}/test-long-chat.js +2 -2
- package/{examples → sandbox}/test-session-chat.js +2 -2
- package/{examples → sandbox}/test-web-plugin.js +1 -1
- package/{examples → sandbox}/test-weixin-feishu.js +2 -2
- package/src/agent/base.js +56 -0
- package/src/{core/agent-chat.js → agent/chat.js} +11 -11
- package/src/{core/coordinator-manager.js → agent/coordinator.js} +3 -3
- package/src/agent/index.js +111 -0
- package/src/agent/main.js +337 -0
- package/src/agent/prompt.js +78 -0
- package/src/agent/sub.js +198 -0
- package/src/agent/worker.js +104 -0
- package/{cli/bin/foliko.js → src/cli/bin.js} +1 -1
- package/{cli/src → src/cli}/commands/chat.js +25 -21
- package/{cli/src → src/cli}/index.js +1 -0
- package/{cli/src → src/cli}/ui/chat-ui-old.js +40 -178
- package/{cli/src → src/cli}/ui/chat-ui.js +3 -3
- package/{cli/src → src/cli}/ui/components/footer-bar.js +1 -1
- package/src/common/errors.js +402 -0
- package/src/{utils → common}/logger.js +33 -0
- package/src/{utils/chat-queue.js → common/queue.js} +2 -2
- package/src/config/plugin-config.js +50 -0
- package/src/context/agent.js +32 -0
- package/src/context/compaction-prompts.js +170 -0
- package/src/context/compaction-utils.js +191 -0
- package/src/context/compressor.js +413 -0
- package/src/context/index.js +9 -0
- package/src/{core/context-manager.js → context/manager.js} +1 -1
- package/src/context/request.js +50 -0
- package/src/context/session.js +33 -0
- package/src/context/storage.js +30 -0
- package/src/executors/mcp-client.js +153 -0
- package/src/executors/mcp-desc.js +236 -0
- package/src/executors/mcp-executor.js +91 -956
- package/src/{core → framework}/command-registry.js +1 -1
- package/src/framework/framework.js +300 -0
- package/src/framework/index.js +18 -0
- package/src/framework/lifecycle.js +203 -0
- package/src/framework/loader.js +78 -0
- package/src/framework/registry.js +86 -0
- package/src/{core/ui-extension-context.js → framework/ui-extension.js} +1 -1
- package/src/index.js +130 -15
- package/src/llm/index.js +26 -0
- package/src/llm/provider.js +212 -0
- package/src/llm/registry.js +11 -0
- package/src/{core/token-counter.js → llm/tokens.js} +4 -37
- package/src/{core/plugin-base.js → plugin/base.js} +10 -136
- package/src/plugin/index.js +14 -0
- package/src/plugin/loader.js +101 -0
- package/src/plugin/manager.js +484 -0
- package/src/{core → session}/branch-summary-auto.js +2 -2
- package/src/{core/chat-session.js → session/chat.js} +2 -2
- package/src/session/index.js +7 -0
- package/src/{core/session-manager.js → session/session.js} +2 -2
- package/src/session/ttl.js +92 -0
- package/src/{core/jsonl-storage.js → storage/jsonl.js} +1 -1
- package/src/tool/executor.js +85 -0
- package/src/tool/index.js +15 -0
- package/src/tool/registry.js +143 -0
- package/src/{core/tool-router.js → tool/router.js} +17 -124
- package/src/tool/schema.js +108 -0
- package/src/utils/data-splitter.js +1 -1
- package/src/utils/download.js +1 -1
- package/src/utils/index.js +6 -6
- package/src/utils/message-validator.js +1 -1
- package/tests/core/context-storage.test.js +46 -0
- package/tests/core/llm.test.js +54 -0
- package/tests/core/plugin.test.js +42 -0
- package/tests/core/tool.test.js +60 -0
- package/tests/setup.js +10 -0
- package/tests/smoke.test.js +58 -0
- package/vitest.config.js +9 -0
- package/cli/src/daemon.js +0 -149
- package/docs/CONTEXT_DESIGN.md +0 -1596
- package/docs/ai-sdk-optimization.md +0 -655
- package/docs/features.md +0 -120
- package/docs/qq-bot.md +0 -976
- package/docs/quick-reference.md +0 -160
- package/docs/user-manual.md +0 -1391
- package/images/geometric_shapes.jpg +0 -0
- package/images/sunset_mountain_lake.jpg +0 -0
- package/skills/poster-guide/SKILL.md +0 -792
- package/src/capabilities/index.js +0 -11
- package/src/core/agent.js +0 -808
- package/src/core/context-compressor.js +0 -959
- package/src/core/enhanced-context-compressor.js +0 -210
- package/src/core/framework.js +0 -1422
- package/src/core/index.js +0 -30
- package/src/core/plugin-manager.js +0 -961
- package/src/core/provider-registry.js +0 -159
- package/src/core/provider.js +0 -156
- package/src/core/request-context.js +0 -98
- package/src/core/subagent.js +0 -442
- package/src/core/system-prompt-builder.js +0 -120
- package/src/core/tool-executor.js +0 -202
- package/src/core/tool-registry.js +0 -517
- package/src/core/worker-agent.js +0 -192
- package/src/executors/executor-base.js +0 -58
- package/src/utils/error-boundary.js +0 -363
- package/src/utils/error.js +0 -374
- package/system.md +0 -1645
- package/website_v2/README.md +0 -57
- package/website_v2/SPEC.md +0 -1
- package/website_v2/docs/api.html +0 -128
- package/website_v2/docs/configuration.html +0 -147
- package/website_v2/docs/plugin-development.html +0 -129
- package/website_v2/docs/project-structure.html +0 -89
- package/website_v2/docs/skill-development.html +0 -85
- package/website_v2/index.html +0 -489
- package/website_v2/scripts/main.js +0 -93
- package/website_v2/styles/animations.css +0 -8
- package/website_v2/styles/docs.css +0 -83
- package/website_v2/styles/main.css +0 -417
- package/xhs_auth.json +0 -268
- package//346/265/267/346/212/245/346/217/222/344/273/266.md +0 -621
- /package/plugins/{ambient-agent → ambient}/constants.js +0 -0
- /package/plugins/{email → messaging/email}/constants.js +0 -0
- /package/plugins/{email → messaging/email}/handlers.js +0 -0
- /package/plugins/{email → messaging/email}/monitor.js +0 -0
- /package/plugins/{email → messaging/email}/parser.js +0 -0
- /package/plugins/{email → messaging/email}/reply.js +0 -0
- /package/plugins/{email → messaging/email}/utils.js +0 -0
- /package/{examples → sandbox}/test-chat.js +0 -0
- /package/{examples → sandbox}/test-mcp.js +0 -0
- /package/{examples → sandbox}/test-reload.js +0 -0
- /package/{examples → sandbox}/test-telegram.js +0 -0
- /package/{examples → sandbox}/test-tg-bot.js +0 -0
- /package/{examples → sandbox}/test-tg-simple.js +0 -0
- /package/{examples → sandbox}/test-tg.js +0 -0
- /package/{examples → sandbox}/test-think.js +0 -0
- /package/src/{core/sub-agent-config.js → agent/sub-config.js} +0 -0
- /package/{cli/src → src/cli}/commands/daemon.js +0 -0
- /package/{cli/src → src/cli}/commands/list.js +0 -0
- /package/{cli/src → src/cli}/commands/plugin.js +0 -0
- /package/{cli/src → src/cli}/ui/components/agent-mention-provider.js +0 -0
- /package/{cli/src → src/cli}/ui/components/chained-autocomplete-provider.js +0 -0
- /package/{cli/src → src/cli}/ui/components/message-bubble.js +0 -0
- /package/{cli/src → src/cli}/ui/components/status-bar.js +0 -0
- /package/{cli/src → src/cli}/utils/ansi.js +0 -0
- /package/{cli/src → src/cli}/utils/config.js +0 -0
- /package/{cli/src → src/cli}/utils/markdown.js +0 -0
- /package/{cli/src → src/cli}/utils/plugin-config.js +0 -0
- /package/{cli/src → src/cli}/utils/render-diff.js +0 -0
- /package/src/{utils/circuit-breaker.js → common/circuit.js} +0 -0
- /package/src/{core → common}/constants.js +0 -0
- /package/src/{utils/edit-diff.js → common/diff.js} +0 -0
- /package/src/{utils/event-emitter.js → common/events.js} +0 -0
- /package/src/{utils → common}/id.js +0 -0
- /package/src/{utils → common}/retry.js +0 -0
- /package/src/{core/notification-manager.js → notification/manager.js} +0 -0
- /package/src/{core/session-entry.js → session/entry.js} +0 -0
- /package/src/{core/storage-manager.js → storage/manager.js} +0 -0
|
@@ -4,14 +4,13 @@
|
|
|
4
4
|
* 任务触发时自动唤醒 Agent 发送消息
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
const { Plugin } = require('
|
|
8
|
-
const { logger } = require('
|
|
7
|
+
const { Plugin } = require('../../../src/plugin/base')
|
|
8
|
+
const { logger } = require('../../../src/common/logger')
|
|
9
9
|
const log = logger.child('Scheduler')
|
|
10
10
|
const { z } = require('zod')
|
|
11
11
|
const fs = require('fs')
|
|
12
12
|
const path = require('path')
|
|
13
13
|
|
|
14
|
-
// 尝试加载 node-schedule
|
|
15
14
|
let schedule = null
|
|
16
15
|
try {
|
|
17
16
|
schedule = require('node-schedule')
|
|
@@ -19,9 +18,6 @@ try {
|
|
|
19
18
|
log.warn(' node-schedule not installed, cron tasks will not work')
|
|
20
19
|
}
|
|
21
20
|
|
|
22
|
-
// ============================================================================
|
|
23
|
-
// TaskStore - 持久化任务到 .foliko/data/scheduler/tasks.json
|
|
24
|
-
// ============================================================================
|
|
25
21
|
class TaskStore {
|
|
26
22
|
constructor(persistencePath) {
|
|
27
23
|
this._persistencePath = persistencePath
|
|
@@ -40,7 +36,6 @@ class TaskStore {
|
|
|
40
36
|
|
|
41
37
|
saveTasks(tasks) {
|
|
42
38
|
try {
|
|
43
|
-
// 序列化时移除不可保存的字段(timer, cronTask)
|
|
44
39
|
const serializable = tasks.map(t => ({
|
|
45
40
|
id: t.id,
|
|
46
41
|
name: t.name,
|
|
@@ -54,10 +49,10 @@ class TaskStore {
|
|
|
54
49
|
cronExpression: t.cronExpression,
|
|
55
50
|
sessionId: t.sessionId,
|
|
56
51
|
llm: t.llm,
|
|
57
|
-
persistDelay: t.persistDelay,
|
|
58
|
-
persistNextRun: t.persistNextRun,
|
|
59
|
-
notify: t.notify,
|
|
60
|
-
shell: t.shell
|
|
52
|
+
persistDelay: t.persistDelay,
|
|
53
|
+
persistNextRun: t.persistNextRun,
|
|
54
|
+
notify: t.notify,
|
|
55
|
+
shell: t.shell
|
|
61
56
|
}))
|
|
62
57
|
fs.writeFileSync(this._getTasksPath(), JSON.stringify(serializable, null, 2))
|
|
63
58
|
} catch (err) {
|
|
@@ -79,7 +74,6 @@ class TaskStore {
|
|
|
79
74
|
}
|
|
80
75
|
}
|
|
81
76
|
|
|
82
|
-
// 时间解析辅助函数
|
|
83
77
|
function parseDelay(delayStr) {
|
|
84
78
|
const match = delayStr.match(/^(\d+)\s*(second|minute|hour|day|week)s?$/i)
|
|
85
79
|
if (!match) return null
|
|
@@ -97,7 +91,6 @@ function parseDelay(delayStr) {
|
|
|
97
91
|
|
|
98
92
|
function parseAtTime(timeStr) {
|
|
99
93
|
const now = new Date()
|
|
100
|
-
// 简单时间格式 "12:00"
|
|
101
94
|
const timeMatch = timeStr.match(/^(\d{1,2}):(\d{2})(?::(\d{2}))?$/)
|
|
102
95
|
if (timeMatch) {
|
|
103
96
|
const date = new Date(now)
|
|
@@ -110,9 +103,6 @@ function parseAtTime(timeStr) {
|
|
|
110
103
|
return new Date(timeStr)
|
|
111
104
|
}
|
|
112
105
|
|
|
113
|
-
/**
|
|
114
|
-
* 生成唯一 ID
|
|
115
|
-
*/
|
|
116
106
|
function generateId() {
|
|
117
107
|
if (require('crypto').randomUUID) {
|
|
118
108
|
return require('crypto').randomUUID()
|
|
@@ -129,7 +119,7 @@ class SchedulerPlugin extends Plugin {
|
|
|
129
119
|
this.priority = 15
|
|
130
120
|
this.system = true
|
|
131
121
|
this.config = {
|
|
132
|
-
checkInterval: config.checkInterval || 1000,
|
|
122
|
+
checkInterval: config.checkInterval || 1000,
|
|
133
123
|
persistencePath: config.persistencePath || '.foliko/data/scheduler'
|
|
134
124
|
}
|
|
135
125
|
|
|
@@ -148,14 +138,10 @@ class SchedulerPlugin extends Plugin {
|
|
|
148
138
|
|
|
149
139
|
install(framework) {
|
|
150
140
|
this._framework = framework
|
|
151
|
-
// 初始化任务存储
|
|
152
141
|
this._taskStore = new TaskStore(this.config.persistencePath)
|
|
153
142
|
return this
|
|
154
143
|
}
|
|
155
144
|
|
|
156
|
-
/**
|
|
157
|
-
* 获取 Agent 实例
|
|
158
|
-
*/
|
|
159
145
|
_getAgent() {
|
|
160
146
|
if (this._agent) return this._agent
|
|
161
147
|
if (this._framework._mainAgent) {
|
|
@@ -168,10 +154,8 @@ class SchedulerPlugin extends Plugin {
|
|
|
168
154
|
}
|
|
169
155
|
|
|
170
156
|
start(framework) {
|
|
171
|
-
// 获取 Agent 实例
|
|
172
157
|
this._agent = this._getAgent()
|
|
173
158
|
|
|
174
|
-
// 注册调度工具
|
|
175
159
|
framework.registerTool({
|
|
176
160
|
name: 'schedule_task',
|
|
177
161
|
description: '设置定时提醒任务。支持多种时间格式:相对时间(1 minute, 2 hours)、具体时间(12:00)、Cron表达式(* * * * *)。系统会自动判断任务是否需要 LLM 处理。',
|
|
@@ -194,7 +178,6 @@ class SchedulerPlugin extends Plugin {
|
|
|
194
178
|
return { success: false, error: 'Agent not available' }
|
|
195
179
|
}
|
|
196
180
|
|
|
197
|
-
// 如果指定了 shell 命令,创建 Shell 任务
|
|
198
181
|
if (shell) {
|
|
199
182
|
const taskId = `task_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
|
|
200
183
|
const isCron = /^[\d*,\/-\s]+$/.test(scheduleTime) && scheduleTime.split(' ').length >= 5
|
|
@@ -240,7 +223,6 @@ class SchedulerPlugin extends Plugin {
|
|
|
240
223
|
}
|
|
241
224
|
}
|
|
242
225
|
} else {
|
|
243
|
-
// 一次性 Shell 任务
|
|
244
226
|
const delayMs = parseDelay(scheduleTime)
|
|
245
227
|
if (!delayMs && !scheduleTime.includes(':')) {
|
|
246
228
|
return { success: false, error: '无效的时间格式' }
|
|
@@ -293,7 +275,6 @@ class SchedulerPlugin extends Plugin {
|
|
|
293
275
|
}
|
|
294
276
|
}
|
|
295
277
|
|
|
296
|
-
// 如果没有指定 sessionId,优先从执行上下文获取(来自 WeChat 等消息源)
|
|
297
278
|
let targetSessionId = sessionId
|
|
298
279
|
if (!targetSessionId) {
|
|
299
280
|
const ctx = this._framework.getExecutionContext()
|
|
@@ -301,21 +282,17 @@ class SchedulerPlugin extends Plugin {
|
|
|
301
282
|
targetSessionId = ctx.sessionId
|
|
302
283
|
}
|
|
303
284
|
}
|
|
304
|
-
// 如果执行上下文也没有,从 sessionPlugin 获取最近活跃会话
|
|
305
285
|
if (!targetSessionId) {
|
|
306
286
|
const sessionPlugin = this._framework.pluginManager.get('session')
|
|
307
287
|
if (sessionPlugin) {
|
|
308
288
|
const sessions = sessionPlugin.listSessions()
|
|
309
|
-
// 获取最近的活跃会话
|
|
310
289
|
if (sessions.length > 0) {
|
|
311
|
-
// 按 lastActive 排序,取最新的
|
|
312
290
|
sessions.sort((a, b) => {
|
|
313
291
|
const aTime = a.lastActive ? new Date(a.lastActive).getTime() : 0
|
|
314
292
|
const bTime = b.lastActive ? new Date(b.lastActive).getTime() : 0
|
|
315
293
|
return bTime - aTime
|
|
316
294
|
})
|
|
317
295
|
targetSessionId = sessions[0].id
|
|
318
|
-
//log.info(` Auto-detected active session: ${targetSessionId}`)
|
|
319
296
|
}
|
|
320
297
|
}
|
|
321
298
|
}
|
|
@@ -323,7 +300,6 @@ class SchedulerPlugin extends Plugin {
|
|
|
323
300
|
const taskId = `task_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
|
|
324
301
|
let task
|
|
325
302
|
|
|
326
|
-
// 自动检测是否需要 LLM 处理
|
|
327
303
|
const LLM_KEYWORDS = [
|
|
328
304
|
'分析', '查询', '查看', '检查', '总结', '搜索', '获取',
|
|
329
305
|
'list', 'get', 'check', 'search', 'find', 'fetch',
|
|
@@ -336,11 +312,9 @@ class SchedulerPlugin extends Plugin {
|
|
|
336
312
|
)
|
|
337
313
|
const llmMode = needsLLM
|
|
338
314
|
|
|
339
|
-
// 检测是否像 Cron 表达式
|
|
340
315
|
const isCron = /^[\d*,\/-\s]+$/.test(scheduleTime) && scheduleTime.split(' ').length >= 5
|
|
341
316
|
|
|
342
317
|
if (isCron || repeat) {
|
|
343
|
-
// Cron 任务
|
|
344
318
|
if (!schedule) {
|
|
345
319
|
return { success: false, error: 'node-schedule not installed' }
|
|
346
320
|
}
|
|
@@ -358,15 +332,13 @@ class SchedulerPlugin extends Plugin {
|
|
|
358
332
|
cronTask: null,
|
|
359
333
|
sessionId: targetSessionId || null,
|
|
360
334
|
llm: llmMode,
|
|
361
|
-
notify: args.notify !== false
|
|
335
|
+
notify: args.notify !== false
|
|
362
336
|
}
|
|
363
337
|
|
|
364
|
-
// 使用 node-schedule 调度
|
|
365
338
|
task.cronTask = schedule.scheduleJob(task.cronExpression, async () => {
|
|
366
339
|
await this._executeTask(task)
|
|
367
340
|
})
|
|
368
341
|
} else if (scheduleTime.includes(':')) {
|
|
369
|
-
// 具体时间
|
|
370
342
|
const runAt = parseAtTime(scheduleTime)
|
|
371
343
|
task = {
|
|
372
344
|
id: taskId,
|
|
@@ -387,7 +359,6 @@ class SchedulerPlugin extends Plugin {
|
|
|
387
359
|
await this._executeTask(task)
|
|
388
360
|
}, runAt.getTime() - Date.now())
|
|
389
361
|
} else {
|
|
390
|
-
// 相对时间
|
|
391
362
|
const delayMs = parseDelay(scheduleTime)
|
|
392
363
|
if (!delayMs) {
|
|
393
364
|
return { success: false, error: '无效的时间格式' }
|
|
@@ -406,7 +377,7 @@ class SchedulerPlugin extends Plugin {
|
|
|
406
377
|
timer: null,
|
|
407
378
|
sessionId: targetSessionId || null,
|
|
408
379
|
llm: llmMode,
|
|
409
|
-
persistDelay: delayMs,
|
|
380
|
+
persistDelay: delayMs,
|
|
410
381
|
notify: args.notify !== false
|
|
411
382
|
}
|
|
412
383
|
task.timer = setTimeout(async () => {
|
|
@@ -416,9 +387,8 @@ class SchedulerPlugin extends Plugin {
|
|
|
416
387
|
|
|
417
388
|
this._tasks.set(task.id, task)
|
|
418
389
|
this._taskStats.total++
|
|
419
|
-
this._saveTasks()
|
|
390
|
+
this._saveTasks()
|
|
420
391
|
|
|
421
|
-
// 发送任务创建事件
|
|
422
392
|
this._framework.emit('scheduler:task_created', {
|
|
423
393
|
taskId: task.id,
|
|
424
394
|
taskName: task.name,
|
|
@@ -489,9 +459,8 @@ class SchedulerPlugin extends Plugin {
|
|
|
489
459
|
|
|
490
460
|
const taskName = task.name
|
|
491
461
|
this._cancelTask(task)
|
|
492
|
-
this._saveTasks()
|
|
462
|
+
this._saveTasks()
|
|
493
463
|
|
|
494
|
-
// 发送任务取消通知
|
|
495
464
|
this._framework.emit('notification', {
|
|
496
465
|
title: '任务已取消',
|
|
497
466
|
message: `定时任务 "${taskName}" 已取消`,
|
|
@@ -528,18 +497,13 @@ class SchedulerPlugin extends Plugin {
|
|
|
528
497
|
}
|
|
529
498
|
})
|
|
530
499
|
|
|
531
|
-
// 启动调度循环(用于检查一次性任务)
|
|
532
500
|
this._startScheduler()
|
|
533
501
|
|
|
534
|
-
// 加载持久化的任务
|
|
535
502
|
this._loadPersistedTasks()
|
|
536
503
|
|
|
537
504
|
return this
|
|
538
505
|
}
|
|
539
506
|
|
|
540
|
-
/**
|
|
541
|
-
* 启动调度循环
|
|
542
|
-
*/
|
|
543
507
|
_startScheduler() {
|
|
544
508
|
if (this._timer) {
|
|
545
509
|
clearInterval(this._timer)
|
|
@@ -550,46 +514,31 @@ class SchedulerPlugin extends Plugin {
|
|
|
550
514
|
}, this.config.checkInterval)
|
|
551
515
|
}
|
|
552
516
|
|
|
553
|
-
/**
|
|
554
|
-
* 检查任务状态(主要用于更新 stats)
|
|
555
|
-
*/
|
|
556
517
|
_checkTasks() {
|
|
557
518
|
for (const [id, task] of this._tasks) {
|
|
558
519
|
if (!task.enabled) continue
|
|
559
|
-
// 统计信息更新
|
|
560
520
|
}
|
|
561
521
|
}
|
|
562
522
|
|
|
563
|
-
/**
|
|
564
|
-
* 保存任务到持久化存储
|
|
565
|
-
*/
|
|
566
523
|
_saveTasks() {
|
|
567
524
|
if (this._taskStore) {
|
|
568
525
|
this._taskStore.saveTasks(Array.from(this._tasks.values()))
|
|
569
526
|
}
|
|
570
527
|
}
|
|
571
528
|
|
|
572
|
-
/**
|
|
573
|
-
* 加载持久化的任务并重新调度
|
|
574
|
-
*/
|
|
575
529
|
_loadPersistedTasks() {
|
|
576
530
|
if (!this._taskStore) return
|
|
577
531
|
|
|
578
532
|
const savedTasks = this._taskStore.loadTasks()
|
|
579
533
|
if (!savedTasks || savedTasks.length === 0) return
|
|
580
534
|
|
|
581
|
-
//log.info(` 加载 ${savedTasks.length} 个持久化任务...`)
|
|
582
|
-
|
|
583
535
|
for (const saved of savedTasks) {
|
|
584
|
-
// 跳过已过期的任务或已清理的任务
|
|
585
536
|
if (saved.type === 'once' && saved.runCount > 0) {
|
|
586
|
-
//log.info(` 跳过已完成的一次性任务: ${saved.name}`)
|
|
587
537
|
continue
|
|
588
538
|
}
|
|
589
539
|
|
|
590
540
|
let task = { ...saved }
|
|
591
541
|
|
|
592
|
-
// 重新调度 Cron 任务
|
|
593
542
|
if (task.type === 'cron' && task.enabled && schedule) {
|
|
594
543
|
try {
|
|
595
544
|
task.cronTask = schedule.scheduleJob(task.cronExpression, async () => {
|
|
@@ -597,12 +546,10 @@ class SchedulerPlugin extends Plugin {
|
|
|
597
546
|
})
|
|
598
547
|
this._tasks.set(task.id, task)
|
|
599
548
|
this._taskStats.total++
|
|
600
|
-
//log.info(` 已恢复 Cron 任务: ${task.name}`)
|
|
601
549
|
} catch (err) {
|
|
602
550
|
log.error(` 恢复 Cron 任务失败: ${task.name}`, err.message)
|
|
603
551
|
}
|
|
604
552
|
}
|
|
605
|
-
// 重新调度 Cron Shell 任务
|
|
606
553
|
else if (task.type === 'shell' && task.enabled && task.cronExpression && schedule) {
|
|
607
554
|
try {
|
|
608
555
|
task.cronTask = schedule.scheduleJob(task.cronExpression, async () => {
|
|
@@ -610,12 +557,10 @@ class SchedulerPlugin extends Plugin {
|
|
|
610
557
|
})
|
|
611
558
|
this._tasks.set(task.id, task)
|
|
612
559
|
this._taskStats.total++
|
|
613
|
-
//log.info(` 已恢复 Shell Cron 任务: ${task.name}`)
|
|
614
560
|
} catch (err) {
|
|
615
561
|
log.error(` 恢复 Shell Cron 任务失败: ${task.name}`, err.message)
|
|
616
562
|
}
|
|
617
563
|
}
|
|
618
|
-
// 重新调度相对时间任务(计算新的执行时间)
|
|
619
564
|
else if (task.type === 'once' && task.enabled && task.persistDelay) {
|
|
620
565
|
const newDelay = task.persistDelay
|
|
621
566
|
if (newDelay > 0) {
|
|
@@ -625,10 +570,8 @@ class SchedulerPlugin extends Plugin {
|
|
|
625
570
|
}, newDelay)
|
|
626
571
|
this._tasks.set(task.id, task)
|
|
627
572
|
this._taskStats.total++
|
|
628
|
-
//log.info(` 已恢复一次性任务: ${task.name},将在 ${newDelay}ms 后执行`)
|
|
629
573
|
}
|
|
630
574
|
}
|
|
631
|
-
// 重新调度绝对时间任务
|
|
632
575
|
else if (task.type === 'once' && task.enabled && task.runAt) {
|
|
633
576
|
const runAt = new Date(task.runAt)
|
|
634
577
|
if (runAt > new Date()) {
|
|
@@ -638,17 +581,11 @@ class SchedulerPlugin extends Plugin {
|
|
|
638
581
|
}, delay)
|
|
639
582
|
this._tasks.set(task.id, task)
|
|
640
583
|
this._taskStats.total++
|
|
641
|
-
//log.info(` 已恢复一次性任务: ${task.name},将在 ${runAt} 执行`)
|
|
642
|
-
} else {
|
|
643
|
-
//log.info(` 跳过已过期的任务: ${task.name}`)
|
|
644
584
|
}
|
|
645
585
|
}
|
|
646
586
|
}
|
|
647
587
|
}
|
|
648
588
|
|
|
649
|
-
/**
|
|
650
|
-
* 取消任务
|
|
651
|
-
*/
|
|
652
589
|
_cancelTask(task) {
|
|
653
590
|
if (task.timer) {
|
|
654
591
|
clearTimeout(task.timer)
|
|
@@ -661,23 +598,12 @@ class SchedulerPlugin extends Plugin {
|
|
|
661
598
|
task.enabled = false
|
|
662
599
|
}
|
|
663
600
|
|
|
664
|
-
/**
|
|
665
|
-
* 执行任务
|
|
666
|
-
*/
|
|
667
601
|
async _executeTask(task) {
|
|
668
|
-
// //log.info(` Executing task: ${task.name} (${task.id})`)
|
|
669
|
-
// //log.info(` Message: ${task.message}`)
|
|
670
|
-
// // if (task.sessionId) {
|
|
671
|
-
// // //log.info(` Target session: ${task.sessionId}`)
|
|
672
|
-
// // }
|
|
673
|
-
// //log.info(` LLM mode: ${task.llm ? 'enabled' : 'disabled'}`)
|
|
674
|
-
|
|
675
602
|
task.lastRun = new Date()
|
|
676
603
|
task.runCount++
|
|
677
604
|
this._taskStats.running++
|
|
678
605
|
|
|
679
606
|
try {
|
|
680
|
-
// Shell 命令执行模式
|
|
681
607
|
if (task.type === 'shell') {
|
|
682
608
|
const result = await this._framework.executeTool('shell', { command: task.shell })
|
|
683
609
|
this._taskStats.completed++
|
|
@@ -705,7 +631,6 @@ class SchedulerPlugin extends Plugin {
|
|
|
705
631
|
|
|
706
632
|
return { success: true }
|
|
707
633
|
} else if (task.llm) {
|
|
708
|
-
// LLM 模式:使用子Agent处理
|
|
709
634
|
const schedulerAgent = this._framework.createSubAgent({
|
|
710
635
|
name: 'scheduler_task',
|
|
711
636
|
role: '定时任务执行助手,专注于处理定时提醒和任务执行'
|
|
@@ -715,17 +640,9 @@ class SchedulerPlugin extends Plugin {
|
|
|
715
640
|
|
|
716
641
|
this._taskStats.completed++
|
|
717
642
|
|
|
718
|
-
// 获取 LLM 返回的消息
|
|
719
643
|
const responseText = result.message
|
|
720
644
|
|
|
721
|
-
// if (responseText) {
|
|
722
|
-
// console.log(`\n🔔 [定时提醒] ${responseText}\n`)
|
|
723
|
-
// }
|
|
724
|
-
|
|
725
|
-
// 根据 notify 参数决定是否发送通知
|
|
726
|
-
// 只有当 LLM 返回了有效消息时才发送通知
|
|
727
645
|
if (task.notify !== false && responseText && responseText.trim()) {
|
|
728
|
-
// 发送统一的通知事件
|
|
729
646
|
this._framework.emit('notification', {
|
|
730
647
|
title: task.name,
|
|
731
648
|
message: responseText,
|
|
@@ -734,7 +651,6 @@ class SchedulerPlugin extends Plugin {
|
|
|
734
651
|
sessionId: task.sessionId,
|
|
735
652
|
timestamp: new Date()
|
|
736
653
|
})
|
|
737
|
-
// 发送 scheduler:reminder 事件
|
|
738
654
|
this._framework.emit('scheduler:reminder', {
|
|
739
655
|
taskId: task.id,
|
|
740
656
|
message: task.message,
|
|
@@ -742,16 +658,12 @@ class SchedulerPlugin extends Plugin {
|
|
|
742
658
|
})
|
|
743
659
|
}
|
|
744
660
|
|
|
745
|
-
// 发送任务完成事件
|
|
746
661
|
this._framework.emit('scheduler:task_completed', {
|
|
747
662
|
taskId: task.id,
|
|
748
663
|
result: responseText || task.message
|
|
749
664
|
})
|
|
750
665
|
} else {
|
|
751
|
-
// 直接显示模式:只显示提醒,不发 LLM
|
|
752
|
-
// 根据 notify 参数决定是否发送通知
|
|
753
666
|
if (task.notify !== false) {
|
|
754
|
-
// 发送统一的通知事件
|
|
755
667
|
this._framework.emit('notification', {
|
|
756
668
|
title: task.name,
|
|
757
669
|
message: task.message,
|
|
@@ -760,7 +672,6 @@ class SchedulerPlugin extends Plugin {
|
|
|
760
672
|
sessionId: task.sessionId,
|
|
761
673
|
timestamp: new Date()
|
|
762
674
|
})
|
|
763
|
-
// 发送 scheduler:reminder 事件
|
|
764
675
|
this._framework.emit('scheduler:reminder', {
|
|
765
676
|
taskId: task.id,
|
|
766
677
|
message: task.message,
|
|
@@ -768,7 +679,6 @@ class SchedulerPlugin extends Plugin {
|
|
|
768
679
|
})
|
|
769
680
|
}
|
|
770
681
|
|
|
771
|
-
// 发送任务完成事件
|
|
772
682
|
this._framework.emit('scheduler:task_completed', {
|
|
773
683
|
taskId: task.id,
|
|
774
684
|
result: task.message
|
|
@@ -776,7 +686,6 @@ class SchedulerPlugin extends Plugin {
|
|
|
776
686
|
this._taskStats.completed++
|
|
777
687
|
}
|
|
778
688
|
|
|
779
|
-
// 一次性任务执行后清理
|
|
780
689
|
if (task.type === 'once' && !task.cronTask) {
|
|
781
690
|
this._cleanupTask(task.id)
|
|
782
691
|
}
|
|
@@ -786,7 +695,6 @@ class SchedulerPlugin extends Plugin {
|
|
|
786
695
|
this._taskStats.failed++
|
|
787
696
|
log.error(` Task ${task.name} failed: ${err.message}`)
|
|
788
697
|
|
|
789
|
-
// 发送统一的通知事件
|
|
790
698
|
this._framework.emit('notification', {
|
|
791
699
|
title: `任务失败: ${task.name}`,
|
|
792
700
|
message: err.message,
|
|
@@ -796,13 +704,11 @@ class SchedulerPlugin extends Plugin {
|
|
|
796
704
|
timestamp: new Date()
|
|
797
705
|
})
|
|
798
706
|
|
|
799
|
-
// 发送任务失败事件
|
|
800
707
|
this._framework.emit('scheduler:task_failed', {
|
|
801
708
|
taskId: task.id,
|
|
802
709
|
error: err.message
|
|
803
710
|
})
|
|
804
711
|
|
|
805
|
-
// 一次性任务失败后也清理
|
|
806
712
|
if (task.type === 'once' && !task.cronTask) {
|
|
807
713
|
this._cleanupTask(task.id)
|
|
808
714
|
}
|
|
@@ -813,9 +719,6 @@ class SchedulerPlugin extends Plugin {
|
|
|
813
719
|
}
|
|
814
720
|
}
|
|
815
721
|
|
|
816
|
-
/**
|
|
817
|
-
* 清理任务
|
|
818
|
-
*/
|
|
819
722
|
_cleanupTask(taskId) {
|
|
820
723
|
const task = this._tasks.get(taskId)
|
|
821
724
|
if (task) {
|
|
@@ -828,13 +731,10 @@ class SchedulerPlugin extends Plugin {
|
|
|
828
731
|
task.cronTask = null
|
|
829
732
|
}
|
|
830
733
|
this._tasks.delete(taskId)
|
|
831
|
-
this._saveTasks()
|
|
734
|
+
this._saveTasks()
|
|
832
735
|
}
|
|
833
736
|
}
|
|
834
737
|
|
|
835
|
-
/**
|
|
836
|
-
* 停止所有任务
|
|
837
|
-
*/
|
|
838
738
|
stopAll() {
|
|
839
739
|
for (const task of this._tasks.values()) {
|
|
840
740
|
this._cancelTask(task)
|
|
@@ -845,7 +745,6 @@ class SchedulerPlugin extends Plugin {
|
|
|
845
745
|
this._timer = null
|
|
846
746
|
}
|
|
847
747
|
|
|
848
|
-
// 保存状态
|
|
849
748
|
this._saveTasks()
|
|
850
749
|
}
|
|
851
750
|
|
|
@@ -853,7 +752,6 @@ class SchedulerPlugin extends Plugin {
|
|
|
853
752
|
this._framework = framework
|
|
854
753
|
this._agent = this._getAgent()
|
|
855
754
|
this._startScheduler()
|
|
856
|
-
// 重新加载持久化任务
|
|
857
755
|
this._loadPersistedTasks()
|
|
858
756
|
}
|
|
859
757
|
|