@wu529778790/open-im 1.11.9 → 1.11.10-beta.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/dist/config/types.d.ts +11 -0
- package/dist/config-web.js +23 -0
- package/dist/config.js +8 -0
- package/dist/index.js +3 -0
- package/dist/shared/keepalive.d.ts +16 -0
- package/dist/shared/keepalive.js +109 -0
- package/package.json +1 -1
- package/web/dist/assets/index-DMoM2juo.js +61 -0
- package/web/dist/index.html +1 -1
- package/dist/config-web-page-i18n.d.ts +0 -232
- package/dist/config-web-page-i18n.js +0 -233
- package/web/dist/assets/index-Dl8fsCaE.js +0 -61
package/dist/config/types.d.ts
CHANGED
|
@@ -64,6 +64,11 @@ export interface Config {
|
|
|
64
64
|
shortRetrySeconds: number;
|
|
65
65
|
autoResumePrompt: string;
|
|
66
66
|
};
|
|
67
|
+
keepalive?: {
|
|
68
|
+
enabled: boolean;
|
|
69
|
+
intervalHours: number;
|
|
70
|
+
target: AiCommand;
|
|
71
|
+
};
|
|
67
72
|
platforms: {
|
|
68
73
|
telegram?: {
|
|
69
74
|
enabled: boolean;
|
|
@@ -211,6 +216,11 @@ export interface FileToolOpenCode {
|
|
|
211
216
|
/** 模型(格式: providerID/modelID) */
|
|
212
217
|
model?: string;
|
|
213
218
|
}
|
|
219
|
+
export interface KeepaliveConfig {
|
|
220
|
+
enabled?: boolean;
|
|
221
|
+
intervalHours?: number;
|
|
222
|
+
target?: AiCommand;
|
|
223
|
+
}
|
|
214
224
|
export interface FileConfig {
|
|
215
225
|
telegramBotToken?: string;
|
|
216
226
|
feishuAppId?: string;
|
|
@@ -241,4 +251,5 @@ export interface FileConfig {
|
|
|
241
251
|
url?: string;
|
|
242
252
|
token?: string;
|
|
243
253
|
};
|
|
254
|
+
keepalive?: KeepaliveConfig;
|
|
244
255
|
}
|
package/dist/config-web.js
CHANGED
|
@@ -421,6 +421,29 @@ export async function startWebConfigServer(options) {
|
|
|
421
421
|
}
|
|
422
422
|
return;
|
|
423
423
|
}
|
|
424
|
+
// --- 保活设置 ---
|
|
425
|
+
if (request.method === "GET" && requestUrl.pathname === "/api/keepalive/config") {
|
|
426
|
+
try {
|
|
427
|
+
const { getKeepaliveConfig } = await import("./shared/keepalive.js");
|
|
428
|
+
json(response, 200, getKeepaliveConfig(), request);
|
|
429
|
+
}
|
|
430
|
+
catch (error) {
|
|
431
|
+
json(response, 500, { error: error instanceof Error ? error.message : String(error) }, request);
|
|
432
|
+
}
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
435
|
+
if (request.method === "POST" && requestUrl.pathname === "/api/keepalive/config") {
|
|
436
|
+
try {
|
|
437
|
+
const body = await readJson(request);
|
|
438
|
+
const { saveKeepaliveConfig } = await import("./shared/keepalive.js");
|
|
439
|
+
saveKeepaliveConfig(body);
|
|
440
|
+
json(response, 200, { message: "保活配置已保存" }, request);
|
|
441
|
+
}
|
|
442
|
+
catch (error) {
|
|
443
|
+
json(response, 500, { error: error instanceof Error ? error.message : String(error) }, request);
|
|
444
|
+
}
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
424
447
|
if (request.method === "GET" && requestUrl.pathname === "/api/health") {
|
|
425
448
|
const file = loadFileConfig();
|
|
426
449
|
const platforms = getHealthPlatformSnapshot(file);
|
package/dist/config.js
CHANGED
|
@@ -519,6 +519,13 @@ export function loadConfig() {
|
|
|
519
519
|
apiToken: clawbotApiToken,
|
|
520
520
|
},
|
|
521
521
|
};
|
|
522
|
+
// 保活配置
|
|
523
|
+
const keepaliveFile = file.keepalive ?? {};
|
|
524
|
+
const keepalive = {
|
|
525
|
+
enabled: keepaliveFile.enabled ?? true,
|
|
526
|
+
intervalHours: keepaliveFile.intervalHours ?? 5,
|
|
527
|
+
target: keepaliveFile.target ?? 'claude',
|
|
528
|
+
};
|
|
522
529
|
return {
|
|
523
530
|
enabledPlatforms,
|
|
524
531
|
telegramBotToken: telegramBotToken ?? '',
|
|
@@ -556,6 +563,7 @@ export function loadConfig() {
|
|
|
556
563
|
enabled: telemetryEnabled,
|
|
557
564
|
},
|
|
558
565
|
autopilot,
|
|
566
|
+
keepalive,
|
|
559
567
|
platforms,
|
|
560
568
|
};
|
|
561
569
|
}
|
package/dist/index.js
CHANGED
|
@@ -29,6 +29,7 @@ import { setupClawbotHandlers } from "./clawbot/event-handler.js";
|
|
|
29
29
|
import { sendTextReply as sendClawbotTextReply } from "./clawbot/message-sender.js";
|
|
30
30
|
import { initClawBotSender } from "./clawbot/message-sender.js";
|
|
31
31
|
import { initAdapters, cleanupAdapters } from "./adapters/registry.js";
|
|
32
|
+
import { startKeepalive, stopKeepalive } from "./shared/keepalive.js";
|
|
32
33
|
import { SessionManager } from "./session/session-manager.js";
|
|
33
34
|
import { loadActiveChats, getActiveChatId, flushActiveChats, } from "./shared/active-chats.js";
|
|
34
35
|
import { destroyAllLiveChildren } from "./shared/process-kill.js";
|
|
@@ -271,6 +272,7 @@ export async function main() {
|
|
|
271
272
|
}
|
|
272
273
|
loadActiveChats();
|
|
273
274
|
initAdapters(config);
|
|
275
|
+
startKeepalive();
|
|
274
276
|
// 尽早启动 shutdown 并写入 port 文件,使 open-im start 的 8s 就绪超时能通过(平台初始化可能较慢)
|
|
275
277
|
let shutdownServer = null;
|
|
276
278
|
await new Promise((resolve, reject) => {
|
|
@@ -386,6 +388,7 @@ export async function main() {
|
|
|
386
388
|
}
|
|
387
389
|
sessionManager.destroy();
|
|
388
390
|
cleanupAdapters();
|
|
391
|
+
stopKeepalive();
|
|
389
392
|
flushActiveChats();
|
|
390
393
|
await flushSentry();
|
|
391
394
|
await closeLogger();
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** 启动保活定时器 */
|
|
2
|
+
export declare function startKeepalive(): void;
|
|
3
|
+
/** 停止保活定时器 */
|
|
4
|
+
export declare function stopKeepalive(): void;
|
|
5
|
+
/** 从 API 读取保活配置(返回给前端) */
|
|
6
|
+
export declare function getKeepaliveConfig(): {
|
|
7
|
+
enabled: boolean;
|
|
8
|
+
intervalHours: number;
|
|
9
|
+
target: string;
|
|
10
|
+
};
|
|
11
|
+
/** 从 API 保存保活配置 */
|
|
12
|
+
export declare function saveKeepaliveConfig(cfg: {
|
|
13
|
+
enabled: boolean;
|
|
14
|
+
intervalHours: number;
|
|
15
|
+
target: string;
|
|
16
|
+
}): void;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { loadFileConfig, saveFileConfig } from "../config/file-io.js";
|
|
2
|
+
import { loadConfig } from "../config.js";
|
|
3
|
+
import { createLogger } from "../logger.js";
|
|
4
|
+
import { getAdapter } from "../adapters/registry.js";
|
|
5
|
+
import { ClaudeSDKAdapter } from "../adapters/claude-sdk-adapter.js";
|
|
6
|
+
import { CodexAdapter } from "../adapters/codex-adapter.js";
|
|
7
|
+
import { CodeBuddyAdapter } from "../adapters/codebuddy-adapter.js";
|
|
8
|
+
import { OpenCodeAdapter } from "../adapters/opencode-adapter.js";
|
|
9
|
+
const log = createLogger("Keepalive");
|
|
10
|
+
const PING_PROMPT = "在吗";
|
|
11
|
+
const PING_TIMEOUT_MS = 60_000;
|
|
12
|
+
let timer = null;
|
|
13
|
+
/** 按需创建临时 adapter(保活的目标 AI 可能未在 enabledPlatforms 中,registry 不会注册) */
|
|
14
|
+
function resolveAdapter(target) {
|
|
15
|
+
const cached = getAdapter(target);
|
|
16
|
+
if (cached)
|
|
17
|
+
return cached;
|
|
18
|
+
const config = loadConfig();
|
|
19
|
+
switch (target) {
|
|
20
|
+
case "claude": return new ClaudeSDKAdapter();
|
|
21
|
+
case "codex": return new CodexAdapter(config.codexCliPath);
|
|
22
|
+
case "codebuddy": return new CodeBuddyAdapter(config.codebuddyCliPath);
|
|
23
|
+
case "opencode": return new OpenCodeAdapter();
|
|
24
|
+
default:
|
|
25
|
+
log.warn(`Unknown AI command: ${target}`);
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/** 发送一句保活消息,等待完成或超时 */
|
|
30
|
+
async function ping(target, workDir) {
|
|
31
|
+
const adapter = resolveAdapter(target);
|
|
32
|
+
if (!adapter)
|
|
33
|
+
return false;
|
|
34
|
+
log.info(`Keepalive ping → ${target}`);
|
|
35
|
+
return await new Promise((resolve) => {
|
|
36
|
+
let settled = false;
|
|
37
|
+
const settle = (ok, reason) => {
|
|
38
|
+
if (settled)
|
|
39
|
+
return;
|
|
40
|
+
settled = true;
|
|
41
|
+
clearTimeout(timeoutHandle);
|
|
42
|
+
log.info(`Keepalive ${target} ${ok ? "OK" : "FAIL"}: ${reason}`);
|
|
43
|
+
resolve(ok);
|
|
44
|
+
};
|
|
45
|
+
const handle = adapter.run(PING_PROMPT, undefined, workDir, {
|
|
46
|
+
onText: () => { },
|
|
47
|
+
onComplete: (r) => settle(r.success, `${r.numTurns} turn(s), ${r.durationMs}ms`),
|
|
48
|
+
onError: (e) => settle(false, `error: ${e}`),
|
|
49
|
+
}, { skipPermissions: true, skipAutoResume: true });
|
|
50
|
+
const timeoutHandle = setTimeout(() => {
|
|
51
|
+
try {
|
|
52
|
+
handle.abort();
|
|
53
|
+
}
|
|
54
|
+
catch { }
|
|
55
|
+
settle(false, `timeout after ${PING_TIMEOUT_MS}ms`);
|
|
56
|
+
}, PING_TIMEOUT_MS);
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
/** 启动保活定时器 */
|
|
60
|
+
export function startKeepalive() {
|
|
61
|
+
stopKeepalive();
|
|
62
|
+
const file = loadFileConfig();
|
|
63
|
+
const ka = file.keepalive ?? {};
|
|
64
|
+
const enabled = ka.enabled ?? true;
|
|
65
|
+
const intervalHours = ka.intervalHours ?? 5;
|
|
66
|
+
const target = ka.target ?? "claude";
|
|
67
|
+
if (!enabled) {
|
|
68
|
+
log.info("Keepalive 已禁用,跳过");
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const config = loadConfig();
|
|
72
|
+
const workDir = config.claudeWorkDir;
|
|
73
|
+
const intervalMs = intervalHours * 60 * 60 * 1000;
|
|
74
|
+
log.info(`Keepalive 已启动,每 ${intervalHours} 小时 ping ${target}`);
|
|
75
|
+
// 不立即执行(启动时不打扰),等到第一个间隔
|
|
76
|
+
timer = setInterval(() => {
|
|
77
|
+
ping(target, workDir).catch((e) => log.warn(`Keepalive ping unhandled: ${e}`));
|
|
78
|
+
}, intervalMs);
|
|
79
|
+
timer.unref?.();
|
|
80
|
+
}
|
|
81
|
+
/** 停止保活定时器 */
|
|
82
|
+
export function stopKeepalive() {
|
|
83
|
+
if (timer) {
|
|
84
|
+
clearInterval(timer);
|
|
85
|
+
timer = null;
|
|
86
|
+
log.info("Keepalive 已停止");
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/** 从 API 读取保活配置(返回给前端) */
|
|
90
|
+
export function getKeepaliveConfig() {
|
|
91
|
+
const file = loadFileConfig();
|
|
92
|
+
const ka = file.keepalive ?? {};
|
|
93
|
+
return {
|
|
94
|
+
enabled: ka.enabled ?? true,
|
|
95
|
+
intervalHours: ka.intervalHours ?? 5,
|
|
96
|
+
target: ka.target ?? "claude",
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
/** 从 API 保存保活配置 */
|
|
100
|
+
export function saveKeepaliveConfig(cfg) {
|
|
101
|
+
const file = loadFileConfig();
|
|
102
|
+
file.keepalive = {
|
|
103
|
+
enabled: cfg.enabled,
|
|
104
|
+
intervalHours: cfg.intervalHours,
|
|
105
|
+
target: cfg.target,
|
|
106
|
+
};
|
|
107
|
+
saveFileConfig(file);
|
|
108
|
+
startKeepalive();
|
|
109
|
+
}
|
package/package.json
CHANGED