flashclaw 1.0.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/LICENSE +21 -0
- package/README.md +305 -0
- package/config/plugins.json +23 -0
- package/dist/agent-runner.d.ts +103 -0
- package/dist/agent-runner.d.ts.map +1 -0
- package/dist/agent-runner.js +530 -0
- package/dist/agent-runner.js.map +1 -0
- package/dist/cli.d.ts +7 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +497 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands.d.ts +68 -0
- package/dist/commands.d.ts.map +1 -0
- package/dist/commands.js +252 -0
- package/dist/commands.js.map +1 -0
- package/dist/config-schema.d.ts +21 -0
- package/dist/config-schema.d.ts.map +1 -0
- package/dist/config-schema.js +26 -0
- package/dist/config-schema.js.map +1 -0
- package/dist/config.d.ts +11 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +36 -0
- package/dist/config.js.map +1 -0
- package/dist/core/api-client.d.ts +236 -0
- package/dist/core/api-client.d.ts.map +1 -0
- package/dist/core/api-client.js +369 -0
- package/dist/core/api-client.js.map +1 -0
- package/dist/core/memory.d.ts +291 -0
- package/dist/core/memory.d.ts.map +1 -0
- package/dist/core/memory.js +754 -0
- package/dist/core/memory.js.map +1 -0
- package/dist/core/model-capabilities.d.ts +45 -0
- package/dist/core/model-capabilities.d.ts.map +1 -0
- package/dist/core/model-capabilities.js +85 -0
- package/dist/core/model-capabilities.js.map +1 -0
- package/dist/db.d.ts +103 -0
- package/dist/db.d.ts.map +1 -0
- package/dist/db.js +380 -0
- package/dist/db.js.map +1 -0
- package/dist/errors.d.ts +22 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +44 -0
- package/dist/errors.js.map +1 -0
- package/dist/health.d.ts +27 -0
- package/dist/health.d.ts.map +1 -0
- package/dist/health.js +55 -0
- package/dist/health.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1181 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +9 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +19 -0
- package/dist/logger.js.map +1 -0
- package/dist/message-queue.d.ts +69 -0
- package/dist/message-queue.d.ts.map +1 -0
- package/dist/message-queue.js +198 -0
- package/dist/message-queue.js.map +1 -0
- package/dist/metrics.d.ts +46 -0
- package/dist/metrics.d.ts.map +1 -0
- package/dist/metrics.js +101 -0
- package/dist/metrics.js.map +1 -0
- package/dist/paths.d.ts +81 -0
- package/dist/paths.d.ts.map +1 -0
- package/dist/paths.js +127 -0
- package/dist/paths.js.map +1 -0
- package/dist/plugins/index.d.ts +9 -0
- package/dist/plugins/index.d.ts.map +1 -0
- package/dist/plugins/index.js +13 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/plugins/installer.d.ts +120 -0
- package/dist/plugins/installer.d.ts.map +1 -0
- package/dist/plugins/installer.js +1008 -0
- package/dist/plugins/installer.js.map +1 -0
- package/dist/plugins/loader.d.ts +37 -0
- package/dist/plugins/loader.d.ts.map +1 -0
- package/dist/plugins/loader.js +429 -0
- package/dist/plugins/loader.js.map +1 -0
- package/dist/plugins/manager.d.ts +72 -0
- package/dist/plugins/manager.d.ts.map +1 -0
- package/dist/plugins/manager.js +187 -0
- package/dist/plugins/manager.js.map +1 -0
- package/dist/plugins/types.d.ts +101 -0
- package/dist/plugins/types.d.ts.map +1 -0
- package/dist/plugins/types.js +12 -0
- package/dist/plugins/types.js.map +1 -0
- package/dist/session-tracker.d.ts +81 -0
- package/dist/session-tracker.d.ts.map +1 -0
- package/dist/session-tracker.js +228 -0
- package/dist/session-tracker.js.map +1 -0
- package/dist/task-scheduler.d.ts +47 -0
- package/dist/task-scheduler.d.ts.map +1 -0
- package/dist/task-scheduler.js +331 -0
- package/dist/task-scheduler.js.map +1 -0
- package/dist/types.d.ts +57 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/env-substitute.d.ts +63 -0
- package/dist/utils/env-substitute.d.ts.map +1 -0
- package/dist/utils/env-substitute.js +133 -0
- package/dist/utils/env-substitute.js.map +1 -0
- package/dist/utils/log-rotate.d.ts +19 -0
- package/dist/utils/log-rotate.d.ts.map +1 -0
- package/dist/utils/log-rotate.js +85 -0
- package/dist/utils/log-rotate.js.map +1 -0
- package/dist/utils/rate-limiter.d.ts +38 -0
- package/dist/utils/rate-limiter.d.ts.map +1 -0
- package/dist/utils/rate-limiter.js +79 -0
- package/dist/utils/rate-limiter.js.map +1 -0
- package/dist/utils/retry.d.ts +10 -0
- package/dist/utils/retry.d.ts.map +1 -0
- package/dist/utils/retry.js +47 -0
- package/dist/utils/retry.js.map +1 -0
- package/dist/utils.d.ts +86 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +218 -0
- package/dist/utils.js.map +1 -0
- package/package.json +78 -0
- package/plugins/cancel-task/index.ts +161 -0
- package/plugins/cancel-task/plugin.json +9 -0
- package/plugins/feishu/index.ts +944 -0
- package/plugins/feishu/plugin.json +29 -0
- package/plugins/list-tasks/index.ts +150 -0
- package/plugins/list-tasks/plugin.json +9 -0
- package/plugins/memory/index.ts +190 -0
- package/plugins/memory/plugin.json +7 -0
- package/plugins/pause-task/index.ts +95 -0
- package/plugins/pause-task/plugin.json +8 -0
- package/plugins/register-group/index.ts +147 -0
- package/plugins/register-group/plugin.json +7 -0
- package/plugins/resume-task/index.ts +92 -0
- package/plugins/resume-task/plugin.json +8 -0
- package/plugins/schedule-task/index.ts +248 -0
- package/plugins/schedule-task/plugin.json +9 -0
- package/plugins/send-message/index.ts +75 -0
- package/plugins/send-message/plugin.json +9 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FlashClaw 任务调度器
|
|
3
|
+
*
|
|
4
|
+
* 功能特性:
|
|
5
|
+
* 1. 精确定时器 - 按需唤醒,而不是固定轮询
|
|
6
|
+
* 2. 并发控制 - 限制同时执行的任务数
|
|
7
|
+
* 3. 超时保护 - 防止任务卡死阻塞调度
|
|
8
|
+
* 4. 重试机制 - 失败任务自动重试(指数退避)
|
|
9
|
+
*/
|
|
10
|
+
import { RegisteredGroup } from './types.js';
|
|
11
|
+
export interface SchedulerDependencies {
|
|
12
|
+
sendMessage: (jid: string, text: string) => Promise<void>;
|
|
13
|
+
registeredGroups: () => Record<string, RegisteredGroup>;
|
|
14
|
+
getSessions: () => Record<string, string>;
|
|
15
|
+
}
|
|
16
|
+
interface SchedulerState {
|
|
17
|
+
timer: NodeJS.Timeout | null;
|
|
18
|
+
running: boolean;
|
|
19
|
+
deps: SchedulerDependencies | null;
|
|
20
|
+
}
|
|
21
|
+
declare global {
|
|
22
|
+
var __flashclaw_scheduler_state: SchedulerState | undefined;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* 启动调度器
|
|
26
|
+
*/
|
|
27
|
+
export declare function startScheduler(deps: SchedulerDependencies): void;
|
|
28
|
+
/**
|
|
29
|
+
* 停止调度器
|
|
30
|
+
*/
|
|
31
|
+
export declare function stopScheduler(): void;
|
|
32
|
+
/**
|
|
33
|
+
* 立即唤醒调度器
|
|
34
|
+
* 用于创建新任务后立即检查是否需要执行
|
|
35
|
+
*/
|
|
36
|
+
export declare function wake(): void;
|
|
37
|
+
/**
|
|
38
|
+
* 获取调度器状态
|
|
39
|
+
*/
|
|
40
|
+
export declare function getSchedulerStatus(): {
|
|
41
|
+
running: boolean;
|
|
42
|
+
nextWakeTime: number | null;
|
|
43
|
+
activeTasks: number;
|
|
44
|
+
};
|
|
45
|
+
export declare function startSchedulerLoop(deps: SchedulerDependencies): void;
|
|
46
|
+
export {};
|
|
47
|
+
//# sourceMappingURL=task-scheduler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-scheduler.d.ts","sourceRoot":"","sources":["../src/task-scheduler.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAiBH,OAAO,EAAiB,eAAe,EAAE,MAAM,YAAY,CAAC;AA0B5D,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1D,gBAAgB,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IACxD,WAAW,EAAE,MAAM,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC3C;AAED,UAAU,cAAc;IACtB,KAAK,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,qBAAqB,GAAG,IAAI,CAAC;CACpC;AAYD,OAAO,CAAC,MAAM,CAAC;IAEb,IAAI,2BAA2B,EAAE,cAAc,GAAG,SAAS,CAAC;CAC7D;AAuTD;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,qBAAqB,GAAG,IAAI,CAIhE;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,IAAI,CAQpC;AAED;;;GAGG;AACH,wBAAgB,IAAI,IAAI,IAAI,CAG3B;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,WAAW,EAAE,MAAM,CAAC;CACrB,CASA;AAGD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,qBAAqB,GAAG,IAAI,CAEpE"}
|
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FlashClaw 任务调度器
|
|
3
|
+
*
|
|
4
|
+
* 功能特性:
|
|
5
|
+
* 1. 精确定时器 - 按需唤醒,而不是固定轮询
|
|
6
|
+
* 2. 并发控制 - 限制同时执行的任务数
|
|
7
|
+
* 3. 超时保护 - 防止任务卡死阻塞调度
|
|
8
|
+
* 4. 重试机制 - 失败任务自动重试(指数退避)
|
|
9
|
+
*/
|
|
10
|
+
import fs from 'fs';
|
|
11
|
+
import path from 'path';
|
|
12
|
+
import pLimit from 'p-limit';
|
|
13
|
+
import { CronExpressionParser } from 'cron-parser';
|
|
14
|
+
import { getDueTasks, updateTaskAfterRun, logTaskRun, getTaskById, getAllTasks, getNextWakeTime, updateTaskRetry, resetTaskRetry, updateTask } from './db.js';
|
|
15
|
+
import { GROUPS_DIR, MAIN_GROUP_FOLDER, TIMEZONE } from './config.js';
|
|
16
|
+
import { runAgent, writeTasksSnapshot } from './agent-runner.js';
|
|
17
|
+
import { createLogger } from './logger.js';
|
|
18
|
+
const logger = createLogger('TaskScheduler');
|
|
19
|
+
// ==================== 配置常量 ====================
|
|
20
|
+
/** 最大并发任务数 */
|
|
21
|
+
const MAX_CONCURRENT_TASKS = 3;
|
|
22
|
+
/** 默认任务超时时间(5 分钟) */
|
|
23
|
+
const DEFAULT_TASK_TIMEOUT_MS = 5 * 60 * 1000;
|
|
24
|
+
/** 最大定时器延迟(避免 Node.js 的 32 位整数溢出) */
|
|
25
|
+
const MAX_TIMEOUT_MS = 2 ** 31 - 1;
|
|
26
|
+
/** 重试基础延迟(1 分钟) */
|
|
27
|
+
const RETRY_BASE_DELAY_MS = 60 * 1000;
|
|
28
|
+
/** 最大重试延迟(1 小时) */
|
|
29
|
+
const MAX_RETRY_DELAY_MS = 60 * 60 * 1000;
|
|
30
|
+
function getState() {
|
|
31
|
+
if (!global.__flashclaw_scheduler_state) {
|
|
32
|
+
global.__flashclaw_scheduler_state = {
|
|
33
|
+
timer: null,
|
|
34
|
+
running: false,
|
|
35
|
+
deps: null
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
return global.__flashclaw_scheduler_state;
|
|
39
|
+
}
|
|
40
|
+
// 注意:所有对 state 的访问都应该使用 getState() 函数,
|
|
41
|
+
// 以确保 jiti 动态加载的模块也能访问到正确的状态
|
|
42
|
+
// 并发限制器
|
|
43
|
+
const taskLimit = pLimit(MAX_CONCURRENT_TASKS);
|
|
44
|
+
// ==================== 精确定时器 ====================
|
|
45
|
+
/**
|
|
46
|
+
* 设置精确定时器
|
|
47
|
+
* 计算下一个任务的执行时间,并设置 setTimeout
|
|
48
|
+
*/
|
|
49
|
+
function armTimer() {
|
|
50
|
+
// 清除旧定时器
|
|
51
|
+
const state = getState();
|
|
52
|
+
if (state.timer) {
|
|
53
|
+
clearTimeout(state.timer);
|
|
54
|
+
state.timer = null;
|
|
55
|
+
}
|
|
56
|
+
// 获取下一个唤醒时间
|
|
57
|
+
const nextAt = getNextWakeTime();
|
|
58
|
+
if (!nextAt) {
|
|
59
|
+
logger.debug('没有待执行的任务,定时器空闲');
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
// 计算延迟时间
|
|
63
|
+
const now = Date.now();
|
|
64
|
+
const delay = Math.max(nextAt - now, 0);
|
|
65
|
+
// 限制最大延迟,避免 32 位整数溢出
|
|
66
|
+
const clampedDelay = Math.min(delay, MAX_TIMEOUT_MS);
|
|
67
|
+
logger.debug({
|
|
68
|
+
nextAt: new Date(nextAt).toISOString(),
|
|
69
|
+
delayMs: clampedDelay
|
|
70
|
+
}, '设置定时器');
|
|
71
|
+
const currentState = getState();
|
|
72
|
+
currentState.timer = setTimeout(() => {
|
|
73
|
+
void onTimer().catch((err) => {
|
|
74
|
+
logger.error({ err: String(err) }, '定时器触发失败');
|
|
75
|
+
});
|
|
76
|
+
}, clampedDelay);
|
|
77
|
+
// 允许进程在没有其他活动时退出
|
|
78
|
+
currentState.timer.unref?.();
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* 定时器触发时的处理函数
|
|
82
|
+
*/
|
|
83
|
+
async function onTimer() {
|
|
84
|
+
if (getState().running) {
|
|
85
|
+
logger.debug('调度器正在运行,跳过本次触发');
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
getState().running = true;
|
|
89
|
+
try {
|
|
90
|
+
await runDueTasks();
|
|
91
|
+
}
|
|
92
|
+
finally {
|
|
93
|
+
getState().running = false;
|
|
94
|
+
armTimer();
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* 执行所有到期任务
|
|
99
|
+
*/
|
|
100
|
+
async function runDueTasks() {
|
|
101
|
+
if (!getState().deps) {
|
|
102
|
+
logger.error('调度器依赖未初始化');
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
const dueTasks = getDueTasks();
|
|
106
|
+
if (dueTasks.length === 0) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
logger.info({ count: dueTasks.length }, '⚡ 发现到期任务');
|
|
110
|
+
// 使用并发限制器执行任务
|
|
111
|
+
const promises = dueTasks.map(task => taskLimit(async () => {
|
|
112
|
+
// 双重检查任务状态
|
|
113
|
+
const currentTask = getTaskById(task.id);
|
|
114
|
+
if (!currentTask || currentTask.status !== 'active') {
|
|
115
|
+
logger.debug({ taskId: task.id }, '任务状态已变更,跳过执行');
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
await executeTask(currentTask);
|
|
119
|
+
}));
|
|
120
|
+
await Promise.all(promises);
|
|
121
|
+
}
|
|
122
|
+
// ==================== 任务执行 ====================
|
|
123
|
+
/**
|
|
124
|
+
* 执行单个任务(带超时和重试)
|
|
125
|
+
*/
|
|
126
|
+
async function executeTask(task) {
|
|
127
|
+
const startTime = Date.now();
|
|
128
|
+
const deps = getState().deps;
|
|
129
|
+
logger.info({ taskId: task.id, group: task.group_folder }, '⚡ 开始执行任务');
|
|
130
|
+
// 执行任务
|
|
131
|
+
const result = await runTaskWithTimeout(task, deps);
|
|
132
|
+
// 记录运行日志
|
|
133
|
+
logTaskRun({
|
|
134
|
+
task_id: task.id,
|
|
135
|
+
run_at: new Date().toISOString(),
|
|
136
|
+
duration_ms: result.durationMs,
|
|
137
|
+
status: result.success ? 'success' : 'error',
|
|
138
|
+
result: result.result,
|
|
139
|
+
error: result.error
|
|
140
|
+
});
|
|
141
|
+
if (result.success) {
|
|
142
|
+
// 成功:重置重试计数,计算下次运行时间
|
|
143
|
+
resetTaskRetry(task.id);
|
|
144
|
+
const nextRun = calculateNextRun(task);
|
|
145
|
+
const resultSummary = result.result ? result.result.slice(0, 200) : 'Completed';
|
|
146
|
+
updateTaskAfterRun(task.id, nextRun, resultSummary);
|
|
147
|
+
logger.info({ taskId: task.id, durationMs: result.durationMs }, '⚡ 任务执行成功');
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
// 失败:处理重试逻辑
|
|
151
|
+
await handleTaskFailure(task, result.error || 'Unknown error');
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* 带超时保护的任务执行
|
|
156
|
+
*/
|
|
157
|
+
async function runTaskWithTimeout(task, deps) {
|
|
158
|
+
const startTime = Date.now();
|
|
159
|
+
const timeoutMs = task.timeout_ms || DEFAULT_TASK_TIMEOUT_MS;
|
|
160
|
+
// 创建超时 Promise
|
|
161
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
162
|
+
setTimeout(() => {
|
|
163
|
+
reject(new Error(`任务执行超时 (${timeoutMs}ms)`));
|
|
164
|
+
}, timeoutMs);
|
|
165
|
+
});
|
|
166
|
+
try {
|
|
167
|
+
// 实际执行任务
|
|
168
|
+
const resultPromise = runTaskCore(task, deps);
|
|
169
|
+
const result = await Promise.race([resultPromise, timeoutPromise]);
|
|
170
|
+
return {
|
|
171
|
+
success: true,
|
|
172
|
+
result: result,
|
|
173
|
+
error: null,
|
|
174
|
+
durationMs: Date.now() - startTime
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
catch (err) {
|
|
178
|
+
return {
|
|
179
|
+
success: false,
|
|
180
|
+
result: null,
|
|
181
|
+
error: err instanceof Error ? err.message : String(err),
|
|
182
|
+
durationMs: Date.now() - startTime
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* 任务执行核心逻辑
|
|
188
|
+
*/
|
|
189
|
+
async function runTaskCore(task, deps) {
|
|
190
|
+
const groupDir = path.join(GROUPS_DIR, task.group_folder);
|
|
191
|
+
fs.mkdirSync(groupDir, { recursive: true });
|
|
192
|
+
const groups = deps.registeredGroups();
|
|
193
|
+
const group = Object.values(groups).find(g => g.folder === task.group_folder);
|
|
194
|
+
if (!group) {
|
|
195
|
+
throw new Error(`Group not found: ${task.group_folder}`);
|
|
196
|
+
}
|
|
197
|
+
// 更新任务快照供 Agent 读取
|
|
198
|
+
const isMain = task.group_folder === MAIN_GROUP_FOLDER;
|
|
199
|
+
const tasks = getAllTasks();
|
|
200
|
+
writeTasksSnapshot(task.group_folder, isMain, tasks.map(t => ({
|
|
201
|
+
id: t.id,
|
|
202
|
+
groupFolder: t.group_folder,
|
|
203
|
+
prompt: t.prompt,
|
|
204
|
+
schedule_type: t.schedule_type,
|
|
205
|
+
schedule_value: t.schedule_value,
|
|
206
|
+
status: t.status,
|
|
207
|
+
next_run: t.next_run
|
|
208
|
+
})));
|
|
209
|
+
// 获取会话 ID
|
|
210
|
+
const sessions = deps.getSessions();
|
|
211
|
+
const sessionId = task.context_mode === 'group' ? sessions[task.group_folder] : undefined;
|
|
212
|
+
// 执行 Agent
|
|
213
|
+
const output = await runAgent(group, {
|
|
214
|
+
prompt: task.prompt,
|
|
215
|
+
sessionId,
|
|
216
|
+
groupFolder: task.group_folder,
|
|
217
|
+
chatJid: task.chat_jid,
|
|
218
|
+
isMain,
|
|
219
|
+
isScheduledTask: true
|
|
220
|
+
});
|
|
221
|
+
if (output.status === 'error') {
|
|
222
|
+
throw new Error(output.error || 'Agent execution failed');
|
|
223
|
+
}
|
|
224
|
+
return output.result || 'Completed';
|
|
225
|
+
}
|
|
226
|
+
// ==================== 重试机制 ====================
|
|
227
|
+
/**
|
|
228
|
+
* 处理任务失败(重试逻辑)
|
|
229
|
+
*/
|
|
230
|
+
async function handleTaskFailure(task, error) {
|
|
231
|
+
const maxRetries = task.max_retries ?? 3;
|
|
232
|
+
const currentRetry = (task.retry_count ?? 0) + 1;
|
|
233
|
+
logger.warn({
|
|
234
|
+
taskId: task.id,
|
|
235
|
+
error,
|
|
236
|
+
retryCount: currentRetry,
|
|
237
|
+
maxRetries
|
|
238
|
+
}, '任务执行失败');
|
|
239
|
+
if (currentRetry >= maxRetries) {
|
|
240
|
+
// 达到最大重试次数
|
|
241
|
+
logger.error({ taskId: task.id, retryCount: currentRetry }, '任务达到最大重试次数,标记为失败');
|
|
242
|
+
// 对于 once 类型任务,标记为 completed(已完成但失败)
|
|
243
|
+
if (task.schedule_type === 'once') {
|
|
244
|
+
updateTask(task.id, { status: 'completed' });
|
|
245
|
+
updateTaskAfterRun(task.id, null, `Error after ${currentRetry} retries: ${error}`);
|
|
246
|
+
}
|
|
247
|
+
else {
|
|
248
|
+
// 对于重复任务,重置重试计数并调度下一次正常执行
|
|
249
|
+
resetTaskRetry(task.id);
|
|
250
|
+
const nextRun = calculateNextRun(task);
|
|
251
|
+
updateTaskAfterRun(task.id, nextRun, `Error: ${error}`);
|
|
252
|
+
}
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
// 计算重试延迟(指数退避)
|
|
256
|
+
const retryDelay = Math.min(RETRY_BASE_DELAY_MS * Math.pow(2, currentRetry - 1), MAX_RETRY_DELAY_MS);
|
|
257
|
+
const nextRetryTime = new Date(Date.now() + retryDelay).toISOString();
|
|
258
|
+
logger.info({
|
|
259
|
+
taskId: task.id,
|
|
260
|
+
retryIn: retryDelay / 1000 + 's',
|
|
261
|
+
nextRetry: nextRetryTime
|
|
262
|
+
}, '安排任务重试');
|
|
263
|
+
// 更新任务重试信息
|
|
264
|
+
updateTaskRetry(task.id, currentRetry, nextRetryTime);
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* 计算下次运行时间
|
|
268
|
+
*/
|
|
269
|
+
function calculateNextRun(task) {
|
|
270
|
+
switch (task.schedule_type) {
|
|
271
|
+
case 'cron': {
|
|
272
|
+
const interval = CronExpressionParser.parse(task.schedule_value, { tz: TIMEZONE });
|
|
273
|
+
return interval.next().toISOString();
|
|
274
|
+
}
|
|
275
|
+
case 'interval': {
|
|
276
|
+
const ms = parseInt(task.schedule_value, 10);
|
|
277
|
+
return new Date(Date.now() + ms).toISOString();
|
|
278
|
+
}
|
|
279
|
+
case 'once':
|
|
280
|
+
// 一次性任务执行后没有下次
|
|
281
|
+
return null;
|
|
282
|
+
default:
|
|
283
|
+
return null;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
// ==================== 公开 API ====================
|
|
287
|
+
/**
|
|
288
|
+
* 启动调度器
|
|
289
|
+
*/
|
|
290
|
+
export function startScheduler(deps) {
|
|
291
|
+
getState().deps = deps;
|
|
292
|
+
logger.info('⚡ 任务调度器已启动');
|
|
293
|
+
armTimer();
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* 停止调度器
|
|
297
|
+
*/
|
|
298
|
+
export function stopScheduler() {
|
|
299
|
+
const state = getState();
|
|
300
|
+
if (state.timer) {
|
|
301
|
+
clearTimeout(state.timer);
|
|
302
|
+
state.timer = null;
|
|
303
|
+
}
|
|
304
|
+
state.deps = null;
|
|
305
|
+
logger.info('⚡ 任务调度器已停止');
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* 立即唤醒调度器
|
|
309
|
+
* 用于创建新任务后立即检查是否需要执行
|
|
310
|
+
*/
|
|
311
|
+
export function wake() {
|
|
312
|
+
logger.debug('收到唤醒信号,重新计算定时器');
|
|
313
|
+
armTimer();
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* 获取调度器状态
|
|
317
|
+
*/
|
|
318
|
+
export function getSchedulerStatus() {
|
|
319
|
+
const nextWakeTime = getNextWakeTime();
|
|
320
|
+
const dueTasks = getDueTasks();
|
|
321
|
+
return {
|
|
322
|
+
running: getState().running,
|
|
323
|
+
nextWakeTime,
|
|
324
|
+
activeTasks: dueTasks.length
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
// 兼容旧 API
|
|
328
|
+
export function startSchedulerLoop(deps) {
|
|
329
|
+
startScheduler(deps);
|
|
330
|
+
}
|
|
331
|
+
//# sourceMappingURL=task-scheduler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-scheduler.js","sourceRoot":"","sources":["../src/task-scheduler.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent 配置
|
|
3
|
+
*/
|
|
4
|
+
export interface AgentConfig {
|
|
5
|
+
timeout?: number;
|
|
6
|
+
env?: Record<string, string>;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* 注册的群组
|
|
10
|
+
*/
|
|
11
|
+
export interface RegisteredGroup {
|
|
12
|
+
name: string;
|
|
13
|
+
folder: string;
|
|
14
|
+
trigger: string;
|
|
15
|
+
added_at: string;
|
|
16
|
+
agentConfig?: AgentConfig;
|
|
17
|
+
}
|
|
18
|
+
export interface Session {
|
|
19
|
+
[folder: string]: string;
|
|
20
|
+
}
|
|
21
|
+
export interface NewMessage {
|
|
22
|
+
id: string;
|
|
23
|
+
chat_jid: string;
|
|
24
|
+
sender: string;
|
|
25
|
+
sender_name: string;
|
|
26
|
+
content: string;
|
|
27
|
+
timestamp: string;
|
|
28
|
+
}
|
|
29
|
+
export interface ScheduledTask {
|
|
30
|
+
id: string;
|
|
31
|
+
group_folder: string;
|
|
32
|
+
chat_jid: string;
|
|
33
|
+
prompt: string;
|
|
34
|
+
schedule_type: 'cron' | 'interval' | 'once';
|
|
35
|
+
schedule_value: string;
|
|
36
|
+
context_mode: 'group' | 'isolated';
|
|
37
|
+
next_run: string | null;
|
|
38
|
+
last_run: string | null;
|
|
39
|
+
last_result: string | null;
|
|
40
|
+
status: 'active' | 'paused' | 'completed';
|
|
41
|
+
created_at: string;
|
|
42
|
+
/** 当前重试次数 */
|
|
43
|
+
retry_count: number;
|
|
44
|
+
/** 最大重试次数(默认 3) */
|
|
45
|
+
max_retries: number;
|
|
46
|
+
/** 任务执行超时时间(毫秒,默认 300000) */
|
|
47
|
+
timeout_ms?: number;
|
|
48
|
+
}
|
|
49
|
+
export interface TaskRunLog {
|
|
50
|
+
task_id: string;
|
|
51
|
+
run_at: string;
|
|
52
|
+
duration_ms: number;
|
|
53
|
+
status: 'success' | 'error';
|
|
54
|
+
result: string | null;
|
|
55
|
+
error: string | null;
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B;AAED,MAAM,WAAW,OAAO;IACtB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,GAAG,UAAU,GAAG,MAAM,CAAC;IAC5C,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,OAAO,GAAG,UAAU,CAAC;IACnC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,QAAQ,GAAG,QAAQ,GAAG,WAAW,CAAC;IAC1C,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,mBAAmB;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,6BAA6B;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC;IAC5B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 环境变量替换工具
|
|
3
|
+
*
|
|
4
|
+
* 支持语法:
|
|
5
|
+
* - ${VAR} - 从环境变量获取值
|
|
6
|
+
* - ${VAR:-default} - 有默认值的环境变量
|
|
7
|
+
*
|
|
8
|
+
* 递归处理对象和数组中的字符串值
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* 替换字符串中的环境变量引用
|
|
12
|
+
*
|
|
13
|
+
* @param str - 包含环境变量引用的字符串
|
|
14
|
+
* @param env - 环境变量对象 (默认使用 process.env)
|
|
15
|
+
* @returns 替换后的字符串
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* substituteEnvVars('${HOME}/config') // '/home/user/config'
|
|
19
|
+
* substituteEnvVars('${PORT:-3000}') // '3000' (如果 PORT 未定义)
|
|
20
|
+
* substituteEnvVars('${API_KEY}') // '' (如果未定义且无默认值)
|
|
21
|
+
*/
|
|
22
|
+
export declare function substituteEnvVars(str: string, env?: Record<string, string | undefined>): string;
|
|
23
|
+
/**
|
|
24
|
+
* 检查字符串是否包含环境变量引用
|
|
25
|
+
*
|
|
26
|
+
* @param str - 要检查的字符串
|
|
27
|
+
* @returns 是否包含环境变量引用
|
|
28
|
+
*/
|
|
29
|
+
export declare function hasEnvVars(str: string): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* 递归替换对象/数组中所有字符串的环境变量
|
|
32
|
+
*
|
|
33
|
+
* @param value - 要处理的值 (任意类型)
|
|
34
|
+
* @param env - 环境变量对象 (默认使用 process.env)
|
|
35
|
+
* @returns 处理后的新值 (不修改原对象)
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* substituteEnvVarsDeep({
|
|
39
|
+
* apiUrl: '${API_URL:-http://localhost:3000}',
|
|
40
|
+
* keys: ['${KEY1}', '${KEY2}'],
|
|
41
|
+
* nested: { secret: '${SECRET}' }
|
|
42
|
+
* })
|
|
43
|
+
*/
|
|
44
|
+
export declare function substituteEnvVarsDeep<T>(value: T, env?: Record<string, string | undefined>): T;
|
|
45
|
+
/**
|
|
46
|
+
* 提取字符串中引用的所有环境变量名称
|
|
47
|
+
*
|
|
48
|
+
* @param str - 要分析的字符串
|
|
49
|
+
* @returns 环境变量名称数组 (去重)
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* extractEnvVarNames('${API_URL} and ${API_KEY:-default}')
|
|
53
|
+
* // ['API_URL', 'API_KEY']
|
|
54
|
+
*/
|
|
55
|
+
export declare function extractEnvVarNames(str: string): string[];
|
|
56
|
+
/**
|
|
57
|
+
* 递归提取对象/数组中所有引用的环境变量名称
|
|
58
|
+
*
|
|
59
|
+
* @param value - 要分析的值
|
|
60
|
+
* @returns 环境变量名称数组 (去重)
|
|
61
|
+
*/
|
|
62
|
+
export declare function extractEnvVarNamesDeep(value: unknown): string[];
|
|
63
|
+
//# sourceMappingURL=env-substitute.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-substitute.d.ts","sourceRoot":"","sources":["../../src/utils/env-substitute.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAQH;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,MAAM,EACX,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe,GACpD,MAAM,CAYR;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAG/C;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EACrC,KAAK,EAAE,CAAC,EACR,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe,GACpD,CAAC,CA2BH;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAYxD;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,EAAE,CAmB/D"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 环境变量替换工具
|
|
3
|
+
*
|
|
4
|
+
* 支持语法:
|
|
5
|
+
* - ${VAR} - 从环境变量获取值
|
|
6
|
+
* - ${VAR:-default} - 有默认值的环境变量
|
|
7
|
+
*
|
|
8
|
+
* 递归处理对象和数组中的字符串值
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* 环境变量替换的正则表达式
|
|
12
|
+
* 匹配 ${VAR} 或 ${VAR:-default} 格式
|
|
13
|
+
*/
|
|
14
|
+
const ENV_VAR_PATTERN = /\$\{([^}:]+)(?::-([^}]*))?\}/g;
|
|
15
|
+
/**
|
|
16
|
+
* 替换字符串中的环境变量引用
|
|
17
|
+
*
|
|
18
|
+
* @param str - 包含环境变量引用的字符串
|
|
19
|
+
* @param env - 环境变量对象 (默认使用 process.env)
|
|
20
|
+
* @returns 替换后的字符串
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* substituteEnvVars('${HOME}/config') // '/home/user/config'
|
|
24
|
+
* substituteEnvVars('${PORT:-3000}') // '3000' (如果 PORT 未定义)
|
|
25
|
+
* substituteEnvVars('${API_KEY}') // '' (如果未定义且无默认值)
|
|
26
|
+
*/
|
|
27
|
+
export function substituteEnvVars(str, env = process.env) {
|
|
28
|
+
return str.replace(ENV_VAR_PATTERN, (match, varName, defaultValue) => {
|
|
29
|
+
const value = env[varName];
|
|
30
|
+
// 如果环境变量存在且不为空字符串,使用它
|
|
31
|
+
if (value !== undefined && value !== '') {
|
|
32
|
+
return value;
|
|
33
|
+
}
|
|
34
|
+
// 否则使用默认值,如果没有默认值则返回空字符串
|
|
35
|
+
return defaultValue !== undefined ? defaultValue : '';
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* 检查字符串是否包含环境变量引用
|
|
40
|
+
*
|
|
41
|
+
* @param str - 要检查的字符串
|
|
42
|
+
* @returns 是否包含环境变量引用
|
|
43
|
+
*/
|
|
44
|
+
export function hasEnvVars(str) {
|
|
45
|
+
ENV_VAR_PATTERN.lastIndex = 0; // 重置正则状态
|
|
46
|
+
return ENV_VAR_PATTERN.test(str);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* 递归替换对象/数组中所有字符串的环境变量
|
|
50
|
+
*
|
|
51
|
+
* @param value - 要处理的值 (任意类型)
|
|
52
|
+
* @param env - 环境变量对象 (默认使用 process.env)
|
|
53
|
+
* @returns 处理后的新值 (不修改原对象)
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* substituteEnvVarsDeep({
|
|
57
|
+
* apiUrl: '${API_URL:-http://localhost:3000}',
|
|
58
|
+
* keys: ['${KEY1}', '${KEY2}'],
|
|
59
|
+
* nested: { secret: '${SECRET}' }
|
|
60
|
+
* })
|
|
61
|
+
*/
|
|
62
|
+
export function substituteEnvVarsDeep(value, env = process.env) {
|
|
63
|
+
// 处理 null 和 undefined
|
|
64
|
+
if (value === null || value === undefined) {
|
|
65
|
+
return value;
|
|
66
|
+
}
|
|
67
|
+
// 处理字符串
|
|
68
|
+
if (typeof value === 'string') {
|
|
69
|
+
return substituteEnvVars(value, env);
|
|
70
|
+
}
|
|
71
|
+
// 处理数组
|
|
72
|
+
if (Array.isArray(value)) {
|
|
73
|
+
return value.map((item) => substituteEnvVarsDeep(item, env));
|
|
74
|
+
}
|
|
75
|
+
// 处理普通对象
|
|
76
|
+
if (typeof value === 'object') {
|
|
77
|
+
const result = {};
|
|
78
|
+
for (const [key, val] of Object.entries(value)) {
|
|
79
|
+
result[key] = substituteEnvVarsDeep(val, env);
|
|
80
|
+
}
|
|
81
|
+
return result;
|
|
82
|
+
}
|
|
83
|
+
// 其他类型 (number, boolean, etc.) 直接返回
|
|
84
|
+
return value;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* 提取字符串中引用的所有环境变量名称
|
|
88
|
+
*
|
|
89
|
+
* @param str - 要分析的字符串
|
|
90
|
+
* @returns 环境变量名称数组 (去重)
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* extractEnvVarNames('${API_URL} and ${API_KEY:-default}')
|
|
94
|
+
* // ['API_URL', 'API_KEY']
|
|
95
|
+
*/
|
|
96
|
+
export function extractEnvVarNames(str) {
|
|
97
|
+
const names = [];
|
|
98
|
+
const regex = new RegExp(ENV_VAR_PATTERN);
|
|
99
|
+
let match;
|
|
100
|
+
while ((match = regex.exec(str)) !== null) {
|
|
101
|
+
if (!names.includes(match[1])) {
|
|
102
|
+
names.push(match[1]);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return names;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* 递归提取对象/数组中所有引用的环境变量名称
|
|
109
|
+
*
|
|
110
|
+
* @param value - 要分析的值
|
|
111
|
+
* @returns 环境变量名称数组 (去重)
|
|
112
|
+
*/
|
|
113
|
+
export function extractEnvVarNamesDeep(value) {
|
|
114
|
+
const names = [];
|
|
115
|
+
function collect(val) {
|
|
116
|
+
if (typeof val === 'string') {
|
|
117
|
+
for (const name of extractEnvVarNames(val)) {
|
|
118
|
+
if (!names.includes(name)) {
|
|
119
|
+
names.push(name);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
else if (Array.isArray(val)) {
|
|
124
|
+
val.forEach(collect);
|
|
125
|
+
}
|
|
126
|
+
else if (val !== null && typeof val === 'object') {
|
|
127
|
+
Object.values(val).forEach(collect);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
collect(value);
|
|
131
|
+
return names;
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=env-substitute.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env-substitute.js","sourceRoot":"","sources":["../../src/utils/env-substitute.ts"],"names":[],"mappings":"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"}
|