@vrs-soft/wecom-aibot-mcp 1.0.2 → 1.0.4
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 +133 -1
- package/dist/bin.js +99 -3
- package/dist/client.d.ts +2 -0
- package/dist/client.js +19 -0
- package/dist/config-wizard.d.ts +5 -0
- package/dist/config-wizard.js +102 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -68,16 +68,59 @@ PermissionRequest Hook 拦截
|
|
|
68
68
|
|
|
69
69
|
### 前置要求
|
|
70
70
|
|
|
71
|
-
- Node.js >= 18
|
|
71
|
+
- **Node.js >= 18**(必需)
|
|
72
72
|
- 企业微信账号(有创建机器人权限)
|
|
73
73
|
- Claude Code 已安装
|
|
74
74
|
|
|
75
|
+
### 安装 Node.js
|
|
76
|
+
|
|
77
|
+
**检查版本**:
|
|
78
|
+
```bash
|
|
79
|
+
node --version
|
|
80
|
+
# 输出应 >= v18.0.0
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
**安装方式**:
|
|
84
|
+
|
|
85
|
+
**macOS**:
|
|
86
|
+
```bash
|
|
87
|
+
# 使用 Homebrew
|
|
88
|
+
brew install node
|
|
89
|
+
|
|
90
|
+
# 或使用 nvm(推荐,可管理多版本)
|
|
91
|
+
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
|
|
92
|
+
nvm install 18
|
|
93
|
+
nvm use 18
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
**Windows**:
|
|
97
|
+
```bash
|
|
98
|
+
# 使用 winget
|
|
99
|
+
winget install OpenJS.NodeJS.LTS
|
|
100
|
+
|
|
101
|
+
# 或下载安装包:https://nodejs.org/
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**Linux**:
|
|
105
|
+
```bash
|
|
106
|
+
# Ubuntu/Debian
|
|
107
|
+
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
|
|
108
|
+
sudo apt-get install -y nodejs
|
|
109
|
+
|
|
110
|
+
# 或使用 nvm
|
|
111
|
+
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
|
|
112
|
+
nvm install 18
|
|
113
|
+
nvm use 18
|
|
114
|
+
```
|
|
115
|
+
|
|
75
116
|
### 方式一:npx 直接运行(推荐)
|
|
76
117
|
|
|
77
118
|
```bash
|
|
78
119
|
npx @vrs-soft/wecom-aibot-mcp
|
|
79
120
|
```
|
|
80
121
|
|
|
122
|
+
运行后会自动启动配置向导,配置完成后自动退出。
|
|
123
|
+
|
|
81
124
|
### 方式二:全局安装
|
|
82
125
|
|
|
83
126
|
```bash
|
|
@@ -345,6 +388,29 @@ Claude:(设置定时任务)
|
|
|
345
388
|
|
|
346
389
|
## 故障排查
|
|
347
390
|
|
|
391
|
+
### 认证失败(错误码 40058)
|
|
392
|
+
|
|
393
|
+
**可能原因**:
|
|
394
|
+
- 机器人未授权
|
|
395
|
+
- Bot ID 或 Secret 配置错误
|
|
396
|
+
- 新建机器人需要等待同步时间
|
|
397
|
+
|
|
398
|
+
**解决方法**:
|
|
399
|
+
```
|
|
400
|
+
1. 新建机器人需要等待约 2 分钟同步时间,请稍后再试
|
|
401
|
+
|
|
402
|
+
2. 完成机器人授权(任选其一):
|
|
403
|
+
• 在电脑端企业微信APP中打开:机器人详情 → 可使用权限 → 授权
|
|
404
|
+
• 打开浏览器访问授权页面,使用手机企业微信扫码:
|
|
405
|
+
https://work.weixin.qq.com/ai/aiHelper/authorizationPage?str_aibotid={BotID}&type=6&from=chat&forceInnerBrowser=1
|
|
406
|
+
|
|
407
|
+
3. 确认 Bot ID 和 Secret 是否正确:
|
|
408
|
+
npx @vrs-soft/wecom-aibot-mcp --status
|
|
409
|
+
|
|
410
|
+
4. 如需重新配置:
|
|
411
|
+
npx @vrs-soft/wecom-aibot-mcp --config
|
|
412
|
+
```
|
|
413
|
+
|
|
348
414
|
### 无法收到消息
|
|
349
415
|
|
|
350
416
|
**可能原因**:
|
|
@@ -395,6 +461,72 @@ ls ~/.wecom-aibot-mcp/port-*
|
|
|
395
461
|
rm ~/.wecom-aibot-mcp/port-*
|
|
396
462
|
```
|
|
397
463
|
|
|
464
|
+
## 卸载
|
|
465
|
+
|
|
466
|
+
如需完全卸载,运行:
|
|
467
|
+
|
|
468
|
+
```bash
|
|
469
|
+
npx @vrs-soft/wecom-aibot-mcp --uninstall
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
这会删除:
|
|
473
|
+
- 配置文件:`~/.wecom-aibot-mcp/config.json`
|
|
474
|
+
- MCP 配置:`~/.claude.json` 中的 `wecom-aibot` 条目
|
|
475
|
+
- Hook 脚本:`~/.wecom-aibot-mcp/permission-hook.sh`
|
|
476
|
+
- Hook 配置:`~/.claude/settings.local.json` 中的 PermissionRequest hook
|
|
477
|
+
- Skill 文件:`~/.claude/skills/headless-mode/`
|
|
478
|
+
|
|
479
|
+
卸载后如需重新安装:
|
|
480
|
+
|
|
481
|
+
```bash
|
|
482
|
+
npx @vrs-soft/wecom-aibot-mcp --config
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
## 修改和增加 Bot
|
|
486
|
+
|
|
487
|
+
### 修改现有 Bot 配置
|
|
488
|
+
|
|
489
|
+
如果需要更换机器人或修改目标用户:
|
|
490
|
+
|
|
491
|
+
```bash
|
|
492
|
+
npx @vrs-soft/wecom-aibot-mcp --config
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
这会重新启动配置向导,让你输入新的 Bot ID、Secret 和目标用户 ID。
|
|
496
|
+
|
|
497
|
+
### 增加多个 Bot(多用户场景)
|
|
498
|
+
|
|
499
|
+
每个用户可以使用独立的机器人,在 `~/.claude.json` 中配置多个 MCP Server 实例:
|
|
500
|
+
|
|
501
|
+
```json
|
|
502
|
+
{
|
|
503
|
+
"mcpServers": {
|
|
504
|
+
"wecom-aibot-zhangsan": {
|
|
505
|
+
"command": "npx",
|
|
506
|
+
"args": ["@vrs-soft/wecom-aibot-mcp"],
|
|
507
|
+
"env": {
|
|
508
|
+
"WECOM_BOT_ID": "bot_zhangsan",
|
|
509
|
+
"WECOM_SECRET": "secret_zhangsan",
|
|
510
|
+
"WECOM_TARGET_USER": "zhangsan"
|
|
511
|
+
}
|
|
512
|
+
},
|
|
513
|
+
"wecom-aibot-lisi": {
|
|
514
|
+
"command": "npx",
|
|
515
|
+
"args": ["@vrs-soft/wecom-aibot-mcp"],
|
|
516
|
+
"env": {
|
|
517
|
+
"WECOM_BOT_ID": "bot_lisi",
|
|
518
|
+
"WECOM_SECRET": "secret_lisi",
|
|
519
|
+
"WECOM_TARGET_USER": "lisi"
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
使用环境变量配置时,每个实例自动独立运行,无需额外的配置文件。
|
|
527
|
+
|
|
528
|
+
> ⚠️ 注意:同一个机器人同时只能保持一个 WebSocket 长连接,不要在多个实例中使用相同的 Bot ID。
|
|
529
|
+
|
|
398
530
|
## 安全建议
|
|
399
531
|
|
|
400
532
|
1. **保护凭证**:Bot ID 和 Secret 不要提交到代码仓库
|
package/dist/bin.js
CHANGED
|
@@ -4,13 +4,30 @@
|
|
|
4
4
|
*
|
|
5
5
|
* npx 运行入口
|
|
6
6
|
*/
|
|
7
|
-
import
|
|
7
|
+
import * as readline from 'readline';
|
|
8
|
+
import { runConfigWizard, loadConfig, deleteConfig, uninstall, ensureHookInstalled } from './config-wizard.js';
|
|
8
9
|
import { initClient } from './client.js';
|
|
9
10
|
import { registerTools } from './tools/index.js';
|
|
10
11
|
import { startHttpServer } from './http-server.js';
|
|
11
12
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
12
13
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
13
14
|
const VERSION = '1.0.0';
|
|
15
|
+
// 等待连接验证(最多等待 10 秒)
|
|
16
|
+
async function waitForConnection(client, timeoutMs = 10000) {
|
|
17
|
+
return new Promise((resolve) => {
|
|
18
|
+
const startTime = Date.now();
|
|
19
|
+
const checkInterval = setInterval(() => {
|
|
20
|
+
if (client.isConnected()) {
|
|
21
|
+
clearInterval(checkInterval);
|
|
22
|
+
resolve(true);
|
|
23
|
+
}
|
|
24
|
+
else if (Date.now() - startTime > timeoutMs) {
|
|
25
|
+
clearInterval(checkInterval);
|
|
26
|
+
resolve(false);
|
|
27
|
+
}
|
|
28
|
+
}, 500);
|
|
29
|
+
});
|
|
30
|
+
}
|
|
14
31
|
function showHelp() {
|
|
15
32
|
console.log(`
|
|
16
33
|
企业微信智能机器人 MCP 服务 v${VERSION}
|
|
@@ -26,6 +43,7 @@ function showHelp() {
|
|
|
26
43
|
--version, -v 显示版本号
|
|
27
44
|
--config 重新配置(修改 Bot ID / Secret / 目标用户)
|
|
28
45
|
--status 显示当前配置状态
|
|
46
|
+
--uninstall 卸载并删除所有配置(包括 MCP 配置、hook、skill)
|
|
29
47
|
|
|
30
48
|
配置方式(按优先级):
|
|
31
49
|
1. 环境变量(推荐多实例场景):
|
|
@@ -111,7 +129,12 @@ async function main() {
|
|
|
111
129
|
showStatus();
|
|
112
130
|
process.exit(0);
|
|
113
131
|
}
|
|
132
|
+
if (args.includes('--uninstall')) {
|
|
133
|
+
uninstall();
|
|
134
|
+
process.exit(0);
|
|
135
|
+
}
|
|
114
136
|
const reconfig = args.includes('--config');
|
|
137
|
+
const isInteractive = process.stdin.isTTY; // 是否为用户交互模式
|
|
115
138
|
console.log('');
|
|
116
139
|
console.log(' ╔════════════════════════════════════════════════════════╗');
|
|
117
140
|
console.log(` ║ 企业微信智能机器人 MCP 服务 v${VERSION} ║`);
|
|
@@ -120,12 +143,30 @@ async function main() {
|
|
|
120
143
|
console.log('');
|
|
121
144
|
// 获取或初始化配置
|
|
122
145
|
let config;
|
|
146
|
+
let ranWizard = false; // 是否运行了配置向导
|
|
123
147
|
if (reconfig) {
|
|
124
148
|
console.log('[config] 重新配置模式\n');
|
|
125
149
|
config = await runConfigWizard();
|
|
150
|
+
ranWizard = true;
|
|
126
151
|
}
|
|
127
152
|
else {
|
|
128
|
-
|
|
153
|
+
// 检查是否已有配置
|
|
154
|
+
const savedConfig = loadConfig();
|
|
155
|
+
if (savedConfig && savedConfig.botId && savedConfig.secret && savedConfig.targetUserId) {
|
|
156
|
+
config = savedConfig;
|
|
157
|
+
}
|
|
158
|
+
else if (isInteractive) {
|
|
159
|
+
// TTY 模式下没有配置,启动配置向导
|
|
160
|
+
console.log('[config] 未找到配置,启动配置向导...\n');
|
|
161
|
+
config = await runConfigWizard();
|
|
162
|
+
ranWizard = true;
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
// 非 TTY 模式(MCP stdio),必须有配置
|
|
166
|
+
console.error('[config] 未找到配置,且当前为非交互模式。');
|
|
167
|
+
console.error('[config] 请在终端运行: npx @vrs-soft/wecom-aibot-mcp --config');
|
|
168
|
+
process.exit(1);
|
|
169
|
+
}
|
|
129
170
|
}
|
|
130
171
|
// 确保 hook 已安装(幂等,每次启动检查)
|
|
131
172
|
ensureHookInstalled();
|
|
@@ -133,6 +174,51 @@ async function main() {
|
|
|
133
174
|
console.log(`[mcp] 初始化企业微信客户端...`);
|
|
134
175
|
console.log(`[mcp] 默认目标用户: ${config.targetUserId}`);
|
|
135
176
|
const wecomClient = initClient(config.botId, config.secret, config.targetUserId);
|
|
177
|
+
// 等待连接验证
|
|
178
|
+
console.log('[mcp] 等待连接验证...');
|
|
179
|
+
const connected = await waitForConnection(wecomClient, 10000);
|
|
180
|
+
if (!connected) {
|
|
181
|
+
console.log('[mcp] 连接失败,可能是配置错误或机器人未授权');
|
|
182
|
+
console.log('[mcp] 请检查上面的错误提示,修复后重新配置');
|
|
183
|
+
// 删除无效配置,让用户重新输入
|
|
184
|
+
deleteConfig();
|
|
185
|
+
if (isInteractive) {
|
|
186
|
+
// TTY 模式询问是否重新配置
|
|
187
|
+
console.log('\n是否重新配置?(Y/n): ');
|
|
188
|
+
const rl = readline.createInterface({
|
|
189
|
+
input: process.stdin,
|
|
190
|
+
output: process.stdout,
|
|
191
|
+
});
|
|
192
|
+
const answer = await new Promise((resolve) => {
|
|
193
|
+
rl.question('', (a) => resolve(a.trim().toLowerCase()));
|
|
194
|
+
});
|
|
195
|
+
rl.close();
|
|
196
|
+
if (answer !== 'n') {
|
|
197
|
+
console.log('\n[mcp] 启动重新配置...\n');
|
|
198
|
+
config = await runConfigWizard();
|
|
199
|
+
const newClient = initClient(config.botId, config.secret, config.targetUserId);
|
|
200
|
+
const newConnected = await waitForConnection(newClient, 10000);
|
|
201
|
+
if (!newConnected) {
|
|
202
|
+
console.log('[mcp] 连接仍然失败,请稍后再试(新建机器人需等待约 2 分钟同步)');
|
|
203
|
+
deleteConfig();
|
|
204
|
+
process.exit(1);
|
|
205
|
+
}
|
|
206
|
+
// 连接成功,如果是交互模式则退出
|
|
207
|
+
console.log('\n[mcp] ✅ 配置成功!');
|
|
208
|
+
console.log('[mcp] 请重启 Claude Code 以加载 MCP 服务\n');
|
|
209
|
+
process.exit(0);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
process.exit(1);
|
|
213
|
+
}
|
|
214
|
+
// 连接成功
|
|
215
|
+
if (isInteractive && (ranWizard || reconfig)) {
|
|
216
|
+
// 用户手动运行配置向导,配置成功后退出
|
|
217
|
+
console.log('\n[mcp] ✅ 配置成功!');
|
|
218
|
+
console.log('[mcp] 请重启 Claude Code 以加载 MCP 服务\n');
|
|
219
|
+
process.exit(0);
|
|
220
|
+
}
|
|
221
|
+
// 非 TTY 模式(MCP stdio),启动 MCP Server
|
|
136
222
|
// 启动本地 HTTP 服务(用于 hooks 审批)
|
|
137
223
|
await startHttpServer(wecomClient);
|
|
138
224
|
// 创建 MCP Server
|
|
@@ -147,10 +233,20 @@ async function main() {
|
|
|
147
233
|
const transport = new StdioServerTransport();
|
|
148
234
|
await server.connect(transport);
|
|
149
235
|
// 定期清理过期消息
|
|
150
|
-
setInterval(() => {
|
|
236
|
+
const cleanupInterval = setInterval(() => {
|
|
151
237
|
wecomClient.cleanupMessages();
|
|
152
238
|
}, 60000);
|
|
153
239
|
console.log('[mcp] MCP Server 已就绪');
|
|
240
|
+
// 退出处理:清理资源
|
|
241
|
+
const gracefulShutdown = () => {
|
|
242
|
+
console.log('[mcp] 正在关闭...');
|
|
243
|
+
clearInterval(cleanupInterval);
|
|
244
|
+
wecomClient.disconnect();
|
|
245
|
+
process.exit(0);
|
|
246
|
+
};
|
|
247
|
+
// 监听进程信号
|
|
248
|
+
process.on('SIGINT', gracefulShutdown);
|
|
249
|
+
process.on('SIGTERM', gracefulShutdown);
|
|
154
250
|
}
|
|
155
251
|
main().catch((err) => {
|
|
156
252
|
console.error('[mcp] 启动失败:', err);
|
package/dist/client.d.ts
CHANGED
|
@@ -19,7 +19,9 @@ declare class WecomClient {
|
|
|
19
19
|
private messages;
|
|
20
20
|
private connected;
|
|
21
21
|
private targetUserId;
|
|
22
|
+
private botId;
|
|
22
23
|
constructor(botId: string, secret: string, targetUserId: string);
|
|
24
|
+
getAuthUrl(): string;
|
|
23
25
|
private setupEventHandlers;
|
|
24
26
|
private handleMessage;
|
|
25
27
|
private handleApprovalResponse;
|
package/dist/client.js
CHANGED
|
@@ -11,7 +11,9 @@ class WecomClient {
|
|
|
11
11
|
messages = [];
|
|
12
12
|
connected = false;
|
|
13
13
|
targetUserId;
|
|
14
|
+
botId; // 保存 botId 用于生成授权 URL
|
|
14
15
|
constructor(botId, secret, targetUserId) {
|
|
16
|
+
this.botId = botId;
|
|
15
17
|
this.targetUserId = targetUserId;
|
|
16
18
|
this.wsClient = new AiBot.WSClient({
|
|
17
19
|
botId,
|
|
@@ -21,6 +23,10 @@ class WecomClient {
|
|
|
21
23
|
});
|
|
22
24
|
this.setupEventHandlers();
|
|
23
25
|
}
|
|
26
|
+
// 生成授权页面 URL
|
|
27
|
+
getAuthUrl() {
|
|
28
|
+
return `https://work.weixin.qq.com/ai/aiHelper/authorizationPage?str_aibotid=${this.botId}&type=6&from=chat&forceInnerBrowser=1`;
|
|
29
|
+
}
|
|
24
30
|
setupEventHandlers() {
|
|
25
31
|
this.wsClient.on('connected', () => {
|
|
26
32
|
console.log('[wecom] WebSocket 连接已建立');
|
|
@@ -38,6 +44,19 @@ class WecomClient {
|
|
|
38
44
|
});
|
|
39
45
|
this.wsClient.on('error', (err) => {
|
|
40
46
|
console.error(`[wecom] 错误: ${err.message}`);
|
|
47
|
+
// 检测授权相关错误(40058: invalid Request Parameter)
|
|
48
|
+
if (err.message.includes('40058') || err.message.includes('invalid Request Parameter')) {
|
|
49
|
+
console.log('');
|
|
50
|
+
console.log(' ⚠️ 机器人未授权或配置有误,请检查以下事项:');
|
|
51
|
+
console.log('');
|
|
52
|
+
console.log(' 1. 新建机器人需要等待约 2 分钟同步时间,请稍后再试');
|
|
53
|
+
console.log(' 2. 确认 Bot ID 和 Secret 是否正确');
|
|
54
|
+
console.log(' 3. 完成机器人授权(任选其一):');
|
|
55
|
+
console.log(' • 在电脑端企业微信APP中打开:机器人详情 → 可使用权限 → 授权');
|
|
56
|
+
console.log(' • 打开浏览器访问以下地址,使用手机企业微信扫码授权:');
|
|
57
|
+
console.log(` ${this.getAuthUrl()}`);
|
|
58
|
+
console.log('');
|
|
59
|
+
}
|
|
41
60
|
});
|
|
42
61
|
// 监听所有消息(存储到队列)
|
|
43
62
|
this.wsClient.on('message', (frame) => {
|
package/dist/config-wizard.d.ts
CHANGED
|
@@ -5,6 +5,11 @@ export interface WecomConfig {
|
|
|
5
5
|
targetUserName?: string;
|
|
6
6
|
}
|
|
7
7
|
export declare function loadConfig(): WecomConfig | null;
|
|
8
|
+
export declare function deleteConfig(): void;
|
|
9
|
+
export declare function deleteMcpConfig(): void;
|
|
10
|
+
export declare function deleteHook(): void;
|
|
11
|
+
export declare function deleteSkills(): void;
|
|
12
|
+
export declare function uninstall(): void;
|
|
8
13
|
export declare function ensureHookInstalled(): void;
|
|
9
14
|
export declare function saveConfig(config: WecomConfig): void;
|
|
10
15
|
/**
|
package/dist/config-wizard.js
CHANGED
|
@@ -43,6 +43,108 @@ export function loadConfig() {
|
|
|
43
43
|
}
|
|
44
44
|
return null;
|
|
45
45
|
}
|
|
46
|
+
// 删除已保存的配置(连接失败时让用户重新输入)
|
|
47
|
+
export function deleteConfig() {
|
|
48
|
+
try {
|
|
49
|
+
if (fs.existsSync(CONFIG_FILE)) {
|
|
50
|
+
fs.unlinkSync(CONFIG_FILE);
|
|
51
|
+
console.log('[config] 已删除配置文件');
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
console.error('[config] 删除配置失败:', err);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
// 删除 MCP Server 配置(从 ~/.claude.json)
|
|
59
|
+
export function deleteMcpConfig() {
|
|
60
|
+
try {
|
|
61
|
+
if (fs.existsSync(CLAUDE_CONFIG_FILE)) {
|
|
62
|
+
const content = fs.readFileSync(CLAUDE_CONFIG_FILE, 'utf-8');
|
|
63
|
+
const claudeConfig = JSON.parse(content);
|
|
64
|
+
if (claudeConfig.mcpServers && claudeConfig.mcpServers['wecom-aibot']) {
|
|
65
|
+
delete claudeConfig.mcpServers['wecom-aibot'];
|
|
66
|
+
fs.writeFileSync(CLAUDE_CONFIG_FILE, JSON.stringify(claudeConfig, null, 2));
|
|
67
|
+
console.log('[config] 已从 ~/.claude.json 删除 wecom-aibot MCP 配置');
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
console.log('[config] ~/.claude.json 中未找到 wecom-aibot 配置');
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
catch (err) {
|
|
75
|
+
console.error('[config] 删除 MCP 配置失败:', err);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// 删除 PermissionRequest hook(从 ~/.claude/settings.local.json)
|
|
79
|
+
export function deleteHook() {
|
|
80
|
+
try {
|
|
81
|
+
if (fs.existsSync(CLAUDE_SETTINGS_FILE)) {
|
|
82
|
+
const content = fs.readFileSync(CLAUDE_SETTINGS_FILE, 'utf-8');
|
|
83
|
+
const settings = JSON.parse(content);
|
|
84
|
+
if (settings.hooks && settings.hooks['PermissionRequest']) {
|
|
85
|
+
// 只删除 wecom-aibot 相关的 hook
|
|
86
|
+
settings.hooks['PermissionRequest'] = settings.hooks['PermissionRequest'].filter((hook) => !hook.hooks?.some?.((h) => h.command?.includes?.('wecom-aibot-mcp')));
|
|
87
|
+
if (settings.hooks['PermissionRequest'].length === 0) {
|
|
88
|
+
delete settings.hooks['PermissionRequest'];
|
|
89
|
+
}
|
|
90
|
+
fs.writeFileSync(CLAUDE_SETTINGS_FILE, JSON.stringify(settings, null, 2));
|
|
91
|
+
console.log('[config] 已删除 PermissionRequest hook');
|
|
92
|
+
}
|
|
93
|
+
// 删除 hook 脚本文件
|
|
94
|
+
if (fs.existsSync(HOOK_SCRIPT_PATH)) {
|
|
95
|
+
fs.unlinkSync(HOOK_SCRIPT_PATH);
|
|
96
|
+
console.log('[config] 已删除 hook 脚本文件');
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
catch (err) {
|
|
101
|
+
console.error('[config] 删除 hook 失败:', err);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
// 删除 skill 文件
|
|
105
|
+
export function deleteSkills() {
|
|
106
|
+
try {
|
|
107
|
+
const skillDir = path.join(os.homedir(), '.claude', 'skills', 'headless-mode');
|
|
108
|
+
if (fs.existsSync(skillDir)) {
|
|
109
|
+
fs.rmSync(skillDir, { recursive: true });
|
|
110
|
+
console.log('[config] 已删除 skill 文件');
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
catch (err) {
|
|
114
|
+
console.error('[config] 删除 skill 失败:', err);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
// 完全卸载(删除所有相关配置)
|
|
118
|
+
export function uninstall() {
|
|
119
|
+
console.log('\n[config] 开始卸载 wecom-aibot-mcp...\n');
|
|
120
|
+
deleteConfig();
|
|
121
|
+
deleteMcpConfig();
|
|
122
|
+
deleteHook();
|
|
123
|
+
deleteSkills();
|
|
124
|
+
// 删除配置目录
|
|
125
|
+
if (fs.existsSync(CONFIG_DIR)) {
|
|
126
|
+
try {
|
|
127
|
+
// 删除所有 port-* 和 headless-* 文件
|
|
128
|
+
const files = fs.readdirSync(CONFIG_DIR);
|
|
129
|
+
for (const file of files) {
|
|
130
|
+
if (file.startsWith('port-') || file.startsWith('headless-')) {
|
|
131
|
+
fs.unlinkSync(path.join(CONFIG_DIR, file));
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
// 如果目录为空,删除目录
|
|
135
|
+
const remainingFiles = fs.readdirSync(CONFIG_DIR);
|
|
136
|
+
if (remainingFiles.length === 0) {
|
|
137
|
+
fs.rmSync(CONFIG_DIR);
|
|
138
|
+
console.log('[config] 已删除配置目录');
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
catch (err) {
|
|
142
|
+
console.error('[config] 删除配置目录失败:', err);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
console.log('\n[config] 卸载完成');
|
|
146
|
+
console.log('[config] 如需重新安装,请运行: npx @vrs-soft/wecom-aibot-mcp --config\n');
|
|
147
|
+
}
|
|
46
148
|
// 生成并写入 hook 脚本(多实例 + headless 模式支持)
|
|
47
149
|
function writeHookScript() {
|
|
48
150
|
const script = `#!/bin/bash
|