@vrs-soft/wecom-aibot-mcp 2.4.24 → 2.4.26
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/bin.js +20 -5
- package/dist/config-wizard.d.ts +9 -1
- package/dist/config-wizard.js +105 -14
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -13,7 +13,7 @@ import { spawn, execSync } from 'child_process';
|
|
|
13
13
|
import * as fs from 'fs';
|
|
14
14
|
import * as path from 'path';
|
|
15
15
|
import * as os from 'os';
|
|
16
|
-
import { runConfigWizard, loadConfig, saveConfig, deleteRobotConfigInteractive, uninstall, addMcpConfig, detectUserIdFromMessage, ensureHookInstalled, listAllRobots, ensureGlobalConfigs, getAuthToken, setAuthToken, getHttpsConfig, setHttpsConfig, updateMcpAuthHeaders, runRemoteInstallWizard, VERSION, } from './config-wizard.js';
|
|
16
|
+
import { runConfigWizard, loadConfig, saveConfig, deleteRobotConfigInteractive, uninstall, addMcpConfig, detectUserIdFromMessage, ensureHookInstalled, listAllRobots, ensureGlobalConfigs, getInstalledMode, getAuthToken, setAuthToken, getHttpsConfig, setHttpsConfig, updateMcpAuthHeaders, runRemoteInstallWizard, VERSION, } from './config-wizard.js';
|
|
17
17
|
import { initClient } from './client.js';
|
|
18
18
|
import { registerTools } from './tools/index.js';
|
|
19
19
|
import { startHttpServer, stopHttpServer, HTTP_PORT } from './http-server.js';
|
|
@@ -373,9 +373,14 @@ function startMcpServerBackground() {
|
|
|
373
373
|
}
|
|
374
374
|
async function main() {
|
|
375
375
|
const args = process.argv.slice(2);
|
|
376
|
-
//
|
|
377
|
-
const
|
|
378
|
-
args.includes('--channel-only') ? 'channel-only' :
|
|
376
|
+
// 确定安装模式:优先 CLI flag,其次复用 version.json 里上次的 mode(保持 remote / channel-only 等模式不被 --upgrade 打回 full)
|
|
377
|
+
const explicitMode = args.includes('--http-only') ? 'http-only' :
|
|
378
|
+
args.includes('--channel-only') ? 'channel-only' : undefined;
|
|
379
|
+
const prior = getInstalledMode();
|
|
380
|
+
const installMode = explicitMode || prior.mode || 'full';
|
|
381
|
+
const remoteOptions = (installMode === 'remote' || installMode === 'remote-channel') && prior.remote?.url
|
|
382
|
+
? { url: prior.remote.url, token: prior.remote.token || '' }
|
|
383
|
+
: undefined;
|
|
379
384
|
// 以下命令跳过顶部 ensureGlobalConfigs,避免覆盖配置
|
|
380
385
|
// --setup: 向导完成后自己调用
|
|
381
386
|
// --channel: 作为 Channel MCP 代理运行,不应改写全局配置
|
|
@@ -390,7 +395,17 @@ async function main() {
|
|
|
390
395
|
args.includes('--clean-cache') || args.includes('--set-token') || args.includes('--config');
|
|
391
396
|
if (!skipEnsure) {
|
|
392
397
|
// 强制覆盖所有全局配置(不依赖智能体)
|
|
393
|
-
|
|
398
|
+
if (installMode === 'remote' || installMode === 'remote-channel') {
|
|
399
|
+
if (remoteOptions) {
|
|
400
|
+
ensureGlobalConfigs(installMode, remoteOptions);
|
|
401
|
+
}
|
|
402
|
+
else {
|
|
403
|
+
console.log(`[mcp] 检测到上次安装模式 ${installMode},但缺少远程参数;跳过配置写入。如需变更请使用 --setup`);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
else {
|
|
407
|
+
ensureGlobalConfigs(installMode);
|
|
408
|
+
}
|
|
394
409
|
}
|
|
395
410
|
// 解析命令行参数
|
|
396
411
|
if (args.includes('--help') || args.includes('-h')) {
|
package/dist/config-wizard.d.ts
CHANGED
|
@@ -40,7 +40,15 @@ export declare function getDocMcpUrl(robotName?: string): {
|
|
|
40
40
|
error?: string;
|
|
41
41
|
};
|
|
42
42
|
export declare function ensureHookInstalled(): void;
|
|
43
|
-
export
|
|
43
|
+
export type InstallMode = 'full' | 'http-only' | 'channel-only' | 'remote' | 'remote-channel';
|
|
44
|
+
export declare function getInstalledMode(): {
|
|
45
|
+
mode?: InstallMode;
|
|
46
|
+
remote?: {
|
|
47
|
+
url: string;
|
|
48
|
+
token?: string;
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
export declare function ensureGlobalConfigs(mode?: InstallMode, remoteOptions?: {
|
|
44
52
|
url: string;
|
|
45
53
|
token: string;
|
|
46
54
|
}): {
|
package/dist/config-wizard.js
CHANGED
|
@@ -177,10 +177,19 @@ export function deleteConfig() {
|
|
|
177
177
|
if (fs.existsSync(CLAUDE_CONFIG_FILE)) {
|
|
178
178
|
const content = fs.readFileSync(CLAUDE_CONFIG_FILE, 'utf-8');
|
|
179
179
|
const claudeConfig = JSON.parse(content);
|
|
180
|
+
let changed = false;
|
|
180
181
|
if (claudeConfig.mcpServers?.['wecom-aibot']) {
|
|
181
182
|
delete claudeConfig.mcpServers['wecom-aibot'];
|
|
182
|
-
fs.writeFileSync(CLAUDE_CONFIG_FILE, JSON.stringify(claudeConfig, null, 2));
|
|
183
183
|
console.log('[config] 已从 ~/.claude.json 删除 wecom-aibot 配置');
|
|
184
|
+
changed = true;
|
|
185
|
+
}
|
|
186
|
+
if (claudeConfig.mcpServers?.['wecom-aibot-channel']) {
|
|
187
|
+
delete claudeConfig.mcpServers['wecom-aibot-channel'];
|
|
188
|
+
console.log('[config] 已从 ~/.claude.json 删除 wecom-aibot-channel 配置');
|
|
189
|
+
changed = true;
|
|
190
|
+
}
|
|
191
|
+
if (changed) {
|
|
192
|
+
fs.writeFileSync(CLAUDE_CONFIG_FILE, JSON.stringify(claudeConfig, null, 2));
|
|
184
193
|
}
|
|
185
194
|
}
|
|
186
195
|
}
|
|
@@ -194,14 +203,27 @@ export function deleteHook() {
|
|
|
194
203
|
if (fs.existsSync(CLAUDE_SETTINGS_FILE)) {
|
|
195
204
|
const content = fs.readFileSync(CLAUDE_SETTINGS_FILE, 'utf-8');
|
|
196
205
|
const settings = JSON.parse(content);
|
|
206
|
+
let changed = false;
|
|
197
207
|
if (settings.hooks && settings.hooks['PermissionRequest']) {
|
|
198
208
|
// 只删除 wecom-aibot 相关的 hook
|
|
199
209
|
settings.hooks['PermissionRequest'] = settings.hooks['PermissionRequest'].filter((hook) => !hook.hooks?.some?.((h) => h.command?.includes?.('wecom-aibot-mcp')));
|
|
200
210
|
if (settings.hooks['PermissionRequest'].length === 0) {
|
|
201
211
|
delete settings.hooks['PermissionRequest'];
|
|
202
212
|
}
|
|
203
|
-
fs.writeFileSync(CLAUDE_SETTINGS_FILE, JSON.stringify(settings, null, 2));
|
|
204
213
|
console.log('[config] 已删除 PermissionRequest hook');
|
|
214
|
+
changed = true;
|
|
215
|
+
}
|
|
216
|
+
// 移除 wecom-aibot 相关的 MCP 权限
|
|
217
|
+
if (Array.isArray(settings.permissions?.allow)) {
|
|
218
|
+
const before = settings.permissions.allow.length;
|
|
219
|
+
settings.permissions.allow = settings.permissions.allow.filter((p) => !/^mcp__wecom-aibot(-channel)?__/.test(p));
|
|
220
|
+
if (settings.permissions.allow.length !== before) {
|
|
221
|
+
console.log(`[config] 已移除 ${before - settings.permissions.allow.length} 条 wecom-aibot MCP 权限`);
|
|
222
|
+
changed = true;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
if (changed) {
|
|
226
|
+
fs.writeFileSync(CLAUDE_SETTINGS_FILE, JSON.stringify(settings, null, 2));
|
|
205
227
|
}
|
|
206
228
|
// 删除 hook 脚本文件
|
|
207
229
|
if (fs.existsSync(HOOK_SCRIPT_PATH)) {
|
|
@@ -1064,6 +1086,30 @@ export function ensureHookInstalled() {
|
|
|
1064
1086
|
writeMcpPermissions();
|
|
1065
1087
|
writeStopHookScript();
|
|
1066
1088
|
}
|
|
1089
|
+
// 读取上次安装的模式 + 远程参数(来自 version.json)
|
|
1090
|
+
export function getInstalledMode() {
|
|
1091
|
+
if (!fs.existsSync(VERSION_FILE))
|
|
1092
|
+
return {};
|
|
1093
|
+
try {
|
|
1094
|
+
const data = JSON.parse(fs.readFileSync(VERSION_FILE, 'utf-8'));
|
|
1095
|
+
const result = {};
|
|
1096
|
+
if (data.mode)
|
|
1097
|
+
result.mode = data.mode;
|
|
1098
|
+
if (data.remote?.url)
|
|
1099
|
+
result.remote = { url: data.remote.url, token: data.remote.token };
|
|
1100
|
+
return result;
|
|
1101
|
+
}
|
|
1102
|
+
catch {
|
|
1103
|
+
return {};
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
// 写 version.json(统一入口,记录 mode + 远程参数,用于后续 --upgrade 复用)
|
|
1107
|
+
function writeVersionFile(mode, remoteOptions) {
|
|
1108
|
+
const payload = { version: VERSION, installedAt: Date.now(), mode };
|
|
1109
|
+
if (remoteOptions?.url)
|
|
1110
|
+
payload.remote = { url: remoteOptions.url, ...(remoteOptions.token ? { token: remoteOptions.token } : {}) };
|
|
1111
|
+
fs.writeFileSync(VERSION_FILE, JSON.stringify(payload, null, 2));
|
|
1112
|
+
}
|
|
1067
1113
|
// 确保所有全局配置已写入(强制覆盖,不依赖智能体)
|
|
1068
1114
|
export function ensureGlobalConfigs(mode = 'full', remoteOptions) {
|
|
1069
1115
|
ensureConfigDir();
|
|
@@ -1085,7 +1131,7 @@ export function ensureGlobalConfigs(mode = 'full', remoteOptions) {
|
|
|
1085
1131
|
// 只写权限配置和 Hook(可选,用于本地调试)
|
|
1086
1132
|
writeMcpPermissions();
|
|
1087
1133
|
console.log('[config] 已写入权限配置到 ~/.claude/settings.local.json');
|
|
1088
|
-
|
|
1134
|
+
writeVersionFile(mode);
|
|
1089
1135
|
return { upgraded, previousVersion };
|
|
1090
1136
|
}
|
|
1091
1137
|
// remote 模式:仅写入远程 HTTP MCP 配置(带 token headers),不装 Channel/Hook
|
|
@@ -1108,7 +1154,7 @@ export function ensureGlobalConfigs(mode = 'full', remoteOptions) {
|
|
|
1108
1154
|
};
|
|
1109
1155
|
fs.writeFileSync(CLAUDE_CONFIG_FILE, JSON.stringify(claudeConfig, null, 2));
|
|
1110
1156
|
console.log('[config] remote 模式:已写入远程 HTTP MCP 配置(带 Token)');
|
|
1111
|
-
|
|
1157
|
+
writeVersionFile(mode, remoteOptions);
|
|
1112
1158
|
return { upgraded, previousVersion };
|
|
1113
1159
|
}
|
|
1114
1160
|
// remote-channel 模式:远程部署的 Channel 客户端——只写 Channel MCP,不写 HTTP MCP
|
|
@@ -1143,7 +1189,7 @@ export function ensureGlobalConfigs(mode = 'full', remoteOptions) {
|
|
|
1143
1189
|
// Channel 模式需要权限配置
|
|
1144
1190
|
writeMcpPermissions();
|
|
1145
1191
|
console.log('[config] 已写入权限配置到 ~/.claude/settings.local.json');
|
|
1146
|
-
|
|
1192
|
+
writeVersionFile(mode, remoteOptions);
|
|
1147
1193
|
return { upgraded, previousVersion };
|
|
1148
1194
|
}
|
|
1149
1195
|
// 1. 强制写入 MCP 配置到 ~/.claude.json
|
|
@@ -1211,7 +1257,7 @@ export function ensureGlobalConfigs(mode = 'full', remoteOptions) {
|
|
|
1211
1257
|
writeMcpPermissions();
|
|
1212
1258
|
console.log('[config] 已写入权限配置到 ~/.claude/settings.local.json');
|
|
1213
1259
|
// 3. 写入版本号
|
|
1214
|
-
|
|
1260
|
+
writeVersionFile(mode);
|
|
1215
1261
|
console.log(`[config] 已记录版本号: ${VERSION}`);
|
|
1216
1262
|
return { upgraded, previousVersion };
|
|
1217
1263
|
}
|
|
@@ -1450,25 +1496,70 @@ export async function runConfigWizard() {
|
|
|
1450
1496
|
docMcpUrl = currentDocUrl;
|
|
1451
1497
|
console.log('[config] 保持原文档 MCP URL');
|
|
1452
1498
|
}
|
|
1453
|
-
//
|
|
1499
|
+
// 第六步:目标用户(默认联系人)
|
|
1500
|
+
// 修改场景:询问是否要重新识别;选 Y 则连接 bot 等待用户消息(与 --add 一致);选 N 保持原值
|
|
1501
|
+
let targetUserId = targetRobot?.targetUserId || '';
|
|
1502
|
+
if (targetRobot) {
|
|
1503
|
+
console.log(`\n当前默认联系人(targetUserId): ${targetUserId || '(未设置)'}`);
|
|
1504
|
+
const changeContact = await question(rl, '是否重新识别?(y/N): ');
|
|
1505
|
+
if (changeContact.toLowerCase() === 'y') {
|
|
1506
|
+
// 临时连接 bot 等待用户消息以识别 userid
|
|
1507
|
+
console.log('\n[config] 正在连接企业微信验证凭证...');
|
|
1508
|
+
const { initClient } = await import('./client.js');
|
|
1509
|
+
const tmpClient = initClient(botId, secret, 'placeholder', 'config-detect');
|
|
1510
|
+
// 等待连接(最多10秒)
|
|
1511
|
+
const connected = await new Promise((resolve) => {
|
|
1512
|
+
const start = Date.now();
|
|
1513
|
+
const iv = setInterval(() => {
|
|
1514
|
+
if (tmpClient.isConnected()) {
|
|
1515
|
+
clearInterval(iv);
|
|
1516
|
+
resolve(true);
|
|
1517
|
+
}
|
|
1518
|
+
else if (Date.now() - start > 10000) {
|
|
1519
|
+
clearInterval(iv);
|
|
1520
|
+
resolve(false);
|
|
1521
|
+
}
|
|
1522
|
+
}, 500);
|
|
1523
|
+
});
|
|
1524
|
+
if (!connected) {
|
|
1525
|
+
console.log('[config] ❌ 连接失败(Bot ID/Secret 可能有误),保持原默认联系人');
|
|
1526
|
+
tmpClient.disconnect();
|
|
1527
|
+
}
|
|
1528
|
+
else {
|
|
1529
|
+
const detectedUserId = await detectUserIdFromMessage(tmpClient, 180);
|
|
1530
|
+
tmpClient.disconnect();
|
|
1531
|
+
if (detectedUserId) {
|
|
1532
|
+
targetUserId = detectedUserId;
|
|
1533
|
+
console.log(`[config] ✅ 默认联系人已更新: ${targetUserId}`);
|
|
1534
|
+
}
|
|
1535
|
+
else {
|
|
1536
|
+
console.log('[config] 未识别到用户消息,保持原默认联系人');
|
|
1537
|
+
}
|
|
1538
|
+
}
|
|
1539
|
+
}
|
|
1540
|
+
else {
|
|
1541
|
+
console.log('[config] 保持原默认联系人');
|
|
1542
|
+
}
|
|
1543
|
+
}
|
|
1544
|
+
// 第七步:确认
|
|
1454
1545
|
console.log('\n─────────────────────────────────────');
|
|
1455
1546
|
console.log('配置确认:');
|
|
1456
|
-
console.log(` 机器人名称:
|
|
1457
|
-
console.log(` Bot ID:
|
|
1458
|
-
console.log(` Secret:
|
|
1459
|
-
console.log(` 文档 MCP:
|
|
1460
|
-
console.log(`
|
|
1547
|
+
console.log(` 机器人名称: ${robotName}`);
|
|
1548
|
+
console.log(` Bot ID: ${botId}`);
|
|
1549
|
+
console.log(` Secret: ${secret.slice(0, 8)}...${secret.slice(-4)}`);
|
|
1550
|
+
console.log(` 文档 MCP: ${docMcpUrl ? '✅ 已配置' : '(未配置)'}`);
|
|
1551
|
+
console.log(` 默认联系人: ${targetUserId || '(将通过消息自动识别)'}`);
|
|
1461
1552
|
console.log('─────────────────────────────────────\n');
|
|
1462
1553
|
const confirm = await question(rl, '确认配置?(Y/n): ');
|
|
1463
1554
|
if (confirm.toLowerCase() === 'n') {
|
|
1464
1555
|
console.log('[config] 配置已取消');
|
|
1465
1556
|
process.exit(0);
|
|
1466
1557
|
}
|
|
1467
|
-
//
|
|
1558
|
+
// 返回最终配置
|
|
1468
1559
|
const config = {
|
|
1469
1560
|
botId,
|
|
1470
1561
|
secret,
|
|
1471
|
-
targetUserId
|
|
1562
|
+
targetUserId, // 修改时保留 / 已变更,新建时为空(稍后识别)
|
|
1472
1563
|
nameTag: robotName,
|
|
1473
1564
|
...(docMcpUrl ? { doc_mcp_url: docMcpUrl } : {}),
|
|
1474
1565
|
};
|