@vrs-soft/wecom-aibot-mcp 3.3.1 → 3.3.3

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.
@@ -16,7 +16,7 @@ import * as fs from 'fs';
16
16
  import * as path from 'path';
17
17
  import { execSync } from 'child_process';
18
18
  import { VERSION, installSkill } from './config-wizard.js';
19
- import { addPermissionHook, registerActiveProject, unregisterActiveProject, updateWechatModeConfig } from './project-config.js';
19
+ import { addPermissionHook, registerActiveProject, unregisterActiveProject, updateWechatModeConfig, loadWechatModeConfig } from './project-config.js';
20
20
  import { logger } from './logger.js';
21
21
  /**
22
22
  * 沿进程树向上查找 Claude Code TUI 的 PID。
@@ -847,12 +847,24 @@ function registerChannelTools(server) {
847
847
  .describe('运行模式:channel=SSE推送(推荐),http=轮询(兼容)'),
848
848
  auto_approve_timeout: z.number().optional().default(600).describe('超时自动决策等待时间(秒,默认 600 即 10 分钟)'),
849
849
  }, async ({ agent_name, cc_id, robot_id, project_dir, mode, auto_approve_timeout }) => {
850
+ // v3.3.2: 远端 daemon 看不到本地 .claude/wecom-aibot.json,无法走 existingConfig 复用 ccId 的路径。
851
+ // 这里在 channel-server 本地读保存的 ccId,没有传入 cc_id 时自动塞进去 —— 避免每次 enter
852
+ // 都因 stale registry entry 撞冲突,生成 商务机器人-2 / -3 之类的奇怪 ccId。
853
+ const effectiveProjectDir = project_dir || process.cwd();
854
+ let effectiveCcId = cc_id;
855
+ if (!effectiveCcId) {
856
+ const saved = loadWechatModeConfig(effectiveProjectDir);
857
+ if (saved?.ccId) {
858
+ effectiveCcId = saved.ccId;
859
+ logger.info('reuse saved ccId from local wecom-aibot.json', { projectDir: effectiveProjectDir, ccId: saved.ccId });
860
+ }
861
+ }
850
862
  // 转发请求
851
863
  const result = await forwardToHttpMcp('enter_headless_mode', {
852
864
  agent_name,
853
- cc_id,
865
+ cc_id: effectiveCcId,
854
866
  robot_id,
855
- project_dir: project_dir || process.cwd(),
867
+ project_dir: effectiveProjectDir,
856
868
  mode,
857
869
  auto_approve_timeout,
858
870
  });
@@ -271,6 +271,9 @@ fi
271
271
  MODE=$(jq -r '.mode // "http"' "$CONFIG_FILE" 2>/dev/null)
272
272
  MCP_BASE_URL="http://127.0.0.1:$MCP_PORT"
273
273
  AUTH_ARGS=()
274
+ # v3.3.3: 远端 daemon 用自签 / Let's Encrypt cert 时若过期或被信任链拒绝,会让 curl 静默失败。
275
+ # hook 已经用 Bearer token 鉴权,TLS 只是传输加密,因此 https URL 一律加 -k 跳过 cert 校验。
276
+ TLS_OPTS=()
274
277
 
275
278
  _try_remote() {
276
279
  CLAUDE_JSON="$HOME/.claude.json"
@@ -284,7 +287,11 @@ _try_remote() {
284
287
  log_debug "[$(date)] No remote URL configured, exit 0"
285
288
  exit 0
286
289
  fi
287
- REMOTE_HEALTH=$(curl -s -m 5 \${REMOTE_TOKEN:+-H "Authorization: Bearer $REMOTE_TOKEN"} "$REMOTE_URL/health" 2>/dev/null)
290
+ # v3.3.3: 远端 https -k cert 校验(cert 过期/不可信不再卡死 hook)
291
+ if [[ "$REMOTE_URL" == https://* ]]; then
292
+ TLS_OPTS=(-k)
293
+ fi
294
+ REMOTE_HEALTH=$(curl -s -m 5 "\${TLS_OPTS[@]}" \${REMOTE_TOKEN:+-H "Authorization: Bearer $REMOTE_TOKEN"} "$REMOTE_URL/health" 2>/dev/null)
288
295
  log_debug "[$(date)] Remote health check ($REMOTE_URL): $REMOTE_HEALTH"
289
296
  if echo "$REMOTE_HEALTH" | jq -e '.status == "ok"' > /dev/null 2>&1; then
290
297
  MCP_BASE_URL="$REMOTE_URL"
@@ -320,7 +327,7 @@ BODY=$(jq -n --arg tool_name "$TOOL_NAME" --argjson tool_input "$TOOL_INPUT" --a
320
327
  '{"tool_name":$tool_name,"tool_input":$tool_input,"projectDir":$project_dir,"robotName":$robot_name,"ccId":$cc_id}')
321
328
 
322
329
  log_debug "[$(date)] Sending approval request..."
323
- RESPONSE=$(curl -s -m 10 -X POST "$MCP_BASE_URL/approve" \\
330
+ RESPONSE=$(curl -s -m 10 "\${TLS_OPTS[@]}" -X POST "$MCP_BASE_URL/approve" \\
324
331
  "\${AUTH_ARGS[@]}" \\
325
332
  -H "Content-Type: application/json" \\
326
333
  -d "$BODY")
@@ -350,7 +357,7 @@ while [[ $POLL_COUNT -lt $MAX_POLL ]]; do
350
357
  sleep 2
351
358
  POLL_COUNT=$((POLL_COUNT + 1))
352
359
 
353
- STATUS=$(curl -s -m 3 "\${AUTH_ARGS[@]}" "$MCP_BASE_URL/approval_status/$TASK_ID" 2>/dev/null)
360
+ STATUS=$(curl -s -m 3 "\${TLS_OPTS[@]}" "\${AUTH_ARGS[@]}" "$MCP_BASE_URL/approval_status/$TASK_ID" 2>/dev/null)
354
361
  RESULT=$(echo "$STATUS" | jq -r '.result // empty')
355
362
  log_debug "[$(date)] Poll $POLL_COUNT/$MAX_POLL: result=$RESULT"
356
363
 
@@ -388,7 +395,7 @@ log_debug "[$(date)] IS_DELETE: $IS_DELETE"
388
395
  if [[ $IS_DELETE -eq 1 ]]; then
389
396
  log_debug "[$(date)] Auto-deny: delete operation"
390
397
  # 通知 MCP Server 发送微信消息
391
- curl -s -m 5 -X POST "$MCP_BASE_URL/approval_timeout/$TASK_ID" "\${AUTH_ARGS[@]}" -H "Content-Type: application/json" -d '{"result":"deny","reason":"超时自动拒绝:删除操作需人工确认"}' > /dev/null 2>&1 &
398
+ curl -s -m 5 "\${TLS_OPTS[@]}" -X POST "$MCP_BASE_URL/approval_timeout/$TASK_ID" "\${AUTH_ARGS[@]}" -H "Content-Type: application/json" -d '{"result":"deny","reason":"超时自动拒绝:删除操作需人工确认"}' > /dev/null 2>&1 &
392
399
  printf '%s\\n' '{"hookSpecificOutput":{"hookEventName":"PermissionRequest","decision":{"behavior":"deny","message":"超时自动拒绝:删除操作需人工确认"}}}'
393
400
  exit 0
394
401
  fi
@@ -449,12 +456,12 @@ log_debug "[$(date)] IS_IN_PROJECT: $IS_IN_PROJECT"
449
456
  if [[ $IS_IN_PROJECT -eq 1 ]]; then
450
457
  log_debug "[$(date)] Auto-allow: project operation"
451
458
  # 通知 MCP Server 发送微信消息
452
- curl -s -m 5 -X POST "$MCP_BASE_URL/approval_timeout/$TASK_ID" "\${AUTH_ARGS[@]}" -H "Content-Type: application/json" -d '{"result":"allow-once","reason":"超时自动允许:项目内操作"}' > /dev/null 2>&1 &
459
+ curl -s -m 5 "\${TLS_OPTS[@]}" -X POST "$MCP_BASE_URL/approval_timeout/$TASK_ID" "\${AUTH_ARGS[@]}" -H "Content-Type: application/json" -d '{"result":"allow-once","reason":"超时自动允许:项目内操作"}' > /dev/null 2>&1 &
453
460
  printf '%s\\n' '{"hookSpecificOutput":{"hookEventName":"PermissionRequest","decision":{"behavior":"allow","message":"超时自动允许:项目内操作"}}}'
454
461
  else
455
462
  log_debug "[$(date)] Auto-deny: outside project"
456
463
  # 通知 MCP Server 发送微信消息
457
- curl -s -m 5 -X POST "$MCP_BASE_URL/approval_timeout/$TASK_ID" "\${AUTH_ARGS[@]}" -H "Content-Type: application/json" -d '{"result":"deny","reason":"超时自动拒绝:项目外操作需人工确认"}' > /dev/null 2>&1 &
464
+ curl -s -m 5 "\${TLS_OPTS[@]}" -X POST "$MCP_BASE_URL/approval_timeout/$TASK_ID" "\${AUTH_ARGS[@]}" -H "Content-Type: application/json" -d '{"result":"deny","reason":"超时自动拒绝:项目外操作需人工确认"}' > /dev/null 2>&1 &
458
465
  printf '%s\\n' '{"hookSpecificOutput":{"hookEventName":"PermissionRequest","decision":{"behavior":"deny","message":"超时自动拒绝:项目外操作需人工确认"}}}'
459
466
  fi
460
467
  `;
package/dist/logger.js CHANGED
@@ -89,12 +89,14 @@ function write(level, msg, data) {
89
89
  // 写文件失败不抛
90
90
  }
91
91
  }
92
- // 控制台
92
+ // 控制台 —— **stdio MCP server 的 stdout 是 JSON-RPC 协议管道,绝不能写非协议内容**
93
+ // 否则 Claude TUI 解析失败 → 判定 disconnect → channel mcp 不断中断。
94
+ // 任何级别的日志一律走 stderr。
93
95
  if (level === 'error') {
94
96
  process.stderr.write(entry);
95
97
  }
96
98
  else if (debugMode) {
97
- process.stdout.write(entry);
99
+ process.stderr.write(entry);
98
100
  }
99
101
  }
100
102
  // 公共 API
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vrs-soft/wecom-aibot-mcp",
3
- "version": "3.3.1",
3
+ "version": "3.3.3",
4
4
  "description": "企业微信智能机器人 MCP 客户端 - 连接 wecom-aibot-server daemon",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",