@wu529778790/open-im 1.11.13-beta.0 → 1.11.13-beta.2
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/codebuddy/cli-runner.js +11 -1
- package/dist/codex/cli-runner.js +13 -2
- package/dist/index.js +25 -2
- package/dist/logger.js +5 -0
- package/dist/shared/ai-task.js +2 -2
- package/dist/shared/keepalive.js +1 -1
- package/dist/telegram/client.js +1 -6
- package/dist/workbuddy/client.js +1 -7
- package/dist/workbuddy/message-sender.js +0 -11
- package/package.json +1 -1
|
@@ -345,7 +345,17 @@ export function runCodeBuddy(cliPath, prompt, sessionId, workDir, callbacks, opt
|
|
|
345
345
|
if (completed)
|
|
346
346
|
return;
|
|
347
347
|
completed = true;
|
|
348
|
-
|
|
348
|
+
const errorCode = err.code;
|
|
349
|
+
const cliPath = child.spawnfile ?? 'codebuddy';
|
|
350
|
+
const cliHint = errorCode === 'ENOENT'
|
|
351
|
+
? `CodeBuddy CLI 路径不存在:${cliPath}。请检查 config.tools.codebuddy.cliPath 或重新 open-im init。`
|
|
352
|
+
: errorCode === 'EFTYPE'
|
|
353
|
+
? `CodeBuddy CLI 不是有效的可执行文件:${cliPath}(macOS 可执行性/Shebang 检查失败)。请确认 cliPath 指向二进制或带 shebang 的脚本。`
|
|
354
|
+
: errorCode === 'EACCES'
|
|
355
|
+
? `CodeBuddy CLI 没有执行权限:${cliPath}。请 chmod +x 或检查文件所有者。`
|
|
356
|
+
: null;
|
|
357
|
+
log.error(`CodeBuddy CLI spawn error: ${err.message}, code=${errorCode}, path=${cliPath}${cliHint ? ` — ${cliHint}` : ''}`);
|
|
358
|
+
callbacks.onError(cliHint ?? `无法启动 CodeBuddy:${err.message}`);
|
|
349
359
|
});
|
|
350
360
|
// 墙钟超时:防止 CLI 挂死永久占用用户队列槽
|
|
351
361
|
const cliTimeoutMs = Number(process.env.OPEN_IM_CLI_TIMEOUT_MS) || 30 * 60 * 1000;
|
package/dist/codex/cli-runner.js
CHANGED
|
@@ -389,10 +389,21 @@ export function runCodex(cliPath, prompt, sessionId, workDir, callbacks, options
|
|
|
389
389
|
});
|
|
390
390
|
child.on('error', (err) => {
|
|
391
391
|
const errorCode = err.code;
|
|
392
|
-
|
|
392
|
+
// EFTYPE / ENOENT / EACCES:cliPath 不可执行、不存在或没有权限。
|
|
393
|
+
// macOS 上缺少 shebang 的脚本会收到 EFTYPE;Windows 上通常是 ENOENT。
|
|
394
|
+
// 给出可操作的修复建议,避免用户只看到冷冰冰的 fork/exec 错误。
|
|
395
|
+
const cliHint = errorCode === 'ENOENT'
|
|
396
|
+
? `Codex CLI 路径不存在:${cliPath}。请检查 config.tools.codex.cliPath 或重新 open-im init。`
|
|
397
|
+
: errorCode === 'EFTYPE'
|
|
398
|
+
? `Codex CLI 不是有效的可执行文件:${cliPath}(macOS 可执行性/Shebang 检查失败)。请确认 cliPath 指向二进制或带 shebang 的脚本。`
|
|
399
|
+
: errorCode === 'EACCES'
|
|
400
|
+
? `Codex CLI 没有执行权限:${cliPath}。请 chmod +x 或检查文件所有者。`
|
|
401
|
+
: null;
|
|
402
|
+
log.error(`Codex CLI spawn error: ${err.message}, code=${errorCode}, path=${cliPath}${cliHint ? ` — ${cliHint}` : ''}`);
|
|
393
403
|
if (!completed) {
|
|
394
404
|
completed = true;
|
|
395
|
-
|
|
405
|
+
const friendlyMsg = cliHint ?? `无法启动 Codex:${err.message}`;
|
|
406
|
+
callbacks.onError(friendlyMsg);
|
|
396
407
|
}
|
|
397
408
|
gate.childClosed = true;
|
|
398
409
|
finalize();
|
package/dist/index.js
CHANGED
|
@@ -274,14 +274,30 @@ export async function main() {
|
|
|
274
274
|
loadActiveChats();
|
|
275
275
|
initAdapters(config);
|
|
276
276
|
startKeepalive();
|
|
277
|
-
// 尽早启动 shutdown 并写入 port 文件,使 open-im start 的 8s
|
|
277
|
+
// 尽早启动 shutdown 并写入 port 文件,使 open-im start 的 8s 就绪超时能通过(平台初始化可能较慢)。
|
|
278
|
+
// HTTP handler 可能在 platform 初始化完成前被外部调用(如 open-im stop / 探测脚本),
|
|
279
|
+
// 此时 shutdown 尚未定义。用占位函数兜底:把请求排进队列,shutdown 就绪后执行。
|
|
280
|
+
const shutdownQueue = [];
|
|
281
|
+
let shutdownImpl = null;
|
|
282
|
+
const runShutdown = () => {
|
|
283
|
+
const fn = shutdownImpl;
|
|
284
|
+
if (!fn)
|
|
285
|
+
throw new Error('shutdown not ready');
|
|
286
|
+
return fn().catch(() => process.exit(1));
|
|
287
|
+
};
|
|
288
|
+
const requestShutdown = () => {
|
|
289
|
+
if (shutdownImpl)
|
|
290
|
+
runShutdown();
|
|
291
|
+
else
|
|
292
|
+
shutdownQueue.push(() => runShutdown());
|
|
293
|
+
};
|
|
278
294
|
let shutdownServer = null;
|
|
279
295
|
await new Promise((resolve, reject) => {
|
|
280
296
|
shutdownServer = createServer((req, res) => {
|
|
281
297
|
if (req.url === "/shutdown" || req.url === "/") {
|
|
282
298
|
res.writeHead(200, { "Content-Type": "text/plain" });
|
|
283
299
|
res.end("ok");
|
|
284
|
-
|
|
300
|
+
requestShutdown();
|
|
285
301
|
}
|
|
286
302
|
else {
|
|
287
303
|
res.writeHead(404);
|
|
@@ -354,6 +370,13 @@ export async function main() {
|
|
|
354
370
|
return;
|
|
355
371
|
shuttingDown = true;
|
|
356
372
|
log.info("Shutting down...");
|
|
373
|
+
// shutdown 已就绪:放行 platform 初始化期间排队的 stop 请求
|
|
374
|
+
shutdownImpl = shutdown;
|
|
375
|
+
for (const pending of shutdownQueue.splice(0))
|
|
376
|
+
pending();
|
|
377
|
+
// 排队请求已全部触发并 await 完成 → 主动退出,避免进程空转
|
|
378
|
+
if (shuttingDown)
|
|
379
|
+
return;
|
|
357
380
|
const uptimeSec = Math.floor((Date.now() - startedAt) / 1000);
|
|
358
381
|
const m = Math.floor(uptimeSec / 60);
|
|
359
382
|
const shutdownMsg = buildShutdownMessage(m);
|
package/dist/logger.js
CHANGED
|
@@ -70,6 +70,11 @@ function checkLogSize() {
|
|
|
70
70
|
return;
|
|
71
71
|
try {
|
|
72
72
|
const currentLogPath = join(logDir, getLogFileName());
|
|
73
|
+
// ENOENT 防御:上次轮转刚 unlink 当前文件、新流尚未建立时,
|
|
74
|
+
// write() 可能追入旧 stream 后立刻触发 checkLogSize()。此时文件不存在,
|
|
75
|
+
// 直接跳过,下一轮 write() 会自动建好新文件。
|
|
76
|
+
if (!existsSync(currentLogPath))
|
|
77
|
+
return;
|
|
73
78
|
const stats = statSync(currentLogPath);
|
|
74
79
|
if (stats.size > MAX_LOG_SIZE) {
|
|
75
80
|
// 关闭当前日志流
|
package/dist/shared/ai-task.js
CHANGED
|
@@ -180,7 +180,7 @@ function buildCompletionNote(result, sessionManager, ctx) {
|
|
|
180
180
|
parts.push(ctxWarning);
|
|
181
181
|
return parts.join(' | ');
|
|
182
182
|
}
|
|
183
|
-
function buildRunOptions(config, sessionManager, ctx, aiCommand
|
|
183
|
+
function buildRunOptions(config, sessionManager, ctx, aiCommand) {
|
|
184
184
|
// 权限 hook 尚未接入 IM,暂时全局跳过
|
|
185
185
|
const defaultSkipPermissions = true;
|
|
186
186
|
return {
|
|
@@ -474,7 +474,7 @@ export function runAITask(deps, ctx, prompt, toolAdapter, platformAdapter) {
|
|
|
474
474
|
cleanup();
|
|
475
475
|
resolve();
|
|
476
476
|
},
|
|
477
|
-
}, buildRunOptions(config, sessionManager, ctx, aiCommand
|
|
477
|
+
}, buildRunOptions(config, sessionManager, ctx, aiCommand));
|
|
478
478
|
return activeHandle;
|
|
479
479
|
};
|
|
480
480
|
taskState = {
|
package/dist/shared/keepalive.js
CHANGED
package/dist/telegram/client.js
CHANGED
|
@@ -3,15 +3,11 @@ import { createLogger } from "../logger.js";
|
|
|
3
3
|
import { isFatalReconnectError, jitteredDelay } from "../shared/reconnect.js";
|
|
4
4
|
const log = createLogger("Telegram");
|
|
5
5
|
let bot;
|
|
6
|
-
let botUsername;
|
|
7
6
|
export function getBot() {
|
|
8
7
|
if (!bot)
|
|
9
8
|
throw new Error("Telegram bot not initialized");
|
|
10
9
|
return bot;
|
|
11
10
|
}
|
|
12
|
-
function getBotUsername() {
|
|
13
|
-
return botUsername;
|
|
14
|
-
}
|
|
15
11
|
export async function initTelegram(config, setupHandlers) {
|
|
16
12
|
const token = config.telegramBotToken ?? "";
|
|
17
13
|
if (!token) {
|
|
@@ -19,8 +15,7 @@ export async function initTelegram(config, setupHandlers) {
|
|
|
19
15
|
}
|
|
20
16
|
bot = new Telegraf(token);
|
|
21
17
|
setupHandlers(bot);
|
|
22
|
-
|
|
23
|
-
botUsername = me.username;
|
|
18
|
+
await bot.telegram.getMe();
|
|
24
19
|
const launchWithRetry = async (attempt = 1) => {
|
|
25
20
|
try {
|
|
26
21
|
await bot.launch();
|
package/dist/workbuddy/client.js
CHANGED
|
@@ -40,9 +40,6 @@ const reconnectManager = new ReconnectManager({
|
|
|
40
40
|
}
|
|
41
41
|
},
|
|
42
42
|
});
|
|
43
|
-
function getChannelState() {
|
|
44
|
-
return stateManager.current;
|
|
45
|
-
}
|
|
46
43
|
export async function initWorkBuddy(config, eventHandler, onStateChange) {
|
|
47
44
|
const pc = config.platforms?.workbuddy;
|
|
48
45
|
if (!pc?.enabled) {
|
|
@@ -96,7 +93,7 @@ async function connect() {
|
|
|
96
93
|
log.error('Host workspace registration failed:', err);
|
|
97
94
|
if (isFatalReconnectError(err)) {
|
|
98
95
|
reconnectManager.setFatal(true);
|
|
99
|
-
log.warn('WorkBuddy 致命错误(鉴权失败),转慢探测(token
|
|
96
|
+
log.warn('WorkBuddy 致命错误(鉴权失败),转慢探测(token 可能已过期)。请运行 open-im init 重新登录 WorkBuddy。:', err);
|
|
100
97
|
}
|
|
101
98
|
reconnectManager.schedule();
|
|
102
99
|
return;
|
|
@@ -242,9 +239,6 @@ async function connect() {
|
|
|
242
239
|
export function getCentrifugeClient() {
|
|
243
240
|
return centrifugeClient;
|
|
244
241
|
}
|
|
245
|
-
function getOAuth() {
|
|
246
|
-
return oauthClient;
|
|
247
|
-
}
|
|
248
242
|
/**
|
|
249
243
|
* 单飞刷新 WorkBuddy access token:并发 401 只触发一次刷新,复用同一 Promise。
|
|
250
244
|
* 刷新成功后 oauthClient.accessToken 原地更新,所有 HTTP 调用(含心跳)自动用新 token。
|
|
@@ -41,14 +41,3 @@ export async function sendErrorReply(_client, chatId, error, msgId) {
|
|
|
41
41
|
stop_reason: 'error',
|
|
42
42
|
});
|
|
43
43
|
}
|
|
44
|
-
/**
|
|
45
|
-
* Send streaming chunk to WeChat KF
|
|
46
|
-
*/
|
|
47
|
-
function sendStreamingChunk(_client, chatId, text, msgId) {
|
|
48
|
-
const client = _client ?? getCentrifugeClient();
|
|
49
|
-
if (!client) {
|
|
50
|
-
log.warn('WorkBuddy client not available, cannot send chunk');
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
client.sendMessageChunk(chatId, msgId, { type: 'text', text: toReplyPlainText(text) });
|
|
54
|
-
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wu529778790/open-im",
|
|
3
|
-
"version": "1.11.13-beta.
|
|
3
|
+
"version": "1.11.13-beta.2",
|
|
4
4
|
"description": "Your AI coding assistant, in every chat app. Multi-platform IM bridge for Claude Code, Codex, and CodeBuddy.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|