@vrs-soft/wecom-aibot-mcp 2.4.0 → 2.4.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/README.md +1 -1
- package/dist/client.d.ts +20 -1
- package/dist/client.js +30 -0
- package/dist/config-wizard.js +4 -3
- package/dist/connection-manager.js +15 -0
- package/dist/http-server.js +4 -1
- package/package.json +1 -1
package/README.md
CHANGED
package/dist/client.d.ts
CHANGED
|
@@ -25,6 +25,12 @@ interface MessageRecord {
|
|
|
25
25
|
chattype: 'single' | 'group';
|
|
26
26
|
quoteContent?: string;
|
|
27
27
|
}
|
|
28
|
+
interface PendingMessage {
|
|
29
|
+
type: 'text' | 'approval';
|
|
30
|
+
content: any;
|
|
31
|
+
targetUser?: string;
|
|
32
|
+
timestamp: number;
|
|
33
|
+
}
|
|
28
34
|
declare class WecomClient extends EventEmitter {
|
|
29
35
|
private wsClient;
|
|
30
36
|
private approvals;
|
|
@@ -77,6 +83,10 @@ declare class WecomClient extends EventEmitter {
|
|
|
77
83
|
* allow-once 消费后标记为已消费
|
|
78
84
|
*/
|
|
79
85
|
consumeApproval(taskId: string): 'allow-once' | 'allow-always' | 'deny' | null;
|
|
86
|
+
/**
|
|
87
|
+
* 获取所有未解决的审批记录 Map(用于重连时迁移到新 client)
|
|
88
|
+
*/
|
|
89
|
+
getUnresolvedApprovalMap(): Map<string, ApprovalRecord>;
|
|
80
90
|
/**
|
|
81
91
|
* 注入审批记录(MCP 重启恢复用)
|
|
82
92
|
* 如果 taskId 已存在则跳过,避免覆盖用户已点击的结果
|
|
@@ -88,6 +98,15 @@ declare class WecomClient extends EventEmitter {
|
|
|
88
98
|
cleanupMessages(maxAgeMs?: number): void;
|
|
89
99
|
private flushPendingMessages;
|
|
90
100
|
getPendingMessageCount(): number;
|
|
101
|
+
/**
|
|
102
|
+
* 取出所有待发送的审批消息并清空队列(用于 client 迁移)
|
|
103
|
+
* 仅迁移 approval 类型,text 通知类消息不需要迁移
|
|
104
|
+
*/
|
|
105
|
+
takePendingApprovalMessages(): PendingMessage[];
|
|
106
|
+
/**
|
|
107
|
+
* 注入待发送消息(用于 client 迁移,新 client 连接后会自动重发)
|
|
108
|
+
*/
|
|
109
|
+
injectPendingMessages(messages: PendingMessage[]): void;
|
|
91
110
|
getReconnectStatus(): {
|
|
92
111
|
wasReconnecting: boolean;
|
|
93
112
|
attempt: number;
|
|
@@ -96,4 +115,4 @@ declare class WecomClient extends EventEmitter {
|
|
|
96
115
|
}
|
|
97
116
|
export declare function initClient(botId: string, secret: string, targetUserId: string, robotName: string): WecomClient;
|
|
98
117
|
export declare function getClient(): WecomClient;
|
|
99
|
-
export { WecomClient, ApprovalRecord, MessageRecord, MAX_PENDING_MESSAGES };
|
|
118
|
+
export { WecomClient, ApprovalRecord, MessageRecord, PendingMessage, MAX_PENDING_MESSAGES };
|
package/dist/client.js
CHANGED
|
@@ -528,6 +528,18 @@ class WecomClient extends EventEmitter {
|
|
|
528
528
|
}
|
|
529
529
|
return approval.result;
|
|
530
530
|
}
|
|
531
|
+
/**
|
|
532
|
+
* 获取所有未解决的审批记录 Map(用于重连时迁移到新 client)
|
|
533
|
+
*/
|
|
534
|
+
getUnresolvedApprovalMap() {
|
|
535
|
+
const pending = new Map();
|
|
536
|
+
this.approvals.forEach((approval, taskId) => {
|
|
537
|
+
if (!approval.resolved) {
|
|
538
|
+
pending.set(taskId, approval);
|
|
539
|
+
}
|
|
540
|
+
});
|
|
541
|
+
return pending;
|
|
542
|
+
}
|
|
531
543
|
/**
|
|
532
544
|
* 注入审批记录(MCP 重启恢复用)
|
|
533
545
|
* 如果 taskId 已存在则跳过,避免覆盖用户已点击的结果
|
|
@@ -607,6 +619,24 @@ class WecomClient extends EventEmitter {
|
|
|
607
619
|
getPendingMessageCount() {
|
|
608
620
|
return this.pendingMessages.length;
|
|
609
621
|
}
|
|
622
|
+
/**
|
|
623
|
+
* 取出所有待发送的审批消息并清空队列(用于 client 迁移)
|
|
624
|
+
* 仅迁移 approval 类型,text 通知类消息不需要迁移
|
|
625
|
+
*/
|
|
626
|
+
takePendingApprovalMessages() {
|
|
627
|
+
const approvalMessages = this.pendingMessages.filter(m => m.type === 'approval');
|
|
628
|
+
this.pendingMessages = this.pendingMessages.filter(m => m.type !== 'approval');
|
|
629
|
+
return approvalMessages;
|
|
630
|
+
}
|
|
631
|
+
/**
|
|
632
|
+
* 注入待发送消息(用于 client 迁移,新 client 连接后会自动重发)
|
|
633
|
+
*/
|
|
634
|
+
injectPendingMessages(messages) {
|
|
635
|
+
if (messages.length === 0)
|
|
636
|
+
return;
|
|
637
|
+
this.pendingMessages.unshift(...messages);
|
|
638
|
+
logger.log(`[wecom] 注入待发送消息: ${messages.length} 条`);
|
|
639
|
+
}
|
|
610
640
|
// 获取重连状态
|
|
611
641
|
getReconnectStatus() {
|
|
612
642
|
return {
|
package/dist/config-wizard.js
CHANGED
|
@@ -444,13 +444,14 @@ if ! echo "$HEALTH" | jq -e '.status == "ok"' > /dev/null 2>&1; then
|
|
|
444
444
|
exit 0
|
|
445
445
|
fi
|
|
446
446
|
|
|
447
|
-
#
|
|
447
|
+
# 读取当前项目使用的机器人名称和 ccId
|
|
448
448
|
ROBOT_NAME=$(jq -r '.robotName // empty' "$CONFIG_FILE" 2>/dev/null)
|
|
449
|
+
CC_ID=$(jq -r '.ccId // empty' "$CONFIG_FILE" 2>/dev/null)
|
|
449
450
|
|
|
450
451
|
# 发送审批请求(使用 pwd 作为 projectDir)
|
|
451
452
|
TOOL_INPUT=$(echo "$INPUT" | jq -c '.tool_input // {}')
|
|
452
|
-
BODY=$(jq -n --arg tool_name "$TOOL_NAME" --argjson tool_input "$TOOL_INPUT" --arg project_dir "$PROJECT_DIR" --arg robot_name "$ROBOT_NAME" \\
|
|
453
|
-
'{"tool_name":$tool_name,"tool_input":$tool_input,"projectDir":$project_dir,"robotName":$robot_name}')
|
|
453
|
+
BODY=$(jq -n --arg tool_name "$TOOL_NAME" --argjson tool_input "$TOOL_INPUT" --arg project_dir "$PROJECT_DIR" --arg robot_name "$ROBOT_NAME" --arg cc_id "$CC_ID" \\
|
|
454
|
+
'{"tool_name":$tool_name,"tool_input":$tool_input,"projectDir":$project_dir,"robotName":$robot_name,"ccId":$cc_id}')
|
|
454
455
|
|
|
455
456
|
log_debug "[$(date)] Sending approval request..."
|
|
456
457
|
RESPONSE=$(curl -s -m 10 -X POST "http://127.0.0.1:$MCP_PORT/approve" \\
|
|
@@ -146,7 +146,22 @@ export async function getClient(robotName) {
|
|
|
146
146
|
const robot = await findRobotConfig(state.robotName);
|
|
147
147
|
if (robot) {
|
|
148
148
|
logger.log(`[connection] 重连机器人: ${robot.name}`);
|
|
149
|
+
const oldClient = state.client;
|
|
150
|
+
// 迁移旧 client 的未解决审批记录和待发送审批消息
|
|
151
|
+
const pendingApprovals = oldClient.getUnresolvedApprovalMap();
|
|
152
|
+
const pendingApprovalMessages = oldClient.takePendingApprovalMessages();
|
|
153
|
+
// 先断开旧 client,防止旧 client 重连后与新 client 并存导致事件分流
|
|
154
|
+
oldClient.disconnect();
|
|
149
155
|
state.client = new WecomClient(robot.botId, robot.secret, robot.targetUserId, robot.name);
|
|
156
|
+
// 注入审批记录,确保 Hook 轮询和用户点击仍能正常处理
|
|
157
|
+
pendingApprovals.forEach((approval, taskId) => {
|
|
158
|
+
state.client.injectApprovalRecord(taskId, {
|
|
159
|
+
toolName: approval.toolName,
|
|
160
|
+
toolInput: approval.toolInput,
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
// 注入待发送的审批卡片消息,新 client 连接后会自动重发
|
|
164
|
+
state.client.injectPendingMessages(pendingApprovalMessages);
|
|
150
165
|
state.client.connect();
|
|
151
166
|
const connected = await waitForConnection(state.client, 5000);
|
|
152
167
|
if (connected) {
|
package/dist/http-server.js
CHANGED
|
@@ -833,7 +833,7 @@ async function handleApprovalRequest(req, res) {
|
|
|
833
833
|
}
|
|
834
834
|
const title = `【待审批】${tool_name}`;
|
|
835
835
|
const requestId = `hook_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
836
|
-
const taskId = await client.sendApprovalRequest(title, description, requestId);
|
|
836
|
+
const taskId = await client.sendApprovalRequest(title, description, requestId, undefined, tool_input, ccId);
|
|
837
837
|
logger.log(`[http] 审批请求已发送: ${taskId} (机器人: ${robotName})`);
|
|
838
838
|
// 存储审批并启动超时计时器
|
|
839
839
|
const entry = {
|
|
@@ -873,6 +873,9 @@ function handleApprovalStatus(_req, res, url) {
|
|
|
873
873
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
874
874
|
res.end(JSON.stringify({ status: 'pending', result: 'pending' }));
|
|
875
875
|
}
|
|
876
|
+
}).catch(() => {
|
|
877
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
878
|
+
res.end(JSON.stringify({ status: 'pending', result: 'pending' }));
|
|
876
879
|
});
|
|
877
880
|
return;
|
|
878
881
|
}
|