@vrs-soft/wecom-aibot-mcp 3.4.9-beta.1 → 3.4.9-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/channel-server.js +30 -6
- package/package.json +1 -1
package/dist/channel-server.js
CHANGED
|
@@ -436,13 +436,32 @@ function connectSSE(ccId) {
|
|
|
436
436
|
sseWatchdogActive = true; // v3.4.3
|
|
437
437
|
// v3.4.5: 每 10s 主动 ping daemon,证明客户端还活着 → 刷 lastOnline
|
|
438
438
|
// 没 ping daemon 端 30s 后视为客户端死亡,立刻 unregister(v1.3.12 daemon 端机制)
|
|
439
|
+
// v3.4.9-beta.2: ping 收到非 2xx(含 404 "ccId not registered")→ abort SSE 触发重连链
|
|
440
|
+
// 修复"SSE 假死但 daemon 已 unregister,CC 端不知情继续飘着"的漏洞
|
|
439
441
|
if (ccId) {
|
|
440
|
-
pingTimer = setInterval(() => {
|
|
442
|
+
pingTimer = setInterval(async () => {
|
|
441
443
|
const pingUrl = `${MCP_URL}/cc/${encodeURIComponent(ccId)}/ping`;
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
444
|
+
try {
|
|
445
|
+
const res = await fetch(pingUrl, {
|
|
446
|
+
method: 'POST',
|
|
447
|
+
headers: { 'Content-Type': 'application/json', ...getAuthHeaders() },
|
|
448
|
+
});
|
|
449
|
+
if (!res.ok) {
|
|
450
|
+
logger.warn?.('ping 收到非 2xx,abort SSE 触发重连', { ccId, status: res.status });
|
|
451
|
+
try {
|
|
452
|
+
sseAbortController?.abort();
|
|
453
|
+
}
|
|
454
|
+
catch { /* ignore */ }
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
catch (err) {
|
|
458
|
+
logChannel('ping daemon failed', { error: String(err) });
|
|
459
|
+
// 网络错误也 abort 触发重连
|
|
460
|
+
try {
|
|
461
|
+
sseAbortController?.abort();
|
|
462
|
+
}
|
|
463
|
+
catch { /* ignore */ }
|
|
464
|
+
}
|
|
446
465
|
}, 10000);
|
|
447
466
|
}
|
|
448
467
|
while (true) {
|
|
@@ -1097,6 +1116,11 @@ function registerChannelTools(server) {
|
|
|
1097
1116
|
project_dir: z.string().optional().describe('项目目录路径(用于更新配置文件)'),
|
|
1098
1117
|
}, async ({ cc_id, project_dir }) => {
|
|
1099
1118
|
const localProjectDir = project_dir || process.cwd();
|
|
1119
|
+
// v3.4.9-beta.2: 顺序改成"先转发 daemon exit,再 abort SSE"
|
|
1120
|
+
// 否则 mcp 端 abort SSE → daemon 端 SSE close 先触发 unregisterCcId 走 grace period(不是 instant)
|
|
1121
|
+
// → daemon 端 exit_headless_mode 走 error 分支(getConnectedClient 找不到 ccId 了)
|
|
1122
|
+
// 结果:instant 释放 robot 的分支永远进不去
|
|
1123
|
+
const result = await forwardToHttpMcp('exit_headless_mode', { cc_id, project_dir: localProjectDir });
|
|
1100
1124
|
// 断开 SSE 连接(abort 后重连逻辑不会触发)
|
|
1101
1125
|
if (sseAbortController) {
|
|
1102
1126
|
sseAbortController.abort();
|
|
@@ -1116,7 +1140,7 @@ function registerChannelTools(server) {
|
|
|
1116
1140
|
heartbeatJobId: undefined,
|
|
1117
1141
|
});
|
|
1118
1142
|
logger.info('本地 wecom-aibot.json wechatMode 已置 false', { projectDir: localProjectDir });
|
|
1119
|
-
return
|
|
1143
|
+
return result;
|
|
1120
1144
|
});
|
|
1121
1145
|
// ============================================
|
|
1122
1146
|
// 工具 11: 从消息识别用户
|