@wu529778790/open-im 1.9.3-beta.14 → 1.9.3-beta.15
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/adapters/claude-sdk-adapter.js +24 -34
- package/dist/adapters/codebuddy-adapter.js +0 -1
- package/dist/adapters/codex-adapter.js +0 -1
- package/dist/adapters/tool-adapter.interface.d.ts +0 -1
- package/dist/codebuddy/cli-runner.d.ts +0 -1
- package/dist/codebuddy/cli-runner.js +0 -61
- package/dist/codex/cli-runner.d.ts +0 -1
- package/dist/codex/cli-runner.js +0 -64
- package/dist/config-web-page-i18n.d.ts +0 -6
- package/dist/config-web-page-i18n.js +0 -6
- package/dist/config-web-page-script.js +0 -9
- package/dist/config-web-page-template.js +0 -12
- package/dist/config-web.js +0 -15
- package/dist/config.d.ts +0 -6
- package/dist/config.js +2 -16
- package/dist/dingtalk/event-handler.js +1 -3
- package/dist/feishu/event-handler.js +1 -3
- package/dist/qq/event-handler.js +1 -3
- package/dist/setup.js +2 -5
- package/dist/shared/ai-task.js +0 -6
- package/dist/shared/ai-task.test.js +0 -3
- package/dist/telegram/event-handler.js +1 -3
- package/dist/wework/event-handler.js +1 -3
- package/dist/workbuddy/event-handler.js +1 -3
- package/package.json +1 -1
- package/dist/shared/task-cleanup.d.ts +0 -2
- package/dist/shared/task-cleanup.js +0 -19
|
@@ -18,11 +18,15 @@ const activeSessions = new Map();
|
|
|
18
18
|
const activeStreams = new Set();
|
|
19
19
|
// 空闲会话清理:跟踪最后使用时间,定期清除超时会话
|
|
20
20
|
const sessionLastUsed = new Map();
|
|
21
|
+
// 跟踪正在执行任务的 session ID,防止空闲清理误杀运行中的长任务
|
|
22
|
+
const runningSessions = new Set();
|
|
21
23
|
const SESSION_IDLE_TTL_MS = 30 * 60 * 1000; // 30 分钟未使用则清理
|
|
22
24
|
const CLEANUP_INTERVAL_MS = 5 * 60 * 1000; // 每 5 分钟检查一次
|
|
23
25
|
const cleanupInterval = setInterval(() => {
|
|
24
26
|
const now = Date.now();
|
|
25
27
|
for (const [id, lastUsed] of sessionLastUsed) {
|
|
28
|
+
if (runningSessions.has(id))
|
|
29
|
+
continue; // 跳过正在运行任务的 session
|
|
26
30
|
if (now - lastUsed > SESSION_IDLE_TTL_MS) {
|
|
27
31
|
const session = activeSessions.get(id);
|
|
28
32
|
if (session) {
|
|
@@ -48,6 +52,8 @@ function lazyCleanupIdleSessions() {
|
|
|
48
52
|
return;
|
|
49
53
|
const now = Date.now();
|
|
50
54
|
for (const [id, lastUsed] of sessionLastUsed) {
|
|
55
|
+
if (runningSessions.has(id))
|
|
56
|
+
continue; // 跳过正在运行任务的 session
|
|
51
57
|
if (now - lastUsed > SESSION_IDLE_TTL_MS) {
|
|
52
58
|
const s = activeSessions.get(id);
|
|
53
59
|
if (s) {
|
|
@@ -212,7 +218,6 @@ export class ClaudeSDKAdapter {
|
|
|
212
218
|
let pendingTempId; // 记录临时 ID,用于 abort 时清理
|
|
213
219
|
let runSettled = false;
|
|
214
220
|
let currentStream; // 用于 abort 时立即中断 stream
|
|
215
|
-
let timeoutHandle;
|
|
216
221
|
const permissionMode = options?.skipPermissions
|
|
217
222
|
? 'bypassPermissions'
|
|
218
223
|
: options?.permissionMode === 'acceptEdits'
|
|
@@ -221,6 +226,7 @@ export class ClaudeSDKAdapter {
|
|
|
221
226
|
? 'plan'
|
|
222
227
|
: 'default';
|
|
223
228
|
const runSession = async () => {
|
|
229
|
+
let trackedRunningId; // 用于 finally 中清理 runningSessions
|
|
224
230
|
try {
|
|
225
231
|
// 检查环境变量
|
|
226
232
|
const hasApiKey = !!process.env.ANTHROPIC_API_KEY;
|
|
@@ -235,6 +241,8 @@ export class ClaudeSDKAdapter {
|
|
|
235
241
|
if (returnedId.startsWith('pending-')) {
|
|
236
242
|
pendingTempId = returnedId;
|
|
237
243
|
}
|
|
244
|
+
runningSessions.add(returnedId);
|
|
245
|
+
trackedRunningId = returnedId;
|
|
238
246
|
// 发送用户消息
|
|
239
247
|
await session.send(prompt);
|
|
240
248
|
// 获取响应流
|
|
@@ -264,6 +272,11 @@ export class ClaudeSDKAdapter {
|
|
|
264
272
|
sessionLastUsed.set(newSessionId, Date.now());
|
|
265
273
|
if (idToClean)
|
|
266
274
|
sessionLastUsed.delete(idToClean);
|
|
275
|
+
// 更新 runningSessions:移除旧 ID,添加新 ID
|
|
276
|
+
if (idToClean)
|
|
277
|
+
runningSessions.delete(idToClean);
|
|
278
|
+
runningSessions.add(newSessionId);
|
|
279
|
+
trackedRunningId = newSessionId;
|
|
267
280
|
actualSessionId = newSessionId;
|
|
268
281
|
log.info(`[V2] Got actual sessionId: ${newSessionId}`);
|
|
269
282
|
callbacks.onSessionId?.(newSessionId);
|
|
@@ -305,8 +318,6 @@ export class ClaudeSDKAdapter {
|
|
|
305
318
|
log.info(`[V2] Result: subtype=${m.subtype}, num_turns=${m.num_turns}, sessionId=${actualSessionId ?? 'unknown'}`);
|
|
306
319
|
// 检查会话错误
|
|
307
320
|
if (!success) {
|
|
308
|
-
if (timeoutHandle)
|
|
309
|
-
clearTimeout(timeoutHandle);
|
|
310
321
|
runSettled = true;
|
|
311
322
|
const noConvErr = errs.find((e) => e.includes('No conversation found') || e.includes('session not found'));
|
|
312
323
|
if (noConvErr) {
|
|
@@ -343,8 +354,6 @@ export class ClaudeSDKAdapter {
|
|
|
343
354
|
result.result = accumulated;
|
|
344
355
|
}
|
|
345
356
|
runSettled = true;
|
|
346
|
-
if (timeoutHandle)
|
|
347
|
-
clearTimeout(timeoutHandle);
|
|
348
357
|
callbacks.onComplete(result);
|
|
349
358
|
return;
|
|
350
359
|
}
|
|
@@ -353,8 +362,6 @@ export class ClaudeSDKAdapter {
|
|
|
353
362
|
if (!streamClosed) {
|
|
354
363
|
if (accumulated) {
|
|
355
364
|
log.info('Stream ended without result message, using accumulated text');
|
|
356
|
-
if (timeoutHandle)
|
|
357
|
-
clearTimeout(timeoutHandle);
|
|
358
365
|
runSettled = true;
|
|
359
366
|
callbacks.onComplete({
|
|
360
367
|
success: true,
|
|
@@ -369,8 +376,6 @@ export class ClaudeSDKAdapter {
|
|
|
369
376
|
else {
|
|
370
377
|
// 流结束但无 result 也无 accumulated:必须触发回调,否则 Promise 永远挂起
|
|
371
378
|
log.warn('Stream ended with no result and no accumulated text, calling onError to prevent stuck state');
|
|
372
|
-
if (timeoutHandle)
|
|
373
|
-
clearTimeout(timeoutHandle);
|
|
374
379
|
runSettled = true;
|
|
375
380
|
callbacks.onError('AI 响应异常结束(无输出),请重试');
|
|
376
381
|
}
|
|
@@ -393,8 +398,6 @@ export class ClaudeSDKAdapter {
|
|
|
393
398
|
return;
|
|
394
399
|
}
|
|
395
400
|
runSettled = true;
|
|
396
|
-
if (timeoutHandle)
|
|
397
|
-
clearTimeout(timeoutHandle);
|
|
398
401
|
const errorObj = err;
|
|
399
402
|
const msg = errorObj.message || String(err);
|
|
400
403
|
log.error(`Claude SDK V2 error: ${msg}`);
|
|
@@ -423,43 +426,30 @@ export class ClaudeSDKAdapter {
|
|
|
423
426
|
}
|
|
424
427
|
callbacks.onError(msg);
|
|
425
428
|
}
|
|
429
|
+
finally {
|
|
430
|
+
// 无论成功、失败还是 abort,都从运行中集合移除
|
|
431
|
+
if (trackedRunningId) {
|
|
432
|
+
runningSessions.delete(trackedRunningId);
|
|
433
|
+
}
|
|
434
|
+
// 也清理 actualSessionId(可能在 init 后更新了)
|
|
435
|
+
if (actualSessionId && actualSessionId !== trackedRunningId) {
|
|
436
|
+
runningSessions.delete(actualSessionId);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
426
439
|
};
|
|
427
440
|
// 启动会话(不等待),catch 兜底防止 unhandledRejection 导致用户请求挂起
|
|
428
441
|
runSession().catch((err) => {
|
|
429
442
|
if (!runSettled) {
|
|
430
443
|
runSettled = true;
|
|
431
|
-
if (timeoutHandle)
|
|
432
|
-
clearTimeout(timeoutHandle);
|
|
433
444
|
const msg = err instanceof Error ? err.message : String(err);
|
|
434
445
|
log.error(`Unhandled runSession error: ${msg}`);
|
|
435
446
|
callbacks.onError(msg);
|
|
436
447
|
}
|
|
437
448
|
});
|
|
438
|
-
// 强制执行超时
|
|
439
|
-
if (options?.timeoutMs && options.timeoutMs > 0) {
|
|
440
|
-
timeoutHandle = setTimeout(() => {
|
|
441
|
-
if (!runSettled) {
|
|
442
|
-
log.warn(`Session timed out after ${options.timeoutMs}ms, aborting`);
|
|
443
|
-
abortController.abort();
|
|
444
|
-
// 立即中断 stream,不等下一条消息
|
|
445
|
-
if (currentStream) {
|
|
446
|
-
try {
|
|
447
|
-
currentStream.return?.();
|
|
448
|
-
}
|
|
449
|
-
catch { /* ignore */ }
|
|
450
|
-
}
|
|
451
|
-
runSettled = true;
|
|
452
|
-
callbacks.onError(`AI 响应超时(${Math.round(options.timeoutMs / 1000)}s),请重试`);
|
|
453
|
-
}
|
|
454
|
-
}, options.timeoutMs);
|
|
455
|
-
timeoutHandle.unref();
|
|
456
|
-
}
|
|
457
449
|
return {
|
|
458
450
|
abort: () => {
|
|
459
451
|
log.info('Aborting session run');
|
|
460
452
|
abortController.abort();
|
|
461
|
-
if (timeoutHandle)
|
|
462
|
-
clearTimeout(timeoutHandle);
|
|
463
453
|
// 立即中断 stream,不等下一条消息
|
|
464
454
|
if (currentStream) {
|
|
465
455
|
try {
|
|
@@ -25,7 +25,6 @@ export interface RunOptions {
|
|
|
25
25
|
skipPermissions?: boolean;
|
|
26
26
|
/** Claude --permission-mode: default | acceptEdits | plan(yolo 时用 skipPermissions) */
|
|
27
27
|
permissionMode?: 'default' | 'acceptEdits' | 'plan';
|
|
28
|
-
timeoutMs?: number;
|
|
29
28
|
model?: string;
|
|
30
29
|
chatId?: string;
|
|
31
30
|
hookPort?: number;
|
|
@@ -3,18 +3,6 @@ import { accessSync, constants } from 'node:fs';
|
|
|
3
3
|
import { isAbsolute, join } from 'node:path';
|
|
4
4
|
import { createLogger } from '../logger.js';
|
|
5
5
|
const log = createLogger('CodeBuddyCli');
|
|
6
|
-
const MAX_TIMEOUT_MS = 2_147_483_647;
|
|
7
|
-
const DEFAULT_IDLE_TIMEOUT_MS = 10 * 60 * 1000;
|
|
8
|
-
function getIdleTimeoutMs(totalTimeoutMs) {
|
|
9
|
-
const raw = process.env.CODEBUDDY_IDLE_TIMEOUT_MS;
|
|
10
|
-
const parsed = raw ? Number.parseInt(raw, 10) : Number.NaN;
|
|
11
|
-
const configuredIdleTimeoutMs = Number.isFinite(parsed) && parsed > 0
|
|
12
|
-
? Math.min(parsed, MAX_TIMEOUT_MS)
|
|
13
|
-
: DEFAULT_IDLE_TIMEOUT_MS;
|
|
14
|
-
return totalTimeoutMs > 0
|
|
15
|
-
? Math.min(configuredIdleTimeoutMs, totalTimeoutMs)
|
|
16
|
-
: configuredIdleTimeoutMs;
|
|
17
|
-
}
|
|
18
6
|
export function buildCodeBuddyArgs(prompt, sessionId, options) {
|
|
19
7
|
const args = ['--print', '--output-format', 'stream-json'];
|
|
20
8
|
if (options?.skipPermissions) {
|
|
@@ -203,50 +191,7 @@ export function runCodeBuddy(cliPath, prompt, sessionId, workDir, callbacks, opt
|
|
|
203
191
|
let currentModel;
|
|
204
192
|
const toolStats = {};
|
|
205
193
|
const startTime = Date.now();
|
|
206
|
-
const timeoutMs = options?.timeoutMs && options.timeoutMs > 0
|
|
207
|
-
? Math.min(options.timeoutMs, MAX_TIMEOUT_MS)
|
|
208
|
-
: 0;
|
|
209
|
-
const idleTimeoutMs = getIdleTimeoutMs(timeoutMs);
|
|
210
|
-
let timeoutHandle = null;
|
|
211
|
-
let idleTimeoutHandle = null;
|
|
212
194
|
const stdoutState = { buffer: '' };
|
|
213
|
-
const clearTimers = () => {
|
|
214
|
-
if (timeoutHandle) {
|
|
215
|
-
clearTimeout(timeoutHandle);
|
|
216
|
-
timeoutHandle = null;
|
|
217
|
-
}
|
|
218
|
-
if (idleTimeoutHandle) {
|
|
219
|
-
clearTimeout(idleTimeoutHandle);
|
|
220
|
-
idleTimeoutHandle = null;
|
|
221
|
-
}
|
|
222
|
-
};
|
|
223
|
-
const resetIdleTimeout = () => {
|
|
224
|
-
if (idleTimeoutMs <= 0 || completed)
|
|
225
|
-
return;
|
|
226
|
-
if (idleTimeoutHandle)
|
|
227
|
-
clearTimeout(idleTimeoutHandle);
|
|
228
|
-
idleTimeoutHandle = setTimeout(() => {
|
|
229
|
-
if (completed)
|
|
230
|
-
return;
|
|
231
|
-
completed = true;
|
|
232
|
-
clearTimers();
|
|
233
|
-
if (!child.killed)
|
|
234
|
-
child.kill('SIGTERM');
|
|
235
|
-
callbacks.onError(`CodeBuddy 执行长时间无输出,已自动终止(${idleTimeoutMs}ms)`);
|
|
236
|
-
}, idleTimeoutMs);
|
|
237
|
-
};
|
|
238
|
-
if (timeoutMs > 0) {
|
|
239
|
-
timeoutHandle = setTimeout(() => {
|
|
240
|
-
if (completed)
|
|
241
|
-
return;
|
|
242
|
-
completed = true;
|
|
243
|
-
clearTimers();
|
|
244
|
-
if (!child.killed)
|
|
245
|
-
child.kill('SIGTERM');
|
|
246
|
-
callbacks.onError(`CodeBuddy 执行超时(${timeoutMs}ms),已终止`);
|
|
247
|
-
}, timeoutMs);
|
|
248
|
-
}
|
|
249
|
-
resetIdleTimeout();
|
|
250
195
|
const MAX_STDERR = 8 * 1024;
|
|
251
196
|
let stderrText = '';
|
|
252
197
|
const handleErrorText = (message) => {
|
|
@@ -299,7 +244,6 @@ export function runCodeBuddy(cliPath, prompt, sessionId, workDir, callbacks, opt
|
|
|
299
244
|
if (completed)
|
|
300
245
|
return;
|
|
301
246
|
completed = true;
|
|
302
|
-
clearTimers();
|
|
303
247
|
const isError = payload.is_error === true;
|
|
304
248
|
const resultText = typeof payload.result === 'string'
|
|
305
249
|
? payload.result
|
|
@@ -324,7 +268,6 @@ export function runCodeBuddy(cliPath, prompt, sessionId, workDir, callbacks, opt
|
|
|
324
268
|
}
|
|
325
269
|
};
|
|
326
270
|
child.stdout?.on('data', (chunk) => {
|
|
327
|
-
resetIdleTimeout();
|
|
328
271
|
stdoutState.buffer += chunk.toString();
|
|
329
272
|
const payloads = extractBufferedPayloads(stdoutState);
|
|
330
273
|
for (const payload of payloads) {
|
|
@@ -337,14 +280,12 @@ export function runCodeBuddy(cliPath, prompt, sessionId, workDir, callbacks, opt
|
|
|
337
280
|
}
|
|
338
281
|
});
|
|
339
282
|
child.stderr?.on('data', (chunk) => {
|
|
340
|
-
resetIdleTimeout();
|
|
341
283
|
stderrText += chunk.toString();
|
|
342
284
|
if (stderrText.length > MAX_STDERR) {
|
|
343
285
|
stderrText = stderrText.slice(-MAX_STDERR);
|
|
344
286
|
}
|
|
345
287
|
});
|
|
346
288
|
child.on('close', (code) => {
|
|
347
|
-
clearTimers();
|
|
348
289
|
if (completed)
|
|
349
290
|
return;
|
|
350
291
|
if (stdoutState.buffer.trim()) {
|
|
@@ -377,7 +318,6 @@ export function runCodeBuddy(cliPath, prompt, sessionId, workDir, callbacks, opt
|
|
|
377
318
|
});
|
|
378
319
|
});
|
|
379
320
|
child.on('error', (err) => {
|
|
380
|
-
clearTimers();
|
|
381
321
|
if (completed)
|
|
382
322
|
return;
|
|
383
323
|
completed = true;
|
|
@@ -386,7 +326,6 @@ export function runCodeBuddy(cliPath, prompt, sessionId, workDir, callbacks, opt
|
|
|
386
326
|
return {
|
|
387
327
|
abort: () => {
|
|
388
328
|
completed = true;
|
|
389
|
-
clearTimers();
|
|
390
329
|
if (!child.killed)
|
|
391
330
|
child.kill('SIGTERM');
|
|
392
331
|
},
|
package/dist/codex/cli-runner.js
CHANGED
|
@@ -8,8 +8,6 @@ import { createInterface } from 'node:readline';
|
|
|
8
8
|
import { createLogger } from '../logger.js';
|
|
9
9
|
const log = createLogger('CodexCli');
|
|
10
10
|
const windowsCodexLaunchCache = new Map();
|
|
11
|
-
const MAX_TIMEOUT_MS = 2_147_483_647;
|
|
12
|
-
const DEFAULT_IDLE_TIMEOUT_MS = 10 * 60 * 1000;
|
|
13
11
|
const SUPPORTED_IMAGE_EXTENSIONS = new Set([
|
|
14
12
|
'.png',
|
|
15
13
|
'.jpg',
|
|
@@ -21,16 +19,6 @@ const SUPPORTED_IMAGE_EXTENSIONS = new Set([
|
|
|
21
19
|
'.tiff',
|
|
22
20
|
'.avif',
|
|
23
21
|
]);
|
|
24
|
-
function getIdleTimeoutMs(totalTimeoutMs) {
|
|
25
|
-
const raw = process.env.CODEX_IDLE_TIMEOUT_MS;
|
|
26
|
-
const parsed = raw ? Number.parseInt(raw, 10) : Number.NaN;
|
|
27
|
-
const configuredIdleTimeoutMs = Number.isFinite(parsed) && parsed > 0
|
|
28
|
-
? Math.min(parsed, MAX_TIMEOUT_MS)
|
|
29
|
-
: DEFAULT_IDLE_TIMEOUT_MS;
|
|
30
|
-
return totalTimeoutMs > 0
|
|
31
|
-
? Math.min(configuredIdleTimeoutMs, totalTimeoutMs)
|
|
32
|
-
: configuredIdleTimeoutMs;
|
|
33
|
-
}
|
|
34
22
|
function parseCodexEvent(line) {
|
|
35
23
|
const trimmed = line.trim();
|
|
36
24
|
if (!trimmed)
|
|
@@ -225,51 +213,7 @@ export function runCodex(cliPath, prompt, sessionId, workDir, callbacks, options
|
|
|
225
213
|
let completed = false;
|
|
226
214
|
const toolStats = {};
|
|
227
215
|
const startTime = Date.now();
|
|
228
|
-
const timeoutMs = options?.timeoutMs && options.timeoutMs > 0
|
|
229
|
-
? Math.min(options.timeoutMs, MAX_TIMEOUT_MS)
|
|
230
|
-
: 0;
|
|
231
|
-
const idleTimeoutMs = getIdleTimeoutMs(timeoutMs);
|
|
232
|
-
let timeoutHandle = null;
|
|
233
|
-
let idleTimeoutHandle = null;
|
|
234
216
|
const rl = createInterface({ input: child.stdout });
|
|
235
|
-
const clearTimers = () => {
|
|
236
|
-
if (timeoutHandle) {
|
|
237
|
-
clearTimeout(timeoutHandle);
|
|
238
|
-
timeoutHandle = null;
|
|
239
|
-
}
|
|
240
|
-
if (idleTimeoutHandle) {
|
|
241
|
-
clearTimeout(idleTimeoutHandle);
|
|
242
|
-
idleTimeoutHandle = null;
|
|
243
|
-
}
|
|
244
|
-
};
|
|
245
|
-
const failAndTerminate = (message, logMessage) => {
|
|
246
|
-
if (completed)
|
|
247
|
-
return;
|
|
248
|
-
completed = true;
|
|
249
|
-
clearTimers();
|
|
250
|
-
log.warn(logMessage);
|
|
251
|
-
rl.close();
|
|
252
|
-
if (!child.killed)
|
|
253
|
-
child.kill('SIGTERM');
|
|
254
|
-
callbacks.onError(message);
|
|
255
|
-
};
|
|
256
|
-
const resetIdleTimeout = () => {
|
|
257
|
-
if (idleTimeoutMs <= 0 || completed)
|
|
258
|
-
return;
|
|
259
|
-
if (idleTimeoutHandle)
|
|
260
|
-
clearTimeout(idleTimeoutHandle);
|
|
261
|
-
idleTimeoutHandle = setTimeout(() => {
|
|
262
|
-
failAndTerminate(`Codex 执行长时间无输出,已自动终止(${idleTimeoutMs}ms)`, `Codex CLI idle timeout after ${idleTimeoutMs}ms, killing pid=${child.pid}`);
|
|
263
|
-
}, idleTimeoutMs);
|
|
264
|
-
};
|
|
265
|
-
if (timeoutMs > 0) {
|
|
266
|
-
timeoutHandle = setTimeout(() => {
|
|
267
|
-
if (!completed && !child.killed) {
|
|
268
|
-
failAndTerminate(`执行超时(${timeoutMs}ms),已终止进程`, `Codex CLI timeout after ${timeoutMs}ms, killing pid=${child.pid}`);
|
|
269
|
-
}
|
|
270
|
-
}, timeoutMs);
|
|
271
|
-
}
|
|
272
|
-
resetIdleTimeout();
|
|
273
217
|
const MAX_STDERR_HEAD = 4 * 1024;
|
|
274
218
|
const MAX_STDERR_TAIL = 6 * 1024;
|
|
275
219
|
let stderrHead = '';
|
|
@@ -277,7 +221,6 @@ export function runCodex(cliPath, prompt, sessionId, workDir, callbacks, options
|
|
|
277
221
|
let stderrTotal = 0;
|
|
278
222
|
let stderrHeadFull = false;
|
|
279
223
|
child.stderr?.on('data', (chunk) => {
|
|
280
|
-
resetIdleTimeout();
|
|
281
224
|
const text = chunk.toString();
|
|
282
225
|
stderrTotal += text.length;
|
|
283
226
|
if (!stderrHeadFull) {
|
|
@@ -295,7 +238,6 @@ export function runCodex(cliPath, prompt, sessionId, workDir, callbacks, options
|
|
|
295
238
|
log.debug(`[stderr] ${text.trimEnd()}`);
|
|
296
239
|
});
|
|
297
240
|
rl.on('line', (line) => {
|
|
298
|
-
resetIdleTimeout();
|
|
299
241
|
const event = parseCodexEvent(line);
|
|
300
242
|
if (!event)
|
|
301
243
|
return;
|
|
@@ -309,7 +251,6 @@ export function runCodex(cliPath, prompt, sessionId, workDir, callbacks, options
|
|
|
309
251
|
}
|
|
310
252
|
if (type === 'turn.failed') {
|
|
311
253
|
completed = true;
|
|
312
|
-
clearTimers();
|
|
313
254
|
const err = event.error;
|
|
314
255
|
callbacks.onError(err?.message ?? 'Codex turn failed');
|
|
315
256
|
return;
|
|
@@ -320,7 +261,6 @@ export function runCodex(cliPath, prompt, sessionId, workDir, callbacks, options
|
|
|
320
261
|
return;
|
|
321
262
|
}
|
|
322
263
|
completed = true;
|
|
323
|
-
clearTimers();
|
|
324
264
|
callbacks.onError(msg ?? 'Codex stream error');
|
|
325
265
|
return;
|
|
326
266
|
}
|
|
@@ -374,7 +314,6 @@ export function runCodex(cliPath, prompt, sessionId, workDir, callbacks, options
|
|
|
374
314
|
}
|
|
375
315
|
if (type === 'turn.completed') {
|
|
376
316
|
completed = true;
|
|
377
|
-
clearTimers();
|
|
378
317
|
callbacks.onComplete({
|
|
379
318
|
success: true,
|
|
380
319
|
result: accumulated,
|
|
@@ -392,7 +331,6 @@ export function runCodex(cliPath, prompt, sessionId, workDir, callbacks, options
|
|
|
392
331
|
const finalize = () => {
|
|
393
332
|
if (!rlClosed || !childClosed)
|
|
394
333
|
return;
|
|
395
|
-
clearTimers();
|
|
396
334
|
if (completed)
|
|
397
335
|
return;
|
|
398
336
|
if (exitCode !== null && exitCode !== 0) {
|
|
@@ -443,7 +381,6 @@ export function runCodex(cliPath, prompt, sessionId, workDir, callbacks, options
|
|
|
443
381
|
child.on('error', (err) => {
|
|
444
382
|
const errorCode = err.code;
|
|
445
383
|
log.error(`Codex CLI spawn error: ${err.message}, code=${errorCode}, path=${cliPath}`);
|
|
446
|
-
clearTimers();
|
|
447
384
|
if (!completed) {
|
|
448
385
|
completed = true;
|
|
449
386
|
callbacks.onError(`Failed to start Codex CLI: ${err.message}`);
|
|
@@ -454,7 +391,6 @@ export function runCodex(cliPath, prompt, sessionId, workDir, callbacks, options
|
|
|
454
391
|
return {
|
|
455
392
|
abort: () => {
|
|
456
393
|
completed = true;
|
|
457
|
-
clearTimers();
|
|
458
394
|
rl.close();
|
|
459
395
|
if (!child.killed)
|
|
460
396
|
child.kill('SIGTERM');
|
|
@@ -101,14 +101,11 @@ export declare const PAGE_TEXTS: {
|
|
|
101
101
|
readonly codexCli: "Codex CLI path";
|
|
102
102
|
readonly codebuddyCli: "CodeBuddy CLI path";
|
|
103
103
|
readonly codexProxy: "Codex proxy";
|
|
104
|
-
readonly claudeTimeout: "Claude timeout (ms)";
|
|
105
104
|
readonly claudeConfigPath: "Config file location";
|
|
106
105
|
readonly claudeAuthToken: "ANTHROPIC_AUTH_TOKEN";
|
|
107
106
|
readonly claudeBaseUrl: "ANTHROPIC_BASE_URL";
|
|
108
107
|
readonly claudeModel: "ANTHROPIC_MODEL";
|
|
109
108
|
readonly claudeProxy: "Proxy (optional)";
|
|
110
|
-
readonly codexTimeout: "Codex timeout (ms)";
|
|
111
|
-
readonly codebuddyTimeout: "CodeBuddy timeout (ms)";
|
|
112
109
|
readonly hookPort: "Hook port";
|
|
113
110
|
readonly logLevel: "Log level";
|
|
114
111
|
readonly logLevelDefault: "default (app default)";
|
|
@@ -253,11 +250,8 @@ export declare const PAGE_TEXTS: {
|
|
|
253
250
|
readonly codexCli: "Codex CLI 路径";
|
|
254
251
|
readonly codebuddyCli: "CodeBuddy CLI 路径";
|
|
255
252
|
readonly codexProxy: "Codex 代理";
|
|
256
|
-
readonly claudeTimeout: "Claude 超时(毫秒)";
|
|
257
253
|
readonly claudeConfigPath: "配置文件位置";
|
|
258
254
|
readonly claudeProxy: "代理(可选)";
|
|
259
|
-
readonly codexTimeout: "Codex 超时(毫秒)";
|
|
260
|
-
readonly codebuddyTimeout: "CodeBuddy 超时(毫秒)";
|
|
261
255
|
readonly hookPort: "Hook 端口";
|
|
262
256
|
readonly logLevel: "日志级别";
|
|
263
257
|
readonly logLevelDefault: "default(程序默认)";
|
|
@@ -101,14 +101,11 @@ export const PAGE_TEXTS = {
|
|
|
101
101
|
codexCli: "Codex CLI path",
|
|
102
102
|
codebuddyCli: "CodeBuddy CLI path",
|
|
103
103
|
codexProxy: "Codex proxy",
|
|
104
|
-
claudeTimeout: "Claude timeout (ms)",
|
|
105
104
|
claudeConfigPath: "Config file location",
|
|
106
105
|
claudeAuthToken: "ANTHROPIC_AUTH_TOKEN",
|
|
107
106
|
claudeBaseUrl: "ANTHROPIC_BASE_URL",
|
|
108
107
|
claudeModel: "ANTHROPIC_MODEL",
|
|
109
108
|
claudeProxy: "Proxy (optional)",
|
|
110
|
-
codexTimeout: "Codex timeout (ms)",
|
|
111
|
-
codebuddyTimeout: "CodeBuddy timeout (ms)",
|
|
112
109
|
hookPort: "Hook port",
|
|
113
110
|
logLevel: "Log level",
|
|
114
111
|
logLevelDefault: "default (app default)",
|
|
@@ -253,11 +250,8 @@ export const PAGE_TEXTS = {
|
|
|
253
250
|
codexCli: "Codex CLI \u8def\u5f84",
|
|
254
251
|
codebuddyCli: "CodeBuddy CLI \u8def\u5f84",
|
|
255
252
|
codexProxy: "Codex \u4ee3\u7406",
|
|
256
|
-
claudeTimeout: "Claude \u8d85\u65f6\uff08\u6beb\u79d2\uff09",
|
|
257
253
|
claudeConfigPath: "\u914d\u7f6e\u6587\u4ef6\u4f4d\u7f6e",
|
|
258
254
|
claudeProxy: "\u4ee3\u7406\uff08\u53ef\u9009\uff09",
|
|
259
|
-
codexTimeout: "Codex \u8d85\u65f6\uff08\u6beb\u79d2\uff09",
|
|
260
|
-
codebuddyTimeout: "CodeBuddy \u8d85\u65f6\uff08\u6beb\u79d2\uff09",
|
|
261
255
|
hookPort: "Hook \u7aef\u53e3",
|
|
262
256
|
logLevel: "\u65e5\u5fd7\u7ea7\u522b",
|
|
263
257
|
logLevelDefault: "default\uff08\u7a0b\u5e8f\u9ed8\u8ba4\uff09",
|
|
@@ -229,14 +229,11 @@ export const PAGE_SCRIPT = String.raw ` const platformDefinitions = [
|
|
|
229
229
|
{ id: "aiCommonTitle", key: "aiCommonTitle" },
|
|
230
230
|
{ id: "ai-aiCommand-label", key: "aiTool" },
|
|
231
231
|
{ id: "ai-claudeWorkDir-label", key: "workDir" },
|
|
232
|
-
{ id: "ai-claudeTimeoutMs-label", key: "claudeTimeout" },
|
|
233
232
|
{ id: "ai-claudeConfigPath-label", key: "claudeConfigPath" },
|
|
234
233
|
{ id: "ai-claudeProxy-label", key: "claudeProxy" },
|
|
235
234
|
{ id: "ai-codexCliPath-label", key: "codexCli" },
|
|
236
|
-
{ id: "ai-codexTimeoutMs-label", key: "codexTimeout" },
|
|
237
235
|
{ id: "ai-codexProxy-label", key: "codexProxy" },
|
|
238
236
|
{ id: "ai-codebuddyCliPath-label", key: "codebuddyCli" },
|
|
239
|
-
{ id: "ai-codebuddyTimeoutMs-label", key: "codebuddyTimeout" },
|
|
240
237
|
{ id: "ai-hookPort-label", key: "hookPort" },
|
|
241
238
|
{ id: "ai-logLevel-label", key: "logLevel" },
|
|
242
239
|
],
|
|
@@ -599,14 +596,11 @@ export const PAGE_SCRIPT = String.raw ` const platformDefinitions = [
|
|
|
599
596
|
const AI_FIELD_MAPPINGS = [
|
|
600
597
|
{ id: "ai-aiCommand", key: "aiCommand" },
|
|
601
598
|
{ id: "ai-claudeWorkDir", key: "claudeWorkDir" },
|
|
602
|
-
{ id: "ai-claudeTimeoutMs", key: "claudeTimeoutMs" },
|
|
603
599
|
{ id: "ai-claudeConfigPath", key: "claudeConfigPath" },
|
|
604
600
|
{ id: "ai-claudeProxy", key: "claudeProxy" },
|
|
605
601
|
{ id: "ai-codexCliPath", key: "codexCliPath" },
|
|
606
|
-
{ id: "ai-codexTimeoutMs", key: "codexTimeoutMs" },
|
|
607
602
|
{ id: "ai-codexProxy", key: "codexProxy" },
|
|
608
603
|
{ id: "ai-codebuddyCliPath", key: "codebuddyCliPath" },
|
|
609
|
-
{ id: "ai-codebuddyTimeoutMs", key: "codebuddyTimeoutMs" },
|
|
610
604
|
{ id: "ai-hookPort", key: "hookPort" },
|
|
611
605
|
{ id: "ai-logLevel", key: "logLevel" },
|
|
612
606
|
];
|
|
@@ -923,11 +917,8 @@ export const PAGE_SCRIPT = String.raw ` const platformDefinitions = [
|
|
|
923
917
|
ai: {
|
|
924
918
|
aiCommand: getValue("ai-aiCommand"),
|
|
925
919
|
claudeWorkDir: getValue("ai-claudeWorkDir"),
|
|
926
|
-
claudeTimeoutMs: getNumber("ai-claudeTimeoutMs"),
|
|
927
920
|
claudeConfigPath: getValue("ai-claudeConfigPath"),
|
|
928
921
|
claudeProxy: getValue("ai-claudeProxy"),
|
|
929
|
-
codexTimeoutMs: getNumber("ai-codexTimeoutMs"),
|
|
930
|
-
codebuddyTimeoutMs: getNumber("ai-codebuddyTimeoutMs"),
|
|
931
922
|
codexCliPath: getValue("ai-codexCliPath"),
|
|
932
923
|
codexProxy: getValue("ai-codexProxy"),
|
|
933
924
|
codebuddyCliPath: getValue("ai-codebuddyCliPath"),
|
|
@@ -1237,10 +1237,6 @@ export const PAGE_HTML_PREFIX = String.raw `<!doctype html>
|
|
|
1237
1237
|
</div>
|
|
1238
1238
|
<div class="ai-card-body">
|
|
1239
1239
|
<div id="ai-tool-claude" class="ai-tool-panel active" data-tool-panel="claude">
|
|
1240
|
-
<div class="form-group">
|
|
1241
|
-
<label class="form-label" id="ai-claudeTimeoutMs-label">Timeout (ms)</label>
|
|
1242
|
-
<input id="ai-claudeTimeoutMs" class="form-input" type="number" min="1" />
|
|
1243
|
-
</div>
|
|
1244
1240
|
<div class="form-group">
|
|
1245
1241
|
<label class="form-label" id="ai-claudeProxy-label">Proxy (optional)</label>
|
|
1246
1242
|
<input id="ai-claudeProxy" class="form-input mono" type="text" />
|
|
@@ -1259,10 +1255,6 @@ export const PAGE_HTML_PREFIX = String.raw `<!doctype html>
|
|
|
1259
1255
|
<label class="form-label" id="ai-codexCliPath-label">CLI Path</label>
|
|
1260
1256
|
<input id="ai-codexCliPath" class="form-input mono" type="text" />
|
|
1261
1257
|
</div>
|
|
1262
|
-
<div class="form-group">
|
|
1263
|
-
<label class="form-label" id="ai-codexTimeoutMs-label">Timeout (ms)</label>
|
|
1264
|
-
<input id="ai-codexTimeoutMs" class="form-input" type="number" min="1" />
|
|
1265
|
-
</div>
|
|
1266
1258
|
<div class="form-group">
|
|
1267
1259
|
<label class="form-label" id="ai-codexProxy-label">Proxy (optional)</label>
|
|
1268
1260
|
<input id="ai-codexProxy" class="form-input mono" type="text" />
|
|
@@ -1274,10 +1266,6 @@ export const PAGE_HTML_PREFIX = String.raw `<!doctype html>
|
|
|
1274
1266
|
<label class="form-label" id="ai-codebuddyCliPath-label">CLI Path</label>
|
|
1275
1267
|
<input id="ai-codebuddyCliPath" class="form-input mono" type="text" />
|
|
1276
1268
|
</div>
|
|
1277
|
-
<div class="form-group">
|
|
1278
|
-
<label class="form-label" id="ai-codebuddyTimeoutMs-label">Timeout (ms)</label>
|
|
1279
|
-
<input id="ai-codebuddyTimeoutMs" class="form-input" type="number" min="1" />
|
|
1280
|
-
</div>
|
|
1281
1269
|
</div>
|
|
1282
1270
|
</div>
|
|
1283
1271
|
</div>
|
package/dist/config-web.js
CHANGED
|
@@ -278,7 +278,6 @@ function buildInitialPayload(file) {
|
|
|
278
278
|
ai: {
|
|
279
279
|
aiCommand: file.aiCommand ?? "claude",
|
|
280
280
|
claudeWorkDir: file.tools?.claude?.workDir ?? process.cwd(),
|
|
281
|
-
claudeTimeoutMs: file.tools?.claude?.timeoutMs ?? 600000,
|
|
282
281
|
claudeConfigPath: process.platform === 'win32'
|
|
283
282
|
? getClaudeConfigHome() + "\\.claude\\settings.json"
|
|
284
283
|
: getClaudeConfigHome() + "/.claude/settings.json",
|
|
@@ -286,8 +285,6 @@ function buildInitialPayload(file) {
|
|
|
286
285
|
claudeBaseUrl: claudeEnv.ANTHROPIC_BASE_URL ?? "",
|
|
287
286
|
claudeModel: claudeEnv.ANTHROPIC_MODEL ?? "",
|
|
288
287
|
claudeProxy: file.tools?.claude?.proxy ?? "",
|
|
289
|
-
codexTimeoutMs: file.tools?.codex?.timeoutMs ?? 600000,
|
|
290
|
-
codebuddyTimeoutMs: file.tools?.codebuddy?.timeoutMs ?? 600000,
|
|
291
288
|
codexCliPath: file.tools?.codex?.cliPath ?? "codex",
|
|
292
289
|
codebuddyCliPath: file.tools?.codebuddy?.cliPath ?? "codebuddy",
|
|
293
290
|
codexProxy: file.tools?.codex?.proxy ?? "",
|
|
@@ -327,12 +324,6 @@ function validatePayload(payload) {
|
|
|
327
324
|
errors.push("WorkBuddy user ID is required.");
|
|
328
325
|
if (!clean(payload.ai.claudeWorkDir))
|
|
329
326
|
errors.push("Default work directory is required.");
|
|
330
|
-
if (!Number.isFinite(payload.ai.claudeTimeoutMs) || payload.ai.claudeTimeoutMs <= 0)
|
|
331
|
-
errors.push("Claude timeout must be positive.");
|
|
332
|
-
if (!Number.isFinite(payload.ai.codexTimeoutMs) || payload.ai.codexTimeoutMs <= 0)
|
|
333
|
-
errors.push("Codex timeout must be positive.");
|
|
334
|
-
if (!Number.isFinite(payload.ai.codebuddyTimeoutMs) || payload.ai.codebuddyTimeoutMs <= 0)
|
|
335
|
-
errors.push("CodeBuddy timeout must be positive.");
|
|
336
327
|
return errors;
|
|
337
328
|
}
|
|
338
329
|
function validateConfigForPlatform(platform, config) {
|
|
@@ -422,9 +413,6 @@ function createProbeConfig(values) {
|
|
|
422
413
|
aiCommand: "claude",
|
|
423
414
|
codexCliPath: "codex",
|
|
424
415
|
claudeWorkDir: process.cwd(),
|
|
425
|
-
claudeTimeoutMs: 600000,
|
|
426
|
-
codexTimeoutMs: 600000,
|
|
427
|
-
codebuddyTimeoutMs: 600000,
|
|
428
416
|
logDir: "",
|
|
429
417
|
logLevel: "INFO",
|
|
430
418
|
codebuddyCliPath: "codebuddy",
|
|
@@ -588,7 +576,6 @@ function toFileConfig(payload, existing) {
|
|
|
588
576
|
claude: {
|
|
589
577
|
...existing.tools?.claude,
|
|
590
578
|
workDir: clean(payload.ai.claudeWorkDir) ?? process.cwd(),
|
|
591
|
-
timeoutMs: payload.ai.claudeTimeoutMs,
|
|
592
579
|
proxy: clean(payload.ai.claudeProxy),
|
|
593
580
|
// model is now saved to ~/.claude/settings.json as env var
|
|
594
581
|
},
|
|
@@ -596,13 +583,11 @@ function toFileConfig(payload, existing) {
|
|
|
596
583
|
...existing.tools?.codex,
|
|
597
584
|
cliPath: clean(payload.ai.codexCliPath) ?? "codex",
|
|
598
585
|
workDir: clean(payload.ai.claudeWorkDir) ?? process.cwd(),
|
|
599
|
-
timeoutMs: payload.ai.codexTimeoutMs,
|
|
600
586
|
proxy: clean(payload.ai.codexProxy),
|
|
601
587
|
},
|
|
602
588
|
codebuddy: {
|
|
603
589
|
...existing.tools?.codebuddy,
|
|
604
590
|
cliPath: clean(payload.ai.codebuddyCliPath) ?? "codebuddy",
|
|
605
|
-
timeoutMs: payload.ai.codebuddyTimeoutMs,
|
|
606
591
|
},
|
|
607
592
|
},
|
|
608
593
|
platforms: {
|
package/dist/config.d.ts
CHANGED
|
@@ -28,9 +28,6 @@ export interface Config {
|
|
|
28
28
|
claudeProxy?: string;
|
|
29
29
|
/** Codex 访问 chatgpt.com 的代理(如 http://127.0.0.1:7890) */
|
|
30
30
|
codexProxy?: string;
|
|
31
|
-
claudeTimeoutMs: number;
|
|
32
|
-
codexTimeoutMs: number;
|
|
33
|
-
codebuddyTimeoutMs: number;
|
|
34
31
|
claudeWorkDir: string;
|
|
35
32
|
claudeModel?: string;
|
|
36
33
|
logDir: string;
|
|
@@ -137,7 +134,6 @@ interface FilePlatformWorkBuddy {
|
|
|
137
134
|
export interface FileToolClaude {
|
|
138
135
|
cliPath?: string;
|
|
139
136
|
workDir?: string;
|
|
140
|
-
timeoutMs?: number;
|
|
141
137
|
skipPermissions?: boolean;
|
|
142
138
|
/** HTTP/HTTPS 代理,用于访问 Claude API(如 http://127.0.0.1:7890) */
|
|
143
139
|
proxy?: string;
|
|
@@ -147,13 +143,11 @@ export interface FileToolClaude {
|
|
|
147
143
|
export interface FileToolCodex {
|
|
148
144
|
cliPath?: string;
|
|
149
145
|
workDir?: string;
|
|
150
|
-
timeoutMs?: number;
|
|
151
146
|
/** HTTP/HTTPS 代理,用于访问 chatgpt.com(如 http://127.0.0.1:7890) */
|
|
152
147
|
proxy?: string;
|
|
153
148
|
}
|
|
154
149
|
export interface FileToolCodeBuddy {
|
|
155
150
|
cliPath?: string;
|
|
156
|
-
timeoutMs?: number;
|
|
157
151
|
}
|
|
158
152
|
export interface FileConfig {
|
|
159
153
|
telegramBotToken?: string;
|
package/dist/config.js
CHANGED
|
@@ -20,7 +20,8 @@ const CODEX_AUTH_PATHS = [
|
|
|
20
20
|
];
|
|
21
21
|
const OLD_ROOT_KEYS = [
|
|
22
22
|
'claudeWorkDir',
|
|
23
|
-
'claudeTimeoutMs',
|
|
23
|
+
'claudeTimeoutMs',
|
|
24
|
+
'claudeModel',
|
|
24
25
|
];
|
|
25
26
|
// Config cache with mtime tracking
|
|
26
27
|
let cachedConfig = null;
|
|
@@ -57,7 +58,6 @@ function migrateToNewConfigFormat(raw) {
|
|
|
57
58
|
claude: {
|
|
58
59
|
...tc,
|
|
59
60
|
workDir: tc.workDir ?? raw.claudeWorkDir ?? process.cwd(),
|
|
60
|
-
timeoutMs: tc.timeoutMs ?? raw.claudeTimeoutMs ?? 600000,
|
|
61
61
|
proxy: tc.proxy,
|
|
62
62
|
// model 现在通过 env 配置,不再在这里处理
|
|
63
63
|
},
|
|
@@ -65,13 +65,11 @@ function migrateToNewConfigFormat(raw) {
|
|
|
65
65
|
...tcod,
|
|
66
66
|
cliPath: tcod.cliPath ?? 'codex',
|
|
67
67
|
workDir: tcod.workDir ?? raw.claudeWorkDir ?? process.cwd(),
|
|
68
|
-
timeoutMs: tcod.timeoutMs ?? raw.claudeTimeoutMs ?? 600000,
|
|
69
68
|
proxy: tcod.proxy,
|
|
70
69
|
},
|
|
71
70
|
codebuddy: {
|
|
72
71
|
...tcb,
|
|
73
72
|
cliPath: tcb.cliPath ?? 'codebuddy',
|
|
74
|
-
timeoutMs: tcb.timeoutMs ?? raw.claudeTimeoutMs ?? 600000,
|
|
75
73
|
},
|
|
76
74
|
};
|
|
77
75
|
for (const k of OLD_ROOT_KEYS) {
|
|
@@ -407,15 +405,6 @@ export function loadConfig() {
|
|
|
407
405
|
}
|
|
408
406
|
}
|
|
409
407
|
const claudeWorkDir = process.env.CLAUDE_WORK_DIR ?? tc.workDir ?? process.cwd();
|
|
410
|
-
const claudeTimeoutMs = process.env.CLAUDE_TIMEOUT_MS !== undefined
|
|
411
|
-
? parseInt(process.env.CLAUDE_TIMEOUT_MS, 10) || 600000
|
|
412
|
-
: tc.timeoutMs ?? 600000;
|
|
413
|
-
const codexTimeoutMs = process.env.CODEX_TIMEOUT_MS !== undefined
|
|
414
|
-
? parseInt(process.env.CODEX_TIMEOUT_MS, 10) || 600000
|
|
415
|
-
: tcod.timeoutMs ?? 600000;
|
|
416
|
-
const codebuddyTimeoutMs = process.env.CODEBUDDY_TIMEOUT_MS !== undefined
|
|
417
|
-
? parseInt(process.env.CODEBUDDY_TIMEOUT_MS, 10) || 600000
|
|
418
|
-
: tcb.timeoutMs ?? 600000;
|
|
419
408
|
// 6. 校验 Claude API 凭证(SDK 模式需要)
|
|
420
409
|
// 支持:官方 API Key、Auth Token、或自定义 API(第三方模型等,BASE_URL + token)
|
|
421
410
|
if (aiCommand === 'claude') {
|
|
@@ -639,9 +628,6 @@ export function loadConfig() {
|
|
|
639
628
|
claudeProxy,
|
|
640
629
|
codexProxy,
|
|
641
630
|
claudeWorkDir,
|
|
642
|
-
claudeTimeoutMs,
|
|
643
|
-
codexTimeoutMs,
|
|
644
|
-
codebuddyTimeoutMs,
|
|
645
631
|
claudeModel: process.env.ANTHROPIC_MODEL,
|
|
646
632
|
logDir,
|
|
647
633
|
logLevel,
|
|
@@ -6,7 +6,6 @@ import { ackMessage, downloadRobotMessageFile, registerSessionWebhook } from './
|
|
|
6
6
|
import { CommandHandler } from '../commands/handler.js';
|
|
7
7
|
import { getAdapter } from '../adapters/registry.js';
|
|
8
8
|
import { runAITask } from '../shared/ai-task.js';
|
|
9
|
-
import { startTaskCleanup } from '../shared/task-cleanup.js';
|
|
10
9
|
import { setActiveChatId, setDingTalkActiveTarget } from '../shared/active-chats.js';
|
|
11
10
|
import { setChatUser } from '../shared/chat-user-map.js';
|
|
12
11
|
import { createLogger } from '../logger.js';
|
|
@@ -159,7 +158,6 @@ export function setupDingTalkHandlers(config, sessionManager) {
|
|
|
159
158
|
const accessControl = new AccessControl(config.dingtalkAllowedUserIds);
|
|
160
159
|
const requestQueue = new RequestQueue();
|
|
161
160
|
const runningTasks = new Map();
|
|
162
|
-
const stopTaskCleanup = startTaskCleanup(runningTasks);
|
|
163
161
|
const commandHandler = new CommandHandler({
|
|
164
162
|
config,
|
|
165
163
|
sessionManager,
|
|
@@ -301,7 +299,7 @@ export function setupDingTalkHandlers(config, sessionManager) {
|
|
|
301
299
|
ackMessage(callbackId, { queued: enqueueResult });
|
|
302
300
|
}
|
|
303
301
|
return {
|
|
304
|
-
stop: () =>
|
|
302
|
+
stop: () => { },
|
|
305
303
|
getRunningTaskCount: () => runningTasks.size,
|
|
306
304
|
handleEvent,
|
|
307
305
|
};
|
|
@@ -7,7 +7,6 @@ import { getAdapter } from '../adapters/registry.js';
|
|
|
7
7
|
import { runAITask } from '../shared/ai-task.js';
|
|
8
8
|
import { buildCardV2 } from './card-builder.js';
|
|
9
9
|
import { disableStreaming, updateCardFull, destroySession } from './cardkit-manager.js';
|
|
10
|
-
import { startTaskCleanup } from '../shared/task-cleanup.js';
|
|
11
10
|
import { CARDKIT_THROTTLE_MS } from '../constants.js';
|
|
12
11
|
import { setActiveChatId } from '../shared/active-chats.js';
|
|
13
12
|
import { setChatUser } from '../shared/chat-user-map.js';
|
|
@@ -126,7 +125,6 @@ export function setupFeishuHandlers(config, sessionManager) {
|
|
|
126
125
|
const accessControl = new AccessControl(config.feishuAllowedUserIds);
|
|
127
126
|
const requestQueue = new RequestQueue();
|
|
128
127
|
const runningTasks = new Map();
|
|
129
|
-
const stopTaskCleanup = startTaskCleanup(runningTasks);
|
|
130
128
|
const commandHandler = new CommandHandler({
|
|
131
129
|
config,
|
|
132
130
|
sessionManager,
|
|
@@ -608,7 +606,7 @@ export function setupFeishuHandlers(config, sessionManager) {
|
|
|
608
606
|
}
|
|
609
607
|
}
|
|
610
608
|
return {
|
|
611
|
-
stop: () =>
|
|
609
|
+
stop: () => { },
|
|
612
610
|
getRunningTaskCount: () => runningTasks.size,
|
|
613
611
|
handleEvent,
|
|
614
612
|
};
|
package/dist/qq/event-handler.js
CHANGED
|
@@ -5,7 +5,6 @@ import { sendThinkingMessage, updateMessage, sendFinalMessages, sendErrorMessage
|
|
|
5
5
|
import { CommandHandler } from "../commands/handler.js";
|
|
6
6
|
import { getAdapter } from "../adapters/registry.js";
|
|
7
7
|
import { runAITask } from "../shared/ai-task.js";
|
|
8
|
-
import { startTaskCleanup } from "../shared/task-cleanup.js";
|
|
9
8
|
import { setActiveChatId } from "../shared/active-chats.js";
|
|
10
9
|
import { setChatUser } from "../shared/chat-user-map.js";
|
|
11
10
|
import { createLogger } from "../logger.js";
|
|
@@ -119,7 +118,6 @@ export function setupQQHandlers(config, sessionManager) {
|
|
|
119
118
|
const runningTasks = new Map();
|
|
120
119
|
const recentEventIds = new Map();
|
|
121
120
|
const recentEventFingerprints = new Map();
|
|
122
|
-
const stopTaskCleanup = startTaskCleanup(runningTasks);
|
|
123
121
|
const commandHandler = new CommandHandler({
|
|
124
122
|
config,
|
|
125
123
|
sessionManager,
|
|
@@ -258,7 +256,7 @@ export function setupQQHandlers(config, sessionManager) {
|
|
|
258
256
|
log.info(`QQ message handled: user=${userId}, chat=${chatId}, status=${enqueueResult}, attachments=${event.attachments?.length ?? 0}`);
|
|
259
257
|
}
|
|
260
258
|
return {
|
|
261
|
-
stop: () =>
|
|
259
|
+
stop: () => { },
|
|
262
260
|
getRunningTaskCount: () => runningTasks.size,
|
|
263
261
|
handleEvent,
|
|
264
262
|
};
|
package/dist/setup.js
CHANGED
|
@@ -75,11 +75,10 @@ function printManualInstructions(configPath) {
|
|
|
75
75
|
"tools": {
|
|
76
76
|
"claude": {
|
|
77
77
|
"cliPath": "claude",
|
|
78
|
-
"workDir": "${process.cwd().replace(/\\/g, "/")}"
|
|
79
|
-
"timeoutMs": 600000
|
|
78
|
+
"workDir": "${process.cwd().replace(/\\/g, "/")}"
|
|
80
79
|
},
|
|
81
80
|
"codex": { "cliPath": "codex", "workDir": "${process.cwd().replace(/\\/g, "/")}", "proxy": "http://127.0.0.1:7890" },
|
|
82
|
-
"codebuddy": { "cliPath": "codebuddy"
|
|
81
|
+
"codebuddy": { "cliPath": "codebuddy" }
|
|
83
82
|
},
|
|
84
83
|
"platforms": {
|
|
85
84
|
"telegram": {
|
|
@@ -862,7 +861,6 @@ export async function runInteractiveSetup() {
|
|
|
862
861
|
...baseTools.claude,
|
|
863
862
|
cliPath: baseTools.claude?.cliPath ?? "claude",
|
|
864
863
|
workDir,
|
|
865
|
-
timeoutMs: baseTools.claude?.timeoutMs ?? 600000,
|
|
866
864
|
},
|
|
867
865
|
codex: {
|
|
868
866
|
...baseTools.codex,
|
|
@@ -875,7 +873,6 @@ export async function runInteractiveSetup() {
|
|
|
875
873
|
codebuddy: {
|
|
876
874
|
...baseTools.codebuddy,
|
|
877
875
|
cliPath: baseTools.codebuddy?.cliPath ?? "codebuddy",
|
|
878
|
-
timeoutMs: baseTools.codebuddy?.timeoutMs ?? 600000,
|
|
879
876
|
},
|
|
880
877
|
},
|
|
881
878
|
};
|
package/dist/shared/ai-task.js
CHANGED
|
@@ -86,11 +86,6 @@ export function runAITask(deps, ctx, prompt, toolAdapter, platformAdapter) {
|
|
|
86
86
|
// 使用 aiCommand 而不是 toolAdapter.toolId,确保 sessionId 的存储和查询使用相同的 key
|
|
87
87
|
const aiCommand = resolvePlatformAiCommand(config, ctx.platform);
|
|
88
88
|
const toolId = toolAdapter.toolId;
|
|
89
|
-
const timeoutMs = aiCommand === 'codex'
|
|
90
|
-
? config.codexTimeoutMs
|
|
91
|
-
: aiCommand === 'codebuddy'
|
|
92
|
-
? config.codebuddyTimeoutMs
|
|
93
|
-
: config.claudeTimeoutMs;
|
|
94
89
|
const startRun = () => {
|
|
95
90
|
log.info(`[AITask] Starting: userId=${ctx.userId}, initialSessionId=${currentSessionId ?? 'new'}, prompt="${prompt.slice(0, 50)}..."`);
|
|
96
91
|
activeHandle = toolAdapter.run(prompt, currentSessionId, ctx.workDir, {
|
|
@@ -225,7 +220,6 @@ export function runAITask(deps, ctx, prompt, toolAdapter, platformAdapter) {
|
|
|
225
220
|
resolve();
|
|
226
221
|
},
|
|
227
222
|
}, {
|
|
228
|
-
timeoutMs,
|
|
229
223
|
model: sessionManager.getModel(ctx.userId, ctx.threadId) ?? config.claudeModel,
|
|
230
224
|
chatId: ctx.chatId,
|
|
231
225
|
// 默认跳过权限确认,保持全自动执行
|
|
@@ -6,7 +6,6 @@ import { sendThinkingMessage, updateMessage, sendFinalMessages, sendTextReply, s
|
|
|
6
6
|
import { CommandHandler } from "../commands/handler.js";
|
|
7
7
|
import { getAdapter } from "../adapters/registry.js";
|
|
8
8
|
import { runAITask } from "../shared/ai-task.js";
|
|
9
|
-
import { startTaskCleanup } from "../shared/task-cleanup.js";
|
|
10
9
|
import { TELEGRAM_THROTTLE_MS } from "../constants.js";
|
|
11
10
|
import { setActiveChatId } from "../shared/active-chats.js";
|
|
12
11
|
import { setChatUser } from "../shared/chat-user-map.js";
|
|
@@ -66,7 +65,6 @@ export function setupTelegramHandlers(bot, config, sessionManager) {
|
|
|
66
65
|
const accessControl = new AccessControl(config.telegramAllowedUserIds);
|
|
67
66
|
const requestQueue = new RequestQueue();
|
|
68
67
|
const runningTasks = new Map();
|
|
69
|
-
const stopTaskCleanup = startTaskCleanup(runningTasks);
|
|
70
68
|
const commandHandler = new CommandHandler({
|
|
71
69
|
config,
|
|
72
70
|
sessionManager,
|
|
@@ -488,7 +486,7 @@ export function setupTelegramHandlers(bot, config, sessionManager) {
|
|
|
488
486
|
}
|
|
489
487
|
});
|
|
490
488
|
return {
|
|
491
|
-
stop: () =>
|
|
489
|
+
stop: () => { },
|
|
492
490
|
getRunningTaskCount: () => runningTasks.size,
|
|
493
491
|
};
|
|
494
492
|
}
|
|
@@ -8,7 +8,6 @@ import { sendThinkingMessage, updateMessage, sendFinalMessages, sendTextReply, s
|
|
|
8
8
|
import { CommandHandler } from '../commands/handler.js';
|
|
9
9
|
import { getAdapter } from '../adapters/registry.js';
|
|
10
10
|
import { runAITask } from '../shared/ai-task.js';
|
|
11
|
-
import { startTaskCleanup } from '../shared/task-cleanup.js';
|
|
12
11
|
import { WEWORK_THROTTLE_MS } from '../constants.js';
|
|
13
12
|
import { setActiveChatId } from '../shared/active-chats.js';
|
|
14
13
|
import { setChatUser } from '../shared/chat-user-map.js';
|
|
@@ -163,7 +162,6 @@ export function setupWeWorkHandlers(config, sessionManager) {
|
|
|
163
162
|
const accessControl = new AccessControl(config.weworkAllowedUserIds);
|
|
164
163
|
const requestQueue = new RequestQueue();
|
|
165
164
|
const runningTasks = new Map();
|
|
166
|
-
const stopTaskCleanup = startTaskCleanup(runningTasks);
|
|
167
165
|
// Mutable ref that captures the req_id of the message currently being handled.
|
|
168
166
|
// WeWork requires req_id to reply; CommandHandler doesn't carry it, so we inject
|
|
169
167
|
// it via a closure. WeWork delivers messages sequentially over WebSocket, so
|
|
@@ -332,7 +330,7 @@ export function setupWeWorkHandlers(config, sessionManager) {
|
|
|
332
330
|
}
|
|
333
331
|
}
|
|
334
332
|
return {
|
|
335
|
-
stop: () =>
|
|
333
|
+
stop: () => { },
|
|
336
334
|
getRunningTaskCount: () => runningTasks.size,
|
|
337
335
|
handleEvent,
|
|
338
336
|
};
|
|
@@ -8,7 +8,6 @@ import { sendTextReply, sendErrorReply } from './message-sender.js';
|
|
|
8
8
|
import { CommandHandler } from '../commands/handler.js';
|
|
9
9
|
import { getAdapter } from '../adapters/registry.js';
|
|
10
10
|
import { runAITask } from '../shared/ai-task.js';
|
|
11
|
-
import { startTaskCleanup } from '../shared/task-cleanup.js';
|
|
12
11
|
import { WORKBUDDY_THROTTLE_MS } from '../constants.js';
|
|
13
12
|
import { setActiveChatId } from '../shared/active-chats.js';
|
|
14
13
|
import { setChatUser } from '../shared/chat-user-map.js';
|
|
@@ -19,7 +18,6 @@ export function setupWorkBuddyHandlers(config, sessionManager) {
|
|
|
19
18
|
const requestQueue = new RequestQueue();
|
|
20
19
|
const runningTasks = new Map();
|
|
21
20
|
const taskKeyByChatId = new Map();
|
|
22
|
-
const stopTaskCleanup = startTaskCleanup(runningTasks);
|
|
23
21
|
// Base dependencies for creating per-event CommandHandler
|
|
24
22
|
const baseCommandDeps = {
|
|
25
23
|
config,
|
|
@@ -116,7 +114,7 @@ export function setupWorkBuddyHandlers(config, sessionManager) {
|
|
|
116
114
|
}
|
|
117
115
|
}
|
|
118
116
|
return {
|
|
119
|
-
stop: () =>
|
|
117
|
+
stop: () => { },
|
|
120
118
|
getRunningTaskCount: () => runningTasks.size,
|
|
121
119
|
handleEvent,
|
|
122
120
|
};
|
package/package.json
CHANGED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { createLogger } from '../logger.js';
|
|
2
|
-
const log = createLogger('TaskCleanup');
|
|
3
|
-
const TASK_TIMEOUT_MS = 30 * 60 * 1000;
|
|
4
|
-
const INTERVAL_MS = 10 * 60 * 1000;
|
|
5
|
-
export function startTaskCleanup(runningTasks) {
|
|
6
|
-
const timer = setInterval(() => {
|
|
7
|
-
const now = Date.now();
|
|
8
|
-
for (const [key, task] of runningTasks) {
|
|
9
|
-
if (now - task.startedAt > TASK_TIMEOUT_MS) {
|
|
10
|
-
log.warn(`Auto-cleaning timeout task: ${key}`);
|
|
11
|
-
task.settle();
|
|
12
|
-
task.handle.abort();
|
|
13
|
-
runningTasks.delete(key);
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
}, INTERVAL_MS);
|
|
17
|
-
timer.unref();
|
|
18
|
-
return () => clearInterval(timer);
|
|
19
|
-
}
|