@vrs-soft/wecom-aibot-mcp 2.4.23 → 2.4.25
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 +51 -3
- package/dist/config-wizard.js +53 -8
- package/package.json +1 -1
package/dist/channel-server.js
CHANGED
|
@@ -12,9 +12,50 @@
|
|
|
12
12
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
13
13
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
14
14
|
import { z } from 'zod';
|
|
15
|
+
import { execSync } from 'child_process';
|
|
15
16
|
import { VERSION, installSkill } from './config-wizard.js';
|
|
16
17
|
import { addPermissionHook, registerActiveProject, unregisterActiveProject, updateWechatModeConfig } from './project-config.js';
|
|
17
18
|
import { logger } from './logger.js';
|
|
19
|
+
/**
|
|
20
|
+
* 沿进程树向上查找 Claude Code TUI 的 PID。
|
|
21
|
+
*
|
|
22
|
+
* 背景:本地 dev (`command: "node"`) 时 channel-server 是 Claude TUI 的直接子进程,
|
|
23
|
+
* process.ppid = Claude TUI ✓
|
|
24
|
+
* 但 npx 部署 (`command: "npx"`) 时多了一层 npx:
|
|
25
|
+
* Claude TUI → npx → node bin.js (channel-server)
|
|
26
|
+
* process.ppid = npx ❌
|
|
27
|
+
* permission-hook.sh 从 hook 自身向上查 active-projects.json 时只能命中 Claude TUI
|
|
28
|
+
* 这条祖先链。如果注册的是 npx 的 PID,hook 永远找不到 → 静默 exit 0 → 跳过审批。
|
|
29
|
+
*
|
|
30
|
+
* 此函数从 startPid 起向上遍历,找到第一个命令名为 "claude" 的进程,返回其 PID。
|
|
31
|
+
* 找不到时回退到 startPid(保持旧行为,至少 dev 场景不退化)。
|
|
32
|
+
*/
|
|
33
|
+
function findClaudePid(startPid) {
|
|
34
|
+
let pid = startPid;
|
|
35
|
+
for (let i = 0; i < 8; i++) {
|
|
36
|
+
if (!pid || pid <= 1)
|
|
37
|
+
break;
|
|
38
|
+
try {
|
|
39
|
+
const comm = execSync(`ps -p ${pid} -o comm=`, { stdio: ['ignore', 'pipe', 'ignore'] })
|
|
40
|
+
.toString()
|
|
41
|
+
.trim();
|
|
42
|
+
// ps comm= 返回执行文件 basename。Claude Code TUI 安装名就是 "claude"
|
|
43
|
+
if (comm === 'claude' || comm.endsWith('/claude'))
|
|
44
|
+
return pid;
|
|
45
|
+
const ppidStr = execSync(`ps -p ${pid} -o ppid=`, { stdio: ['ignore', 'pipe', 'ignore'] })
|
|
46
|
+
.toString()
|
|
47
|
+
.trim();
|
|
48
|
+
const ppid = parseInt(ppidStr, 10);
|
|
49
|
+
if (!ppid || ppid === pid)
|
|
50
|
+
break;
|
|
51
|
+
pid = ppid;
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return startPid;
|
|
58
|
+
}
|
|
18
59
|
const MCP_URL = process.env.MCP_URL || 'http://127.0.0.1:18963';
|
|
19
60
|
const MCP_AUTH_TOKEN = process.env.MCP_AUTH_TOKEN;
|
|
20
61
|
// 构建带 auth 的 fetch headers
|
|
@@ -437,9 +478,16 @@ function registerChannelTools(server) {
|
|
|
437
478
|
const localProjectDir = project_dir || process.cwd();
|
|
438
479
|
const hookResult = addPermissionHook(localProjectDir);
|
|
439
480
|
logger.info('本地 PermissionRequest hook 已写入', { path: hookResult.path, success: hookResult.success });
|
|
440
|
-
//
|
|
441
|
-
|
|
442
|
-
|
|
481
|
+
// 注册 Claude TUI 的 PID(不能用 process.ppid,npx 部署时 ppid 是 npx 不是 Claude)
|
|
482
|
+
const startPid = process.ppid ?? process.pid;
|
|
483
|
+
const claudePid = findClaudePid(startPid);
|
|
484
|
+
registerActiveProject(claudePid, localProjectDir);
|
|
485
|
+
logger.info('本地 active-projects 已注册', {
|
|
486
|
+
pid: claudePid,
|
|
487
|
+
rawPpid: startPid,
|
|
488
|
+
resolvedClaudePid: claudePid !== startPid,
|
|
489
|
+
projectDir: localProjectDir,
|
|
490
|
+
});
|
|
443
491
|
// 写入本地 wecom-aibot.json(远程 HTTP MCP 写在远端 fs,agent 本地需要自己落地)
|
|
444
492
|
updateWechatModeConfig(localProjectDir, {
|
|
445
493
|
wechatMode: true,
|
package/dist/config-wizard.js
CHANGED
|
@@ -1450,25 +1450,70 @@ export async function runConfigWizard() {
|
|
|
1450
1450
|
docMcpUrl = currentDocUrl;
|
|
1451
1451
|
console.log('[config] 保持原文档 MCP URL');
|
|
1452
1452
|
}
|
|
1453
|
-
//
|
|
1453
|
+
// 第六步:目标用户(默认联系人)
|
|
1454
|
+
// 修改场景:询问是否要重新识别;选 Y 则连接 bot 等待用户消息(与 --add 一致);选 N 保持原值
|
|
1455
|
+
let targetUserId = targetRobot?.targetUserId || '';
|
|
1456
|
+
if (targetRobot) {
|
|
1457
|
+
console.log(`\n当前默认联系人(targetUserId): ${targetUserId || '(未设置)'}`);
|
|
1458
|
+
const changeContact = await question(rl, '是否重新识别?(y/N): ');
|
|
1459
|
+
if (changeContact.toLowerCase() === 'y') {
|
|
1460
|
+
// 临时连接 bot 等待用户消息以识别 userid
|
|
1461
|
+
console.log('\n[config] 正在连接企业微信验证凭证...');
|
|
1462
|
+
const { initClient } = await import('./client.js');
|
|
1463
|
+
const tmpClient = initClient(botId, secret, 'placeholder', 'config-detect');
|
|
1464
|
+
// 等待连接(最多10秒)
|
|
1465
|
+
const connected = await new Promise((resolve) => {
|
|
1466
|
+
const start = Date.now();
|
|
1467
|
+
const iv = setInterval(() => {
|
|
1468
|
+
if (tmpClient.isConnected()) {
|
|
1469
|
+
clearInterval(iv);
|
|
1470
|
+
resolve(true);
|
|
1471
|
+
}
|
|
1472
|
+
else if (Date.now() - start > 10000) {
|
|
1473
|
+
clearInterval(iv);
|
|
1474
|
+
resolve(false);
|
|
1475
|
+
}
|
|
1476
|
+
}, 500);
|
|
1477
|
+
});
|
|
1478
|
+
if (!connected) {
|
|
1479
|
+
console.log('[config] ❌ 连接失败(Bot ID/Secret 可能有误),保持原默认联系人');
|
|
1480
|
+
tmpClient.disconnect();
|
|
1481
|
+
}
|
|
1482
|
+
else {
|
|
1483
|
+
const detectedUserId = await detectUserIdFromMessage(tmpClient, 180);
|
|
1484
|
+
tmpClient.disconnect();
|
|
1485
|
+
if (detectedUserId) {
|
|
1486
|
+
targetUserId = detectedUserId;
|
|
1487
|
+
console.log(`[config] ✅ 默认联系人已更新: ${targetUserId}`);
|
|
1488
|
+
}
|
|
1489
|
+
else {
|
|
1490
|
+
console.log('[config] 未识别到用户消息,保持原默认联系人');
|
|
1491
|
+
}
|
|
1492
|
+
}
|
|
1493
|
+
}
|
|
1494
|
+
else {
|
|
1495
|
+
console.log('[config] 保持原默认联系人');
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1498
|
+
// 第七步:确认
|
|
1454
1499
|
console.log('\n─────────────────────────────────────');
|
|
1455
1500
|
console.log('配置确认:');
|
|
1456
|
-
console.log(` 机器人名称:
|
|
1457
|
-
console.log(` Bot ID:
|
|
1458
|
-
console.log(` Secret:
|
|
1459
|
-
console.log(` 文档 MCP:
|
|
1460
|
-
console.log(`
|
|
1501
|
+
console.log(` 机器人名称: ${robotName}`);
|
|
1502
|
+
console.log(` Bot ID: ${botId}`);
|
|
1503
|
+
console.log(` Secret: ${secret.slice(0, 8)}...${secret.slice(-4)}`);
|
|
1504
|
+
console.log(` 文档 MCP: ${docMcpUrl ? '✅ 已配置' : '(未配置)'}`);
|
|
1505
|
+
console.log(` 默认联系人: ${targetUserId || '(将通过消息自动识别)'}`);
|
|
1461
1506
|
console.log('─────────────────────────────────────\n');
|
|
1462
1507
|
const confirm = await question(rl, '确认配置?(Y/n): ');
|
|
1463
1508
|
if (confirm.toLowerCase() === 'n') {
|
|
1464
1509
|
console.log('[config] 配置已取消');
|
|
1465
1510
|
process.exit(0);
|
|
1466
1511
|
}
|
|
1467
|
-
//
|
|
1512
|
+
// 返回最终配置
|
|
1468
1513
|
const config = {
|
|
1469
1514
|
botId,
|
|
1470
1515
|
secret,
|
|
1471
|
-
targetUserId
|
|
1516
|
+
targetUserId, // 修改时保留 / 已变更,新建时为空(稍后识别)
|
|
1472
1517
|
nameTag: robotName,
|
|
1473
1518
|
...(docMcpUrl ? { doc_mcp_url: docMcpUrl } : {}),
|
|
1474
1519
|
};
|